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.


Cleanup and sanity-checking of use of strncpy/strcpy (Coverity static analysis)
[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->name[127] = 0;
188     host_dev->v3_dev.host_data = host_dev;
189     
190
191     host_dev->type = PASSTHROUGH;
192     host_dev->hw_dev.bus = hw_dev_arg.bus;
193     host_dev->hw_dev.devfn = PCI_DEVFN(hw_dev_arg.dev, hw_dev_arg.func);
194     
195
196     palacios_spinlock_lock_irqsave(&lock, flags);
197     if (!find_dev_by_name(hw_dev_arg.name)) {
198         list_add(&(host_dev->dev_node), &device_list);
199         ret = 1;
200     }
201     palacios_spinlock_unlock_irqrestore(&lock, flags);
202
203     if (ret == 0) {
204         // Error device already exists
205         palacios_free(host_dev);
206         return -EFAULT;
207     }
208
209     
210     setup_hw_pci_dev(host_dev);
211
212     return 0;
213 }
214
215
216 static int register_pci_user_dev(unsigned int cmd, unsigned long arg) {
217     return 0;
218 }
219
220
221
222
223 static int host_pci_init( void ) {
224     INIT_LIST_HEAD(&(device_list));
225     palacios_spinlock_init(&lock);
226
227     V3_Init_Host_PCI(&pci_hooks);
228     
229
230     add_global_ctrl(V3_ADD_PCI_HW_DEV, register_pci_hw_dev);
231     add_global_ctrl(V3_ADD_PCI_USER_DEV, register_pci_user_dev);
232
233     return 0;
234 }
235
236 static int host_pci_deinit(void) {
237   remove_global_ctrl(V3_ADD_PCI_USER_DEV);
238   remove_global_ctrl(V3_ADD_PCI_HW_DEV);
239
240   palacios_spinlock_deinit(&lock);
241   return 0;
242 }
243
244 static struct linux_ext host_pci_ext = {
245     .name = "HOST_PCI",
246     .init = host_pci_init,
247     .deinit = host_pci_deinit,
248 };
249
250
251
252 register_extension(&host_pci_ext);