FD.io VPP  v18.10-34-gcce845e
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, sizeof (ifr.ifr_name));
446  ifr.ifr_name[ARRAY_LEN (ifr.ifr_name) - 1] = '\0';
447  drvinfo.cmd = ETHTOOL_GDRVINFO;
448  if (ioctl (fd, SIOCETHTOOL, &ifr) < 0)
449  {
450  /* Some interfaces (eg "lo") don't support this ioctl */
451  if ((errno != ENOTSUP) && (errno != ENODEV))
452  clib_unix_warning ("ioctl fetch intf %s bus info error",
453  e->d_name);
454  continue;
455  }
456 
457  if (strcmp ((char *) s, drvinfo.bus_info))
458  continue;
459 
460  memset (&ifr, 0, sizeof (ifr));
461  strncpy (ifr.ifr_name, e->d_name, sizeof (ifr.ifr_name));
462  ifr.ifr_name[ARRAY_LEN (ifr.ifr_name) - 1] = '\0';
463  if (ioctl (fd, SIOCGIFFLAGS, &ifr) < 0)
464  {
465  error = clib_error_return_unix (0, "ioctl fetch intf %s flags",
466  e->d_name);
467  close (fd);
468  goto done;
469  }
470 
471  if (ifr.ifr_flags & IFF_UP)
472  {
473  error = clib_error_return (0, "Skipping PCI device %U as host "
474  "interface %s is up",
475  format_vlib_pci_addr, addr, e->d_name);
476  close (fd);
477  goto done;
478  }
479  }
480 
481  close (fd);
482  vec_reset_length (s);
483 
484  s = format (s, "%v/driver/unbind%c", dev_dir_name, 0);
485  clib_sysfs_write ((char *) s, "%U", format_vlib_pci_addr, addr);
486  vec_reset_length (s);
487 
488  s = format (s, "%v/driver_override%c", dev_dir_name, 0);
489  if (access ((char *) s, F_OK) == 0)
490  {
491  clib_sysfs_write ((char *) s, "%s", uio_drv_name);
492  clear_driver_override = 1;
493  }
494  else
495  {
496  vec_reset_length (s);
497  s = format (s, "%s/%s/new_id%c", sysfs_pci_drv_path, uio_drv_name, 0);
498  clib_sysfs_write ((char *) s, "0x%04x 0x%04x", di->vendor_id,
499  di->device_id);
500  }
501  vec_reset_length (s);
502 
503  s = format (s, "%s/%s/bind%c", sysfs_pci_drv_path, uio_drv_name, 0);
504  clib_sysfs_write ((char *) s, "%U", format_vlib_pci_addr, addr);
505  vec_reset_length (s);
506 
507  if (clear_driver_override)
508  {
509  s = format (s, "%v/driver_override%c", dev_dir_name, 0);
510  clib_sysfs_write ((char *) s, "%c", 0);
511  vec_reset_length (s);
512  }
513 
514 done:
515  closedir (dir);
516  vec_free (s);
517  vec_free (dev_dir_name);
518  vec_free (driver_name);
519  return error;
520 }
521 
522 
523 static clib_error_t *
524 scan_uio_dir (void *arg, u8 * path_name, u8 * file_name)
525 {
526  linux_pci_device_t *l = arg;
527  unformat_input_t input;
528 
529  unformat_init_string (&input, (char *) file_name, vec_len (file_name));
530 
531  if (!unformat (&input, "uio%d", &l->uio_minor))
532  abort ();
533 
534  unformat_free (&input);
535  return 0;
536 }
537 
538 static clib_error_t *
540  u32 flags, int *efds)
541 {
542  int data_len = efds ? count * sizeof (int) : 0;
543  u8 buf[sizeof (struct vfio_irq_set) + data_len];
544  struct vfio_irq_info irq_info = { 0 };
545  struct vfio_irq_set *irq_set = (struct vfio_irq_set *) buf;
546 
547 
548  irq_info.argsz = sizeof (struct vfio_irq_info);
549  irq_info.index = index;
550 
551  if (ioctl (p->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info) < 0)
552  return clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_IRQ_INFO) "
553  "'%U'", format_vlib_pci_addr, &p->addr);
554 
555  if (irq_info.count < start + count)
556  return clib_error_return_unix (0, "vfio_set_irq: unexistng interrupt on "
557  "'%U'", format_vlib_pci_addr, &p->addr);
558 
559 
560  if (efds)
561  {
562  flags |= VFIO_IRQ_SET_DATA_EVENTFD;
563  clib_memcpy (&irq_set->data, efds, data_len);
564  }
565  else
566  flags |= VFIO_IRQ_SET_DATA_NONE;
567 
568  ASSERT ((flags & (VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_DATA_EVENTFD)) !=
569  (VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_DATA_EVENTFD));
570 
571  irq_set->argsz = sizeof (struct vfio_irq_set) + data_len;
572  irq_set->index = index;
573  irq_set->start = start;
574  irq_set->count = count;
575  irq_set->flags = flags;
576 
577  if (ioctl (p->fd, VFIO_DEVICE_SET_IRQS, irq_set) < 0)
578  return clib_error_return_unix (0, "%U:ioctl(VFIO_DEVICE_SET_IRQS) "
579  "[index = %u, start = %u, count = %u, "
580  "flags = 0x%x]",
582  index, start, count, flags);
583  return 0;
584 }
585 
586 static clib_error_t *
588 {
589  int __attribute__ ((unused)) rv;
592  linux_pci_irq_t *irq = &p->intx_irq;
593 
594  u32 icount;
595  rv = read (uf->file_descriptor, &icount, 4);
596 
597  if (irq->intx_handler)
598  irq->intx_handler (h);
599 
601 
602  return /* no error */ 0;
603 }
604 
605 static clib_error_t *
607 {
608  return vfio_set_irqs (d, VFIO_PCI_INTX_IRQ_INDEX, 0, 1,
609  VFIO_IRQ_SET_ACTION_UNMASK, 0);
610 }
611 
612 static clib_error_t *
614 {
615  u32 error_index = (u32) uf->private_data;
616 
617  return clib_error_return (0, "pci device %d: error", error_index);
618 }
619 
620 static clib_error_t *
622 {
623  int __attribute__ ((unused)) rv;
625  u16 line = uf->private_data & 0xffff;
627  linux_pci_irq_t *irq = vec_elt_at_index (p->msix_irqs, line);
628 
629  u64 icount;
630  rv = read (uf->file_descriptor, &icount, sizeof (icount));
631 
632  if (irq->msix_handler)
633  irq->msix_handler (h, line);
634 
635  return /* no error */ 0;
636 }
637 
638 static clib_error_t *
640 {
641  int __attribute__ ((unused)) rv;
644  linux_pci_irq_t *irq = &p->intx_irq;
645 
646  u64 icount;
647  rv = read (uf->file_descriptor, &icount, sizeof (icount));
648 
649  if (irq->intx_handler)
650  irq->intx_handler (h);
651 
653 
654  return /* no error */ 0;
655 }
656 
657 static clib_error_t *
659 {
660  u32 error_index = (u32) uf->private_data;
661 
662  return clib_error_return (0, "pci device %d: error", error_index);
663 }
664 
665 static clib_error_t *
668 {
670  clib_error_t *err = 0;
671  u8 *s = 0;
672 
673  p->addr.as_u32 = di->addr.as_u32;
674  p->fd = -1;
676 
677  s = format (s, "%s/%U/config%c", sysfs_pci_dev_path,
678  format_vlib_pci_addr, &di->addr, 0);
679 
680  p->config_fd = open ((char *) s, O_RDWR);
681  p->config_offset = 0;
682  vec_reset_length (s);
683 
684  if (p->config_fd == -1)
685  {
686  err = clib_error_return_unix (0, "open '%s'", s);
687  goto error;
688  }
689 
690  s = format (0, "%s/%U/uio", sysfs_pci_dev_path,
691  format_vlib_pci_addr, &di->addr);
692  foreach_directory_file ((char *) s, scan_uio_dir, p, /* scan_dirs */
693  1);
694  vec_reset_length (s);
695 
696  s = format (s, "/dev/uio%d%c", p->uio_minor, 0);
697  p->fd = open ((char *) s, O_RDWR);
698  if (p->fd < 0)
699  {
700  err = clib_error_return_unix (0, "open '%s'", s);
701  goto error;
702  }
703 
704  if (r && r->interrupt_handler)
705  vlib_pci_register_intx_handler (p->handle, r->interrupt_handler);
706 
707  if (r && r->init_function)
708  err = r->init_function (lpm->vlib_main, p->handle);
709 
710 error:
711  vec_free (s);
712  if (err)
713  {
714  if (p->config_fd != -1)
715  close (p->config_fd);
716  if (p->fd != -1)
717  close (p->fd);
718  }
719  return err;
720 }
721 
722 clib_error_t *
724  pci_intx_handler_function_t * intx_handler)
725 {
727  clib_file_t t = { 0 };
728  linux_pci_irq_t *irq = &p->intx_irq;
729  ASSERT (irq->fd == -1);
730 
732  {
733  struct vfio_irq_info irq_info = { 0 };
734  irq_info.argsz = sizeof (struct vfio_irq_info);
735  irq_info.index = VFIO_PCI_INTX_IRQ_INDEX;
736  if (ioctl (p->fd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info) < 0)
737  return clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_IRQ_INFO) '"
738  "%U'", format_vlib_pci_addr, &p->addr);
739  if (irq_info.count != 1)
740  return clib_error_return (0, "INTx interrupt does not exist on device"
741  "'%U'", format_vlib_pci_addr, &p->addr);
742 
743  irq->fd = eventfd (0, EFD_NONBLOCK);
744  if (irq->fd == -1)
745  return clib_error_return_unix (0, "eventfd");
746  t.file_descriptor = irq->fd;
748  }
749  else if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
750  {
751  t.file_descriptor = p->fd;
753  }
754  else
755  return 0;
756 
758  t.private_data = p->handle;
759  t.description = format (0, "PCI %U INTx", format_vlib_pci_addr, &p->addr);
761  irq->intx_handler = intx_handler;
762  return 0;
763 }
764 
765 clib_error_t *
767  pci_msix_handler_function_t * msix_handler)
768 {
769  clib_error_t *err = 0;
771  u32 i;
772 
774  return clib_error_return (0, "vfio driver is needed for MSI-X interrupt "
775  "support");
776 
777  /* *INDENT-OFF* */
778  vec_validate_init_empty (p->msix_irqs, start + count - 1, (linux_pci_irq_t)
779  { .fd = -1});
780  /* *INDENT-ON* */
781 
782  for (i = start; i < start + count; i++)
783  {
784  clib_file_t t = { 0 };
786  ASSERT (irq->fd == -1);
787 
788  irq->fd = eventfd (0, EFD_NONBLOCK);
789  if (irq->fd == -1)
790  {
791  err = clib_error_return_unix (0, "eventfd");
792  goto error;
793  }
794 
796  t.file_descriptor = irq->fd;
798  t.private_data = p->handle << 16 | i;
799  t.description = format (0, "PCI %U MSI-X #%u", format_vlib_pci_addr,
800  &p->addr, i);
802  irq->msix_handler = msix_handler;
803  }
804 
805  return 0;
806 
807 error:
808  while (i-- > start)
809  {
811  if (irq->fd != -1)
812  {
814  close (irq->fd);
815  irq->fd = -1;
816  }
817  }
818  return err;
819 }
820 
821 clib_error_t *
823 {
825  int fds[count];
826  int i;
827 
829  return clib_error_return (0, "vfio driver is needed for MSI-X interrupt "
830  "support");
831 
832  for (i = start; i < start + count; i++)
833  {
835  fds[i] = irq->fd;
836  }
837 
838  return vfio_set_irqs (p, VFIO_PCI_MSIX_IRQ_INDEX, start, count,
839  VFIO_IRQ_SET_ACTION_TRIGGER, fds);
840 }
841 
842 clib_error_t *
844 {
846  int i, fds[count];
847 
849  return clib_error_return (0, "vfio driver is needed for MSI-X interrupt "
850  "support");
851 
852  for (i = start; i < start + count; i++)
853  fds[i] = -1;
854 
855  return vfio_set_irqs (p, VFIO_PCI_MSIX_IRQ_INDEX, start, count,
856  VFIO_IRQ_SET_ACTION_TRIGGER, fds);
857 }
858 
859 static clib_error_t *
862 {
864  struct vfio_device_info device_info = { 0 };
865  struct vfio_region_info reg = { 0 };
866  clib_error_t *err = 0;
867  u8 *s = 0;
868 
869  p->addr.as_u32 = di->addr.as_u32;
871 
872  if (di->driver_name == 0 ||
873  (strcmp ("vfio-pci", (char *) di->driver_name) != 0))
874  return clib_error_return (0, "Device '%U' (iommu group %d) not bound to "
875  "vfio-pci", format_vlib_pci_addr, &di->addr,
876  di->iommu_group);
877 
878  if ((err = linux_vfio_group_get_device_fd (&p->addr, &p->fd)))
879  return err;
880 
881  device_info.argsz = sizeof (device_info);
882  if (ioctl (p->fd, VFIO_DEVICE_GET_INFO, &device_info) < 0)
883  {
884  err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_INFO) '%U'",
885  format_vlib_pci_addr, &di->addr);
886  goto error;
887  }
888 
889  reg.argsz = sizeof (struct vfio_region_info);
890  reg.index = VFIO_PCI_CONFIG_REGION_INDEX;
891  if (ioctl (p->fd, VFIO_DEVICE_GET_REGION_INFO, &reg) < 0)
892  {
893  err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_INFO) '%U'",
894  format_vlib_pci_addr, &di->addr);
895  goto error;
896  }
897  p->config_offset = reg.offset;
898  p->config_fd = p->fd;
899 
900  /* reset if device supports it */
901  if (device_info.flags & VFIO_DEVICE_FLAGS_RESET)
902  if (ioctl (p->fd, VFIO_DEVICE_RESET) < 0)
903  {
904  err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_RESET) '%U'",
905  format_vlib_pci_addr, &di->addr);
906  goto error;
907  }
908 
909  if (r && r->interrupt_handler)
910  {
911  vlib_pci_register_intx_handler (p->handle, r->interrupt_handler);
913  }
914 
915  if (r && r->init_function)
916  err = r->init_function (lpm->vlib_main, p->handle);
917 
918 error:
919  vec_free (s);
920  if (err)
921  {
922  if (p->fd != -1)
923  close (p->fd);
924  if (p->config_fd != -1 && p->config_fd != p->fd)
925  close (p->config_fd);
926  p->config_fd = p->fd = -1;
927  }
928  return err;
929 }
930 
931 /* Configuration space read/write. */
932 clib_error_t *
934  vlib_read_or_write_t read_or_write,
935  uword address, void *data, u32 n_bytes)
936 {
938  int n;
939 
940  if (read_or_write == VLIB_READ)
941  n = pread (p->config_fd, data, n_bytes, p->config_offset + address);
942  else
943  n = pwrite (p->config_fd, data, n_bytes, p->config_offset + address);
944 
945  if (n != n_bytes)
946  return clib_error_return_unix (0, "%s",
947  read_or_write == VLIB_READ
948  ? "read" : "write");
949 
950  return 0;
951 }
952 
953 static clib_error_t *
955  u32 bar, u8 * addr, void **result)
956 {
958  int fd = -1;
959  clib_error_t *error;
960  int flags = MAP_SHARED;
961  u64 size = 0, offset = 0;
962 
963  ASSERT (bar <= 5);
964 
965  error = 0;
966 
968  {
969  u8 *file_name;
970  struct stat stat_buf;
971  file_name = format (0, "%s/%U/resource%d%c", sysfs_pci_dev_path,
972  format_vlib_pci_addr, &p->addr, bar, 0);
973 
974  fd = open ((char *) file_name, O_RDWR);
975  if (fd < 0)
976  {
977  error = clib_error_return_unix (0, "open `%s'", file_name);
978  vec_free (file_name);
979  return error;
980  }
981 
982  if (fstat (fd, &stat_buf) < 0)
983  {
984  error = clib_error_return_unix (0, "fstat `%s'", file_name);
985  vec_free (file_name);
986  close (fd);
987  return error;
988  }
989 
990  vec_free (file_name);
991  if (addr != 0)
992  flags |= MAP_FIXED;
993  size = stat_buf.st_size;
994  offset = 0;
995  }
996  else if (p->type == LINUX_PCI_DEVICE_TYPE_VFIO)
997  {
998  struct vfio_region_info reg = { 0 };
999  reg.argsz = sizeof (struct vfio_region_info);
1000  reg.index = bar;
1001  if (ioctl (p->fd, VFIO_DEVICE_GET_REGION_INFO, &reg) < 0)
1002  return clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_INFO) "
1003  "'%U'", format_vlib_pci_addr,
1004  &p->addr);
1005  fd = p->fd;
1006  size = reg.size;
1007  offset = reg.offset;
1008  }
1009  else
1010  ASSERT (0);
1011 
1012  *result = mmap (addr, size, PROT_READ | PROT_WRITE, flags, fd, offset);
1013  if (*result == (void *) -1)
1014  {
1015  error = clib_error_return_unix (0, "mmap `BAR%u'", bar);
1016  if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
1017  close (fd);
1018  return error;
1019  }
1020 
1021  /* *INDENT-OFF* */
1023  (linux_pci_region_t) { .fd = -1});
1024  /* *INDENT-ON* */
1025  if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
1026  p->regions[bar].fd = fd;
1027  p->regions[bar].addr = *result;
1028  p->regions[bar].size = size;
1029  return 0;
1030 }
1031 
1032 clib_error_t *
1034 {
1035  return (vlib_pci_map_region_int (h, resource, 0 /* addr */ , result));
1036 }
1037 
1038 clib_error_t *
1040  void **result)
1041 {
1042  return (vlib_pci_map_region_int (h, resource, addr, result));
1043 }
1044 
1045 clib_error_t *
1046 vlib_pci_device_open (vlib_pci_addr_t * addr,
1047  pci_device_id_t ids[], vlib_pci_dev_handle_t * handle)
1048 {
1051  linux_pci_device_t *p;
1052  clib_error_t *err = 0;
1053  pci_device_id_t *i;
1054 
1055  di = vlib_pci_get_device_info (addr, &err);
1056 
1057  if (err)
1058  return err;
1059  for (i = ids; i->vendor_id != 0; i++)
1060  if (i->vendor_id == di->vendor_id && i->device_id == di->device_id)
1061  break;
1062 
1063  if (i->vendor_id == 0)
1064  return clib_error_return (0, "Wrong vendor or device id");
1065 
1066  pool_get (lpm->linux_pci_devices, p);
1067  p->handle = p - lpm->linux_pci_devices;
1068  p->intx_irq.fd = -1;
1069 
1070  if (di->iommu_group != -1)
1071  err = add_device_vfio (p, di, 0);
1072  else
1073  err = add_device_uio (p, di, 0);
1074  if (err)
1075  goto error;
1076 
1077  *handle = p->handle;
1078 
1079 error:
1081  if (err)
1082  {
1083  memset (p, 0, sizeof (linux_pci_device_t));
1084  pool_put (lpm->linux_pci_devices, p);
1085  }
1086 
1087  return err;
1088 }
1089 
1090 void
1092 {
1095  linux_pci_irq_t *irq;
1096  linux_pci_region_t *res;
1097  clib_error_t *err = 0;
1098 
1099  if (p->type == LINUX_PCI_DEVICE_TYPE_UIO)
1100  {
1101  irq = &p->intx_irq;
1103  close (p->config_fd);
1104  }
1105  else if (p->type == LINUX_PCI_DEVICE_TYPE_VFIO)
1106  {
1107  irq = &p->intx_irq;
1108  /* close INTx irqs */
1109  if (irq->fd != -1)
1110  {
1111  err = vfio_set_irqs (p, VFIO_PCI_INTX_IRQ_INDEX, 0, 0,
1112  VFIO_IRQ_SET_ACTION_TRIGGER, 0);
1113  clib_error_free (err);
1115  close (irq->fd);
1116  }
1117 
1118  /* close MSI-X irqs */
1119  if (vec_len (p->msix_irqs))
1120  {
1121  err = vfio_set_irqs (p, VFIO_PCI_MSIX_IRQ_INDEX, 0, 0,
1122  VFIO_IRQ_SET_ACTION_TRIGGER, 0);
1123  clib_error_free (err);
1124  /* *INDENT-OFF* */
1125  vec_foreach (irq, p->msix_irqs)
1126  {
1127  if (irq->fd == -1)
1128  continue;
1130  close (irq->fd);
1131  }
1132  /* *INDENT-ON* */
1133  vec_free (p->msix_irqs);
1134  }
1135  }
1136 
1137  /* *INDENT-OFF* */
1138  vec_foreach (res, p->regions)
1139  {
1140  if (res->size == 0)
1141  continue;
1142  munmap (res->addr, res->size);
1143  if (res->fd != -1)
1144  close (res->fd);
1145  }
1146  /* *INDENT-ON* */
1147  vec_free (p->regions);
1148 
1149  close (p->fd);
1150  memset (p, 0, sizeof (linux_pci_device_t));
1151  pool_put (lpm->linux_pci_devices, p);
1152 }
1153 
1154 void
1156 {
1157  vlib_pci_main_t *pm = &pci_main;
1160  pci_device_id_t *i;
1161  clib_error_t *err = 0;
1162  linux_pci_device_t *p;
1163 
1164  pool_get (lpm->linux_pci_devices, p);
1165  p->handle = p - lpm->linux_pci_devices;
1166  p->intx_irq.fd = -1;
1167 
1168  r = pm->pci_device_registrations;
1169 
1170  while (r)
1171  {
1172  for (i = r->supported_devices; i->vendor_id != 0; i++)
1173  if (i->vendor_id == di->vendor_id && i->device_id == di->device_id)
1174  {
1175  if (di->iommu_group != -1)
1176  err = add_device_vfio (p, di, r);
1177  else
1178  err = add_device_uio (p, di, r);
1179 
1180  if (err)
1181  clib_error_report (err);
1182  else
1183  return;
1184  }
1185  r = r->next_registration;
1186  }
1187 
1188  /* No driver, close the PCI config-space FD */
1189  memset (p, 0, sizeof (linux_pci_device_t));
1190  pool_put (lpm->linux_pci_devices, p);
1191 }
1192 
1193 static clib_error_t *
1194 scan_pci_addr (void *arg, u8 * dev_dir_name, u8 * ignored)
1195 {
1196  vlib_pci_addr_t addr, **addrv = arg;
1197  unformat_input_t input;
1198  clib_error_t *err = 0;
1199 
1200  unformat_init_string (&input, (char *) dev_dir_name,
1201  vec_len (dev_dir_name));
1202 
1203  if (!unformat (&input, "/sys/bus/pci/devices/%U",
1204  unformat_vlib_pci_addr, &addr))
1205  err = clib_error_return (0, "unformat error `%v`", dev_dir_name);
1206 
1207  unformat_free (&input);
1208 
1209  if (err)
1210  return err;
1211 
1212  vec_add1 (*addrv, addr);
1213  return 0;
1214 }
1215 
1216 static int
1217 pci_addr_cmp (void *v1, void *v2)
1218 {
1219  vlib_pci_addr_t *a1 = v1;
1220  vlib_pci_addr_t *a2 = v2;
1221 
1222  if (a1->domain > a2->domain)
1223  return 1;
1224  if (a1->domain < a2->domain)
1225  return -1;
1226  if (a1->bus > a2->bus)
1227  return 1;
1228  if (a1->bus < a2->bus)
1229  return -1;
1230  if (a1->slot > a2->slot)
1231  return 1;
1232  if (a1->slot < a2->slot)
1233  return -1;
1234  if (a1->function > a2->function)
1235  return 1;
1236  if (a1->function < a2->function)
1237  return -1;
1238  return 0;
1239 }
1240 
1241 vlib_pci_addr_t *
1243 {
1244  vlib_pci_addr_t *addrs = 0;
1245  clib_error_t *err;
1247  &addrs, /* scan_dirs */ 0);
1248  if (err)
1249  {
1250  vec_free (addrs);
1251  return 0;
1252  }
1253 
1255 
1256  return addrs;
1257 }
1258 
1259 clib_error_t *
1261 {
1262  vlib_pci_main_t *pm = &pci_main;
1263  vlib_pci_addr_t *addr = 0, *addrs;
1264  clib_error_t *error;
1265 
1266  pm->vlib_main = vm;
1267 
1268  if ((error = vlib_call_init_function (vm, unix_input_init)))
1269  return error;
1270 
1271  ASSERT (sizeof (vlib_pci_addr_t) == sizeof (u32));
1272 
1273  addrs = vlib_pci_get_all_dev_addrs ();
1274  /* *INDENT-OFF* */
1275  vec_foreach (addr, addrs)
1276  {
1278  if ((d = vlib_pci_get_device_info (addr, 0)))
1279  {
1282  }
1283  }
1284  /* *INDENT-ON* */
1285 
1286  return error;
1287 }
1288 
1290 
1291 /*
1292  * fd.io coding-style-patch-verification: ON
1293  *
1294  * Local Variables:
1295  * eval: (c-set-style "gnu")
1296  * End:
1297  */
clib_error_t * vlib_pci_register_intx_handler(vlib_pci_dev_handle_t h, pci_intx_handler_function_t *intx_handler)
Definition: pci.c:723
#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:35
static clib_error_t * unix_input_init(vlib_main_t *vm)
Definition: input.c:376
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:860
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:168
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:843
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:613
vlib_pci_addr_t addr
Definition: pci.c:92
vlib_pci_addr_t * vlib_pci_get_all_dev_addrs()
Definition: pci.c:1242
#define pool_get(P, E)
Allocate an object E from a pool P (unspecified alignment).
Definition: pool.h:228
vhost_vring_addr_t addr
Definition: vhost_user.h:121
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:1039
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:766
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
memset(h->entries, 0, sizeof(h->entries[0])*entries)
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:163
static clib_error_t * linux_pci_vfio_intx_read_ready(clib_file_t *uf)
Definition: pci.c:639
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:1046
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:1155
#define vlib_call_init_function(vm, x)
Definition: init.h:260
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:464
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:1260
static clib_error_t * scan_pci_addr(void *arg, u8 *dev_dir_name, u8 *ignored)
Definition: pci.c:1194
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:274
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:658
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:587
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:666
u32 flags
Definition: vhost_user.h:115
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
#define ARRAY_LEN(x)
Definition: clib.h:61
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:621
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:1091
#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:954
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:46
vlib_pci_addr_t addr
Definition: pci.h:66
static void * clib_mem_alloc(uword size)
Definition: mem.h:132
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:539
static int pci_addr_cmp(void *v1, void *v2)
Definition: pci.c:1217
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:982
static void unformat_free(unformat_input_t *i)
Definition: format.h:162
#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:606
#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:1033
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:822
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
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
#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:524
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:933