vlib: add PCI MSI-X interrupt support (vfio only)
[vpp.git] / src / vlib / linux / pci.c
1 /*
2  * Copyright (c) 2016 Cisco and/or its affiliates.
3  * Licensed under the Apache License, Version 2.0 (the "License");
4  * you may not use this file except in compliance with the License.
5  * You may obtain a copy of the License at:
6  *
7  *     http://www.apache.org/licenses/LICENSE-2.0
8  *
9  * Unless required by applicable law or agreed to in writing, software
10  * distributed under the License is distributed on an "AS IS" BASIS,
11  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12  * See the License for the specific language governing permissions and
13  * limitations under the License.
14  */
15 /*
16  * pci.c: Linux user space PCI bus management.
17  *
18  * Copyright (c) 2008 Eliot Dresselhaus
19  *
20  * Permission is hereby granted, free of charge, to any person obtaining
21  * a copy of this software and associated documentation files (the
22  * "Software"), to deal in the Software without restriction, including
23  * without limitation the rights to use, copy, modify, merge, publish,
24  * distribute, sublicense, and/or sell copies of the Software, and to
25  * permit persons to whom the Software is furnished to do so, subject to
26  * the following conditions:
27  *
28  * The above copyright notice and this permission notice shall be
29  * included in all copies or substantial portions of the Software.
30  *
31  *  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
32  *  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
33  *  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
34  *  NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
35  *  LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
36  *  OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
37  *  WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
38  */
39
40 #include <vppinfra/linux/sysfs.h>
41
42 #include <vlib/vlib.h>
43 #include <vlib/pci/pci.h>
44 #include <vlib/unix/unix.h>
45
46 #include <sys/types.h>
47 #include <sys/stat.h>
48 #include <fcntl.h>
49 #include <dirent.h>
50 #include <sys/ioctl.h>
51 #include <net/if.h>
52 #include <linux/ethtool.h>
53 #include <linux/sockios.h>
54 #include <linux/vfio.h>
55 #include <sys/eventfd.h>
56
57 static const char *sysfs_pci_dev_path = "/sys/bus/pci/devices";
58 static const char *sysfs_pci_drv_path = "/sys/bus/pci/drivers";
59 static char *sysfs_mod_vfio_noiommu =
60   "/sys/module/vfio/parameters/enable_unsafe_noiommu_mode";
61
62 typedef struct
63 {
64   int fd;
65   void *addr;
66   size_t size;
67 } linux_pci_region_t;
68
69 typedef struct
70 {
71   int fd;
72   u32 clib_file_index;
73   union
74   {
75     pci_msix_handler_function_t *msix_handler;
76   };
77 } linux_pci_irq_t;
78
79 typedef enum
80 {
81   LINUX_PCI_DEVICE_TYPE_UNKNOWN,
82   LINUX_PCI_DEVICE_TYPE_UIO,
83   LINUX_PCI_DEVICE_TYPE_VFIO,
84 } linux_pci_device_type_t;
85
86 typedef struct
87 {
88   linux_pci_device_type_t type;
89   vlib_pci_dev_handle_t handle;
90   vlib_pci_addr_t addr;
91
92   /* Resource file descriptors. */
93   linux_pci_region_t *regions;
94
95   /* File descriptor for config space read/write. */
96   int config_fd;
97   u64 config_offset;
98
99   /* Device File descriptor */
100   int fd;
101
102   /* Minor device for uio device. */
103   u32 uio_minor;
104
105   /* Index given by clib_file_add. */
106   u32 clib_file_index;
107
108   /* Interrupt handler */
109   void (*interrupt_handler) (vlib_pci_dev_handle_t h);
110   linux_pci_irq_t *msix_irqs;
111
112   /* private data */
113   uword private_data;
114
115 } linux_pci_device_t;
116
117 typedef struct
118 {
119   int group;
120   int fd;
121   int refcnt;
122 } linux_pci_vfio_iommu_group_t;
123
124 /* Pool of PCI devices. */
125 typedef struct
126 {
127   vlib_main_t *vlib_main;
128   linux_pci_device_t *linux_pci_devices;
129
130   /* VFIO */
131   int vfio_container_fd;
132   int vfio_iommu_mode;
133
134   /* pool of IOMMU groups */
135   linux_pci_vfio_iommu_group_t *iommu_groups;
136
137   /* iommu group pool index by group id  hash */
138   uword *iommu_pool_index_by_group;
139
140 } linux_pci_main_t;
141
142 extern linux_pci_main_t linux_pci_main;
143
144 static linux_pci_device_t *
145 linux_pci_get_device (vlib_pci_dev_handle_t h)
146 {
147   linux_pci_main_t *lpm = &linux_pci_main;
148   return pool_elt_at_index (lpm->linux_pci_devices, h);
149 }
150
151 uword
152 vlib_pci_get_private_data (vlib_pci_dev_handle_t h)
153 {
154   linux_pci_device_t *d = linux_pci_get_device (h);
155   return d->private_data;
156 }
157
158 void
159 vlib_pci_set_private_data (vlib_pci_dev_handle_t h, uword private_data)
160 {
161   linux_pci_device_t *d = linux_pci_get_device (h);
162   d->private_data = private_data;
163 }
164
165 vlib_pci_addr_t *
166 vlib_pci_get_addr (vlib_pci_dev_handle_t h)
167 {
168   linux_pci_device_t *d = linux_pci_get_device (h);
169   return &d->addr;
170 }
171
172 /* Call to allocate/initialize the pci subsystem.
173    This is not an init function so that users can explicitly enable
174    pci only when it's needed. */
175 clib_error_t *pci_bus_init (vlib_main_t * vm);
176
177 linux_pci_main_t linux_pci_main;
178
179 vlib_pci_device_info_t *
180 vlib_pci_get_device_info (vlib_pci_addr_t * addr, clib_error_t ** error)
181 {
182   linux_pci_main_t *lpm = &linux_pci_main;
183   clib_error_t *err;
184   vlib_pci_device_info_t *di;
185   u8 *f = 0;
186   u32 tmp;
187   int fd;
188
189   di = clib_mem_alloc (sizeof (vlib_pci_device_info_t));
190   memset (di, 0, sizeof (vlib_pci_device_info_t));
191   di->addr.as_u32 = addr->as_u32;
192
193   u8 *dev_dir_name = format (0, "%s/%U", sysfs_pci_dev_path,
194                              format_vlib_pci_addr, addr);
195
196   f = format (0, "%v/config%c", dev_dir_name, 0);
197   fd = open ((char *) f, O_RDWR);
198
199   /* Try read-only access if write fails. */
200   if (fd < 0)
201     fd = open ((char *) f, O_RDONLY);
202
203   if (fd < 0)
204     {
205       err = clib_error_return_unix (0, "open `%s'", f);
206       goto error;
207     }
208
209   /* You can only read more that 64 bytes of config space as root; so we try to
210      read the full space but fall back to just the first 64 bytes. */
211   if (read (fd, &di->config_data, sizeof (di->config_data)) <
212       sizeof (di->config0))
213     {
214       err = clib_error_return_unix (0, "read `%s'", f);
215       close (fd);
216       goto error;
217     }
218
219   {
220     static pci_config_header_t all_ones;
221     if (all_ones.vendor_id == 0)
222       memset (&all_ones, ~0, sizeof (all_ones));
223
224     if (!memcmp (&di->config0.header, &all_ones, sizeof (all_ones)))
225       {
226         err = clib_error_return (0, "invalid PCI config for `%s'", f);
227         close (fd);
228         goto error;
229       }
230   }
231
232   if (di->config0.header.header_type == 0)
233     pci_config_type0_little_to_host (&di->config0);
234   else
235     pci_config_type1_little_to_host (&di->config1);
236
237   di->numa_node = -1;
238   vec_reset_length (f);
239   f = format (f, "%v/numa_node%c", dev_dir_name, 0);
240   err = clib_sysfs_read ((char *) f, "%u", &di->numa_node);
241   if (err)
242     {
243       di->numa_node = -1;
244       clib_error_free (err);
245     }
246
247   vec_reset_length (f);
248   f = format (f, "%v/class%c", dev_dir_name, 0);
249   err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
250   if (err)
251     goto error;
252   di->device_class = tmp >> 8;
253
254   vec_reset_length (f);
255   f = format (f, "%v/vendor%c", dev_dir_name, 0);
256   err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
257   if (err)
258     goto error;
259   di->vendor_id = tmp;
260
261   vec_reset_length (f);
262   f = format (f, "%v/device%c", dev_dir_name, 0);
263   err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
264   if (err)
265     goto error;
266   di->device_id = tmp;
267
268   vec_reset_length (f);
269   f = format (f, "%v/driver%c", dev_dir_name, 0);
270   di->driver_name = clib_sysfs_link_to_name ((char *) f);
271
272   di->iommu_group = -1;
273   if (lpm->vfio_container_fd != -1)
274     {
275       u8 *tmpstr;
276       vec_reset_length (f);
277       f = format (f, "%v/iommu_group%c", dev_dir_name, 0);
278       tmpstr = clib_sysfs_link_to_name ((char *) f);
279       if (tmpstr)
280         {
281           di->iommu_group = atoi ((char *) tmpstr);
282           vec_free (tmpstr);
283         }
284     }
285
286   close (fd);
287
288   vec_reset_length (f);
289   f = format (f, "%v/vpd%c", dev_dir_name, 0);
290   fd = open ((char *) f, O_RDONLY);
291   if (fd >= 0)
292     {
293       while (1)
294         {
295           u8 tag[3];
296           u8 *data = 0;
297           uword len;
298
299           if (read (fd, &tag, 3) != 3)
300             break;
301
302           if (tag[0] != 0x82 && tag[0] != 0x90 && tag[0] != 0x91)
303             break;
304
305           len = (tag[2] << 8) | tag[1];
306           vec_validate (data, len);
307
308           if (read (fd, data, len) != len)
309             {
310               vec_free (data);
311               break;
312             }
313           if (tag[0] == 0x82)
314             di->product_name = data;
315           else if (tag[0] == 0x90)
316             di->vpd_r = data;
317           else if (tag[0] == 0x91)
318             di->vpd_w = data;
319
320           data = 0;
321         }
322       close (fd);
323     }
324
325   goto done;
326
327 error:
328   vlib_pci_free_device_info (di);
329   di = 0;
330
331 done:
332   vec_free (f);
333   vec_free (dev_dir_name);
334   if (error)
335     *error = err;
336   else
337     clib_error_free (err);
338   return di;
339 }
340
341 static int
342 directory_exists (char *path)
343 {
344   struct stat s = { 0 };
345   if (stat (path, &s) == -1)
346     return 0;
347
348   return S_ISDIR (s.st_mode);
349 }
350
351 clib_error_t *
352 vlib_pci_bind_to_uio (vlib_pci_addr_t * addr, char *uio_drv_name)
353 {
354   clib_error_t *error = 0;
355   u8 *s = 0, *driver_name = 0;
356   DIR *dir = 0;
357   struct dirent *e;
358   vlib_pci_device_info_t *di;
359   int fd, clear_driver_override = 0;
360   u8 *dev_dir_name = format (0, "%s/%U", sysfs_pci_dev_path,
361                              format_vlib_pci_addr, addr);
362
363   di = vlib_pci_get_device_info (addr, &error);
364
365   if (error)
366     return error;
367
368   if (strncmp ("auto", uio_drv_name, 5) == 0)
369     {
370       int vfio_pci_loaded = 0;
371
372       if (directory_exists ("/sys/module/vfio_pci"))
373         vfio_pci_loaded = 1;
374
375       if (di->iommu_group != -1)
376         {
377           /* device is bound to IOMMU group */
378           if (!vfio_pci_loaded)
379             {
380               error = clib_error_return (0, "Skipping PCI device %U: device "
381                                          "is bound to IOMMU group and "
382                                          "vfio-pci driver is not loaded",
383                                          format_vlib_pci_addr, addr);
384               goto done;
385             }
386           else
387             uio_drv_name = "vfio-pci";
388         }
389       else
390         {
391           /* device is not bound to IOMMU group so we have multiple options */
392           if (vfio_pci_loaded &&
393               (error = clib_sysfs_write (sysfs_mod_vfio_noiommu, "Y")) == 0)
394             uio_drv_name = "vfio-pci";
395           else if (directory_exists ("/sys/module/uio_pci_generic"))
396             uio_drv_name = "uio_pci_generic";
397           else if (directory_exists ("/sys/module/igb_uio"))
398             uio_drv_name = "igb_uio";
399           else
400             {
401               clib_error_free (error);
402               error = clib_error_return (0, "Skipping PCI device %U: missing "
403                                          "kernel VFIO or UIO driver",
404                                          format_vlib_pci_addr, addr);
405               goto done;
406             }
407           clib_error_free (error);
408         }
409     }
410
411   s = format (s, "%v/driver%c", dev_dir_name, 0);
412   driver_name = clib_sysfs_link_to_name ((char *) s);
413   vec_reset_length (s);
414
415   if (driver_name &&
416       ((strcmp ("vfio-pci", (char *) driver_name) == 0) ||
417        (strcmp ("uio_pci_generic", (char *) driver_name) == 0) ||
418        (strcmp ("igb_uio", (char *) driver_name) == 0)))
419     goto done;
420
421   /* walk trough all linux interfaces and if interface belonging to
422      this device is founf check if interface is admin up  */
423   dir = opendir ("/sys/class/net");
424   s = format (s, "%U%c", format_vlib_pci_addr, addr, 0);
425
426   if (!dir)
427     {
428       error = clib_error_return (0, "Skipping PCI device %U: failed to "
429                                  "read /sys/class/net",
430                                  format_vlib_pci_addr, addr);
431       goto done;
432     }
433
434   fd = socket (PF_INET, SOCK_DGRAM, 0);
435   if (fd < 0)
436     {
437       error = clib_error_return_unix (0, "socket");
438       goto done;
439     }
440
441   while ((e = readdir (dir)))
442     {
443       struct ifreq ifr;
444       struct ethtool_drvinfo drvinfo;
445
446       if (e->d_name[0] == '.')  /* skip . and .. */
447         continue;
448
449       memset (&ifr, 0, sizeof ifr);
450       memset (&drvinfo, 0, sizeof drvinfo);
451       ifr.ifr_data = (char *) &drvinfo;
452       strncpy (ifr.ifr_name, e->d_name, IFNAMSIZ - 1);
453       drvinfo.cmd = ETHTOOL_GDRVINFO;
454       if (ioctl (fd, SIOCETHTOOL, &ifr) < 0)
455         {
456           /* Some interfaces (eg "lo") don't support this ioctl */
457           if ((errno != ENOTSUP) && (errno != ENODEV))
458             clib_unix_warning ("ioctl fetch intf %s bus info error",
459                                e->d_name);
460           continue;
461         }
462
463       if (strcmp ((char *) s, drvinfo.bus_info))
464         continue;
465
466       memset (&ifr, 0, sizeof (ifr));
467       strncpy (ifr.ifr_name, e->d_name, IFNAMSIZ - 1);
468       if (ioctl (fd, SIOCGIFFLAGS, &ifr) < 0)
469         {
470           error = clib_error_return_unix (0, "ioctl fetch intf %s flags",
471                                           e->d_name);
472           close (fd);
473           goto done;
474         }
475
476       if (ifr.ifr_flags & IFF_UP)
477         {
478           error = clib_error_return (0, "Skipping PCI device %U as host "
479                                      "interface %s is up",
480                                      format_vlib_pci_addr, addr, e->d_name);
481           close (fd);
482           goto done;
483         }
484     }
485
486   close (fd);
487   vec_reset_length (s);
488
489   s = format (s, "%v/driver/unbind%c", dev_dir_name, 0);
490   clib_sysfs_write ((char *) s, "%U", format_vlib_pci_addr, addr);
491   vec_reset_length (s);
492
493   s = format (s, "%v/driver_override%c", dev_dir_name, 0);
494   if (access ((char *) s, F_OK) == 0)
495     {
496       clib_sysfs_write ((char *) s, "%s", uio_drv_name);
497       clear_driver_override = 1;
498     }
499   else
500     {
501       vec_reset_length (s);
502       s = format (s, "%s/%s/new_id%c", sysfs_pci_drv_path, uio_drv_name, 0);
503       clib_sysfs_write ((char *) s, "0x%04x 0x%04x", di->vendor_id,
504                         di->device_id);
505     }
506   vec_reset_length (s);
507
508   s = format (s, "%s/%s/bind%c", sysfs_pci_drv_path, uio_drv_name, 0);
509   clib_sysfs_write ((char *) s, "%U", format_vlib_pci_addr, addr);
510   vec_reset_length (s);
511
512   if (clear_driver_override)
513     {
514       s = format (s, "%v/driver_override%c", dev_dir_name, 0);
515       clib_sysfs_write ((char *) s, "%c", 0);
516       vec_reset_length (s);
517     }
518
519 done:
520   closedir (dir);
521   vec_free (s);
522   vec_free (dev_dir_name);
523   vec_free (driver_name);
524   return error;
525 }
526
527
528 static clib_error_t *
529 scan_uio_dir (void *arg, u8 * path_name, u8 * file_name)
530 {
531   linux_pci_device_t *l = arg;
532   unformat_input_t input;
533
534   unformat_init_string (&input, (char *) file_name, vec_len (file_name));
535
536   if (!unformat (&input, "uio%d", &l->uio_minor))
537     abort ();
538
539   unformat_free (&input);
540   return 0;
541 }
542
543 static clib_error_t *
544 vfio_set_irqs (linux_pci_device_t * p, u32 index, u32 start, u32 count,
545                u32 flags, int *efds)
546 {
547   int data_len = efds ? count * sizeof (int) : 0;
548   u8 buf[sizeof (struct vfio_irq_set) + data_len];
549   struct vfio_irq_info irq_info = { 0 };
550   struct vfio_irq_set *irq_set = (struct vfio_irq_set *) buf;
551
552
553   irq_info.argsz = sizeof (struct vfio_irq_info);
554   irq_info.index = index;
555
556   if (ioctl (p->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info) < 0)
557     return clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_IRQ_INFO) "
558                                    "'%U'", format_vlib_pci_addr, &p->addr);
559
560   if (irq_info.count < start + count)
561     return clib_error_return_unix (0, "vfio_set_irq: unexistng interrupt on "
562                                    "'%U'", format_vlib_pci_addr, &p->addr);
563
564
565   if (efds)
566     {
567       flags |= VFIO_IRQ_SET_DATA_EVENTFD;
568       clib_memcpy (&irq_set->data, efds, data_len);
569     }
570   else
571     flags |= VFIO_IRQ_SET_DATA_NONE;
572
573   ASSERT ((flags & (VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_DATA_EVENTFD)) !=
574           (VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_DATA_EVENTFD));
575
576   irq_set->argsz = sizeof (struct vfio_irq_set) + data_len;
577   irq_set->index = index;
578   irq_set->start = start;
579   irq_set->count = count;
580   irq_set->flags = flags;
581
582   if (ioctl (p->fd, VFIO_DEVICE_SET_IRQS, irq_set) < 0)
583     return clib_error_return_unix (0, "%U:ioctl(VFIO_DEVICE_SET_IRQS) "
584                                    "[index = %u, start = %u, count = %u, "
585                                    "flags = 0x%x]",
586                                    format_vlib_pci_addr, &p->addr,
587                                    index, start, count, flags);
588   return 0;
589 }
590
591 static clib_error_t *
592 linux_pci_uio_read_ready (clib_file_t * uf)
593 {
594   int __attribute__ ((unused)) rv;
595   vlib_pci_dev_handle_t h = uf->private_data;
596   linux_pci_device_t *p = linux_pci_get_device (h);
597
598   u32 icount;
599   rv = read (uf->file_descriptor, &icount, 4);
600
601   if (p->interrupt_handler)
602     p->interrupt_handler (h);
603
604   vlib_pci_intr_enable (h);
605
606   return /* no error */ 0;
607 }
608
609 static clib_error_t *
610 linux_pci_vfio_unmask_intx (linux_pci_device_t * d)
611 {
612   clib_error_t *err = 0;
613   struct vfio_irq_set i = {
614     .argsz = sizeof (struct vfio_irq_set),
615     .start = 0,
616     .count = 1,
617     .index = VFIO_PCI_INTX_IRQ_INDEX,
618     .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK,
619   };
620
621   if (ioctl (d->fd, VFIO_DEVICE_SET_IRQS, &i) < 0)
622     {
623       err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_SET_IRQS) '%U'",
624                                     format_vlib_pci_addr, &d->addr);
625     }
626   return err;
627 }
628
629 clib_error_t *
630 vlib_pci_vfio_unmask_msix (vlib_pci_dev_handle_t h, u32 start, u32 count)
631 {
632   linux_pci_device_t *p = linux_pci_get_device (h);
633   return vfio_set_irqs (p, VFIO_PCI_MSIX_IRQ_INDEX, start, count,
634                         VFIO_IRQ_SET_ACTION_UNMASK, 0);
635 }
636
637 static clib_error_t *
638 linux_pci_uio_error_ready (clib_file_t * uf)
639 {
640   u32 error_index = (u32) uf->private_data;
641
642   return clib_error_return (0, "pci device %d: error", error_index);
643 }
644
645 static clib_error_t *
646 linux_pci_vfio_msix_read_ready (clib_file_t * uf)
647 {
648   int __attribute__ ((unused)) rv;
649   vlib_pci_dev_handle_t h = uf->private_data >> 16;
650   u16 line = uf->private_data & 0xffff;
651   linux_pci_device_t *p = linux_pci_get_device (h);
652   linux_pci_irq_t *irq = vec_elt_at_index (p->msix_irqs, line);
653
654   u64 icount;
655   rv = read (uf->file_descriptor, &icount, sizeof (icount));
656
657   if (irq->msix_handler)
658     irq->msix_handler (h, line);
659
660   return /* no error */ 0;
661 }
662
663 static clib_error_t *
664 linux_pci_vfio_intx_read_ready (clib_file_t * uf)
665 {
666   int __attribute__ ((unused)) rv;
667   vlib_pci_dev_handle_t h = uf->private_data;
668   linux_pci_device_t *p = linux_pci_get_device (h);
669
670   u64 icount;
671   rv = read (uf->file_descriptor, &icount, sizeof (icount));
672
673   if (p->interrupt_handler)
674     p->interrupt_handler (h);
675
676   linux_pci_vfio_unmask_intx (p);
677
678   return /* no error */ 0;
679 }
680
681 static clib_error_t *
682 linux_pci_vfio_error_ready (clib_file_t * uf)
683 {
684   u32 error_index = (u32) uf->private_data;
685
686   return clib_error_return (0, "pci device %d: error", error_index);
687 }
688
689 static clib_error_t *
690 add_device_uio (vlib_main_t * vm, linux_pci_device_t * p,
691                 vlib_pci_device_info_t * di, pci_device_registration_t * r)
692 {
693   clib_error_t *err = 0;
694   clib_file_t t = { 0 };
695   u8 *s = 0;
696
697   p->addr.as_u32 = di->addr.as_u32;
698   p->fd = -1;
699   p->type = LINUX_PCI_DEVICE_TYPE_UIO;
700
701   s = format (s, "%s/%U/config%c", sysfs_pci_dev_path,
702               format_vlib_pci_addr, &di->addr, 0);
703
704   p->config_fd = open ((char *) s, O_RDWR);
705   p->config_offset = 0;
706   vec_reset_length (s);
707
708   if (p->config_fd == -1)
709     {
710       err = clib_error_return_unix (0, "open '%s'", s);
711       goto error;
712     }
713
714   s = format (0, "%s/%U/uio", sysfs_pci_dev_path,
715               format_vlib_pci_addr, &di->addr);
716   foreach_directory_file ((char *) s, scan_uio_dir, p,  /* scan_dirs */
717                           1);
718   vec_reset_length (s);
719
720   s = format (s, "/dev/uio%d%c", p->uio_minor, 0);
721   p->fd = open ((char *) s, O_RDWR);
722   if (p->fd < 0)
723     {
724       err = clib_error_return_unix (0, "open '%s'", s);
725       goto error;
726     }
727
728   t.read_function = linux_pci_uio_read_ready;
729   t.file_descriptor = p->fd;
730   t.error_function = linux_pci_uio_error_ready;
731   t.private_data = p->handle;
732
733   p->clib_file_index = clib_file_add (&file_main, &t);
734   p->interrupt_handler = r->interrupt_handler;
735   err = r->init_function (vm, p->handle);
736
737 error:
738   free (s);
739   if (err)
740     {
741       if (p->config_fd != -1)
742         close (p->config_fd);
743       if (p->fd != -1)
744         close (p->fd);
745     }
746   return err;
747 }
748
749 clib_error_t *
750 vlib_pci_register_msix_handler (vlib_pci_dev_handle_t h, u32 start, u32 count,
751                                 pci_msix_handler_function_t * msix_handler)
752 {
753   clib_error_t *err = 0;
754   linux_pci_device_t *p = linux_pci_get_device (h);
755   u32 i;
756
757   if (p->type != LINUX_PCI_DEVICE_TYPE_VFIO)
758     return clib_error_return (0, "vfio driver is needed for MSI-X interrupt "
759                               "support");
760
761   /* *INDENT-OFF* */
762   vec_validate_init_empty (p->msix_irqs, start + count - 1, (linux_pci_irq_t)
763                            { .fd = -1});
764   /* *INDENT-ON* */
765
766   for (i = start; i < start + count; i++)
767     {
768       clib_file_t t = { 0 };
769       linux_pci_irq_t *irq = vec_elt_at_index (p->msix_irqs, i);
770       ASSERT (irq->fd == -1);
771
772       irq->fd = eventfd (0, EFD_NONBLOCK);
773       if (irq->fd == -1)
774         {
775           err = clib_error_return_unix (0, "eventfd");
776           goto error;
777         }
778
779       t.read_function = linux_pci_vfio_msix_read_ready;
780       t.file_descriptor = irq->fd;
781       t.error_function = linux_pci_vfio_error_ready;
782       t.private_data = p->handle << 16 | i;
783       t.description = format (0, "PCI %U MSI-X #%u", format_vlib_pci_addr,
784                               &p->addr, i);
785       irq->clib_file_index = clib_file_add (&file_main, &t);
786       irq->msix_handler = msix_handler;
787     }
788
789   return 0;
790
791 error:
792   while (i-- > start)
793     {
794       linux_pci_irq_t *irq = vec_elt_at_index (p->msix_irqs, i);
795       if (irq->fd != -1)
796         {
797           clib_file_del_by_index (&file_main, irq->clib_file_index);
798           close (irq->fd);
799           irq->fd = -1;
800         }
801     }
802   return err;
803 }
804
805 clib_error_t *
806 vlib_pci_enable_msix_irq (vlib_pci_dev_handle_t h, u16 start, u16 count)
807 {
808   linux_pci_device_t *p = linux_pci_get_device (h);
809   int fds[count];
810   int i;
811
812   if (p->type != LINUX_PCI_DEVICE_TYPE_VFIO)
813     return clib_error_return (0, "vfio driver is needed for MSI-X interrupt "
814                               "support");
815
816   for (i = start; i < start + count; i++)
817     {
818       linux_pci_irq_t *irq = vec_elt_at_index (p->msix_irqs, i);
819       fds[i] = irq->fd;
820     }
821
822   return vfio_set_irqs (p, VFIO_PCI_MSIX_IRQ_INDEX, start, count,
823                         VFIO_IRQ_SET_ACTION_TRIGGER, fds);
824 }
825
826 clib_error_t *
827 vlib_pci_disable_msix_irq (vlib_pci_dev_handle_t h, u16 start, u16 count)
828 {
829   linux_pci_device_t *p = linux_pci_get_device (h);
830   int i, fds[count];
831
832   if (p->type != LINUX_PCI_DEVICE_TYPE_VFIO)
833     return clib_error_return (0, "vfio driver is needed for MSI-X interrupt "
834                               "support");
835
836   for (i = start; i < start + count; i++)
837     fds[i] = -1;
838
839   return vfio_set_irqs (p, VFIO_PCI_MSIX_IRQ_INDEX, start, count,
840                         VFIO_IRQ_SET_ACTION_TRIGGER, fds);
841 }
842
843 static linux_pci_vfio_iommu_group_t *
844 get_vfio_iommu_group (int group)
845 {
846   linux_pci_main_t *lpm = &linux_pci_main;
847   uword *p;
848
849   p = hash_get (lpm->iommu_pool_index_by_group, group);
850
851   return p ? pool_elt_at_index (lpm->iommu_groups, p[0]) : 0;
852 }
853
854 static clib_error_t *
855 open_vfio_iommu_group (int group)
856 {
857   linux_pci_main_t *lpm = &linux_pci_main;
858   linux_pci_vfio_iommu_group_t *g;
859   clib_error_t *err = 0;
860   struct vfio_group_status group_status;
861   u8 *s = 0;
862   int fd;
863
864   g = get_vfio_iommu_group (group);
865   if (g)
866     {
867       g->refcnt++;
868       return 0;
869     }
870   s = format (s, "/dev/vfio/%u%c", group, 0);
871   fd = open ((char *) s, O_RDWR);
872   if (fd < 0)
873     return clib_error_return_unix (0, "open '%s'", s);
874
875   group_status.argsz = sizeof (group_status);
876   if (ioctl (fd, VFIO_GROUP_GET_STATUS, &group_status) < 0)
877     {
878       err = clib_error_return_unix (0, "ioctl(VFIO_GROUP_GET_STATUS) '%s'",
879                                     s);
880       goto error;
881     }
882
883   if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE))
884     {
885       err = clib_error_return (0, "iommu group %d is not viable (not all "
886                                "devices in this group bound to vfio-pci)",
887                                group);
888       goto error;
889     }
890
891   if (ioctl (fd, VFIO_GROUP_SET_CONTAINER, &lpm->vfio_container_fd) < 0)
892     {
893       err = clib_error_return_unix (0, "ioctl(VFIO_GROUP_SET_CONTAINER) '%s'",
894                                     s);
895       goto error;
896     }
897
898   if (lpm->vfio_iommu_mode == 0)
899     {
900       if (ioctl (lpm->vfio_container_fd, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU) <
901           0)
902         {
903           err = clib_error_return_unix (0, "ioctl(VFIO_SET_IOMMU) "
904                                         "'/dev/vfio/vfio'");
905           goto error;
906         }
907       lpm->vfio_iommu_mode = VFIO_TYPE1_IOMMU;
908     }
909
910
911   pool_get (lpm->iommu_groups, g);
912   g->fd = fd;
913   g->refcnt = 1;
914   hash_set (lpm->iommu_pool_index_by_group, group, g - lpm->iommu_groups);
915   vec_free (s);
916   return 0;
917 error:
918   close (fd);
919   return err;
920 }
921
922 static clib_error_t *
923 add_device_vfio (vlib_main_t * vm, linux_pci_device_t * p,
924                  vlib_pci_device_info_t * di, pci_device_registration_t * r)
925 {
926   linux_pci_vfio_iommu_group_t *g;
927   struct vfio_device_info device_info = { 0 };
928   struct vfio_region_info reg = { 0 };
929   struct vfio_irq_info irq_info = { 0 };
930   clib_error_t *err = 0;
931   u8 *s = 0;
932
933   p->addr.as_u32 = di->addr.as_u32;
934   p->type = LINUX_PCI_DEVICE_TYPE_VFIO;
935
936   if (di->driver_name == 0 ||
937       (strcmp ("vfio-pci", (char *) di->driver_name) != 0))
938     return clib_error_return (0, "Device '%U' (iommu group %d) not bound to "
939                               "vfio-pci", format_vlib_pci_addr, &di->addr,
940                               di->iommu_group);
941
942   if ((err = open_vfio_iommu_group (di->iommu_group)))
943     return err;
944
945   g = get_vfio_iommu_group (di->iommu_group);
946
947   s = format (s, "%U%c", format_vlib_pci_addr, &di->addr, 0);
948   if ((p->fd = ioctl (g->fd, VFIO_GROUP_GET_DEVICE_FD, (char *) s)) < 0)
949     {
950       err = clib_error_return_unix (0, "ioctl(VFIO_GROUP_GET_DEVICE_FD) '%U'",
951                                     format_vlib_pci_addr, &di->addr);
952       goto error;
953     }
954   vec_reset_length (s);
955
956   device_info.argsz = sizeof (device_info);
957   if (ioctl (p->fd, VFIO_DEVICE_GET_INFO, &device_info) < 0)
958     {
959       err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_INFO) '%U'",
960                                     format_vlib_pci_addr, &di->addr);
961       goto error;
962     }
963
964   irq_info.argsz = sizeof (struct vfio_irq_info);
965   irq_info.index = VFIO_PCI_INTX_IRQ_INDEX;
966   if (ioctl (p->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info) < 0)
967     {
968       err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_IRQ_INFO) "
969                                     "'%U'", format_vlib_pci_addr, &di->addr);
970       goto error;
971     }
972
973   /* reset if device supports it */
974   if (device_info.flags & VFIO_DEVICE_FLAGS_RESET)
975     if (ioctl (p->fd, VFIO_DEVICE_RESET) < 0)
976       {
977         err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_RESET) '%U'",
978                                       format_vlib_pci_addr, &di->addr);
979         goto error;
980       }
981
982   if ((irq_info.flags & VFIO_IRQ_INFO_EVENTFD) && irq_info.count == 1)
983     {
984       u8 buf[sizeof (struct vfio_irq_set) + sizeof (int)] = { 0 };
985       struct vfio_irq_set *irq_set = (struct vfio_irq_set *) buf;
986       clib_file_t t = { 0 };
987       int efd = eventfd (0, EFD_NONBLOCK);
988
989       irq_set->argsz = sizeof (buf);
990       irq_set->count = 1;
991       irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
992       irq_set->flags =
993         VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
994       clib_memcpy (&irq_set->data, &efd, sizeof (int));
995
996       if (ioctl (p->fd, VFIO_DEVICE_SET_IRQS, irq_set) < 0)
997         {
998           err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_SET_IRQS) '%U'",
999                                         format_vlib_pci_addr, &di->addr);
1000           goto error;
1001         }
1002
1003       t.read_function = linux_pci_vfio_intx_read_ready;
1004       t.file_descriptor = efd;
1005       t.error_function = linux_pci_vfio_error_ready;
1006       t.private_data = p->handle;
1007       p->clib_file_index = clib_file_add (&file_main, &t);
1008
1009       /* unmask the interrupt */
1010       linux_pci_vfio_unmask_intx (p);
1011     }
1012
1013   p->interrupt_handler = r->interrupt_handler;
1014
1015   reg.argsz = sizeof (struct vfio_region_info);
1016   reg.index = VFIO_PCI_CONFIG_REGION_INDEX;
1017   if (ioctl (p->fd, VFIO_DEVICE_GET_REGION_INFO, &reg) < 0)
1018     {
1019       err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_REGION_INFO) "
1020                                     "'%U'", format_vlib_pci_addr, &di->addr);
1021       goto error;
1022     }
1023   p->config_offset = reg.offset;
1024   p->config_fd = p->fd;
1025
1026   err = r->init_function (vm, p->handle);
1027
1028 error:
1029   vec_free (s);
1030   if (err)
1031     {
1032       if (p->fd != -1)
1033         close (p->fd);
1034       if (p->config_fd != -1)
1035         close (p->config_fd);
1036     }
1037   return err;
1038 }
1039
1040 /* Configuration space read/write. */
1041 clib_error_t *
1042 vlib_pci_read_write_config (vlib_pci_dev_handle_t h,
1043                             vlib_read_or_write_t read_or_write,
1044                             uword address, void *data, u32 n_bytes)
1045 {
1046   linux_pci_device_t *p = linux_pci_get_device (h);
1047   int n;
1048
1049   if (read_or_write == VLIB_READ)
1050     n = pread (p->config_fd, data, n_bytes, p->config_offset + address);
1051   else
1052     n = pwrite (p->config_fd, data, n_bytes, p->config_offset + address);
1053
1054   if (n != n_bytes)
1055     return clib_error_return_unix (0, "%s",
1056                                    read_or_write == VLIB_READ
1057                                    ? "read" : "write");
1058
1059   return 0;
1060 }
1061
1062 static clib_error_t *
1063 vlib_pci_map_region_int (vlib_pci_dev_handle_t h,
1064                          u32 bar, u8 * addr, void **result)
1065 {
1066   linux_pci_device_t *p = linux_pci_get_device (h);
1067   int fd = -1;
1068   clib_error_t *error;
1069   int flags = MAP_SHARED;
1070   u64 size = 0, offset = 0;
1071
1072   ASSERT (bar <= 5);
1073
1074   error = 0;
1075
1076   if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
1077     {
1078       u8 *file_name;
1079       struct stat stat_buf;
1080       file_name = format (0, "%s/%U/resource%d%c", sysfs_pci_dev_path,
1081                           format_vlib_pci_addr, &p->addr, bar, 0);
1082
1083       fd = open ((char *) file_name, O_RDWR);
1084       if (fd < 0)
1085         {
1086           error = clib_error_return_unix (0, "open `%s'", file_name);
1087           vec_free (file_name);
1088           return error;
1089         }
1090
1091       if (fstat (fd, &stat_buf) < 0)
1092         {
1093           error = clib_error_return_unix (0, "fstat `%s'", file_name);
1094           vec_free (file_name);
1095           close (fd);
1096           return error;
1097         }
1098
1099       vec_free (file_name);
1100       if (addr != 0)
1101         flags |= MAP_FIXED;
1102       size = stat_buf.st_size;
1103       offset = 0;
1104     }
1105   else if (p->type == LINUX_PCI_DEVICE_TYPE_VFIO)
1106     {
1107       struct vfio_region_info reg = { 0 };
1108       reg.argsz = sizeof (struct vfio_region_info);
1109       reg.index = bar;
1110       if (ioctl (p->fd, VFIO_DEVICE_GET_REGION_INFO, &reg) < 0)
1111         return clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_INFO) "
1112                                        "'%U'", format_vlib_pci_addr,
1113                                        &p->addr);
1114       fd = p->fd;
1115       size = reg.size;
1116       offset = reg.offset;
1117     }
1118   else
1119     ASSERT (0);
1120
1121   *result = mmap (addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
1122   if (*result == (void *) -1)
1123     {
1124       error = clib_error_return_unix (0, "mmap `BAR%u'", bar);
1125       if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
1126         close (fd);
1127       return error;
1128     }
1129
1130   /* *INDENT-OFF* */
1131   vec_validate_init_empty (p->regions, bar,
1132                            (linux_pci_region_t) { .fd = -1});
1133   /* *INDENT-ON* */
1134   if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
1135     p->regions[bar].fd = fd;
1136   p->regions[bar].addr = *result;
1137   p->regions[bar].size = size;
1138   return 0;
1139 }
1140
1141 clib_error_t *
1142 vlib_pci_map_region (vlib_pci_dev_handle_t h, u32 resource, void **result)
1143 {
1144   return (vlib_pci_map_region_int (h, resource, 0 /* addr */ , result));
1145 }
1146
1147 clib_error_t *
1148 vlib_pci_map_region_fixed (vlib_pci_dev_handle_t h, u32 resource, u8 * addr,
1149                            void **result)
1150 {
1151   return (vlib_pci_map_region_int (h, resource, addr, result));
1152 }
1153
1154 void
1155 init_device_from_registered (vlib_main_t * vm, vlib_pci_device_info_t * di)
1156 {
1157   vlib_pci_main_t *pm = &pci_main;
1158   linux_pci_main_t *lpm = &linux_pci_main;
1159   pci_device_registration_t *r;
1160   pci_device_id_t *i;
1161   clib_error_t *err = 0;
1162   linux_pci_device_t *p;
1163
1164   pool_get (lpm->linux_pci_devices, p);
1165   p->handle = p - lpm->linux_pci_devices;
1166
1167   r = pm->pci_device_registrations;
1168
1169   while (r)
1170     {
1171       for (i = r->supported_devices; i->vendor_id != 0; i++)
1172         if (i->vendor_id == di->vendor_id && i->device_id == di->device_id)
1173           {
1174             if (di->iommu_group != -1)
1175               err = add_device_vfio (vm, p, di, r);
1176             else
1177               err = add_device_uio (vm, p, di, r);
1178
1179             if (err)
1180               clib_error_report (err);
1181             else
1182               return;
1183           }
1184       r = r->next_registration;
1185     }
1186
1187   /* No driver, close the PCI config-space FD */
1188   memset (p, 0, sizeof (linux_pci_device_t));
1189   pool_put (lpm->linux_pci_devices, p);
1190 }
1191
1192 static clib_error_t *
1193 scan_pci_addr (void *arg, u8 * dev_dir_name, u8 * ignored)
1194 {
1195   vlib_pci_addr_t addr, **addrv = arg;
1196   unformat_input_t input;
1197   clib_error_t *err = 0;
1198
1199   unformat_init_string (&input, (char *) dev_dir_name,
1200                         vec_len (dev_dir_name));
1201
1202   if (!unformat (&input, "/sys/bus/pci/devices/%U",
1203                  unformat_vlib_pci_addr, &addr))
1204     err = clib_error_return (0, "unformat error `%v`", dev_dir_name);
1205
1206   unformat_free (&input);
1207
1208   if (err)
1209     return err;
1210
1211   vec_add1 (*addrv, addr);
1212   return 0;
1213 }
1214
1215 static int
1216 pci_addr_cmp (void *v1, void *v2)
1217 {
1218   vlib_pci_addr_t *a1 = v1;
1219   vlib_pci_addr_t *a2 = v2;
1220
1221   if (a1->domain > a2->domain)
1222     return 1;
1223   if (a1->domain < a2->domain)
1224     return -1;
1225   if (a1->bus > a2->bus)
1226     return 1;
1227   if (a1->bus < a2->bus)
1228     return -1;
1229   if (a1->slot > a2->slot)
1230     return 1;
1231   if (a1->slot < a2->slot)
1232     return -1;
1233   if (a1->function > a2->function)
1234     return 1;
1235   if (a1->function < a2->function)
1236     return -1;
1237   return 0;
1238 }
1239
1240 vlib_pci_addr_t *
1241 vlib_pci_get_all_dev_addrs ()
1242 {
1243   vlib_pci_addr_t *addrs = 0;
1244   clib_error_t *err;
1245   err = foreach_directory_file ((char *) sysfs_pci_dev_path, scan_pci_addr,
1246                                 &addrs, /* scan_dirs */ 0);
1247   if (err)
1248     {
1249       vec_free (addrs);
1250       return 0;
1251     }
1252
1253   vec_sort_with_function (addrs, pci_addr_cmp);
1254
1255   return addrs;
1256 }
1257
1258 clib_error_t *
1259 linux_pci_init (vlib_main_t * vm)
1260 {
1261   vlib_pci_main_t *pm = &pci_main;
1262   linux_pci_main_t *lpm = &linux_pci_main;
1263   vlib_pci_addr_t *addr = 0, *addrs;
1264   clib_error_t *error;
1265   int fd;
1266
1267   pm->vlib_main = vm;
1268
1269   if ((error = vlib_call_init_function (vm, unix_input_init)))
1270     return error;
1271
1272   ASSERT (sizeof (vlib_pci_addr_t) == sizeof (u32));
1273
1274   fd = open ("/dev/vfio/vfio", O_RDWR);
1275
1276   if ((fd != -1) && (ioctl (fd, VFIO_GET_API_VERSION) != VFIO_API_VERSION))
1277     {
1278       close (fd);
1279       fd = -1;
1280     }
1281
1282   if ((fd != -1) && (ioctl (fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU) == 0))
1283     {
1284       close (fd);
1285       fd = -1;
1286     }
1287
1288   lpm->vfio_container_fd = fd;
1289   lpm->iommu_pool_index_by_group = hash_create (0, sizeof (uword));
1290
1291   addrs = vlib_pci_get_all_dev_addrs ();
1292   /* *INDENT-OFF* */
1293   vec_foreach (addr, addrs)
1294     {
1295       vlib_pci_device_info_t *d;
1296       if ((d = vlib_pci_get_device_info (addr, 0)))
1297         {
1298           init_device_from_registered (vm, d);
1299           vlib_pci_free_device_info (d);
1300         }
1301     }
1302   /* *INDENT-ON* */
1303
1304   return error;
1305 }
1306
1307 VLIB_INIT_FUNCTION (linux_pci_init);
1308
1309 /*
1310  * fd.io coding-style-patch-verification: ON
1311  *
1312  * Local Variables:
1313  * eval: (c-set-style "gnu")
1314  * End:
1315  */