FD.io VPP  v18.07-rc0-415-g6c78436
Vector Packet Processing
pci.c
Go to the documentation of this file.
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 typedef struct
64 {
65  int fd;
66  void *addr;
67  size_t size;
69 
70 typedef struct
71 {
72  int fd;
74  union
75  {
78  };
80 
81 typedef enum
82 {
87 
88 typedef struct
89 {
92  vlib_pci_addr_t addr;
93 
94  /* Resource file descriptors. */
96 
97  /* File descriptor for config space read/write. */
98  int config_fd;
100 
101  /* Device File descriptor */
102  int fd;
103 
104  /* Minor device for uio device. */
106 
107  /* Interrupt handlers */
110 
111  /* private data */
113 
115 
116 /* Pool of PCI devices. */
117 typedef struct
118 {
121 
123 
125 
126 static linux_pci_device_t *
128 {
130  return pool_elt_at_index (lpm->linux_pci_devices, h);
131 }
132 
133 uword
135 {
137  return d->private_data;
138 }
139 
140 void
142 {
144  d->private_data = private_data;
145 }
146 
147 vlib_pci_addr_t *
149 {
151  return &d->addr;
152 }
153 
154 /* Call to allocate/initialize the pci subsystem.
155  This is not an init function so that users can explicitly enable
156  pci only when it's needed. */
158 
160 
162 vlib_pci_get_device_info (vlib_pci_addr_t * addr, clib_error_t ** error)
163 {
165  clib_error_t *err;
167  u8 *f = 0;
168  u32 tmp;
169  int fd;
170 
171  di = clib_mem_alloc (sizeof (vlib_pci_device_info_t));
172  memset (di, 0, sizeof (vlib_pci_device_info_t));
173  di->addr.as_u32 = addr->as_u32;
174 
175  u8 *dev_dir_name = format (0, "%s/%U", sysfs_pci_dev_path,
176  format_vlib_pci_addr, addr);
177 
178  f = format (0, "%v/config%c", dev_dir_name, 0);
179  fd = open ((char *) f, O_RDWR);
180 
181  /* Try read-only access if write fails. */
182  if (fd < 0)
183  fd = open ((char *) f, O_RDONLY);
184 
185  if (fd < 0)
186  {
187  err = clib_error_return_unix (0, "open `%s'", f);
188  goto error;
189  }
190 
191  /* You can only read more that 64 bytes of config space as root; so we try to
192  read the full space but fall back to just the first 64 bytes. */
193  if (read (fd, &di->config_data, sizeof (di->config_data)) <
194  sizeof (di->config0))
195  {
196  err = clib_error_return_unix (0, "read `%s'", f);
197  close (fd);
198  goto error;
199  }
200 
201  {
202  static pci_config_header_t all_ones;
203  if (all_ones.vendor_id == 0)
204  memset (&all_ones, ~0, sizeof (all_ones));
205 
206  if (!memcmp (&di->config0.header, &all_ones, sizeof (all_ones)))
207  {
208  err = clib_error_return (0, "invalid PCI config for `%s'", f);
209  close (fd);
210  goto error;
211  }
212  }
213 
214  if (di->config0.header.header_type == 0)
216  else
218 
219  di->numa_node = -1;
220  vec_reset_length (f);
221  f = format (f, "%v/numa_node%c", dev_dir_name, 0);
222  err = clib_sysfs_read ((char *) f, "%u", &di->numa_node);
223  if (err)
224  {
225  di->numa_node = -1;
226  clib_error_free (err);
227  }
228 
229  vec_reset_length (f);
230  f = format (f, "%v/class%c", dev_dir_name, 0);
231  err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
232  if (err)
233  goto error;
234  di->device_class = tmp >> 8;
235 
236  vec_reset_length (f);
237  f = format (f, "%v/vendor%c", dev_dir_name, 0);
238  err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
239  if (err)
240  goto error;
241  di->vendor_id = tmp;
242 
243  vec_reset_length (f);
244  f = format (f, "%v/device%c", dev_dir_name, 0);
245  err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
246  if (err)
247  goto error;
248  di->device_id = tmp;
249 
250  vec_reset_length (f);
251  f = format (f, "%v/driver%c", dev_dir_name, 0);
252  di->driver_name = clib_sysfs_link_to_name ((char *) f);
253 
254  di->iommu_group = -1;
255  if (lvm->container_fd != -1)
256  {
257  u8 *tmpstr;
258  vec_reset_length (f);
259  f = format (f, "%v/iommu_group%c", dev_dir_name, 0);
260  tmpstr = clib_sysfs_link_to_name ((char *) f);
261  if (tmpstr)
262  {
263  di->iommu_group = atoi ((char *) tmpstr);
264  vec_free (tmpstr);
265  }
266  vec_reset_length (f);
267  f = format (f, "%v/iommu_group/name%c", dev_dir_name, 0);
268  err = clib_sysfs_read ((char *) f, "%s", &tmpstr);
269  if (err == 0)
270  {
271  if (strncmp ((char *) tmpstr, "vfio-noiommu", 12) == 0)
273  vec_free (tmpstr);
274  }
275  else
276  clib_error_free (err);
277  }
278 
279  close (fd);
280 
281  vec_reset_length (f);
282  f = format (f, "%v/vpd%c", dev_dir_name, 0);
283  fd = open ((char *) f, O_RDONLY);
284  if (fd >= 0)
285  {
286  while (1)
287  {
288  u8 tag[3];
289  u8 *data = 0;
290  uword len;
291 
292  if (read (fd, &tag, 3) != 3)
293  break;
294 
295  if (tag[0] != 0x82 && tag[0] != 0x90 && tag[0] != 0x91)
296  break;
297 
298  len = (tag[2] << 8) | tag[1];
299  vec_validate (data, len);
300 
301  if (read (fd, data, len) != len)
302  {
303  vec_free (data);
304  break;
305  }
306  if (tag[0] == 0x82)
307  di->product_name = data;
308  else if (tag[0] == 0x90)
309  di->vpd_r = data;
310  else if (tag[0] == 0x91)
311  di->vpd_w = data;
312 
313  data = 0;
314  }
315  close (fd);
316  }
317 
318  goto done;
319 
320 error:
322  di = 0;
323 
324 done:
325  vec_free (f);
326  vec_free (dev_dir_name);
327  if (error)
328  *error = err;
329  else
330  clib_error_free (err);
331  return di;
332 }
333 
334 static int
335 directory_exists (char *path)
336 {
337  struct stat s = { 0 };
338  if (stat (path, &s) == -1)
339  return 0;
340 
341  return S_ISDIR (s.st_mode);
342 }
343 
344 clib_error_t *
345 vlib_pci_bind_to_uio (vlib_pci_addr_t * addr, char *uio_drv_name)
346 {
347  clib_error_t *error = 0;
348  u8 *s = 0, *driver_name = 0;
349  DIR *dir = 0;
350  struct dirent *e;
352  int fd, clear_driver_override = 0;
353  u8 *dev_dir_name = format (0, "%s/%U", sysfs_pci_dev_path,
354  format_vlib_pci_addr, addr);
355 
356  di = vlib_pci_get_device_info (addr, &error);
357 
358  if (error)
359  return error;
360 
361  if (strncmp ("auto", uio_drv_name, 5) == 0)
362  {
363  int vfio_pci_loaded = 0;
364 
365  if (directory_exists ("/sys/module/vfio_pci"))
366  vfio_pci_loaded = 1;
367 
368  if (di->iommu_group != -1)
369  {
370  /* device is bound to IOMMU group */
371  if (!vfio_pci_loaded)
372  {
373  error = clib_error_return (0, "Skipping PCI device %U: device "
374  "is bound to IOMMU group and "
375  "vfio-pci driver is not loaded",
376  format_vlib_pci_addr, addr);
377  goto done;
378  }
379  else
380  uio_drv_name = "vfio-pci";
381  }
382  else
383  {
384  /* device is not bound to IOMMU group so we have multiple options */
385  if (vfio_pci_loaded &&
386  (error = clib_sysfs_write (sysfs_mod_vfio_noiommu, "Y")) == 0)
387  uio_drv_name = "vfio-pci";
388  else if (directory_exists ("/sys/module/uio_pci_generic"))
389  uio_drv_name = "uio_pci_generic";
390  else if (directory_exists ("/sys/module/igb_uio"))
391  uio_drv_name = "igb_uio";
392  else
393  {
394  clib_error_free (error);
395  error = clib_error_return (0, "Skipping PCI device %U: missing "
396  "kernel VFIO or UIO driver",
397  format_vlib_pci_addr, addr);
398  goto done;
399  }
400  clib_error_free (error);
401  }
402  }
403 
404  s = format (s, "%v/driver%c", dev_dir_name, 0);
405  driver_name = clib_sysfs_link_to_name ((char *) s);
406  vec_reset_length (s);
407 
408  if (driver_name &&
409  ((strcmp ("vfio-pci", (char *) driver_name) == 0) ||
410  (strcmp ("uio_pci_generic", (char *) driver_name) == 0) ||
411  (strcmp ("igb_uio", (char *) driver_name) == 0)))
412  goto done;
413 
414  /* walk trough all linux interfaces and if interface belonging to
415  this device is founf check if interface is admin up */
416  dir = opendir ("/sys/class/net");
417  s = format (s, "%U%c", format_vlib_pci_addr, addr, 0);
418 
419  if (!dir)
420  {
421  error = clib_error_return (0, "Skipping PCI device %U: failed to "
422  "read /sys/class/net",
423  format_vlib_pci_addr, addr);
424  goto done;
425  }
426 
427  fd = socket (PF_INET, SOCK_DGRAM, 0);
428  if (fd < 0)
429  {
430  error = clib_error_return_unix (0, "socket");
431  goto done;
432  }
433 
434  while ((e = readdir (dir)))
435  {
436  struct ifreq ifr;
437  struct ethtool_drvinfo drvinfo;
438 
439  if (e->d_name[0] == '.') /* skip . and .. */
440  continue;
441 
442  memset (&ifr, 0, sizeof ifr);
443  memset (&drvinfo, 0, sizeof drvinfo);
444  ifr.ifr_data = (char *) &drvinfo;
445  strncpy (ifr.ifr_name, e->d_name, IFNAMSIZ - 1);
446  drvinfo.cmd = ETHTOOL_GDRVINFO;
447  if (ioctl (fd, SIOCETHTOOL, &ifr) < 0)
448  {
449  /* Some interfaces (eg "lo") don't support this ioctl */
450  if ((errno != ENOTSUP) && (errno != ENODEV))
451  clib_unix_warning ("ioctl fetch intf %s bus info error",
452  e->d_name);
453  continue;
454  }
455 
456  if (strcmp ((char *) s, drvinfo.bus_info))
457  continue;
458 
459  memset (&ifr, 0, sizeof (ifr));
460  strncpy (ifr.ifr_name, e->d_name, IFNAMSIZ - 1);
461  if (ioctl (fd, SIOCGIFFLAGS, &ifr) < 0)
462  {
463  error = clib_error_return_unix (0, "ioctl fetch intf %s flags",
464  e->d_name);
465  close (fd);
466  goto done;
467  }
468 
469  if (ifr.ifr_flags & IFF_UP)
470  {
471  error = clib_error_return (0, "Skipping PCI device %U as host "
472  "interface %s is up",
473  format_vlib_pci_addr, addr, e->d_name);
474  close (fd);
475  goto done;
476  }
477  }
478 
479  close (fd);
480  vec_reset_length (s);
481 
482  s = format (s, "%v/driver/unbind%c", dev_dir_name, 0);
483  clib_sysfs_write ((char *) s, "%U", format_vlib_pci_addr, addr);
484  vec_reset_length (s);
485 
486  s = format (s, "%v/driver_override%c", dev_dir_name, 0);
487  if (access ((char *) s, F_OK) == 0)
488  {
489  clib_sysfs_write ((char *) s, "%s", uio_drv_name);
490  clear_driver_override = 1;
491  }
492  else
493  {
494  vec_reset_length (s);
495  s = format (s, "%s/%s/new_id%c", sysfs_pci_drv_path, uio_drv_name, 0);
496  clib_sysfs_write ((char *) s, "0x%04x 0x%04x", di->vendor_id,
497  di->device_id);
498  }
499  vec_reset_length (s);
500 
501  s = format (s, "%s/%s/bind%c", sysfs_pci_drv_path, uio_drv_name, 0);
502  clib_sysfs_write ((char *) s, "%U", format_vlib_pci_addr, addr);
503  vec_reset_length (s);
504 
505  if (clear_driver_override)
506  {
507  s = format (s, "%v/driver_override%c", dev_dir_name, 0);
508  clib_sysfs_write ((char *) s, "%c", 0);
509  vec_reset_length (s);
510  }
511 
512 done:
513  closedir (dir);
514  vec_free (s);
515  vec_free (dev_dir_name);
516  vec_free (driver_name);
517  return error;
518 }
519 
520 
521 static clib_error_t *
522 scan_uio_dir (void *arg, u8 * path_name, u8 * file_name)
523 {
524  linux_pci_device_t *l = arg;
525  unformat_input_t input;
526 
527  unformat_init_string (&input, (char *) file_name, vec_len (file_name));
528 
529  if (!unformat (&input, "uio%d", &l->uio_minor))
530  abort ();
531 
532  unformat_free (&input);
533  return 0;
534 }
535 
536 static clib_error_t *
538  u32 flags, int *efds)
539 {
540  int data_len = efds ? count * sizeof (int) : 0;
541  u8 buf[sizeof (struct vfio_irq_set) + data_len];
542  struct vfio_irq_info irq_info = { 0 };
543  struct vfio_irq_set *irq_set = (struct vfio_irq_set *) buf;
544 
545 
546  irq_info.argsz = sizeof (struct vfio_irq_info);
547  irq_info.index = index;
548 
549  if (ioctl (p->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info) < 0)
550  return clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_IRQ_INFO) "
551  "'%U'", format_vlib_pci_addr, &p->addr);
552 
553  if (irq_info.count < start + count)
554  return clib_error_return_unix (0, "vfio_set_irq: unexistng interrupt on "
555  "'%U'", format_vlib_pci_addr, &p->addr);
556 
557 
558  if (efds)
559  {
560  flags |= VFIO_IRQ_SET_DATA_EVENTFD;
561  clib_memcpy (&irq_set->data, efds, data_len);
562  }
563  else
564  flags |= VFIO_IRQ_SET_DATA_NONE;
565 
566  ASSERT ((flags & (VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_DATA_EVENTFD)) !=
567  (VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_DATA_EVENTFD));
568 
569  irq_set->argsz = sizeof (struct vfio_irq_set) + data_len;
570  irq_set->index = index;
571  irq_set->start = start;
572  irq_set->count = count;
573  irq_set->flags = flags;
574 
575  if (ioctl (p->fd, VFIO_DEVICE_SET_IRQS, irq_set) < 0)
576  return clib_error_return_unix (0, "%U:ioctl(VFIO_DEVICE_SET_IRQS) "
577  "[index = %u, start = %u, count = %u, "
578  "flags = 0x%x]",
580  index, start, count, flags);
581  return 0;
582 }
583 
584 static clib_error_t *
586 {
587  int __attribute__ ((unused)) rv;
590  linux_pci_irq_t *irq = &p->intx_irq;
591 
592  u32 icount;
593  rv = read (uf->file_descriptor, &icount, 4);
594 
595  if (irq->intx_handler)
596  irq->intx_handler (h);
597 
599 
600  return /* no error */ 0;
601 }
602 
603 static clib_error_t *
605 {
606  return vfio_set_irqs (d, VFIO_PCI_INTX_IRQ_INDEX, 0, 1,
607  VFIO_IRQ_SET_ACTION_UNMASK, 0);
608 }
609 
610 static clib_error_t *
612 {
613  u32 error_index = (u32) uf->private_data;
614 
615  return clib_error_return (0, "pci device %d: error", error_index);
616 }
617 
618 static clib_error_t *
620 {
621  int __attribute__ ((unused)) rv;
623  u16 line = uf->private_data & 0xffff;
625  linux_pci_irq_t *irq = vec_elt_at_index (p->msix_irqs, line);
626 
627  u64 icount;
628  rv = read (uf->file_descriptor, &icount, sizeof (icount));
629 
630  if (irq->msix_handler)
631  irq->msix_handler (h, line);
632 
633  return /* no error */ 0;
634 }
635 
636 static clib_error_t *
638 {
639  int __attribute__ ((unused)) rv;
642  linux_pci_irq_t *irq = &p->intx_irq;
643 
644  u64 icount;
645  rv = read (uf->file_descriptor, &icount, sizeof (icount));
646 
647  if (irq->intx_handler)
648  irq->intx_handler (h);
649 
651 
652  return /* no error */ 0;
653 }
654 
655 static clib_error_t *
657 {
658  u32 error_index = (u32) uf->private_data;
659 
660  return clib_error_return (0, "pci device %d: error", error_index);
661 }
662 
663 static clib_error_t *
666 {
668  clib_error_t *err = 0;
669  u8 *s = 0;
670 
671  p->addr.as_u32 = di->addr.as_u32;
672  p->fd = -1;
674 
675  s = format (s, "%s/%U/config%c", sysfs_pci_dev_path,
676  format_vlib_pci_addr, &di->addr, 0);
677 
678  p->config_fd = open ((char *) s, O_RDWR);
679  p->config_offset = 0;
680  vec_reset_length (s);
681 
682  if (p->config_fd == -1)
683  {
684  err = clib_error_return_unix (0, "open '%s'", s);
685  goto error;
686  }
687 
688  s = format (0, "%s/%U/uio", sysfs_pci_dev_path,
689  format_vlib_pci_addr, &di->addr);
690  foreach_directory_file ((char *) s, scan_uio_dir, p, /* scan_dirs */
691  1);
692  vec_reset_length (s);
693 
694  s = format (s, "/dev/uio%d%c", p->uio_minor, 0);
695  p->fd = open ((char *) s, O_RDWR);
696  if (p->fd < 0)
697  {
698  err = clib_error_return_unix (0, "open '%s'", s);
699  goto error;
700  }
701 
702  if (r && r->interrupt_handler)
703  vlib_pci_register_intx_handler (p->handle, r->interrupt_handler);
704 
705  if (r && r->init_function)
706  err = r->init_function (lpm->vlib_main, p->handle);
707 
708 error:
709  vec_free (s);
710  if (err)
711  {
712  if (p->config_fd != -1)
713  close (p->config_fd);
714  if (p->fd != -1)
715  close (p->fd);
716  }
717  return err;
718 }
719 
720 clib_error_t *
722  pci_intx_handler_function_t * intx_handler)
723 {
725  clib_file_t t = { 0 };
726  linux_pci_irq_t *irq = &p->intx_irq;
727  ASSERT (irq->fd == -1);
728 
730  {
731  struct vfio_irq_info irq_info = { 0 };
732  irq_info.argsz = sizeof (struct vfio_irq_info);
733  irq_info.index = VFIO_PCI_INTX_IRQ_INDEX;
734  if (ioctl (p->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info) < 0)
735  return clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_IRQ_INFO) '"
736  "%U'", format_vlib_pci_addr, &p->addr);
737  if (irq_info.count != 1)
738  return clib_error_return (0, "INTx interrupt does not exist on device"
739  "'%U'", format_vlib_pci_addr, &p->addr);
740 
741  irq->fd = eventfd (0, EFD_NONBLOCK);
742  if (irq->fd == -1)
743  return clib_error_return_unix (0, "eventfd");
744  t.file_descriptor = irq->fd;
746  }
747  else if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
748  {
749  t.file_descriptor = p->fd;
751  }
752  else
753  return 0;
754 
756  t.private_data = p->handle;
757  t.description = format (0, "PCI %U INTx", format_vlib_pci_addr, &p->addr);
759  irq->intx_handler = intx_handler;
760  return 0;
761 }
762 
763 clib_error_t *
765  pci_msix_handler_function_t * msix_handler)
766 {
767  clib_error_t *err = 0;
769  u32 i;
770 
772  return clib_error_return (0, "vfio driver is needed for MSI-X interrupt "
773  "support");
774 
775  /* *INDENT-OFF* */
776  vec_validate_init_empty (p->msix_irqs, start + count - 1, (linux_pci_irq_t)
777  { .fd = -1});
778  /* *INDENT-ON* */
779 
780  for (i = start; i < start + count; i++)
781  {
782  clib_file_t t = { 0 };
784  ASSERT (irq->fd == -1);
785 
786  irq->fd = eventfd (0, EFD_NONBLOCK);
787  if (irq->fd == -1)
788  {
789  err = clib_error_return_unix (0, "eventfd");
790  goto error;
791  }
792 
794  t.file_descriptor = irq->fd;
796  t.private_data = p->handle << 16 | i;
797  t.description = format (0, "PCI %U MSI-X #%u", format_vlib_pci_addr,
798  &p->addr, i);
800  irq->msix_handler = msix_handler;
801  }
802 
803  return 0;
804 
805 error:
806  while (i-- > start)
807  {
809  if (irq->fd != -1)
810  {
812  close (irq->fd);
813  irq->fd = -1;
814  }
815  }
816  return err;
817 }
818 
819 clib_error_t *
821 {
823  int fds[count];
824  int i;
825 
827  return clib_error_return (0, "vfio driver is needed for MSI-X interrupt "
828  "support");
829 
830  for (i = start; i < start + count; i++)
831  {
833  fds[i] = irq->fd;
834  }
835 
836  return vfio_set_irqs (p, VFIO_PCI_MSIX_IRQ_INDEX, start, count,
837  VFIO_IRQ_SET_ACTION_TRIGGER, fds);
838 }
839 
840 clib_error_t *
842 {
844  int i, fds[count];
845 
847  return clib_error_return (0, "vfio driver is needed for MSI-X interrupt "
848  "support");
849 
850  for (i = start; i < start + count; i++)
851  fds[i] = -1;
852 
853  return vfio_set_irqs (p, VFIO_PCI_MSIX_IRQ_INDEX, start, count,
854  VFIO_IRQ_SET_ACTION_TRIGGER, fds);
855 }
856 
857 static clib_error_t *
860 {
862  struct vfio_device_info device_info = { 0 };
863  struct vfio_region_info reg = { 0 };
864  clib_error_t *err = 0;
865  u8 *s = 0;
866 
867  p->addr.as_u32 = di->addr.as_u32;
869 
870  if (di->driver_name == 0 ||
871  (strcmp ("vfio-pci", (char *) di->driver_name) != 0))
872  return clib_error_return (0, "Device '%U' (iommu group %d) not bound to "
873  "vfio-pci", format_vlib_pci_addr, &di->addr,
874  di->iommu_group);
875 
876  if ((err = linux_vfio_group_get_device_fd (&p->addr, &p->fd)))
877  return err;
878 
879  device_info.argsz = sizeof (device_info);
880  if (ioctl (p->fd, VFIO_DEVICE_GET_INFO, &device_info) < 0)
881  {
882  err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_INFO) '%U'",
883  format_vlib_pci_addr, &di->addr);
884  goto error;
885  }
886 
887  reg.argsz = sizeof (struct vfio_region_info);
888  reg.index = VFIO_PCI_CONFIG_REGION_INDEX;
889  if (ioctl (p->fd, VFIO_DEVICE_GET_REGION_INFO, &reg) < 0)
890  {
891  err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_INFO) '%U'",
892  format_vlib_pci_addr, &di->addr);
893  goto error;
894  }
895  p->config_offset = reg.offset;
896  p->config_fd = p->fd;
897 
898  /* reset if device supports it */
899  if (device_info.flags & VFIO_DEVICE_FLAGS_RESET)
900  if (ioctl (p->fd, VFIO_DEVICE_RESET) < 0)
901  {
902  err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_RESET) '%U'",
903  format_vlib_pci_addr, &di->addr);
904  goto error;
905  }
906 
907  if (r && r->interrupt_handler)
908  {
909  vlib_pci_register_intx_handler (p->handle, r->interrupt_handler);
911  }
912 
913  if (r && r->init_function)
914  err = r->init_function (lpm->vlib_main, p->handle);
915 
916 error:
917  vec_free (s);
918  if (err)
919  {
920  if (p->fd != -1)
921  close (p->fd);
922  if (p->config_fd != -1 && p->config_fd != p->fd)
923  close (p->config_fd);
924  p->config_fd = p->fd = -1;
925  }
926  return err;
927 }
928 
929 /* Configuration space read/write. */
930 clib_error_t *
932  vlib_read_or_write_t read_or_write,
933  uword address, void *data, u32 n_bytes)
934 {
936  int n;
937 
938  if (read_or_write == VLIB_READ)
939  n = pread (p->config_fd, data, n_bytes, p->config_offset + address);
940  else
941  n = pwrite (p->config_fd, data, n_bytes, p->config_offset + address);
942 
943  if (n != n_bytes)
944  return clib_error_return_unix (0, "%s",
945  read_or_write == VLIB_READ
946  ? "read" : "write");
947 
948  return 0;
949 }
950 
951 static clib_error_t *
953  u32 bar, u8 * addr, void **result)
954 {
956  int fd = -1;
957  clib_error_t *error;
958  int flags = MAP_SHARED;
959  u64 size = 0, offset = 0;
960 
961  ASSERT (bar <= 5);
962 
963  error = 0;
964 
966  {
967  u8 *file_name;
968  struct stat stat_buf;
969  file_name = format (0, "%s/%U/resource%d%c", sysfs_pci_dev_path,
970  format_vlib_pci_addr, &p->addr, bar, 0);
971 
972  fd = open ((char *) file_name, O_RDWR);
973  if (fd < 0)
974  {
975  error = clib_error_return_unix (0, "open `%s'", file_name);
976  vec_free (file_name);
977  return error;
978  }
979 
980  if (fstat (fd, &stat_buf) < 0)
981  {
982  error = clib_error_return_unix (0, "fstat `%s'", file_name);
983  vec_free (file_name);
984  close (fd);
985  return error;
986  }
987 
988  vec_free (file_name);
989  if (addr != 0)
990  flags |= MAP_FIXED;
991  size = stat_buf.st_size;
992  offset = 0;
993  }
994  else if (p->type == LINUX_PCI_DEVICE_TYPE_VFIO)
995  {
996  struct vfio_region_info reg = { 0 };
997  reg.argsz = sizeof (struct vfio_region_info);
998  reg.index = bar;
999  if (ioctl (p->fd, VFIO_DEVICE_GET_REGION_INFO, &reg) < 0)
1000  return clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_INFO) "
1001  "'%U'", format_vlib_pci_addr,
1002  &p->addr);
1003  fd = p->fd;
1004  size = reg.size;
1005  offset = reg.offset;
1006  }
1007  else
1008  ASSERT (0);
1009 
1010  *result = mmap (addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
1011  if (*result == (void *) -1)
1012  {
1013  error = clib_error_return_unix (0, "mmap `BAR%u'", bar);
1014  if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
1015  close (fd);
1016  return error;
1017  }
1018 
1019  /* *INDENT-OFF* */
1021  (linux_pci_region_t) { .fd = -1});
1022  /* *INDENT-ON* */
1023  if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
1024  p->regions[bar].fd = fd;
1025  p->regions[bar].addr = *result;
1026  p->regions[bar].size = size;
1027  return 0;
1028 }
1029 
1030 clib_error_t *
1032 {
1033  return (vlib_pci_map_region_int (h, resource, 0 /* addr */ , result));
1034 }
1035 
1036 clib_error_t *
1038  void **result)
1039 {
1040  return (vlib_pci_map_region_int (h, resource, addr, result));
1041 }
1042 
1043 clib_error_t *
1044 vlib_pci_device_open (vlib_pci_addr_t * addr,
1045  pci_device_id_t ids[], vlib_pci_dev_handle_t * handle)
1046 {
1049  linux_pci_device_t *p;
1050  clib_error_t *err = 0;
1051  pci_device_id_t *i;
1052 
1053  di = vlib_pci_get_device_info (addr, &err);
1054 
1055  if (err)
1056  return err;
1057  for (i = ids; i->vendor_id != 0; i++)
1058  if (i->vendor_id == di->vendor_id && i->device_id == di->device_id)
1059  break;
1060 
1061  if (i->vendor_id == 0)
1062  return clib_error_return (0, "Wrong vendor or device id");
1063 
1064  pool_get (lpm->linux_pci_devices, p);
1065  p->handle = p - lpm->linux_pci_devices;
1066  p->intx_irq.fd = -1;
1067 
1068  if (di->iommu_group != -1)
1069  err = add_device_vfio (p, di, 0);
1070  else
1071  err = add_device_uio (p, di, 0);
1072  if (err)
1073  goto error;
1074 
1075  *handle = p->handle;
1076 
1077 error:
1079  if (err)
1080  {
1081  memset (p, 0, sizeof (linux_pci_device_t));
1082  pool_put (lpm->linux_pci_devices, p);
1083  }
1084 
1085  return err;
1086 }
1087 
1088 void
1090 {
1093  linux_pci_irq_t *irq;
1094  linux_pci_region_t *res;
1095  clib_error_t *err = 0;
1096 
1097  if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
1098  {
1099  irq = &p->intx_irq;
1101  close (p->config_fd);
1102  }
1103  else if (p->type == LINUX_PCI_DEVICE_TYPE_VFIO)
1104  {
1105  irq = &p->intx_irq;
1106  /* close INTx irqs */
1107  if (irq->fd != -1)
1108  {
1109  err = vfio_set_irqs (p, VFIO_PCI_INTX_IRQ_INDEX, 0, 0,
1110  VFIO_IRQ_SET_ACTION_TRIGGER, 0);
1111  clib_error_free (err);
1113  close (irq->fd);
1114  }
1115 
1116  /* close MSI-X irqs */
1117  if (vec_len (p->msix_irqs))
1118  {
1119  err = vfio_set_irqs (p, VFIO_PCI_MSIX_IRQ_INDEX, 0, 0,
1120  VFIO_IRQ_SET_ACTION_TRIGGER, 0);
1121  clib_error_free (err);
1122  /* *INDENT-OFF* */
1123  vec_foreach (irq, p->msix_irqs)
1124  {
1125  if (irq->fd == -1)
1126  continue;
1128  close (irq->fd);
1129  }
1130  /* *INDENT-ON* */
1131  vec_free (p->msix_irqs);
1132  }
1133  }
1134 
1135  /* *INDENT-OFF* */
1136  vec_foreach (res, p->regions)
1137  {
1138  if (res->size == 0)
1139  continue;
1140  munmap (res->addr, res->size);
1141  if (res->fd != -1)
1142  close (res->fd);
1143  }
1144  /* *INDENT-ON* */
1145  vec_free (p->regions);
1146 
1147  close (p->fd);
1148  memset (p, 0, sizeof (linux_pci_device_t));
1149  pool_put (lpm->linux_pci_devices, p);
1150 }
1151 
1152 void
1154 {
1155  vlib_pci_main_t *pm = &pci_main;
1158  pci_device_id_t *i;
1159  clib_error_t *err = 0;
1160  linux_pci_device_t *p;
1161 
1162  pool_get (lpm->linux_pci_devices, p);
1163  p->handle = p - lpm->linux_pci_devices;
1164  p->intx_irq.fd = -1;
1165 
1166  r = pm->pci_device_registrations;
1167 
1168  while (r)
1169  {
1170  for (i = r->supported_devices; i->vendor_id != 0; i++)
1171  if (i->vendor_id == di->vendor_id && i->device_id == di->device_id)
1172  {
1173  if (di->iommu_group != -1)
1174  err = add_device_vfio (p, di, r);
1175  else
1176  err = add_device_uio (p, di, r);
1177 
1178  if (err)
1179  clib_error_report (err);
1180  else
1181  return;
1182  }
1183  r = r->next_registration;
1184  }
1185 
1186  /* No driver, close the PCI config-space FD */
1187  memset (p, 0, sizeof (linux_pci_device_t));
1188  pool_put (lpm->linux_pci_devices, p);
1189 }
1190 
1191 static clib_error_t *
1192 scan_pci_addr (void *arg, u8 * dev_dir_name, u8 * ignored)
1193 {
1194  vlib_pci_addr_t addr, **addrv = arg;
1195  unformat_input_t input;
1196  clib_error_t *err = 0;
1197 
1198  unformat_init_string (&input, (char *) dev_dir_name,
1199  vec_len (dev_dir_name));
1200 
1201  if (!unformat (&input, "/sys/bus/pci/devices/%U",
1202  unformat_vlib_pci_addr, &addr))
1203  err = clib_error_return (0, "unformat error `%v`", dev_dir_name);
1204 
1205  unformat_free (&input);
1206 
1207  if (err)
1208  return err;
1209 
1210  vec_add1 (*addrv, addr);
1211  return 0;
1212 }
1213 
1214 static int
1215 pci_addr_cmp (void *v1, void *v2)
1216 {
1217  vlib_pci_addr_t *a1 = v1;
1218  vlib_pci_addr_t *a2 = v2;
1219 
1220  if (a1->domain > a2->domain)
1221  return 1;
1222  if (a1->domain < a2->domain)
1223  return -1;
1224  if (a1->bus > a2->bus)
1225  return 1;
1226  if (a1->bus < a2->bus)
1227  return -1;
1228  if (a1->slot > a2->slot)
1229  return 1;
1230  if (a1->slot < a2->slot)
1231  return -1;
1232  if (a1->function > a2->function)
1233  return 1;
1234  if (a1->function < a2->function)
1235  return -1;
1236  return 0;
1237 }
1238 
1239 vlib_pci_addr_t *
1241 {
1242  vlib_pci_addr_t *addrs = 0;
1243  clib_error_t *err;
1245  &addrs, /* scan_dirs */ 0);
1246  if (err)
1247  {
1248  vec_free (addrs);
1249  return 0;
1250  }
1251 
1253 
1254  return addrs;
1255 }
1256 
1257 clib_error_t *
1259 {
1260  vlib_pci_main_t *pm = &pci_main;
1261  vlib_pci_addr_t *addr = 0, *addrs;
1262  clib_error_t *error;
1263 
1264  pm->vlib_main = vm;
1265 
1266  if ((error = vlib_call_init_function (vm, unix_input_init)))
1267  return error;
1268 
1269  ASSERT (sizeof (vlib_pci_addr_t) == sizeof (u32));
1270 
1271  addrs = vlib_pci_get_all_dev_addrs ();
1272  /* *INDENT-OFF* */
1273  vec_foreach (addr, addrs)
1274  {
1276  if ((d = vlib_pci_get_device_info (addr, 0)))
1277  {
1280  }
1281  }
1282  /* *INDENT-ON* */
1283 
1284  return error;
1285 }
1286 
1288 
1289 /*
1290  * fd.io coding-style-patch-verification: ON
1291  *
1292  * Local Variables:
1293  * eval: (c-set-style "gnu")
1294  * End:
1295  */
clib_error_t * vlib_pci_register_intx_handler(vlib_pci_dev_handle_t h, pci_intx_handler_function_t *intx_handler)
Definition: pci.c:721
#define vec_validate(V, I)
Make sure vector is long enough for given index (no header, unspecified alignment) ...
Definition: vec.h:437
u8 * format_vlib_pci_addr(u8 *s, va_list *va)
Definition: pci.c:140
typedef address
Definition: ip_types.api:34
static clib_error_t * unix_input_init(vlib_main_t *vm)
Definition: input.c:347
static clib_error_t * add_device_vfio(linux_pci_device_t *p, vlib_pci_device_info_t *di, pci_device_registration_t *r)
Definition: pci.c:858
linux_pci_device_type_t type
Definition: pci.c:90
uword unformat_vlib_pci_addr(unformat_input_t *input, va_list *args)
Definition: pci.c:123
linux_pci_irq_t intx_irq
Definition: pci.c:108
unsigned long u64
Definition: types.h:89
pci_device_registration_t * pci_device_registrations
Definition: pci.h:147
vlib_read_or_write_t
Definition: defs.h:54
vlib_pci_device_info_t * vlib_pci_get_device_info(vlib_pci_addr_t *addr, clib_error_t **error)
Definition: pci.c:162
vlib_pci_addr_t * vlib_pci_get_addr(vlib_pci_dev_handle_t h)
Definition: pci.c:148
clib_error_t * linux_vfio_group_get_device_fd(vlib_pci_addr_t *addr, int *fdp)
Definition: vfio.c:157
u32 file_descriptor
Definition: file.h:54
#define vec_add1(V, E)
Add 1 element to end of vector (unspecified alignment).
Definition: vec.h:523
int i
clib_error_t * vlib_pci_disable_msix_irq(vlib_pci_dev_handle_t h, u16 start, u16 count)
Definition: pci.c:841
u8 * format(u8 *s, const char *fmt,...)
Definition: format.c:419
static clib_error_t * linux_pci_uio_error_ready(clib_file_t *uf)
Definition: pci.c:611
vlib_pci_addr_t addr
Definition: pci.c:92
vlib_pci_addr_t * vlib_pci_get_all_dev_addrs()
Definition: pci.c:1240
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:227
clib_error_t * clib_sysfs_write(char *file_name, char *fmt,...)
Definition: sysfs.c:26
unsigned char u8
Definition: types.h:56
clib_error_t * vlib_pci_map_region_fixed(vlib_pci_dev_handle_t h, u32 resource, u8 *addr, void **result)
Definition: pci.c:1037
void * addr
Definition: pci.c:66
static char * sysfs_mod_vfio_noiommu
Definition: pci.c:60
clib_error_t * vlib_pci_register_msix_handler(vlib_pci_dev_handle_t h, u32 start, u32 count, pci_msix_handler_function_t *msix_handler)
Definition: pci.c:764
vlib_pci_main_t pci_main
Definition: pci.c:53
#define vec_reset_length(v)
Reset vector length to zero NULL-pointer tolerant.
clib_file_function_t * read_function
Definition: file.h:67
linux_pci_main_t linux_pci_main
Definition: pci.c:159
int fd
Definition: pci.c:72
static void pci_config_type1_little_to_host(pci_config_type1_regs_t *r)
Definition: pci_config.h:353
#define VLIB_INIT_FUNCTION(x)
Definition: init.h:156
static clib_error_t * linux_pci_vfio_intx_read_ready(clib_file_t *uf)
Definition: pci.c:637
void di(unformat_input_t *i)
Definition: unformat.c:163
clib_error_t * vlib_pci_bind_to_uio(vlib_pci_addr_t *addr, char *uio_drv_name)
Definition: pci.c:345
#define vec_elt_at_index(v, i)
Get vector value at index i checking that i is in bounds.
#define clib_error_return(e, args...)
Definition: error.h:99
clib_file_main_t file_main
Definition: main.c:63
clib_error_t * vlib_pci_device_open(vlib_pci_addr_t *addr, pci_device_id_t ids[], vlib_pci_dev_handle_t *handle)
Definition: pci.c:1044
struct _pci_device_registration pci_device_registration_t
vlib_main_t * vlib_main
Definition: pci.c:119
unsigned int u32
Definition: types.h:88
linux_pci_irq_t * msix_irqs
Definition: pci.c:109
void init_device_from_registered(vlib_pci_device_info_t *di)
Definition: pci.c:1153
#define vlib_call_init_function(vm, x)
Definition: init.h:227
pci_config_type1_regs_t config1
Definition: pci.h:88
vlib_pci_dev_handle_t handle
Definition: pci.c:91
void unformat_init_string(unformat_input_t *input, char *string, int string_len)
Definition: unformat.c:1023
uword private_data
Definition: pci.c:112
u8 config_data[256]
Definition: pci.h:89
u8 * description
Definition: file.h:70
#define pool_elt_at_index(p, i)
Returns pointer to element at given index.
Definition: pool.h:461
uword size
u32 clib_file_index
Definition: pci.c:73
int config_fd
Definition: pci.c:98
clib_error_t * linux_pci_init(vlib_main_t *vm)
Definition: pci.c:1258
static clib_error_t * scan_pci_addr(void *arg, u8 *dev_dir_name, u8 *ignored)
Definition: pci.c:1192
struct _unformat_input_t unformat_input_t
unsigned short u16
Definition: types.h:57
u32 vlib_pci_dev_handle_t
Definition: pci.h:97
#define clib_error_return_unix(e, args...)
Definition: error.h:102
#define pool_put(P, E)
Free an object E in pool P.
Definition: pool.h:273
static const char * sysfs_pci_drv_path
Definition: pci.c:59
static clib_error_t * linux_pci_vfio_error_ready(clib_file_t *uf)
Definition: pci.c:656
clib_error_t * clib_sysfs_read(char *file_name, char *fmt,...)
Definition: sysfs.c:50
static clib_error_t * linux_pci_uio_read_ready(clib_file_t *uf)
Definition: pci.c:585
static clib_error_t * add_device_uio(linux_pci_device_t *p, vlib_pci_device_info_t *di, pci_device_registration_t *r)
Definition: pci.c:664
static void pci_config_type0_little_to_host(pci_config_type0_regs_t *r)
Definition: pci_config.h:279
void( pci_intx_handler_function_t)(vlib_pci_dev_handle_t handle)
Definition: pci.h:123
vlib_main_t * vm
Definition: buffer.c:294
#define vec_free(V)
Free vector&#39;s memory (no header).
Definition: vec.h:339
u8 * driver_name
Definition: pci.h:82
clib_error_t * pci_bus_init(vlib_main_t *vm)
Definition: pci.c:251
#define clib_memcpy(a, b, c)
Definition: string.h:75
static linux_pci_device_t * linux_pci_get_device(vlib_pci_dev_handle_t h)
Definition: pci.c:127
linux_pci_device_type_t
Definition: pci.c:81
static clib_error_t * linux_pci_vfio_msix_read_ready(clib_file_t *uf)
Definition: pci.c:619
pci_msix_handler_function_t * msix_handler
Definition: pci.c:77
#define VLIB_PCI_DEVICE_INFO_F_NOIOMMU
Definition: pci.h:63
size_t size
Definition: pci.c:67
void vlib_pci_device_close(vlib_pci_dev_handle_t h)
Definition: pci.c:1089
#define ASSERT(truth)
static clib_error_t * vlib_pci_map_region_int(vlib_pci_dev_handle_t h, u32 bar, u8 *addr, void **result)
Definition: pci.c:952
void( pci_msix_handler_function_t)(vlib_pci_dev_handle_t handle, u16 line)
Definition: pci.h:124
static uword clib_file_add(clib_file_main_t *um, clib_file_t *template)
Definition: file.h:96
static void clib_file_del_by_index(clib_file_main_t *um, uword index)
Definition: file.h:119
pci_config_type0_regs_t config0
Definition: pci.h:87
#define clib_error_report(e)
Definition: error.h:113
size_t count
Definition: vapi.c:42
vlib_pci_addr_t addr
Definition: pci.h:66
static void * clib_mem_alloc(uword size)
Definition: mem.h:112
template key/value backing page structure
Definition: bihash_doc.h:44
Definition: defs.h:56
static clib_error_t * vfio_set_irqs(linux_pci_device_t *p, u32 index, u32 start, u32 count, u32 flags, int *efds)
Definition: pci.c:537
static int pci_addr_cmp(void *v1, void *v2)
Definition: pci.c:1215
clib_error_t * foreach_directory_file(char *dir_name, clib_error_t *(*f)(void *arg, u8 *path_name, u8 *file_name), void *arg, int scan_dirs)
Definition: util.c:49
#define vec_len(v)
Number of elements in vector (rvalue-only, NULL tolerant)
static int directory_exists(char *path)
Definition: pci.c:335
uword vlib_pci_get_private_data(vlib_pci_dev_handle_t h)
Definition: pci.c:134
u64 uword
Definition: types.h:112
#define vec_sort_with_function(vec, f)
Sort a vector using the supplied element comparison function.
Definition: vec.h:961
static void unformat_free(unformat_input_t *i)
Definition: format.h:161
#define clib_unix_warning(format, args...)
Definition: error.h:68
void vlib_pci_set_private_data(vlib_pci_dev_handle_t h, uword private_data)
Definition: pci.c:141
static clib_error_t * linux_pci_vfio_unmask_intx(linux_pci_device_t *d)
Definition: pci.c:604
#define clib_error_free(e)
Definition: error.h:86
clib_error_t * vlib_pci_map_region(vlib_pci_dev_handle_t h, u32 resource, void **result)
Definition: pci.c:1031
clib_file_function_t * error_function
Definition: file.h:67
linux_pci_region_t * regions
Definition: pci.c:95
pci_intx_handler_function_t * intx_handler
Definition: pci.c:76
int container_fd
Definition: vfio.h:31
u16 device_id
Definition: pci.h:120
clib_error_t * vlib_pci_enable_msix_irq(vlib_pci_dev_handle_t h, u16 start, u16 count)
Definition: pci.c:820
static clib_error_t * vlib_pci_intr_enable(vlib_pci_dev_handle_t h)
Definition: pci.h:212
#define vec_foreach(var, vec)
Vector iterator.
uword private_data
Definition: file.h:64
Definition: file.h:51
vhost_vring_addr_t addr
Definition: vhost-user.h:83
static const char * sysfs_pci_dev_path
Definition: pci.c:58
static void vlib_pci_free_device_info(vlib_pci_device_info_t *di)
Definition: pci.h:107
u32 flags
Definition: vhost-user.h:77
#define vec_validate_init_empty(V, I, INIT)
Make sure vector is long enough for given index and initialize empty space (no header, unspecified alignment)
Definition: vec.h:486
u16 device_class
Definition: pci.h:72
linux_pci_device_t * linux_pci_devices
Definition: pci.c:120
vlib_main_t * vlib_main
Definition: pci.h:146
pci_config_header_t header
Definition: pci_config.h:247
u64 config_offset
Definition: pci.c:99
static clib_error_t * scan_uio_dir(void *arg, u8 *path_name, u8 *file_name)
Definition: pci.c:522
u8 * product_name
Definition: pci.h:77
u16 vendor_id
Definition: pci.h:120
uword unformat(unformat_input_t *i, const char *fmt,...)
Definition: unformat.c:972
u8 * clib_sysfs_link_to_name(char *link)
Definition: sysfs.c:90
linux_vfio_main_t vfio_main
Definition: vfio.c:35
clib_error_t * vlib_pci_read_write_config(vlib_pci_dev_handle_t h, vlib_read_or_write_t read_or_write, uword address, void *data, u32 n_bytes)
Definition: pci.c:931