Palacios Public Git Repository

To checkout Palacios execute

  git clone http://v3vee.org/palacios/palacios.web/palacios.git
This will give you the master branch. You probably want the devel branch or one of the release branches. To switch to the devel branch, simply execute
  cd palacios
  git checkout --track -b devel origin/devel
The other branches are similar.


48097d8322d74bd4a63b88acb2eff0cc3d6b1a86
[palacios.git] / linux_module / iface-host-pci.c
1 /* Host PCI interface 
2  *  (c) Jack Lange, 2012
3  *  jacklange@cs.pitt.edu 
4  */
5
6 #include <linux/uaccess.h>
7 #include <linux/fs.h>
8 #include <linux/kernel.h>
9 #include <linux/module.h>
10
11 #include "palacios.h"
12 #include "linux-exts.h"
13
14
15 #include <interfaces/host_pci.h>
16
17 static struct list_head device_list;
18 static spinlock_t lock;
19
20
21
22
23 struct pci_dev;
24 struct iommu_domain;
25
26 struct host_pci_device {
27     char name[128];
28     
29     enum {PASSTHROUGH, USER} type; 
30   
31     enum {INTX_IRQ, MSI_IRQ, MSIX_IRQ} irq_type;
32     uint32_t num_vecs;
33
34     union {
35         struct {    
36             u8 in_use;
37             u8 iommu_enabled;
38             
39             u32 bus;
40             u32 devfn;
41             
42             spinlock_t intx_lock;
43             u8 intx_disabled;
44
45             u32 num_msix_vecs;
46             struct msix_entry * msix_entries;
47             struct iommu_domain * iommu_domain;
48             
49             struct pci_dev * dev; 
50         } hw_dev;
51
52         //      struct user_dev_state user_dev;
53     };
54
55     struct v3_host_pci_dev v3_dev;
56
57     struct list_head dev_node;
58 };
59
60
61 //#include "iface-host-pci-user.h"
62 #include "iface-host-pci-hw.h"
63
64
65 static struct host_pci_device * find_dev_by_name(char * name) {
66     struct host_pci_device * dev = NULL;
67
68     list_for_each_entry(dev, &device_list, dev_node) {
69         if (strncmp(dev->name, name, 128) == 0) {
70             return dev;
71         }
72     }
73
74     return NULL;
75 }
76
77
78
79 static struct v3_host_pci_dev * request_pci_dev(char * url, void * v3_ctx) {
80    
81     unsigned long flags;
82     struct host_pci_device * host_dev = NULL;
83
84     palacios_spinlock_lock_irqsave(&lock, flags);
85     host_dev = find_dev_by_name(url);
86     palacios_spinlock_unlock_irqrestore(&lock, flags);
87     
88     if (host_dev == NULL) {
89         printk("Could not find host device (%s)\n", url);
90         return NULL;
91     }
92
93     if (host_dev->type == PASSTHROUGH) {
94         if (reserve_hw_pci_dev(host_dev, v3_ctx) == -1) {
95             printk("Could not reserve host device (%s)\n", url);
96             return NULL;
97         }
98     } else {
99         printk("Unsupported Host device type\n");
100         return NULL;
101     }
102
103
104
105     return &(host_dev->v3_dev);
106
107 }
108
109
110 static int host_pci_config_write(struct v3_host_pci_dev * v3_dev, unsigned int reg_num, 
111                                   void * src, unsigned int length) {
112     struct host_pci_device * host_dev = v3_dev->host_data;
113
114     if (host_dev->type == PASSTHROUGH) {
115         return write_hw_pci_config(host_dev, reg_num, src, length);
116     }
117  
118     printk("Error in config write handler\n");
119     return -1;
120 }
121
122 static int host_pci_config_read(struct v3_host_pci_dev * v3_dev, unsigned int reg_num, 
123                                   void * dst, unsigned int length) {
124     struct host_pci_device * host_dev = v3_dev->host_data;
125
126     if (host_dev->type == PASSTHROUGH) {
127         return read_hw_pci_config(host_dev, reg_num, dst, length);
128     }
129  
130     printk("Error in config read handler\n");
131     return -1;
132 }
133
134
135 static int host_pci_ack_irq(struct v3_host_pci_dev * v3_dev, unsigned int vector) {
136     struct host_pci_device * host_dev = v3_dev->host_data;
137
138     if (host_dev->type == PASSTHROUGH) {
139         return hw_ack_irq(host_dev, vector);
140     }
141  
142     printk("Error in config irq ack handler\n");
143     return -1;
144 }
145
146
147
148 static int host_pci_cmd(struct v3_host_pci_dev * v3_dev, host_pci_cmd_t cmd, u64 arg) {
149     struct host_pci_device * host_dev = v3_dev->host_data;
150
151     if (host_dev->type == PASSTHROUGH) {
152         return hw_pci_cmd(host_dev, cmd, arg);
153     }
154  
155     printk("Error in config pci cmd handler\n");
156     return -1;
157     
158 }
159
160 static struct v3_host_pci_hooks pci_hooks = {
161     .request_device = request_pci_dev,
162     .config_write = host_pci_config_write,
163     .config_read = host_pci_config_read,
164     .ack_irq = host_pci_ack_irq,
165     .pci_cmd = host_pci_cmd,
166
167 };
168
169
170
171 static int register_pci_hw_dev(unsigned int cmd, unsigned long arg) {
172     void __user * argp = (void __user *)arg;
173     struct v3_hw_pci_dev hw_dev_arg ;
174     struct host_pci_device * host_dev = NULL;
175     unsigned long flags;
176     int ret = 0;
177
178     if (copy_from_user(&hw_dev_arg, argp, sizeof(struct v3_hw_pci_dev))) {
179         printk("%s(%d): copy from user error...\n", __FILE__, __LINE__);
180         return -EFAULT;
181     }
182
183     host_dev = kzalloc(sizeof(struct host_pci_device), GFP_KERNEL);
184
185     
186     strncpy(host_dev->name, hw_dev_arg.name, 128);
187     host_dev->v3_dev.host_data = host_dev;
188     
189
190     host_dev->type = PASSTHROUGH;
191     host_dev->hw_dev.bus = hw_dev_arg.bus;
192     host_dev->hw_dev.devfn = PCI_DEVFN(hw_dev_arg.dev, hw_dev_arg.func);
193     
194
195     palacios_spinlock_lock_irqsave(&lock, flags);
196     if (!find_dev_by_name(hw_dev_arg.name)) {
197         list_add(&(host_dev->dev_node), &device_list);
198         ret = 1;
199     }
200     palacios_spinlock_unlock_irqrestore(&lock, flags);
201
202     if (ret == 0) {
203         // Error device already exists
204         palacios_free(host_dev);
205         return -EFAULT;
206     }
207
208     
209     setup_hw_pci_dev(host_dev);
210
211     return 0;
212 }
213
214
215 static int register_pci_user_dev(unsigned int cmd, unsigned long arg) {
216     return 0;
217 }
218
219
220
221
222 static int host_pci_init( void ) {
223     INIT_LIST_HEAD(&(device_list));
224     palacios_spinlock_init(&lock);
225
226     V3_Init_Host_PCI(&pci_hooks);
227     
228
229     add_global_ctrl(V3_ADD_PCI_HW_DEV, register_pci_hw_dev);
230     add_global_ctrl(V3_ADD_PCI_USER_DEV, register_pci_user_dev);
231
232     return 0;
233 }
234
235 static int host_pci_deinit(void) {
236   remove_global_ctrl(V3_ADD_PCI_USER_DEV);
237   remove_global_ctrl(V3_ADD_PCI_HW_DEV);
238
239   palacios_spinlock_deinit(&lock);
240   return 0;
241 }
242
243 static struct linux_ext host_pci_ext = {
244     .name = "HOST_PCI",
245     .init = host_pci_init,
246     .deinit = host_pci_deinit,
247 };
248
249
250
251 register_extension(&host_pci_ext);