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