pci: auto-detect right vfio/uio driver
[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   vlib_pci_dev_handle_t handle;
65   vlib_pci_addr_t addr;
66
67   /* Resource file descriptors. */
68   int *resource_fds;
69
70   /* File descriptor for config space read/write. */
71   int config_fd;
72
73   /* File descriptor for /dev/uio%d */
74   int uio_fd;
75
76   /* Minor device for uio device. */
77   u32 uio_minor;
78
79   /* vfio */
80   int vfio_device_fd;
81
82   /* Index given by clib_file_add. */
83   u32 clib_file_index;
84
85   /* Interrupt handler */
86   void (*interrupt_handler) (vlib_pci_dev_handle_t h);
87
88   /* private data */
89   uword private_data;
90
91 } linux_pci_device_t;
92
93 typedef struct
94 {
95   int group;
96   int fd;
97   int refcnt;
98 } linux_pci_vfio_iommu_group_t;
99
100 /* Pool of PCI devices. */
101 typedef struct
102 {
103   vlib_main_t *vlib_main;
104   linux_pci_device_t *linux_pci_devices;
105
106   /* VFIO */
107   int vfio_container_fd;
108   int vfio_iommu_mode;
109
110   /* pool of IOMMU groups */
111   linux_pci_vfio_iommu_group_t *iommu_groups;
112
113   /* iommu group pool index by group id  hash */
114   uword *iommu_pool_index_by_group;
115
116 } linux_pci_main_t;
117
118 extern linux_pci_main_t linux_pci_main;
119
120 linux_pci_device_t *
121 linux_pci_get_device (vlib_pci_dev_handle_t h)
122 {
123   linux_pci_main_t *lpm = &linux_pci_main;
124   return pool_elt_at_index (lpm->linux_pci_devices, h);
125 }
126
127 uword
128 vlib_pci_get_private_data (vlib_pci_dev_handle_t h)
129 {
130   linux_pci_device_t *d = linux_pci_get_device (h);
131   return d->private_data;
132 }
133
134 void
135 vlib_pci_set_private_data (vlib_pci_dev_handle_t h, uword private_data)
136 {
137   linux_pci_device_t *d = linux_pci_get_device (h);
138   d->private_data = private_data;
139 }
140
141 vlib_pci_addr_t *
142 vlib_pci_get_addr (vlib_pci_dev_handle_t h)
143 {
144   linux_pci_device_t *lpm = linux_pci_get_device (h);
145   return &lpm->addr;
146 }
147
148 /* Call to allocate/initialize the pci subsystem.
149    This is not an init function so that users can explicitly enable
150    pci only when it's needed. */
151 clib_error_t *pci_bus_init (vlib_main_t * vm);
152
153 linux_pci_main_t linux_pci_main;
154
155 vlib_pci_device_info_t *
156 vlib_pci_get_device_info (vlib_pci_addr_t * addr, clib_error_t ** error)
157 {
158   linux_pci_main_t *lpm = &linux_pci_main;
159   clib_error_t *err;
160   vlib_pci_device_info_t *di;
161   u8 *f = 0;
162   u32 tmp;
163   int fd;
164
165   di = clib_mem_alloc (sizeof (vlib_pci_device_info_t));
166   memset (di, 0, sizeof (vlib_pci_device_info_t));
167   di->addr.as_u32 = addr->as_u32;
168
169   u8 *dev_dir_name = format (0, "%s/%U", sysfs_pci_dev_path,
170                              format_vlib_pci_addr, addr);
171
172   f = format (0, "%v/config%c", dev_dir_name, 0);
173   fd = open ((char *) f, O_RDWR);
174
175   /* Try read-only access if write fails. */
176   if (fd < 0)
177     fd = open ((char *) f, O_RDONLY);
178
179   if (fd < 0)
180     {
181       err = clib_error_return_unix (0, "open `%s'", f);
182       goto error;
183     }
184
185   /* You can only read more that 64 bytes of config space as root; so we try to
186      read the full space but fall back to just the first 64 bytes. */
187   if (read (fd, &di->config_data, sizeof (di->config_data)) !=
188       sizeof (di->config_data)
189       && read (fd, &di->config0,
190                sizeof (di->config0)) != sizeof (di->config0))
191     {
192       err = clib_error_return_unix (0, "read `%s'", f);
193       close (fd);
194       goto error;
195     }
196
197   {
198     static pci_config_header_t all_ones;
199     if (all_ones.vendor_id == 0)
200       memset (&all_ones, ~0, sizeof (all_ones));
201
202     if (!memcmp (&di->config0.header, &all_ones, sizeof (all_ones)))
203       {
204         err = clib_error_return (0, "invalid PCI config for `%s'", f);
205         close (fd);
206         goto error;
207       }
208   }
209
210   if (di->config0.header.header_type == 0)
211     pci_config_type0_little_to_host (&di->config0);
212   else
213     pci_config_type1_little_to_host (&di->config1);
214
215   di->numa_node = -1;
216   vec_reset_length (f);
217   f = format (f, "%v/numa_node%c", dev_dir_name, 0);
218   err = clib_sysfs_read ((char *) f, "%u", &di->numa_node);
219   if (err)
220     {
221       di->numa_node = -1;
222       clib_error_free (err);
223     }
224
225   vec_reset_length (f);
226   f = format (f, "%v/class%c", dev_dir_name, 0);
227   err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
228   if (err)
229     goto error;
230   di->device_class = tmp >> 8;
231
232   vec_reset_length (f);
233   f = format (f, "%v/vendor%c", dev_dir_name, 0);
234   err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
235   if (err)
236     goto error;
237   di->vendor_id = tmp;
238
239   vec_reset_length (f);
240   f = format (f, "%v/device%c", dev_dir_name, 0);
241   err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
242   if (err)
243     goto error;
244   di->device_id = tmp;
245
246   vec_reset_length (f);
247   f = format (f, "%v/driver%c", dev_dir_name, 0);
248   di->driver_name = clib_sysfs_link_to_name ((char *) f);
249
250   di->iommu_group = -1;
251   if (lpm->vfio_container_fd != -1)
252     {
253       u8 *tmpstr;
254       vec_reset_length (f);
255       f = format (f, "%v/iommu_group%c", dev_dir_name, 0);
256       tmpstr = clib_sysfs_link_to_name ((char *) f);
257       if (tmpstr)
258         {
259           di->iommu_group = atoi ((char *) tmpstr);
260           vec_free (tmpstr);
261         }
262     }
263
264   close (fd);
265
266   vec_reset_length (f);
267   f = format (f, "%v/vpd%c", dev_dir_name, 0);
268   fd = open ((char *) f, O_RDONLY);
269   if (fd >= 0)
270     {
271       while (1)
272         {
273           u8 tag[3];
274           u8 *data = 0;
275           uword len;
276
277           if (read (fd, &tag, 3) != 3)
278             break;
279
280           if (tag[0] != 0x82 && tag[0] != 0x90 && tag[0] != 0x91)
281             break;
282
283           len = (tag[2] << 8) | tag[1];
284           vec_validate (data, len);
285
286           if (read (fd, data, len) != len)
287             {
288               vec_free (data);
289               break;
290             }
291           if (tag[0] == 0x82)
292             di->product_name = data;
293           else if (tag[0] == 0x90)
294             di->vpd_r = data;
295           else if (tag[0] == 0x91)
296             di->vpd_w = data;
297
298           data = 0;
299         }
300       close (fd);
301     }
302
303   goto done;
304
305 error:
306   vlib_pci_free_device_info (di);
307   di = 0;
308
309 done:
310   vec_free (f);
311   vec_free (dev_dir_name);
312   if (error)
313     *error = err;
314   else
315     clib_error_free (err);
316   return di;
317 }
318
319 static int
320 directory_exists (char *path)
321 {
322   struct stat s = { 0 };
323   if (stat (path, &s) == -1)
324     return 0;
325
326   return S_ISDIR (s.st_mode);
327 }
328
329 clib_error_t *
330 vlib_pci_bind_to_uio (vlib_pci_addr_t * addr, char *uio_drv_name)
331 {
332   clib_error_t *error = 0;
333   u8 *s = 0, *driver_name = 0;
334   DIR *dir = 0;
335   struct dirent *e;
336   vlib_pci_device_info_t *di;
337   int fd, clear_driver_override = 0;
338   u8 *dev_dir_name = format (0, "%s/%U", sysfs_pci_dev_path,
339                              format_vlib_pci_addr, addr);
340
341   di = vlib_pci_get_device_info (addr, &error);
342
343   if (error)
344     return error;
345
346   if (strncmp ("auto", uio_drv_name, 5) == 0)
347     {
348       int vfio_pci_loaded = 0;
349
350       if (directory_exists ("/sys/module/vfio_pci"))
351         vfio_pci_loaded = 1;
352
353       if (di->iommu_group != -1)
354         {
355           /* device is bound to IOMMU group */
356           if (!vfio_pci_loaded)
357             {
358               error = clib_error_return (0, "Skipping PCI device %U: device "
359                                          "is bound to IOMMU group and "
360                                          "vfio-pci driver is not loaded",
361                                          format_vlib_pci_addr, addr);
362               goto done;
363             }
364           else
365             uio_drv_name = "vfio-pci";
366         }
367       else
368         {
369           /* device is not bound to IOMMU group so we have multiple options */
370           if (vfio_pci_loaded &&
371               (error = clib_sysfs_write (sysfs_mod_vfio_noiommu, "Y")) == 0)
372             uio_drv_name = "vfio-pci";
373           else if (directory_exists ("/sys/module/uio_pci_generic"))
374             uio_drv_name = "uio_pci_generic";
375           else if (directory_exists ("/sys/module/igb_uio"))
376             uio_drv_name = "igb_uio";
377           else
378             {
379               clib_error_free (error);
380               error = clib_error_return (0, "Skipping PCI device %U: missing "
381                                          "kernel VFIO or UIO driver",
382                                          format_vlib_pci_addr, addr);
383               goto done;
384             }
385           clib_error_free (error);
386         }
387     }
388
389   s = format (s, "%v/driver%c", dev_dir_name, 0);
390   driver_name = clib_sysfs_link_to_name ((char *) s);
391   vec_reset_length (s);
392
393   if (driver_name &&
394       ((strcmp ("vfio-pci", (char *) driver_name) == 0) ||
395        (strcmp ("uio_pci_generic", (char *) driver_name) == 0) ||
396        (strcmp ("igb_uio", (char *) driver_name) == 0)))
397     goto done;
398
399   /* walk trough all linux interfaces and if interface belonging to
400      this device is founf check if interface is admin up  */
401   dir = opendir ("/sys/class/net");
402   s = format (s, "%U%c", format_vlib_pci_addr, addr, 0);
403
404   if (!dir)
405     {
406       error = clib_error_return (0, "Skipping PCI device %U: failed to "
407                                  "read /sys/class/net",
408                                  format_vlib_pci_addr, addr);
409       goto done;
410     }
411
412   fd = socket (PF_INET, SOCK_DGRAM, 0);
413   if (fd < 0)
414     {
415       error = clib_error_return_unix (0, "socket");
416       goto done;
417     }
418
419   while ((e = readdir (dir)))
420     {
421       struct ifreq ifr;
422       struct ethtool_drvinfo drvinfo;
423
424       if (e->d_name[0] == '.')  /* skip . and .. */
425         continue;
426
427       memset (&ifr, 0, sizeof ifr);
428       memset (&drvinfo, 0, sizeof drvinfo);
429       ifr.ifr_data = (char *) &drvinfo;
430       strncpy (ifr.ifr_name, e->d_name, IFNAMSIZ - 1);
431       drvinfo.cmd = ETHTOOL_GDRVINFO;
432       if (ioctl (fd, SIOCETHTOOL, &ifr) < 0)
433         {
434           /* Some interfaces (eg "lo") don't support this ioctl */
435           if ((errno != ENOTSUP) && (errno != ENODEV))
436             clib_unix_warning ("ioctl fetch intf %s bus info error",
437                                e->d_name);
438           continue;
439         }
440
441       if (strcmp ((char *) s, drvinfo.bus_info))
442         continue;
443
444       memset (&ifr, 0, sizeof (ifr));
445       strncpy (ifr.ifr_name, e->d_name, IFNAMSIZ - 1);
446       if (ioctl (fd, SIOCGIFFLAGS, &ifr) < 0)
447         {
448           error = clib_error_return_unix (0, "ioctl fetch intf %s flags",
449                                           e->d_name);
450           close (fd);
451           goto done;
452         }
453
454       if (ifr.ifr_flags & IFF_UP)
455         {
456           error = clib_error_return (0, "Skipping PCI device %U as host "
457                                      "interface %s is up",
458                                      format_vlib_pci_addr, addr, e->d_name);
459           close (fd);
460           goto done;
461         }
462     }
463
464   close (fd);
465   vec_reset_length (s);
466
467   s = format (s, "%v/driver/unbind%c", dev_dir_name, 0);
468   clib_sysfs_write ((char *) s, "%U", format_vlib_pci_addr, addr);
469   vec_reset_length (s);
470
471   s = format (s, "%v/driver_override%c", dev_dir_name, 0);
472   if (access ((char *) s, F_OK) == 0)
473     {
474       clib_sysfs_write ((char *) s, "%s", uio_drv_name);
475       clear_driver_override = 1;
476     }
477   else
478     {
479       vec_reset_length (s);
480       s = format (s, "%s/%s/new_id%c", sysfs_pci_drv_path, uio_drv_name, 0);
481       clib_sysfs_write ((char *) s, "0x%04x 0x%04x", di->vendor_id,
482                         di->device_id);
483     }
484   vec_reset_length (s);
485
486   s = format (s, "%s/%s/bind%c", sysfs_pci_drv_path, uio_drv_name, 0);
487   clib_sysfs_write ((char *) s, "%U", format_vlib_pci_addr, addr);
488   vec_reset_length (s);
489
490   if (clear_driver_override)
491     {
492       s = format (s, "%v/driver_override%c", dev_dir_name, 0);
493       clib_sysfs_write ((char *) s, "%c", 0);
494       vec_reset_length (s);
495     }
496
497 done:
498   closedir (dir);
499   vec_free (s);
500   vec_free (dev_dir_name);
501   vec_free (driver_name);
502   return error;
503 }
504
505
506 static clib_error_t *
507 scan_uio_dir (void *arg, u8 * path_name, u8 * file_name)
508 {
509   linux_pci_device_t *l = arg;
510   unformat_input_t input;
511
512   unformat_init_string (&input, (char *) file_name, vec_len (file_name));
513
514   if (!unformat (&input, "uio%d", &l->uio_minor))
515     abort ();
516
517   unformat_free (&input);
518   return 0;
519 }
520
521 static clib_error_t *
522 linux_pci_uio_read_ready (clib_file_t * uf)
523 {
524   int __attribute__ ((unused)) rv;
525   vlib_pci_dev_handle_t h = uf->private_data;
526   linux_pci_device_t *p = linux_pci_get_device (h);
527
528   u32 icount;
529   rv = read (uf->file_descriptor, &icount, 4);
530
531   if (p->interrupt_handler)
532     p->interrupt_handler (h);
533
534   vlib_pci_intr_enable (h);
535
536   return /* no error */ 0;
537 }
538
539 static clib_error_t *
540 linux_pci_vfio_unmask_intx (linux_pci_device_t * d)
541 {
542   clib_error_t *err = 0;
543   struct vfio_irq_set i = {
544     .argsz = sizeof (struct vfio_irq_set),
545     .start = 0,
546     .count = 1,
547     .index = VFIO_PCI_INTX_IRQ_INDEX,
548     .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK,
549   };
550
551   if (ioctl (d->vfio_device_fd, VFIO_DEVICE_SET_IRQS, &i) < 0)
552     {
553       err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_SET_IRQS) '%U'",
554                                     format_vlib_pci_addr, &d->addr);
555     }
556   return err;
557 }
558
559 static clib_error_t *
560 linux_pci_uio_error_ready (clib_file_t * uf)
561 {
562   u32 error_index = (u32) uf->private_data;
563
564   return clib_error_return (0, "pci device %d: error", error_index);
565 }
566
567 static clib_error_t *
568 linux_pci_vfio_read_ready (clib_file_t * uf)
569 {
570   int __attribute__ ((unused)) rv;
571   vlib_pci_dev_handle_t h = uf->private_data;
572   linux_pci_device_t *p = linux_pci_get_device (h);
573
574   u64 icount;
575   rv = read (uf->file_descriptor, &icount, sizeof (icount));
576
577   if (p->interrupt_handler)
578     p->interrupt_handler (h);
579
580   linux_pci_vfio_unmask_intx (p);
581
582   return /* no error */ 0;
583 }
584
585 static clib_error_t *
586 linux_pci_vfio_error_ready (clib_file_t * uf)
587 {
588   u32 error_index = (u32) uf->private_data;
589
590   return clib_error_return (0, "pci device %d: error", error_index);
591 }
592
593 static clib_error_t *
594 add_device_uio (vlib_main_t * vm, linux_pci_device_t * p,
595                 vlib_pci_device_info_t * di, pci_device_registration_t * r)
596 {
597   clib_error_t *err = 0;
598   clib_file_t t = { 0 };
599   u8 *s = 0;
600
601   p->addr.as_u32 = di->addr.as_u32;
602   p->uio_fd = -1;
603
604   s = format (s, "%s/%U/config%c", sysfs_pci_dev_path,
605               format_vlib_pci_addr, &di->addr, 0);
606
607   p->config_fd = open ((char *) s, O_RDWR);
608   vec_reset_length (s);
609
610   if (p->config_fd == -1)
611     {
612       err = clib_error_return_unix (0, "open '%s'", s);
613       goto error;
614     }
615
616   s = format (0, "%s/%U/uio", sysfs_pci_dev_path,
617               format_vlib_pci_addr, &di->addr);
618   foreach_directory_file ((char *) s, scan_uio_dir, p,  /* scan_dirs */
619                           1);
620   vec_reset_length (s);
621
622   s = format (s, "/dev/uio%d%c", p->uio_minor, 0);
623   p->uio_fd = open ((char *) s, O_RDWR);
624   if (p->uio_fd < 0)
625     {
626       err = clib_error_return_unix (0, "open '%s'", s);
627       goto error;
628     }
629
630   t.read_function = linux_pci_uio_read_ready;
631   t.file_descriptor = p->uio_fd;
632   t.error_function = linux_pci_uio_error_ready;
633   t.private_data = p->handle;
634
635   p->clib_file_index = clib_file_add (&file_main, &t);
636   p->interrupt_handler = r->interrupt_handler;
637   err = r->init_function (vm, p->handle);
638
639 error:
640   free (s);
641   if (err)
642     {
643       if (p->config_fd != -1)
644         close (p->config_fd);
645       if (p->uio_fd != -1)
646         close (p->uio_fd);
647     }
648   return err;
649 }
650
651 static linux_pci_vfio_iommu_group_t *
652 get_vfio_iommu_group (int group)
653 {
654   linux_pci_main_t *lpm = &linux_pci_main;
655   uword *p;
656
657   p = hash_get (lpm->iommu_pool_index_by_group, group);
658
659   return p ? pool_elt_at_index (lpm->iommu_groups, p[0]) : 0;
660 }
661
662 static clib_error_t *
663 open_vfio_iommu_group (int group)
664 {
665   linux_pci_main_t *lpm = &linux_pci_main;
666   linux_pci_vfio_iommu_group_t *g;
667   clib_error_t *err = 0;
668   struct vfio_group_status group_status;
669   u8 *s = 0;
670   int fd;
671
672   g = get_vfio_iommu_group (group);
673   if (g)
674     {
675       g->refcnt++;
676       return 0;
677     }
678   s = format (s, "/dev/vfio/%u%c", group, 0);
679   fd = open ((char *) s, O_RDWR);
680   if (fd < 0)
681     return clib_error_return_unix (0, "open '%s'", s);
682
683   group_status.argsz = sizeof (group_status);
684   if (ioctl (fd, VFIO_GROUP_GET_STATUS, &group_status) < 0)
685     {
686       err = clib_error_return_unix (0, "ioctl(VFIO_GROUP_GET_STATUS) '%s'",
687                                     s);
688       goto error;
689     }
690
691   if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE))
692     {
693       err = clib_error_return (0, "iommu group %d is not viable (not all "
694                                "devices in this group bound to vfio-pci)",
695                                group);
696       goto error;
697     }
698
699   if (ioctl (fd, VFIO_GROUP_SET_CONTAINER, &lpm->vfio_container_fd) < 0)
700     {
701       err = clib_error_return_unix (0, "ioctl(VFIO_GROUP_SET_CONTAINER) '%s'",
702                                     s);
703       goto error;
704     }
705
706   if (lpm->vfio_iommu_mode == 0)
707     {
708       if (ioctl (lpm->vfio_container_fd, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU) <
709           0)
710         {
711           err = clib_error_return_unix (0, "ioctl(VFIO_SET_IOMMU) "
712                                         "'/dev/vfio/vfio'");
713           goto error;
714         }
715       lpm->vfio_iommu_mode = VFIO_TYPE1_IOMMU;
716     }
717
718
719   pool_get (lpm->iommu_groups, g);
720   g->fd = fd;
721   g->refcnt = 1;
722   hash_set (lpm->iommu_pool_index_by_group, group, g - lpm->iommu_groups);
723   vec_free (s);
724   return 0;
725 error:
726   close (fd);
727   return err;
728 }
729
730 static clib_error_t *
731 add_device_vfio (vlib_main_t * vm, linux_pci_device_t * p,
732                  vlib_pci_device_info_t * di, pci_device_registration_t * r)
733 {
734   linux_pci_vfio_iommu_group_t *g;
735   struct vfio_device_info device_info;
736   struct vfio_irq_info irq_info = { 0 };
737   clib_error_t *err = 0;
738   u8 *s = 0;
739   int dfd;
740
741   p->addr.as_u32 = di->addr.as_u32;
742
743   if (di->driver_name == 0 ||
744       (strcmp ("vfio-pci", (char *) di->driver_name) != 0))
745     return clib_error_return (0, "Device '%U' (iommu group %d) not bound to "
746                               "vfio-pci", format_vlib_pci_addr, &di->addr,
747                               di->iommu_group);
748
749   if ((err = open_vfio_iommu_group (di->iommu_group)))
750     return err;
751
752   g = get_vfio_iommu_group (di->iommu_group);
753
754   s = format (s, "%U%c", format_vlib_pci_addr, &di->addr, 0);
755   if ((dfd = ioctl (g->fd, VFIO_GROUP_GET_DEVICE_FD, (char *) s)) < 0)
756     {
757       err = clib_error_return_unix (0, "ioctl(VFIO_GROUP_GET_DEVICE_FD) '%U'",
758                                     format_vlib_pci_addr, &di->addr);
759       goto error;
760     }
761   vec_reset_length (s);
762   p->vfio_device_fd = dfd;
763
764   device_info.argsz = sizeof (device_info);
765   if (ioctl (dfd, VFIO_DEVICE_GET_INFO, &device_info) < 0)
766     {
767       err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_INFO) '%U'",
768                                     format_vlib_pci_addr, &di->addr);
769       goto error;
770     }
771
772   irq_info.argsz = sizeof (struct vfio_irq_info);
773   irq_info.index = VFIO_PCI_INTX_IRQ_INDEX;
774   if (ioctl (dfd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info) < 0)
775     {
776       err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_IRQ_INFO) "
777                                     "'%U'", format_vlib_pci_addr, &di->addr);
778       goto error;
779     }
780
781   /* reset if device supports it */
782   if (device_info.flags & VFIO_DEVICE_FLAGS_RESET)
783     if (ioctl (dfd, VFIO_DEVICE_RESET) < 0)
784       {
785         err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_RESET) '%U'",
786                                       format_vlib_pci_addr, &di->addr);
787         goto error;
788       }
789
790   if ((irq_info.flags & VFIO_IRQ_INFO_EVENTFD) && irq_info.count == 1)
791     {
792       u8 buf[sizeof (struct vfio_irq_set) + sizeof (int)] = { 0 };
793       struct vfio_irq_set *irq_set = (struct vfio_irq_set *) buf;
794       clib_file_t t = { 0 };
795       int efd = eventfd (0, EFD_NONBLOCK);
796
797       irq_set->argsz = sizeof (buf);
798       irq_set->count = 1;
799       irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
800       irq_set->flags =
801         VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
802       clib_memcpy (&irq_set->data, &efd, sizeof (int));
803
804       if (ioctl (dfd, VFIO_DEVICE_SET_IRQS, irq_set) < 0)
805         {
806           err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_SET_IRQS) '%U'",
807                                         format_vlib_pci_addr, &di->addr);
808           goto error;
809         }
810
811       t.read_function = linux_pci_vfio_read_ready;
812       t.file_descriptor = efd;
813       t.error_function = linux_pci_vfio_error_ready;
814       t.private_data = p->handle;
815       p->clib_file_index = clib_file_add (&file_main, &t);
816
817       /* unmask the interrupt */
818       linux_pci_vfio_unmask_intx (p);
819     }
820
821   p->interrupt_handler = r->interrupt_handler;
822
823   s = format (s, "%s/%U/config%c", sysfs_pci_dev_path,
824               format_vlib_pci_addr, &di->addr, 0);
825
826   p->config_fd = open ((char *) s, O_RDWR);
827   vec_reset_length (s);
828
829   if (p->config_fd == -1)
830     {
831       err = clib_error_return_unix (0, "open '%s'", s);
832       goto error;
833     }
834
835   err = r->init_function (vm, p->handle);
836
837 error:
838   vec_free (s);
839   if (err)
840     {
841       if (dfd != -1)
842         close (dfd);
843       if (p->config_fd != -1)
844         close (p->config_fd);
845     }
846   return err;
847 }
848
849 /* Configuration space read/write. */
850 clib_error_t *
851 vlib_pci_read_write_config (vlib_pci_dev_handle_t h,
852                             vlib_read_or_write_t read_or_write,
853                             uword address, void *data, u32 n_bytes)
854 {
855   linux_pci_device_t *p = linux_pci_get_device (h);
856   int n;
857
858   if (read_or_write == VLIB_READ)
859     n = pread (p->config_fd, data, n_bytes, address);
860   else
861     n = pwrite (p->config_fd, data, n_bytes, address);
862
863   if (n != n_bytes)
864     return clib_error_return_unix (0, "%s",
865                                    read_or_write == VLIB_READ
866                                    ? "read" : "write");
867
868   return 0;
869 }
870
871 static clib_error_t *
872 vlib_pci_map_resource_int (vlib_pci_dev_handle_t h,
873                            u32 resource, u8 * addr, void **result)
874 {
875   linux_pci_device_t *p = linux_pci_get_device (h);
876   struct stat stat_buf;
877   u8 *file_name;
878   int fd;
879   clib_error_t *error;
880   int flags = MAP_SHARED;
881
882   error = 0;
883
884   file_name = format (0, "%s/%U/resource%d%c", sysfs_pci_dev_path,
885                       format_vlib_pci_addr, &p->addr, resource, 0);
886
887   fd = open ((char *) file_name, O_RDWR);
888   if (fd < 0)
889     {
890       error = clib_error_return_unix (0, "open `%s'", file_name);
891       goto done;
892     }
893
894   if (fstat (fd, &stat_buf) < 0)
895     {
896       error = clib_error_return_unix (0, "fstat `%s'", file_name);
897       goto done;
898     }
899
900   vec_validate (p->resource_fds, resource);
901   p->resource_fds[resource] = fd;
902   if (addr != 0)
903     flags |= MAP_FIXED;
904
905   *result = mmap (addr,
906                   /* size */ stat_buf.st_size,
907                   PROT_READ | PROT_WRITE, flags,
908                   /* file */ fd,
909                   /* offset */ 0);
910   if (*result == (void *) -1)
911     {
912       error = clib_error_return_unix (0, "mmap `%s'", file_name);
913       goto done;
914     }
915
916 done:
917   if (error)
918     {
919       if (fd >= 0)
920         close (fd);
921     }
922   vec_free (file_name);
923   return error;
924 }
925
926 clib_error_t *
927 vlib_pci_map_resource (vlib_pci_dev_handle_t h, u32 resource, void **result)
928 {
929   return (vlib_pci_map_resource_int (h, resource, 0 /* addr */ , result));
930 }
931
932 clib_error_t *
933 vlib_pci_map_resource_fixed (vlib_pci_dev_handle_t h,
934                              u32 resource, u8 * addr, void **result)
935 {
936   return (vlib_pci_map_resource_int (h, resource, addr, result));
937 }
938
939 void
940 init_device_from_registered (vlib_main_t * vm, vlib_pci_device_info_t * di)
941 {
942   vlib_pci_main_t *pm = &pci_main;
943   linux_pci_main_t *lpm = &linux_pci_main;
944   pci_device_registration_t *r;
945   pci_device_id_t *i;
946   clib_error_t *err = 0;
947   linux_pci_device_t *p;
948
949   pool_get (lpm->linux_pci_devices, p);
950   p->handle = p - lpm->linux_pci_devices;
951
952   r = pm->pci_device_registrations;
953
954   while (r)
955     {
956       for (i = r->supported_devices; i->vendor_id != 0; i++)
957         if (i->vendor_id == di->config0.header.vendor_id &&
958             i->device_id == di->config0.header.device_id)
959           {
960             if (di->iommu_group != -1)
961               err = add_device_vfio (vm, p, di, r);
962             else
963               err = add_device_uio (vm, p, di, r);
964
965             if (err)
966               clib_error_report (err);
967             else
968               return;
969           }
970       r = r->next_registration;
971     }
972
973   /* No driver, close the PCI config-space FD */
974   memset (p, 0, sizeof (linux_pci_device_t));
975   pool_put (lpm->linux_pci_devices, p);
976 }
977
978 static clib_error_t *
979 scan_pci_addr (void *arg, u8 * dev_dir_name, u8 * ignored)
980 {
981   vlib_pci_addr_t addr, **addrv = arg;
982   unformat_input_t input;
983   clib_error_t *err = 0;
984
985   unformat_init_string (&input, (char *) dev_dir_name,
986                         vec_len (dev_dir_name));
987
988   if (!unformat (&input, "/sys/bus/pci/devices/%U",
989                  unformat_vlib_pci_addr, &addr))
990     err = clib_error_return (0, "unformat error `%v`", dev_dir_name);
991
992   unformat_free (&input);
993
994   if (err)
995     return err;
996
997   vec_add1 (*addrv, addr);
998   return 0;
999 }
1000
1001 static int
1002 pci_addr_cmp (void *v1, void *v2)
1003 {
1004   vlib_pci_addr_t *a1 = v1;
1005   vlib_pci_addr_t *a2 = v2;
1006
1007   if (a1->domain > a2->domain)
1008     return 1;
1009   if (a1->domain < a2->domain)
1010     return -1;
1011   if (a1->bus > a2->bus)
1012     return 1;
1013   if (a1->bus < a2->bus)
1014     return -1;
1015   if (a1->slot > a2->slot)
1016     return 1;
1017   if (a1->slot < a2->slot)
1018     return -1;
1019   if (a1->function > a2->function)
1020     return 1;
1021   if (a1->function < a2->function)
1022     return -1;
1023   return 0;
1024 }
1025
1026 vlib_pci_addr_t *
1027 vlib_pci_get_all_dev_addrs ()
1028 {
1029   vlib_pci_addr_t *addrs = 0;
1030   clib_error_t *err;
1031   err = foreach_directory_file ((char *) sysfs_pci_dev_path, scan_pci_addr,
1032                                 &addrs, /* scan_dirs */ 0);
1033   if (err)
1034     {
1035       vec_free (addrs);
1036       return 0;
1037     }
1038
1039   vec_sort_with_function (addrs, pci_addr_cmp);
1040
1041   return addrs;
1042 }
1043
1044 clib_error_t *
1045 linux_pci_init (vlib_main_t * vm)
1046 {
1047   vlib_pci_main_t *pm = &pci_main;
1048   linux_pci_main_t *lpm = &linux_pci_main;
1049   vlib_pci_addr_t *addr = 0, *addrs;
1050   clib_error_t *error;
1051   int fd;
1052
1053   pm->vlib_main = vm;
1054
1055   if ((error = vlib_call_init_function (vm, unix_input_init)))
1056     return error;
1057
1058   ASSERT (sizeof (vlib_pci_addr_t) == sizeof (u32));
1059
1060   fd = open ("/dev/vfio/vfio", O_RDWR);
1061
1062   if ((fd != -1) && (ioctl (fd, VFIO_GET_API_VERSION) != VFIO_API_VERSION))
1063     {
1064       close (fd);
1065       fd = -1;
1066     }
1067
1068   if ((fd != -1) && (ioctl (fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU) == 0))
1069     {
1070       close (fd);
1071       fd = -1;
1072     }
1073
1074   lpm->vfio_container_fd = fd;
1075   lpm->iommu_pool_index_by_group = hash_create (0, sizeof (uword));
1076
1077   addrs = vlib_pci_get_all_dev_addrs ();
1078   /* *INDENT-OFF* */
1079   vec_foreach (addr, addrs)
1080     {
1081       vlib_pci_device_info_t *d;
1082       if ((d = vlib_pci_get_device_info (addr, 0)))
1083         {
1084           init_device_from_registered (vm, d);
1085           vlib_pci_free_device_info (d);
1086         }
1087     }
1088   /* *INDENT-ON* */
1089
1090   return error;
1091 }
1092
1093 VLIB_INIT_FUNCTION (linux_pci_init);
1094
1095 /*
1096  * fd.io coding-style-patch-verification: ON
1097  *
1098  * Local Variables:
1099  * eval: (c-set-style "gnu")
1100  * End:
1101  */