udp: fix csum computation when offload disabled
[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 #include <vppinfra/bitmap.h>
42 #include <vppinfra/unix.h>
43
44 #include <vlib/vlib.h>
45 #include <vlib/pci/pci.h>
46 #include <vlib/unix/unix.h>
47 #include <vlib/linux/vfio.h>
48
49 #include <sys/types.h>
50 #include <sys/stat.h>
51 #include <fcntl.h>
52 #include <dirent.h>
53 #include <sys/ioctl.h>
54 #include <net/if.h>
55 #include <linux/ethtool.h>
56 #include <linux/sockios.h>
57 #include <linux/vfio.h>
58 #include <limits.h>
59 #include <sys/eventfd.h>
60
61 #define SYSFS_DEVICES_PCI "/sys/devices/pci"
62 static const char *sysfs_pci_dev_path = "/sys/bus/pci/devices";
63 static const char *sysfs_pci_drv_path = "/sys/bus/pci/drivers";
64 static char *sysfs_mod_vfio_noiommu =
65   "/sys/module/vfio/parameters/enable_unsafe_noiommu_mode";
66
67 VLIB_REGISTER_LOG_CLASS (pci_log, static) = {
68   .class_name = "pci",
69   .subclass_name = "linux",
70 };
71
72 #define log_debug(p, f, ...)                                                  \
73   vlib_log (VLIB_LOG_LEVEL_DEBUG, pci_log.class, "%U: " f,                    \
74             format_vlib_pci_log, p->handle, ##__VA_ARGS__)
75 #define log_err(p, f, ...)                                                    \
76   vlib_log (VLIB_LOG_LEVEL_ERR, pci_log.class, "%U: " f, format_vlib_pci_log, \
77             p->handle, ##__VA_ARGS__)
78
79 typedef struct
80 {
81   int fd;
82   void *addr;
83   size_t size;
84 } linux_pci_region_t;
85
86 typedef struct
87 {
88   int fd;
89   u32 clib_file_index;
90   union
91   {
92     pci_intx_handler_function_t *intx_handler;
93     pci_msix_handler_function_t *msix_handler;
94   };
95 } linux_pci_irq_t;
96
97 typedef enum
98 {
99   LINUX_PCI_DEVICE_TYPE_UNKNOWN,
100   LINUX_PCI_DEVICE_TYPE_UIO,
101   LINUX_PCI_DEVICE_TYPE_VFIO,
102 } linux_pci_device_type_t;
103
104 typedef struct
105 {
106   linux_pci_device_type_t type;
107   vlib_pci_dev_handle_t handle;
108   vlib_pci_addr_t addr;
109   u32 numa_node;
110
111   /* Resource file descriptors. */
112   linux_pci_region_t *regions;
113
114   /* File descriptor for config space read/write. */
115   int config_fd;
116   u64 config_offset;
117
118   /* Device File descriptor */
119   int fd;
120
121   /* read/write file descriptor for io bar */
122   int io_fd;
123   u64 io_offset;
124
125   /* Minor device for uio device. */
126   u32 uio_minor;
127
128   /* Interrupt handlers */
129   linux_pci_irq_t intx_irq;
130   linux_pci_irq_t *msix_irqs;
131
132   /* private data */
133   uword private_data;
134
135   u8 supports_va_dma;
136
137 } linux_pci_device_t;
138
139 /* Pool of PCI devices. */
140 typedef struct
141 {
142   vlib_main_t *vlib_main;
143   linux_pci_device_t *linux_pci_devices;
144
145 } linux_pci_main_t;
146
147 extern linux_pci_main_t linux_pci_main;
148
149 static linux_pci_device_t *
150 linux_pci_get_device (vlib_pci_dev_handle_t h)
151 {
152   linux_pci_main_t *lpm = &linux_pci_main;
153   return pool_elt_at_index (lpm->linux_pci_devices, h);
154 }
155
156 uword
157 vlib_pci_get_private_data (vlib_main_t * vm, vlib_pci_dev_handle_t h)
158 {
159   linux_pci_device_t *d = linux_pci_get_device (h);
160   return d->private_data;
161 }
162
163 void
164 vlib_pci_set_private_data (vlib_main_t * vm, vlib_pci_dev_handle_t h,
165                            uword private_data)
166 {
167   linux_pci_device_t *d = linux_pci_get_device (h);
168   d->private_data = private_data;
169 }
170
171 vlib_pci_addr_t *
172 vlib_pci_get_addr (vlib_main_t * vm, vlib_pci_dev_handle_t h)
173 {
174   linux_pci_device_t *d = linux_pci_get_device (h);
175   return &d->addr;
176 }
177
178 u32
179 vlib_pci_get_numa_node (vlib_main_t * vm, vlib_pci_dev_handle_t h)
180 {
181   linux_pci_device_t *d = linux_pci_get_device (h);
182   return d->numa_node;
183 }
184
185 u32
186 vlib_pci_get_num_msix_interrupts (vlib_main_t * vm, vlib_pci_dev_handle_t h)
187 {
188   linux_pci_device_t *d = linux_pci_get_device (h);
189
190   if (d->type == LINUX_PCI_DEVICE_TYPE_VFIO)
191     {
192       struct vfio_irq_info ii = { 0 };
193
194       ii.argsz = sizeof (struct vfio_irq_info);
195       ii.index = VFIO_PCI_MSIX_IRQ_INDEX;
196       if (ioctl (d->fd, VFIO_DEVICE_GET_IRQ_INFO, &ii) < 0)
197         return 0;
198       return ii.count;
199     }
200   return 0;
201 }
202
203 /* Call to allocate/initialize the pci subsystem.
204    This is not an init function so that users can explicitly enable
205    pci only when it's needed. */
206 clib_error_t *pci_bus_init (vlib_main_t * vm);
207
208 linux_pci_main_t linux_pci_main;
209
210 vlib_pci_device_info_t *
211 vlib_pci_get_device_info (vlib_main_t * vm, vlib_pci_addr_t * addr,
212                           clib_error_t ** error)
213 {
214   clib_error_t *err;
215   vlib_pci_device_info_t *di;
216   u8 *f = 0;
217   u32 tmp;
218   int fd;
219   u8 *tmpstr;
220   clib_bitmap_t *bmp = 0;
221
222   di = clib_mem_alloc (sizeof (vlib_pci_device_info_t));
223   clib_memset (di, 0, sizeof (vlib_pci_device_info_t));
224   di->addr.as_u32 = addr->as_u32;
225
226   u8 *dev_dir_name = format (0, "%s/%U", sysfs_pci_dev_path,
227                              format_vlib_pci_addr, addr);
228
229   f = format (0, "%v/config%c", dev_dir_name, 0);
230   fd = open ((char *) f, O_RDWR);
231
232   /* Try read-only access if write fails. */
233   if (fd < 0)
234     fd = open ((char *) f, O_RDONLY);
235
236   if (fd < 0)
237     {
238       err = clib_error_return_unix (0, "open `%s'", f);
239       goto error;
240     }
241
242   /* You can only read more that 64 bytes of config space as root; so we try to
243      read the full space but fall back to just the first 64 bytes. */
244   if (read (fd, &di->config, sizeof (di->config)) <
245       sizeof (vlib_pci_config_hdr_t))
246     {
247       err = clib_error_return_unix (0, "read `%s'", f);
248       close (fd);
249       goto error;
250     }
251
252   di->numa_node = -1;
253   vec_reset_length (f);
254   f = format (f, "%v/numa_node%c", dev_dir_name, 0);
255   err = clib_sysfs_read ((char *) f, "%d", &di->numa_node);
256   if (err)
257     {
258       di->numa_node = -1;
259       clib_error_free (err);
260     }
261   if (di->numa_node == -1)
262     {
263       bmp = os_get_online_cpu_node_bitmap ();
264       if (clib_bitmap_count_set_bits (bmp) == 1)
265         di->numa_node = 0;
266     }
267
268   vec_reset_length (f);
269   f = format (f, "%v/class%c", dev_dir_name, 0);
270   err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
271   if (err)
272     goto error;
273   di->device_class = tmp >> 8;
274
275   vec_reset_length (f);
276   f = format (f, "%v/vendor%c", dev_dir_name, 0);
277   err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
278   if (err)
279     goto error;
280   di->vendor_id = tmp;
281
282   vec_reset_length (f);
283   f = format (f, "%v/device%c", dev_dir_name, 0);
284   err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
285   if (err)
286     goto error;
287   di->device_id = tmp;
288
289   vec_reset_length (f);
290   f = format (f, "%v/revision%c", dev_dir_name, 0);
291   err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
292   if (err)
293     goto error;
294   di->revision = tmp;
295
296   di->driver_name =
297     clib_file_get_resolved_basename ("%v/driver", dev_dir_name);
298   if (!di->driver_name)
299     di->driver_name = format (0, "<NONE>%c", 0);
300
301   di->iommu_group = -1;
302   tmpstr = clib_file_get_resolved_basename ("%v/iommu_group", dev_dir_name);
303   if (tmpstr)
304     {
305       di->iommu_group = atoi ((char *) tmpstr);
306       vec_free (tmpstr);
307     }
308
309   vec_reset_length (f);
310   f = format (f, "%v/iommu_group/name%c", dev_dir_name, 0);
311   err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
312   if (err == 0)
313     {
314       if (strncmp ((char *) tmpstr, "vfio-noiommu", 12) == 0)
315         di->flags |= VLIB_PCI_DEVICE_INFO_F_NOIOMMU;
316       vec_free (tmpstr);
317     }
318   else
319     clib_error_free (err);
320
321   close (fd);
322
323   vec_reset_length (f);
324   f = format (f, "%v/vpd%c", dev_dir_name, 0);
325   fd = open ((char *) f, O_RDONLY);
326   if (fd >= 0)
327     {
328       while (1)
329         {
330           u8 tag[3];
331           u8 *data = 0;
332           uword len;
333
334           if (read (fd, &tag, 3) != 3)
335             break;
336
337           if (tag[0] != 0x82 && tag[0] != 0x90 && tag[0] != 0x91)
338             break;
339
340           len = (tag[2] << 8) | tag[1];
341           vec_validate (data, len - 1);
342
343           if (read (fd, data, len) != len)
344             {
345               vec_free (data);
346               break;
347             }
348           if (tag[0] == 0x82)
349             di->product_name = data;
350           else if (tag[0] == 0x90)
351             di->vpd_r = data;
352           else if (tag[0] == 0x91)
353             di->vpd_w = data;
354
355           data = 0;
356         }
357       close (fd);
358     }
359
360   goto done;
361
362 error:
363   vlib_pci_free_device_info (di);
364   di = 0;
365
366 done:
367   vec_free (bmp);
368   vec_free (f);
369   vec_free (dev_dir_name);
370   if (error)
371     *error = err;
372   else
373     clib_error_free (err);
374   return di;
375 }
376
377 clib_error_t *__attribute__ ((weak))
378 vlib_pci_get_device_root_bus (vlib_pci_addr_t *addr, vlib_pci_addr_t *root_bus)
379 {
380   u8 *rel_path = 0, *abs_path = 0, *link_path = 0;
381   unformat_input_t input;
382   int fd = open (sysfs_pci_dev_path, O_RDONLY);
383   ssize_t size = 0;
384   u32 domain = 0, bus;
385   clib_error_t *err = NULL;
386
387   if (fd < 0)
388     return clib_error_return_unix (0, "failed to open %s", sysfs_pci_dev_path);
389
390   vec_alloc (rel_path, PATH_MAX);
391   vec_alloc (abs_path, PATH_MAX);
392
393   link_path =
394     format (0, "%s/%U", sysfs_pci_dev_path, format_vlib_pci_addr, addr);
395   size = readlinkat (fd, (char *) link_path, (char *) rel_path, PATH_MAX);
396   if (size < 0)
397     {
398       err = clib_error_return_unix (0, "failed to read %s", rel_path);
399       goto done;
400     }
401
402   rel_path[size] = '\0';
403   vec_free (link_path);
404
405   link_path = format (0, "%s/%s", sysfs_pci_dev_path, rel_path);
406   if (!realpath ((char *) link_path, (char *) abs_path))
407     {
408       err = clib_error_return_unix (0, "failed to resolve %s", link_path);
409       goto done;
410     }
411
412   unformat_init_string (&input, (char *) abs_path,
413                         clib_strnlen ((char *) abs_path, PATH_MAX));
414
415   if (!unformat (&input, SYSFS_DEVICES_PCI "%x:%x/%s", &domain, &bus,
416                  link_path))
417     {
418       err = clib_error_return (0, "unknown input '%U'", format_unformat_error,
419                                input);
420       goto done;
421     }
422
423   root_bus->domain = domain;
424   root_bus->bus = bus;
425
426 done:
427   vec_free (abs_path);
428   vec_free (link_path);
429   vec_free (rel_path);
430   close (fd);
431
432   return err;
433 }
434
435 static int
436 directory_exists (char *path)
437 {
438   struct stat s = { 0 };
439   if (stat (path, &s) == -1)
440     return 0;
441
442   return S_ISDIR (s.st_mode);
443 }
444
445 clib_error_t *
446 vlib_pci_bind_to_uio (vlib_main_t *vm, vlib_pci_addr_t *addr,
447                       char *uio_drv_name, int force)
448 {
449   clib_error_t *error = 0;
450   u8 *s = 0, *driver_name = 0;
451   DIR *dir = 0;
452   struct dirent *e;
453   vlib_pci_device_info_t *di;
454   int fd, clear_driver_override = 0;
455   u8 *dev_dir_name = format (0, "%s/%U", sysfs_pci_dev_path,
456                              format_vlib_pci_addr, addr);
457
458   di = vlib_pci_get_device_info (vm, addr, &error);
459
460   if (error)
461     return error;
462
463   if (strncmp ("auto", uio_drv_name, 5) == 0)
464     {
465       int vfio_pci_loaded = 0;
466
467       if (directory_exists ("/sys/module/vfio_pci"))
468         vfio_pci_loaded = 1;
469
470       if (di->iommu_group != -1)
471         {
472           /* device is bound to IOMMU group */
473           if (!vfio_pci_loaded)
474             {
475               error = clib_error_return (0, "Skipping PCI device %U: device "
476                                          "is bound to IOMMU group and "
477                                          "vfio-pci driver is not loaded",
478                                          format_vlib_pci_addr, addr);
479               goto err0;
480             }
481           else
482             uio_drv_name = "vfio-pci";
483         }
484       else
485         {
486           /* device is not bound to IOMMU group so we have multiple options */
487           if (vfio_pci_loaded &&
488               (error = clib_sysfs_write (sysfs_mod_vfio_noiommu, "Y")) == 0)
489             uio_drv_name = "vfio-pci";
490           else if (directory_exists ("/sys/module/uio_pci_generic"))
491             uio_drv_name = "uio_pci_generic";
492           else if (directory_exists ("/sys/module/igb_uio"))
493             uio_drv_name = "igb_uio";
494           else
495             {
496               clib_error_free (error);
497               error = clib_error_return (0, "Skipping PCI device %U: missing "
498                                          "kernel VFIO or UIO driver",
499                                          format_vlib_pci_addr, addr);
500               goto err0;
501             }
502           clib_error_free (error);
503         }
504     }
505
506   driver_name = clib_file_get_resolved_basename ("%v/driver", dev_dir_name);
507
508   if (driver_name &&
509       ((strcmp ("vfio-pci", (char *) driver_name) == 0) ||
510        (strcmp ("uio_pci_generic", (char *) driver_name) == 0) ||
511        (strcmp ("igb_uio", (char *) driver_name) == 0)))
512     goto err0;
513
514   if (!force)
515     {
516       /* walk trough all linux interfaces and if interface belonging to
517          this device is found check if interface is admin up  */
518       dir = opendir ("/sys/class/net");
519       s = format (s, "%U%c", format_vlib_pci_addr, addr, 0);
520
521       if (!dir)
522         {
523           error = clib_error_return (0,
524                                      "Skipping PCI device %U: failed to "
525                                      "read /sys/class/net",
526                                      format_vlib_pci_addr, addr);
527           goto err0;
528         }
529
530       fd = socket (PF_INET, SOCK_DGRAM, 0);
531       if (fd < 0)
532         {
533           error = clib_error_return_unix (0, "socket");
534           goto err1;
535         }
536
537       while ((e = readdir (dir)))
538         {
539           struct ifreq ifr;
540           struct ethtool_drvinfo drvinfo;
541
542           if (e->d_name[0] == '.') /* skip . and .. */
543             continue;
544
545           clib_memset (&ifr, 0, sizeof ifr);
546           clib_memset (&drvinfo, 0, sizeof drvinfo);
547           ifr.ifr_data = (char *) &drvinfo;
548           clib_strncpy (ifr.ifr_name, e->d_name, sizeof (ifr.ifr_name) - 1);
549
550           drvinfo.cmd = ETHTOOL_GDRVINFO;
551           if (ioctl (fd, SIOCETHTOOL, &ifr) < 0)
552             {
553               /* Some interfaces (eg "lo") don't support this ioctl */
554               if ((errno != ENOTSUP) && (errno != ENODEV))
555                 clib_unix_warning ("ioctl fetch intf %s bus info error",
556                                    e->d_name);
557               continue;
558             }
559
560           if (strcmp ((char *) s, drvinfo.bus_info))
561             continue;
562
563           clib_memset (&ifr, 0, sizeof (ifr));
564           clib_strncpy (ifr.ifr_name, e->d_name, sizeof (ifr.ifr_name) - 1);
565
566           if (ioctl (fd, SIOCGIFFLAGS, &ifr) < 0)
567             {
568               error = clib_error_return_unix (0, "ioctl fetch intf %s flags",
569                                               e->d_name);
570               close (fd);
571               goto err1;
572             }
573
574           if (ifr.ifr_flags & IFF_UP)
575             {
576               vlib_log (VLIB_LOG_LEVEL_WARNING, pci_main.log_default,
577                         "Skipping PCI device %U as host "
578                         "interface %s is up",
579                         format_vlib_pci_addr, addr, e->d_name);
580               close (fd);
581               goto err1;
582             }
583         }
584
585       close (fd);
586       vec_reset_length (s);
587     }
588
589   s = format (s, "%v/driver/unbind%c", dev_dir_name, 0);
590   clib_sysfs_write ((char *) s, "%U", format_vlib_pci_addr, addr);
591   vec_reset_length (s);
592
593   s = format (s, "%v/driver_override%c", dev_dir_name, 0);
594   if (access ((char *) s, F_OK) == 0)
595     {
596       clib_sysfs_write ((char *) s, "%s", uio_drv_name);
597       clear_driver_override = 1;
598     }
599   else
600     {
601       vec_reset_length (s);
602       s = format (s, "%s/%s/new_id%c", sysfs_pci_drv_path, uio_drv_name, 0);
603       clib_sysfs_write ((char *) s, "0x%04x 0x%04x", di->vendor_id,
604                         di->device_id);
605     }
606   vec_reset_length (s);
607
608   s = format (s, "%s/%s/bind%c", sysfs_pci_drv_path, uio_drv_name, 0);
609   clib_sysfs_write ((char *) s, "%U", format_vlib_pci_addr, addr);
610   vec_reset_length (s);
611
612   if (clear_driver_override)
613     {
614       s = format (s, "%v/driver_override%c", dev_dir_name, 0);
615       clib_sysfs_write ((char *) s, "%c", 0);
616       vec_reset_length (s);
617     }
618
619 err1:
620   closedir (dir);
621 err0:
622   vec_free (s);
623   vec_free (dev_dir_name);
624   vec_free (driver_name);
625   return error;
626 }
627
628
629 static clib_error_t *
630 scan_uio_dir (void *arg, u8 * path_name, u8 * file_name)
631 {
632   linux_pci_device_t *l = arg;
633   unformat_input_t input;
634
635   unformat_init_string (&input, (char *) file_name, vec_len (file_name));
636
637   if (!unformat (&input, "uio%d", &l->uio_minor))
638     abort ();
639
640   unformat_free (&input);
641   return 0;
642 }
643
644 static clib_error_t *
645 vfio_set_irqs (vlib_main_t * vm, linux_pci_device_t * p, u32 index, u32 start,
646                u32 count, u32 flags, int *efds)
647 {
648   int data_len = efds ? count * sizeof (int) : 0;
649   u8 buf[sizeof (struct vfio_irq_set) + data_len];
650   struct vfio_irq_set *irq_set = (struct vfio_irq_set *) buf;
651
652   if (efds)
653     {
654       int *data = (int *) irq_set->data;
655       flags |= VFIO_IRQ_SET_DATA_EVENTFD;
656       for (u32 i = 0; i < count; i++)
657         data[i] = efds[i];
658     }
659   else
660     flags |= VFIO_IRQ_SET_DATA_NONE;
661
662   ASSERT ((flags & (VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_DATA_EVENTFD)) !=
663           (VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_DATA_EVENTFD));
664
665   irq_set->argsz = sizeof (struct vfio_irq_set) + data_len;
666   irq_set->index = index;
667   irq_set->start = start;
668   irq_set->count = count;
669   irq_set->flags = flags;
670
671   if (ioctl (p->fd, VFIO_DEVICE_SET_IRQS, irq_set) < 0)
672     return clib_error_return_unix (0, "%U:ioctl(VFIO_DEVICE_SET_IRQS)\n%U",
673                                    format_vlib_pci_addr, &p->addr,
674                                    format_vfio_irq_set, irq_set);
675
676   log_debug (p, "%s:\n%U", __func__, format_vfio_irq_set, irq_set);
677   return 0;
678 }
679
680 static clib_error_t *
681 linux_pci_uio_read_ready (clib_file_t * uf)
682 {
683   vlib_main_t *vm = vlib_get_main ();
684   int __attribute__ ((unused)) rv;
685   vlib_pci_dev_handle_t h = uf->private_data;
686   linux_pci_device_t *p = linux_pci_get_device (h);
687   linux_pci_irq_t *irq = &p->intx_irq;
688
689   u32 icount;
690   rv = read (uf->file_descriptor, &icount, 4);
691
692   if (irq->intx_handler)
693     irq->intx_handler (vm, h);
694
695   vlib_pci_intr_enable (vm, h);
696
697   return /* no error */ 0;
698 }
699
700 static clib_error_t *
701 linux_pci_vfio_unmask_intx (vlib_main_t * vm, linux_pci_device_t * d)
702 {
703   return vfio_set_irqs (vm, d, VFIO_PCI_INTX_IRQ_INDEX, 0, 1,
704                         VFIO_IRQ_SET_ACTION_UNMASK, 0);
705 }
706
707 static clib_error_t *
708 linux_pci_uio_error_ready (clib_file_t * uf)
709 {
710   u32 error_index = (u32) uf->private_data;
711
712   return clib_error_return (0, "pci device %d: error", error_index);
713 }
714
715 static clib_error_t *
716 linux_pci_vfio_msix_read_ready (clib_file_t * uf)
717 {
718   vlib_main_t *vm = vlib_get_main ();
719   int __attribute__ ((unused)) rv;
720   vlib_pci_dev_handle_t h = uf->private_data >> 16;
721   u16 line = uf->private_data & 0xffff;
722   linux_pci_device_t *p = linux_pci_get_device (h);
723   linux_pci_irq_t *irq = vec_elt_at_index (p->msix_irqs, line);
724
725   u64 icount;
726   rv = read (uf->file_descriptor, &icount, sizeof (icount));
727
728   if (irq->msix_handler)
729     irq->msix_handler (vm, h, line);
730
731   return /* no error */ 0;
732 }
733
734 static clib_error_t *
735 linux_pci_vfio_intx_read_ready (clib_file_t * uf)
736 {
737   vlib_main_t *vm = vlib_get_main ();
738   int __attribute__ ((unused)) rv;
739   vlib_pci_dev_handle_t h = uf->private_data;
740   linux_pci_device_t *p = linux_pci_get_device (h);
741   linux_pci_irq_t *irq = &p->intx_irq;
742
743   u64 icount;
744   rv = read (uf->file_descriptor, &icount, sizeof (icount));
745
746   if (irq->intx_handler)
747     irq->intx_handler (vm, h);
748
749   linux_pci_vfio_unmask_intx (vm, p);
750
751   return /* no error */ 0;
752 }
753
754 static clib_error_t *
755 linux_pci_vfio_error_ready (clib_file_t * uf)
756 {
757   u32 error_index = (u32) uf->private_data;
758
759   return clib_error_return (0, "pci device %d: error", error_index);
760 }
761
762 static clib_error_t *
763 add_device_uio (vlib_main_t * vm, linux_pci_device_t * p,
764                 vlib_pci_device_info_t * di, pci_device_registration_t * r)
765 {
766   linux_pci_main_t *lpm = &linux_pci_main;
767   clib_error_t *err = 0;
768   u8 *s = 0;
769
770   p->fd = -1;
771   p->type = LINUX_PCI_DEVICE_TYPE_UIO;
772
773   s = format (s, "%s/%U/config%c", sysfs_pci_dev_path,
774               format_vlib_pci_addr, &di->addr, 0);
775
776   p->config_fd = open ((char *) s, O_RDWR);
777   p->config_offset = 0;
778   vec_reset_length (s);
779
780   if (p->config_fd == -1)
781     {
782       err = clib_error_return_unix (0, "open '%s'", s);
783       goto error;
784     }
785
786   s = format (0, "%s/%U/uio%c", sysfs_pci_dev_path,
787               format_vlib_pci_addr, &di->addr, 0);
788   foreach_directory_file ((char *) s, scan_uio_dir, p,  /* scan_dirs */
789                           1);
790   vec_reset_length (s);
791
792   s = format (s, "/dev/uio%d%c", p->uio_minor, 0);
793   p->fd = open ((char *) s, O_RDWR);
794   if (p->fd < 0)
795     {
796       err = clib_error_return_unix (0, "open '%s'", s);
797       goto error;
798     }
799
800   if (r && r->interrupt_handler)
801     vlib_pci_register_intx_handler (vm, p->handle, r->interrupt_handler);
802
803   if (r && r->init_function)
804     err = r->init_function (lpm->vlib_main, p->handle);
805
806 error:
807   vec_free (s);
808   if (err)
809     {
810       if (p->config_fd != -1)
811         close (p->config_fd);
812       if (p->fd != -1)
813         close (p->fd);
814     }
815   return err;
816 }
817
818 clib_error_t *
819 vlib_pci_register_intx_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h,
820                                 pci_intx_handler_function_t * intx_handler)
821 {
822   linux_pci_device_t *p = linux_pci_get_device (h);
823   clib_file_t t = { 0 };
824   linux_pci_irq_t *irq = &p->intx_irq;
825   ASSERT (irq->fd == -1);
826
827   if (p->type == LINUX_PCI_DEVICE_TYPE_VFIO)
828     {
829       struct vfio_irq_info ii = { 0 };
830       ii.argsz = sizeof (struct vfio_irq_info);
831       ii.index = VFIO_PCI_INTX_IRQ_INDEX;
832       if (ioctl (p->fd, VFIO_DEVICE_GET_IRQ_INFO, &ii) < 0)
833         return clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_IRQ_INFO) '"
834                                        "%U'", format_vlib_pci_addr, &p->addr);
835       log_debug (
836         p, "%s index:%u count:%u flags: %s%s%s%s(0x%x)", __func__, ii.index,
837         ii.count, ii.flags & VFIO_IRQ_INFO_EVENTFD ? "eventfd " : "",
838         ii.flags & VFIO_IRQ_INFO_MASKABLE ? "maskable " : "",
839         ii.flags & VFIO_IRQ_INFO_AUTOMASKED ? "automasked " : "",
840         ii.flags & VFIO_IRQ_INFO_NORESIZE ? "noresize " : "", ii.flags);
841       if (ii.count != 1)
842         return clib_error_return (0, "INTx interrupt does not exist on device"
843                                   "'%U'", format_vlib_pci_addr, &p->addr);
844
845       irq->fd = eventfd (0, EFD_NONBLOCK);
846       if (irq->fd == -1)
847         return clib_error_return_unix (0, "eventfd");
848
849       t.file_descriptor = irq->fd;
850       t.read_function = linux_pci_vfio_intx_read_ready;
851     }
852   else if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
853     {
854       t.file_descriptor = p->fd;
855       t.read_function = linux_pci_uio_read_ready;
856     }
857   else
858     return 0;
859
860   t.error_function = linux_pci_uio_error_ready;
861   t.private_data = p->handle;
862   t.description = format (0, "PCI %U INTx", format_vlib_pci_addr, &p->addr);
863   irq->clib_file_index = clib_file_add (&file_main, &t);
864   irq->intx_handler = intx_handler;
865   return 0;
866 }
867
868 clib_error_t *
869 vlib_pci_unregister_intx_handler (vlib_main_t *vm, vlib_pci_dev_handle_t h)
870 {
871   linux_pci_device_t *p = linux_pci_get_device (h);
872   linux_pci_irq_t *irq = &p->intx_irq;
873
874   if (irq->intx_handler == 0)
875     return 0;
876
877   clib_file_del_by_index (&file_main, irq->clib_file_index);
878   if (p->type == LINUX_PCI_DEVICE_TYPE_VFIO)
879     {
880       close (irq->fd);
881       irq->fd = -1;
882     }
883
884   irq->intx_handler = 0;
885
886   return 0;
887 }
888
889 clib_error_t *
890 vlib_pci_register_msix_handler (vlib_main_t * vm, vlib_pci_dev_handle_t h,
891                                 u32 start, u32 count,
892                                 pci_msix_handler_function_t * msix_handler)
893 {
894   clib_error_t *err = 0;
895   linux_pci_device_t *p = linux_pci_get_device (h);
896   u32 i;
897
898   if (p->type != LINUX_PCI_DEVICE_TYPE_VFIO)
899     return clib_error_return (0, "vfio driver is needed for MSI-X interrupt "
900                               "support");
901
902   vec_validate_init_empty (p->msix_irqs, start + count - 1, (linux_pci_irq_t)
903                            { .fd = -1});
904
905   for (i = start; i < start + count; i++)
906     {
907       clib_file_t t = { 0 };
908       linux_pci_irq_t *irq = vec_elt_at_index (p->msix_irqs, i);
909       ASSERT (irq->fd == -1);
910
911       irq->fd = eventfd (0, EFD_NONBLOCK);
912       if (irq->fd == -1)
913         {
914           err = clib_error_return_unix (0, "eventfd");
915           goto error;
916         }
917
918       t.read_function = linux_pci_vfio_msix_read_ready;
919       t.file_descriptor = irq->fd;
920       t.error_function = linux_pci_vfio_error_ready;
921       t.private_data = p->handle << 16 | i;
922       t.description = format (0, "PCI %U MSI-X #%u", format_vlib_pci_addr,
923                               &p->addr, i);
924       irq->clib_file_index = clib_file_add (&file_main, &t);
925       irq->msix_handler = msix_handler;
926     }
927
928   return 0;
929
930 error:
931   while (i-- > start)
932     {
933       linux_pci_irq_t *irq = vec_elt_at_index (p->msix_irqs, i);
934       if (irq->fd != -1)
935         {
936           clib_file_del_by_index (&file_main, irq->clib_file_index);
937           close (irq->fd);
938           irq->fd = -1;
939         }
940     }
941   return err;
942 }
943
944 clib_error_t *
945 vlib_pci_unregister_msix_handler (vlib_main_t *vm, vlib_pci_dev_handle_t h,
946                                   u32 start, u32 count)
947 {
948   clib_error_t *err = 0;
949   linux_pci_device_t *p = linux_pci_get_device (h);
950   u32 i;
951
952   if (p->type != LINUX_PCI_DEVICE_TYPE_VFIO)
953     return clib_error_return (0, "vfio driver is needed for MSI-X interrupt "
954                                  "support");
955
956   for (i = start; i < start + count; i++)
957     {
958       linux_pci_irq_t *irq = vec_elt_at_index (p->msix_irqs, i);
959
960       if (irq->fd != -1)
961         {
962           clib_file_del_by_index (&file_main, irq->clib_file_index);
963           close (irq->fd);
964           irq->fd = -1;
965         }
966     }
967
968   return err;
969 }
970
971 clib_error_t *
972 vlib_pci_enable_msix_irq (vlib_main_t * vm, vlib_pci_dev_handle_t h,
973                           u16 start, u16 count)
974 {
975   linux_pci_device_t *p = linux_pci_get_device (h);
976   int fds[count];
977   int i;
978
979   if (p->type != LINUX_PCI_DEVICE_TYPE_VFIO)
980     return clib_error_return (0, "vfio driver is needed for MSI-X interrupt "
981                               "support");
982
983   for (i = 0; i < count; i++)
984     {
985       linux_pci_irq_t *irq = vec_elt_at_index (p->msix_irqs, start + i);
986       fds[i] = irq->fd;
987     }
988
989   return vfio_set_irqs (vm, p, VFIO_PCI_MSIX_IRQ_INDEX, start, count,
990                         VFIO_IRQ_SET_ACTION_TRIGGER, fds);
991 }
992
993 uword
994 vlib_pci_get_msix_file_index (vlib_main_t * vm, vlib_pci_dev_handle_t h,
995                               u16 index)
996 {
997   linux_pci_device_t *p = linux_pci_get_device (h);
998   linux_pci_irq_t *irq = vec_elt_at_index (p->msix_irqs, index);
999   if (irq->fd == -1)
1000     return ~0;
1001   return irq->clib_file_index;
1002 }
1003
1004 clib_error_t *
1005 vlib_pci_disable_msix_irq (vlib_main_t * vm, vlib_pci_dev_handle_t h,
1006                            u16 start, u16 count)
1007 {
1008   linux_pci_device_t *p = linux_pci_get_device (h);
1009   int i, fds[count];
1010
1011   if (p->type != LINUX_PCI_DEVICE_TYPE_VFIO)
1012     return clib_error_return (0, "vfio driver is needed for MSI-X interrupt "
1013                               "support");
1014
1015   for (i = start; i < start + count; i++)
1016     fds[i] = -1;
1017
1018   return vfio_set_irqs (vm, p, VFIO_PCI_MSIX_IRQ_INDEX, start, count,
1019                         VFIO_IRQ_SET_ACTION_TRIGGER, fds);
1020 }
1021
1022 static clib_error_t *
1023 add_device_vfio (vlib_main_t * vm, linux_pci_device_t * p,
1024                  vlib_pci_device_info_t * di, pci_device_registration_t * r)
1025 {
1026   linux_pci_main_t *lpm = &linux_pci_main;
1027   struct vfio_device_info device_info = { 0 };
1028   struct vfio_region_info reg = { 0 };
1029   clib_error_t *err = 0;
1030   u8 *s = 0;
1031   int is_noiommu;
1032
1033   p->type = LINUX_PCI_DEVICE_TYPE_VFIO;
1034
1035   if ((err = linux_vfio_group_get_device_fd (&p->addr, &p->fd, &is_noiommu)))
1036     return err;
1037
1038   if (is_noiommu == 0)
1039     p->supports_va_dma = 1;
1040
1041   device_info.argsz = sizeof (device_info);
1042   if (ioctl (p->fd, VFIO_DEVICE_GET_INFO, &device_info) < 0)
1043     {
1044       err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_INFO) '%U'",
1045                                     format_vlib_pci_addr, &di->addr);
1046       goto error;
1047     }
1048
1049   reg.argsz = sizeof (struct vfio_region_info);
1050   reg.index = VFIO_PCI_CONFIG_REGION_INDEX;
1051   if (ioctl (p->fd, VFIO_DEVICE_GET_REGION_INFO, &reg) < 0)
1052     {
1053       err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_INFO) '%U'",
1054                                     format_vlib_pci_addr, &di->addr);
1055       goto error;
1056     }
1057
1058   log_debug (p, "%s %U", __func__, format_vfio_region_info, &reg);
1059
1060   p->config_offset = reg.offset;
1061   p->config_fd = p->fd;
1062
1063   /* reset if device supports it */
1064   if (device_info.flags & VFIO_DEVICE_FLAGS_RESET)
1065     if (ioctl (p->fd, VFIO_DEVICE_RESET) < 0)
1066       {
1067         err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_RESET) '%U'",
1068                                       format_vlib_pci_addr, &di->addr);
1069         goto error;
1070       }
1071
1072   if (r && r->interrupt_handler)
1073     {
1074       vlib_pci_register_intx_handler (vm, p->handle, r->interrupt_handler);
1075       linux_pci_vfio_unmask_intx (vm, p);
1076     }
1077
1078   if (p->supports_va_dma)
1079     {
1080       vlib_buffer_pool_t *bp;
1081       vec_foreach (bp, vm->buffer_main->buffer_pools)
1082         {
1083           u32 i;
1084           vlib_physmem_map_t *pm;
1085           pm = vlib_physmem_get_map (vm, bp->physmem_map_index);
1086           for (i = 0; i < pm->n_pages; i++)
1087             vfio_map_physmem_page (vm, pm->base + (i << pm->log2_page_size));
1088         }
1089     }
1090
1091   if (r && r->init_function)
1092     err = r->init_function (lpm->vlib_main, p->handle);
1093
1094 error:
1095   vec_free (s);
1096   if (err)
1097     {
1098       if (p->fd != -1)
1099         close (p->fd);
1100       if (p->config_fd != -1 && p->config_fd != p->fd)
1101         close (p->config_fd);
1102       p->config_fd = p->fd = -1;
1103     }
1104   return err;
1105 }
1106
1107 /* Configuration space read/write. */
1108 clib_error_t *
1109 vlib_pci_read_write_config (vlib_main_t * vm, vlib_pci_dev_handle_t h,
1110                             vlib_read_or_write_t read_or_write,
1111                             uword address, void *data, u32 n_bytes)
1112 {
1113   linux_pci_device_t *p = linux_pci_get_device (h);
1114   int n;
1115
1116   if (read_or_write == VLIB_READ)
1117     n = pread (p->config_fd, data, n_bytes, p->config_offset + address);
1118   else
1119     n = pwrite (p->config_fd, data, n_bytes, p->config_offset + address);
1120
1121   if (n != n_bytes)
1122     return clib_error_return_unix (0, "%s",
1123                                    read_or_write == VLIB_READ
1124                                    ? "read" : "write");
1125
1126   return 0;
1127 }
1128
1129 static clib_error_t *
1130 vlib_pci_region (vlib_main_t * vm, vlib_pci_dev_handle_t h, u32 bar, int *fd,
1131                  u64 * size, u64 * offset)
1132 {
1133   linux_pci_device_t *p = linux_pci_get_device (h);
1134   clib_error_t *error = 0;
1135   int _fd = -1;
1136   u64 _size = 0, _offset = 0;
1137
1138   ASSERT (bar <= 5);
1139
1140   error = 0;
1141
1142   if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
1143     {
1144       u8 *file_name;
1145       struct stat stat_buf;
1146       file_name = format (0, "%s/%U/resource%d%c", sysfs_pci_dev_path,
1147                           format_vlib_pci_addr, &p->addr, bar, 0);
1148
1149       _fd = open ((char *) file_name, O_RDWR);
1150       if (_fd < 0)
1151         {
1152           error = clib_error_return_unix (0, "open `%s'", file_name);
1153           vec_free (file_name);
1154           return error;
1155         }
1156
1157       if (fstat (_fd, &stat_buf) < 0)
1158         {
1159           error = clib_error_return_unix (0, "fstat `%s'", file_name);
1160           vec_free (file_name);
1161           close (_fd);
1162           return error;
1163         }
1164
1165       vec_free (file_name);
1166       _size = stat_buf.st_size;
1167       _offset = 0;
1168     }
1169   else if (p->type == LINUX_PCI_DEVICE_TYPE_VFIO)
1170     {
1171       struct vfio_region_info *r;
1172       u32 sz = sizeof (struct vfio_region_info);
1173     again:
1174       r = clib_mem_alloc (sz);
1175       clib_memset (r, 0, sz);
1176       r->argsz = sz;
1177       r->index = bar;
1178       if (ioctl (p->fd, VFIO_DEVICE_GET_REGION_INFO, r) < 0)
1179         return clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_INFO) "
1180                                        "'%U'", format_vlib_pci_addr,
1181                                        &p->addr);
1182       if (sz != r->argsz)
1183         {
1184           sz = r->argsz;
1185           clib_mem_free (r);
1186           goto again;
1187         }
1188       _fd = p->fd;
1189       _size = r->size;
1190       _offset = r->offset;
1191       log_debug (p, "%s %U", __func__, format_vfio_region_info, r);
1192       clib_mem_free (r);
1193     }
1194   else
1195     ASSERT (0);
1196
1197   *fd = _fd;
1198   *size = _size;
1199   *offset = _offset;
1200
1201   return error;
1202 }
1203
1204 static clib_error_t *
1205 vlib_pci_map_region_int (vlib_main_t * vm, vlib_pci_dev_handle_t h,
1206                          u32 bar, u8 * addr, void **result)
1207 {
1208   linux_pci_device_t *p = linux_pci_get_device (h);
1209   int fd = -1;
1210   clib_error_t *error;
1211   u64 size = 0, offset = 0;
1212   vlib_pci_config_reg_command_t command;
1213
1214   log_debug (p, "map region %u to va %p", bar, addr);
1215
1216   if ((error = vlib_pci_read_config_u16 (vm, h, 4, &command.as_u16)))
1217     return error;
1218
1219   if (!(command.mem_space))
1220     {
1221       log_debug (p, "setting memory enable bit");
1222       command.mem_space = 1;
1223       if ((error = vlib_pci_write_config_u16 (vm, h, 4, &command.as_u16)))
1224         return error;
1225     }
1226
1227   if ((error = vlib_pci_region (vm, h, bar, &fd, &size, &offset)))
1228     return error;
1229
1230   *result = clib_mem_vm_map_shared (addr, size, fd, offset,
1231                                     "PCIe %U region %u", format_vlib_pci_addr,
1232                                     vlib_pci_get_addr (vm, h), bar);
1233   if (*result == CLIB_MEM_VM_MAP_FAILED)
1234     {
1235       error = clib_error_return_unix (0, "mmap `BAR%u'", bar);
1236       if (p->type == LINUX_PCI_DEVICE_TYPE_UIO && (fd != -1))
1237         close (fd);
1238       return error;
1239     }
1240
1241   vec_validate_init_empty (p->regions, bar,
1242                            (linux_pci_region_t) { .fd = -1});
1243   if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
1244     p->regions[bar].fd = fd;
1245   p->regions[bar].addr = *result;
1246   p->regions[bar].size = size;
1247   return 0;
1248 }
1249
1250 clib_error_t *
1251 vlib_pci_map_region (vlib_main_t * vm, vlib_pci_dev_handle_t h, u32 resource,
1252                      void **result)
1253 {
1254   return (vlib_pci_map_region_int (vm, h, resource, 0 /* addr */ , result));
1255 }
1256
1257 clib_error_t *
1258 vlib_pci_map_region_fixed (vlib_main_t * vm, vlib_pci_dev_handle_t h,
1259                            u32 resource, u8 * addr, void **result)
1260 {
1261   return (vlib_pci_map_region_int (vm, h, resource, addr, result));
1262 }
1263
1264 clib_error_t *
1265 vlib_pci_io_region (vlib_main_t * vm, vlib_pci_dev_handle_t h, u32 resource)
1266 {
1267   linux_pci_device_t *p = linux_pci_get_device (h);
1268   clib_error_t *error = 0;
1269   int fd = -1;
1270   u64 size = 0, offset = 0;
1271
1272   if ((error = vlib_pci_region (vm, h, resource, &fd, &size, &offset)))
1273     return error;
1274
1275   p->io_fd = fd;
1276   p->io_offset = offset;
1277   return error;
1278 }
1279
1280 clib_error_t *
1281 vlib_pci_read_write_io (vlib_main_t * vm, vlib_pci_dev_handle_t h,
1282                         vlib_read_or_write_t read_or_write,
1283                         uword offset, void *data, u32 length)
1284 {
1285   linux_pci_device_t *p = linux_pci_get_device (h);
1286   int n = 0;
1287
1288   if (read_or_write == VLIB_READ)
1289     n = pread (p->io_fd, data, length, p->io_offset + offset);
1290   else
1291     n = pwrite (p->io_fd, data, length, p->io_offset + offset);
1292
1293   if (n != length)
1294     return clib_error_return_unix (0, "%s",
1295                                    read_or_write == VLIB_READ
1296                                    ? "read" : "write");
1297   return 0;
1298 }
1299
1300 clib_error_t *
1301 vlib_pci_map_dma (vlib_main_t * vm, vlib_pci_dev_handle_t h, void *ptr)
1302 {
1303   linux_pci_device_t *p = linux_pci_get_device (h);
1304
1305   if (!p->supports_va_dma)
1306     return 0;
1307
1308   return vfio_map_physmem_page (vm, ptr);
1309 }
1310
1311 int
1312 vlib_pci_supports_virtual_addr_dma (vlib_main_t * vm, vlib_pci_dev_handle_t h)
1313 {
1314   linux_pci_device_t *p = linux_pci_get_device (h);
1315
1316   return p->supports_va_dma != 0;
1317 }
1318
1319 clib_error_t *
1320 vlib_pci_device_open (vlib_main_t * vm, vlib_pci_addr_t * addr,
1321                       pci_device_id_t ids[], vlib_pci_dev_handle_t * handle)
1322 {
1323   linux_pci_main_t *lpm = &linux_pci_main;
1324   vlib_pci_device_info_t *di;
1325   linux_pci_device_t *p;
1326   clib_error_t *err = 0;
1327   pci_device_id_t *i;
1328
1329   di = vlib_pci_get_device_info (vm, addr, &err);
1330
1331   if (err)
1332     return err;
1333
1334   if (ids)
1335     {
1336       for (i = ids; i->vendor_id != 0; i++)
1337         if (i->vendor_id == di->vendor_id && i->device_id == di->device_id)
1338           break;
1339
1340       if (i->vendor_id == 0)
1341         {
1342           vlib_pci_free_device_info (di);
1343           return clib_error_return (0, "Wrong vendor or device id");
1344         }
1345     }
1346
1347   pool_get (lpm->linux_pci_devices, p);
1348   p->handle = p - lpm->linux_pci_devices;
1349   p->addr.as_u32 = di->addr.as_u32;
1350   p->intx_irq.fd = -1;
1351   p->intx_irq.clib_file_index = -1;
1352   p->numa_node = di->numa_node;
1353   /*
1354    * pci io bar read/write fd
1355    */
1356   p->io_fd = -1;
1357
1358   log_debug (p, "open vid:0x%04x did:0x%04x driver:%s iommu_group:%d",
1359              di->vendor_id, di->device_id, di->driver_name, di->iommu_group);
1360
1361   if (clib_strncmp ("vfio-pci", (char *) di->driver_name, 8) == 0)
1362     err = add_device_vfio (vm, p, di, 0);
1363   else if (clib_strncmp ("uio_pci_generic", (char *) di->driver_name, 8) == 0)
1364     err = add_device_uio (vm, p, di, 0);
1365   else
1366     err = clib_error_create ("device not bound to 'vfio-pci' or "
1367                              "'uio_pci_generic' kernel module");
1368   if (err)
1369     goto error;
1370
1371   *handle = p->handle;
1372
1373 error:
1374   vlib_pci_free_device_info (di);
1375   if (err)
1376     {
1377       log_err (p, "%U", format_clib_error, err);
1378       clib_memset (p, 0, sizeof (linux_pci_device_t));
1379       pool_put (lpm->linux_pci_devices, p);
1380     }
1381
1382   return err;
1383 }
1384
1385 void
1386 vlib_pci_device_close (vlib_main_t * vm, vlib_pci_dev_handle_t h)
1387 {
1388   linux_pci_main_t *lpm = &linux_pci_main;
1389   linux_pci_device_t *p = linux_pci_get_device (h);
1390   linux_pci_irq_t *irq;
1391   linux_pci_region_t *res;
1392   clib_error_t *err = 0;
1393
1394   if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
1395     {
1396       irq = &p->intx_irq;
1397       if (irq->clib_file_index != -1)
1398         clib_file_del_by_index (&file_main, irq->clib_file_index);
1399       close (p->config_fd);
1400       if (p->io_fd != -1)
1401         close (p->io_fd);
1402     }
1403   else if (p->type == LINUX_PCI_DEVICE_TYPE_VFIO)
1404     {
1405       irq = &p->intx_irq;
1406       /* close INTx irqs */
1407       if (irq->fd != -1)
1408         {
1409           err = vfio_set_irqs (vm, p, VFIO_PCI_INTX_IRQ_INDEX, 0, 0,
1410                                VFIO_IRQ_SET_ACTION_TRIGGER, 0);
1411           clib_error_free (err);
1412           if (irq->clib_file_index != -1)
1413             clib_file_del_by_index (&file_main, irq->clib_file_index);
1414           close (irq->fd);
1415         }
1416
1417       /* close MSI-X irqs */
1418       if (vec_len (p->msix_irqs))
1419         {
1420           err = vfio_set_irqs (vm, p, VFIO_PCI_MSIX_IRQ_INDEX, 0, 0,
1421                                VFIO_IRQ_SET_ACTION_TRIGGER, 0);
1422           clib_error_free (err);
1423           vec_foreach (irq, p->msix_irqs)
1424             {
1425               if (irq->fd == -1)
1426                 continue;
1427               clib_file_del_by_index (&file_main, irq->clib_file_index);
1428               close (irq->fd);
1429             }
1430           vec_free (p->msix_irqs);
1431         }
1432     }
1433
1434   vec_foreach (res, p->regions)
1435     {
1436       if (res->size == 0)
1437         continue;
1438       clib_mem_vm_unmap (res->addr);
1439       if (res->fd != -1)
1440         close (res->fd);
1441     }
1442   vec_free (p->regions);
1443
1444   close (p->fd);
1445   clib_memset (p, 0, sizeof (linux_pci_device_t));
1446   pool_put (lpm->linux_pci_devices, p);
1447 }
1448
1449 void
1450 init_device_from_registered (vlib_main_t * vm, vlib_pci_device_info_t * di)
1451 {
1452   vlib_pci_main_t *pm = &pci_main;
1453   linux_pci_main_t *lpm = &linux_pci_main;
1454   pci_device_registration_t *r;
1455   pci_device_id_t *i;
1456   clib_error_t *err = 0;
1457   linux_pci_device_t *p;
1458
1459   pool_get (lpm->linux_pci_devices, p);
1460   p->handle = p - lpm->linux_pci_devices;
1461   p->intx_irq.fd = -1;
1462
1463   r = pm->pci_device_registrations;
1464
1465   while (r)
1466     {
1467       for (i = r->supported_devices; i->vendor_id != 0; i++)
1468         if (i->vendor_id == di->vendor_id && i->device_id == di->device_id)
1469           {
1470             if (di->iommu_group != -1)
1471               err = add_device_vfio (vm, p, di, r);
1472             else
1473               err = add_device_uio (vm, p, di, r);
1474
1475             if (err)
1476               clib_error_report (err);
1477             else
1478               return;
1479           }
1480       r = r->next_registration;
1481     }
1482
1483   /* No driver, close the PCI config-space FD */
1484   clib_memset (p, 0, sizeof (linux_pci_device_t));
1485   pool_put (lpm->linux_pci_devices, p);
1486 }
1487
1488 static clib_error_t *
1489 scan_pci_addr (void *arg, u8 * dev_dir_name, u8 * ignored)
1490 {
1491   vlib_pci_addr_t addr, **addrv = arg;
1492   unformat_input_t input;
1493   clib_error_t *err = 0;
1494
1495   unformat_init_string (&input, (char *) dev_dir_name,
1496                         vec_len (dev_dir_name));
1497
1498   if (!unformat (&input, "/sys/bus/pci/devices/%U",
1499                  unformat_vlib_pci_addr, &addr))
1500     err = clib_error_return (0, "unformat error `%v`", dev_dir_name);
1501
1502   unformat_free (&input);
1503
1504   if (err)
1505     return err;
1506
1507   vec_add1 (*addrv, addr);
1508   return 0;
1509 }
1510
1511 static int
1512 pci_addr_cmp (void *v1, void *v2)
1513 {
1514   vlib_pci_addr_t *a1 = v1;
1515   vlib_pci_addr_t *a2 = v2;
1516
1517   if (a1->domain > a2->domain)
1518     return 1;
1519   if (a1->domain < a2->domain)
1520     return -1;
1521   if (a1->bus > a2->bus)
1522     return 1;
1523   if (a1->bus < a2->bus)
1524     return -1;
1525   if (a1->slot > a2->slot)
1526     return 1;
1527   if (a1->slot < a2->slot)
1528     return -1;
1529   if (a1->function > a2->function)
1530     return 1;
1531   if (a1->function < a2->function)
1532     return -1;
1533   return 0;
1534 }
1535
1536 vlib_pci_addr_t *
1537 vlib_pci_get_all_dev_addrs ()
1538 {
1539   vlib_pci_addr_t *addrs = 0;
1540   clib_error_t *err;
1541   err = foreach_directory_file ((char *) sysfs_pci_dev_path, scan_pci_addr,
1542                                 &addrs, /* scan_dirs */ 0);
1543   if (err)
1544     {
1545       vec_free (addrs);
1546       return 0;
1547     }
1548
1549   vec_sort_with_function (addrs, pci_addr_cmp);
1550
1551   return addrs;
1552 }
1553
1554 clib_error_t *
1555 linux_pci_init (vlib_main_t * vm)
1556 {
1557   vlib_pci_main_t *pm = &pci_main;
1558   vlib_pci_addr_t *addr = 0, *addrs;
1559
1560   pm->vlib_main = vm;
1561
1562   ASSERT (sizeof (vlib_pci_addr_t) == sizeof (u32));
1563
1564   if (pm->pci_device_registrations)
1565     {
1566       addrs = vlib_pci_get_all_dev_addrs ();
1567       vec_foreach (addr, addrs)
1568         {
1569           vlib_pci_device_info_t *d;
1570           if ((d = vlib_pci_get_device_info (vm, addr, 0)))
1571             {
1572               init_device_from_registered (vm, d);
1573               vlib_pci_free_device_info (d);
1574             }
1575         }
1576     }
1577
1578   return 0;
1579 }
1580
1581 VLIB_INIT_FUNCTION (linux_pci_init) =
1582 {
1583   .runs_after = VLIB_INITS("unix_input_init"),
1584 };
1585
1586 /*
1587  * fd.io coding-style-patch-verification: ON
1588  *
1589  * Local Variables:
1590  * eval: (c-set-style "gnu")
1591  * End:
1592  */