blob: 69dcdd0d760f077d1d5e9ade96a0b56341d34e99 [file] [log] [blame]
Ed Warnickecb9cada2015-12-08 15:45:58 -07001/*
Damjan Marion5a206ea2016-05-12 22:11:03 +02002 * Copyright (c) 2016 Cisco and/or its affiliates.
Ed Warnickecb9cada2015-12-08 15:45:58 -07003 * 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
Damjan Marion01914ce2017-09-14 19:04:50 +020040#include <vppinfra/linux/sysfs.h>
41
Ed Warnickecb9cada2015-12-08 15:45:58 -070042#include <vlib/vlib.h>
43#include <vlib/pci/pci.h>
44#include <vlib/unix/unix.h>
Ed Warnickecb9cada2015-12-08 15:45:58 -070045
46#include <sys/types.h>
47#include <sys/stat.h>
48#include <fcntl.h>
49#include <dirent.h>
Damjan Mariona42cd342016-04-13 18:03:20 +020050#include <sys/ioctl.h>
51#include <net/if.h>
52#include <linux/ethtool.h>
53#include <linux/sockios.h>
Damjan Marioncef87f12017-10-05 15:32:41 +020054#include <linux/vfio.h>
55#include <sys/eventfd.h>
56
57static const char *sysfs_pci_dev_path = "/sys/bus/pci/devices";
58static const char *sysfs_pci_drv_path = "/sys/bus/pci/drivers";
Damjan Mariona42cd342016-04-13 18:03:20 +020059
Dave Barach9b8ffd92016-07-08 08:13:45 -040060typedef struct
61{
Damjan Marioncef87f12017-10-05 15:32:41 +020062 vlib_pci_dev_handle_t handle;
63 vlib_pci_addr_t addr;
Damjan Marion5a206ea2016-05-12 22:11:03 +020064
65 /* Resource file descriptors. */
Dave Barach9b8ffd92016-07-08 08:13:45 -040066 int *resource_fds;
Damjan Marion5a206ea2016-05-12 22:11:03 +020067
68 /* File descriptor for config space read/write. */
69 int config_fd;
70
71 /* File descriptor for /dev/uio%d */
72 int uio_fd;
73
74 /* Minor device for uio device. */
75 u32 uio_minor;
76
Damjan Marioncef87f12017-10-05 15:32:41 +020077 /* vfio */
78 int vfio_device_fd;
79
Damjan Marion56dd5432017-09-08 19:52:02 +020080 /* Index given by clib_file_add. */
81 u32 clib_file_index;
Damjan Marion5a206ea2016-05-12 22:11:03 +020082
Damjan Marioncef87f12017-10-05 15:32:41 +020083 /* Interrupt handler */
84 void (*interrupt_handler) (vlib_pci_dev_handle_t h);
85
86 /* private data */
87 uword private_data;
88
Damjan Marion5a206ea2016-05-12 22:11:03 +020089} linux_pci_device_t;
90
Damjan Marioncef87f12017-10-05 15:32:41 +020091typedef struct
92{
93 int group;
94 int fd;
95 int refcnt;
96} linux_pci_vfio_iommu_group_t;
97
Damjan Marion5a206ea2016-05-12 22:11:03 +020098/* Pool of PCI devices. */
Dave Barach9b8ffd92016-07-08 08:13:45 -040099typedef struct
100{
101 vlib_main_t *vlib_main;
102 linux_pci_device_t *linux_pci_devices;
Damjan Marioncef87f12017-10-05 15:32:41 +0200103
104 /* VFIO */
105 int vfio_container_fd;
106 int vfio_iommu_mode;
107
108 /* pool of IOMMU groups */
109 linux_pci_vfio_iommu_group_t *iommu_groups;
110
111 /* iommu group pool index by group id hash */
112 uword *iommu_pool_index_by_group;
113
Damjan Marion5a206ea2016-05-12 22:11:03 +0200114} linux_pci_main_t;
115
116extern linux_pci_main_t linux_pci_main;
117
Damjan Marioncef87f12017-10-05 15:32:41 +0200118linux_pci_device_t *
119linux_pci_get_device (vlib_pci_dev_handle_t h)
120{
121 linux_pci_main_t *lpm = &linux_pci_main;
122 return pool_elt_at_index (lpm->linux_pci_devices, h);
123}
124
125uword
126vlib_pci_get_private_data (vlib_pci_dev_handle_t h)
127{
128 linux_pci_device_t *d = linux_pci_get_device (h);
129 return d->private_data;
130}
131
132void
133vlib_pci_set_private_data (vlib_pci_dev_handle_t h, uword private_data)
134{
135 linux_pci_device_t *d = linux_pci_get_device (h);
136 d->private_data = private_data;
137}
138
139vlib_pci_addr_t *
140vlib_pci_get_addr (vlib_pci_dev_handle_t h)
141{
142 linux_pci_device_t *lpm = linux_pci_get_device (h);
143 return &lpm->addr;
144}
145
Damjan Marion5a206ea2016-05-12 22:11:03 +0200146/* Call to allocate/initialize the pci subsystem.
147 This is not an init function so that users can explicitly enable
148 pci only when it's needed. */
Dave Barach9b8ffd92016-07-08 08:13:45 -0400149clib_error_t *pci_bus_init (vlib_main_t * vm);
Damjan Marion5a206ea2016-05-12 22:11:03 +0200150
Ed Warnickecb9cada2015-12-08 15:45:58 -0700151linux_pci_main_t linux_pci_main;
152
Damjan Marioncef87f12017-10-05 15:32:41 +0200153vlib_pci_device_info_t *
154vlib_pci_get_device_info (vlib_pci_addr_t * addr, clib_error_t ** error)
155{
156 linux_pci_main_t *lpm = &linux_pci_main;
157 clib_error_t *err;
158 vlib_pci_device_info_t *di;
159 u8 *f = 0;
160 u32 tmp;
161 int fd;
162
163 di = clib_mem_alloc (sizeof (vlib_pci_device_info_t));
164 memset (di, 0, sizeof (vlib_pci_device_info_t));
165 di->addr.as_u32 = addr->as_u32;
166
167 u8 *dev_dir_name = format (0, "%s/%U", sysfs_pci_dev_path,
168 format_vlib_pci_addr, addr);
169
170 f = format (0, "%v/config%c", dev_dir_name, 0);
171 fd = open ((char *) f, O_RDWR);
172
173 /* Try read-only access if write fails. */
174 if (fd < 0)
175 fd = open ((char *) f, O_RDONLY);
176
177 if (fd < 0)
178 {
179 err = clib_error_return_unix (0, "open `%s'", f);
180 goto error;
181 }
182
183 /* You can only read more that 64 bytes of config space as root; so we try to
184 read the full space but fall back to just the first 64 bytes. */
185 if (read (fd, &di->config_data, sizeof (di->config_data)) !=
186 sizeof (di->config_data)
187 && read (fd, &di->config0,
188 sizeof (di->config0)) != sizeof (di->config0))
189 {
190 err = clib_error_return_unix (0, "read `%s'", f);
191 close (fd);
192 goto error;
193 }
194
195 {
196 static pci_config_header_t all_ones;
197 if (all_ones.vendor_id == 0)
198 memset (&all_ones, ~0, sizeof (all_ones));
199
200 if (!memcmp (&di->config0.header, &all_ones, sizeof (all_ones)))
201 {
202 err = clib_error_return (0, "invalid PCI config for `%s'", f);
203 close (fd);
204 goto error;
205 }
206 }
207
208 if (di->config0.header.header_type == 0)
209 pci_config_type0_little_to_host (&di->config0);
210 else
211 pci_config_type1_little_to_host (&di->config1);
212
213 di->numa_node = -1;
214 vec_reset_length (f);
215 f = format (f, "%v/numa_node%c", dev_dir_name, 0);
216 err = clib_sysfs_read ((char *) f, "%u", &di->numa_node);
217 if (err)
218 {
219 di->numa_node = -1;
220 clib_error_free (err);
221 }
222
223 vec_reset_length (f);
224 f = format (f, "%v/class%c", dev_dir_name, 0);
225 err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
226 if (err)
227 goto error;
228 di->device_class = tmp >> 8;
229
230 vec_reset_length (f);
231 f = format (f, "%v/vendor%c", dev_dir_name, 0);
232 err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
233 if (err)
234 goto error;
235 di->vendor_id = tmp;
236
237 vec_reset_length (f);
238 f = format (f, "%v/device%c", dev_dir_name, 0);
239 err = clib_sysfs_read ((char *) f, "0x%x", &tmp);
240 if (err)
241 goto error;
242 di->device_id = tmp;
243
244 vec_reset_length (f);
245 f = format (f, "%v/driver%c", dev_dir_name, 0);
246 di->driver_name = clib_sysfs_link_to_name ((char *) f);
247
248 di->iommu_group = -1;
249 if (lpm->vfio_container_fd != -1)
250 {
251 u8 *tmpstr;
252 vec_reset_length (f);
253 f = format (f, "%v/iommu_group%c", dev_dir_name, 0);
254 tmpstr = clib_sysfs_link_to_name ((char *) f);
255 if (tmpstr)
256 {
257 di->iommu_group = atoi ((char *) tmpstr);
258 vec_free (tmpstr);
259 }
260 }
261
Damjan Marion96504182017-12-10 23:54:46 +0100262 close (fd);
263
Damjan Marioncef87f12017-10-05 15:32:41 +0200264 vec_reset_length (f);
265 f = format (f, "%v/vpd%c", dev_dir_name, 0);
266 fd = open ((char *) f, O_RDONLY);
267 if (fd >= 0)
268 {
269 while (1)
270 {
271 u8 tag[3];
272 u8 *data = 0;
Damjan Marion96504182017-12-10 23:54:46 +0100273 uword len;
Damjan Marioncef87f12017-10-05 15:32:41 +0200274
275 if (read (fd, &tag, 3) != 3)
276 break;
277
278 if (tag[0] != 0x82 && tag[0] != 0x90 && tag[0] != 0x91)
279 break;
280
281 len = (tag[2] << 8) | tag[1];
282 vec_validate (data, len);
283
284 if (read (fd, data, len) != len)
285 {
286 vec_free (data);
287 break;
288 }
289 if (tag[0] == 0x82)
290 di->product_name = data;
291 else if (tag[0] == 0x90)
292 di->vpd_r = data;
293 else if (tag[0] == 0x91)
294 di->vpd_w = data;
295
296 data = 0;
297 }
298 close (fd);
299 }
300
301 goto done;
302
303error:
304 vlib_pci_free_device_info (di);
305 di = 0;
306
307done:
308 vec_free (f);
309 vec_free (dev_dir_name);
310 if (error)
311 *error = err;
312 else
313 clib_error_free (err);
314 return di;
315}
316
Damjan Mariona42cd342016-04-13 18:03:20 +0200317clib_error_t *
Damjan Marioncef87f12017-10-05 15:32:41 +0200318vlib_pci_bind_to_uio (vlib_pci_addr_t * addr, char *uio_drv_name)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700319{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400320 clib_error_t *error = 0;
Damjan Mariona7f74572017-05-23 18:32:21 +0200321 u8 *s = 0, *driver_name = 0;
Damjan Mariona42cd342016-04-13 18:03:20 +0200322 DIR *dir = 0;
323 struct dirent *e;
Damjan Marioncef87f12017-10-05 15:32:41 +0200324 vlib_pci_device_info_t *di;
Damjan Mariona7f74572017-05-23 18:32:21 +0200325 int fd, clear_driver_override = 0;
Damjan Marioncef87f12017-10-05 15:32:41 +0200326 u8 *dev_dir_name = format (0, "%s/%U", sysfs_pci_dev_path,
327 format_vlib_pci_addr, addr);
328
329 di = vlib_pci_get_device_info (addr, &error);
330
331 if (error)
332 return error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700333
Damjan Mariona7f74572017-05-23 18:32:21 +0200334 s = format (s, "%v/driver%c", dev_dir_name, 0);
Damjan Marion01914ce2017-09-14 19:04:50 +0200335 driver_name = clib_sysfs_link_to_name ((char *) s);
Damjan Mariona42cd342016-04-13 18:03:20 +0200336 vec_reset_length (s);
337
Damjan Mariona7f74572017-05-23 18:32:21 +0200338 if (driver_name &&
339 ((strcmp ("vfio-pci", (char *) driver_name) == 0) ||
340 (strcmp ("uio_pci_generic", (char *) driver_name) == 0) ||
341 (strcmp ("igb_uio", (char *) driver_name) == 0)))
Damjan Marion3c785e02017-05-08 18:37:54 +0200342 goto done;
Damjan Marion3c785e02017-05-08 18:37:54 +0200343
Damjan Mariona42cd342016-04-13 18:03:20 +0200344 /* walk trough all linux interfaces and if interface belonging to
345 this device is founf check if interface is admin up */
346 dir = opendir ("/sys/class/net");
Damjan Marioncef87f12017-10-05 15:32:41 +0200347 s = format (s, "%U%c", format_vlib_pci_addr, addr, 0);
Damjan Mariona42cd342016-04-13 18:03:20 +0200348
349 if (!dir)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700350 {
Damjan Mariona42cd342016-04-13 18:03:20 +0200351 error = clib_error_return (0, "Skipping PCI device %U: failed to "
352 "read /sys/class/net",
Damjan Marioncef87f12017-10-05 15:32:41 +0200353 format_vlib_pci_addr, addr);
Damjan Mariona42cd342016-04-13 18:03:20 +0200354 goto done;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700355 }
356
Dave Barach9b8ffd92016-07-08 08:13:45 -0400357 fd = socket (PF_INET, SOCK_DGRAM, 0);
Chris Luke370e9e32016-07-07 11:01:17 -0400358 if (fd < 0)
359 {
360 error = clib_error_return_unix (0, "socket");
361 goto done;
362 }
Damjan Mariona42cd342016-04-13 18:03:20 +0200363
Dave Barach9b8ffd92016-07-08 08:13:45 -0400364 while ((e = readdir (dir)))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700365 {
Damjan Mariona42cd342016-04-13 18:03:20 +0200366 struct ifreq ifr;
367 struct ethtool_drvinfo drvinfo;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700368
Dave Barach9b8ffd92016-07-08 08:13:45 -0400369 if (e->d_name[0] == '.') /* skip . and .. */
Damjan Mariona42cd342016-04-13 18:03:20 +0200370 continue;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700371
Dave Barach9b8ffd92016-07-08 08:13:45 -0400372 memset (&ifr, 0, sizeof ifr);
373 memset (&drvinfo, 0, sizeof drvinfo);
Damjan Mariona42cd342016-04-13 18:03:20 +0200374 ifr.ifr_data = (char *) &drvinfo;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400375 strncpy (ifr.ifr_name, e->d_name, IFNAMSIZ - 1);
Damjan Mariona42cd342016-04-13 18:03:20 +0200376 drvinfo.cmd = ETHTOOL_GDRVINFO;
Chris Luke370e9e32016-07-07 11:01:17 -0400377 if (ioctl (fd, SIOCETHTOOL, &ifr) < 0)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400378 {
John Loe2821212016-07-13 18:13:02 -0400379 /* Some interfaces (eg "lo") don't support this ioctl */
380 if ((errno != ENOTSUP) && (errno != ENODEV))
Ed Warnicke853e7202016-08-12 11:42:26 -0700381 clib_unix_warning ("ioctl fetch intf %s bus info error",
382 e->d_name);
John Loe2821212016-07-13 18:13:02 -0400383 continue;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400384 }
Damjan Mariona42cd342016-04-13 18:03:20 +0200385
386 if (strcmp ((char *) s, drvinfo.bus_info))
387 continue;
388
Dave Barach9b8ffd92016-07-08 08:13:45 -0400389 memset (&ifr, 0, sizeof (ifr));
Chris Luke370e9e32016-07-07 11:01:17 -0400390 strncpy (ifr.ifr_name, e->d_name, IFNAMSIZ - 1);
391 if (ioctl (fd, SIOCGIFFLAGS, &ifr) < 0)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400392 {
393 error = clib_error_return_unix (0, "ioctl fetch intf %s flags",
394 e->d_name);
395 close (fd);
396 goto done;
397 }
Damjan Mariona42cd342016-04-13 18:03:20 +0200398
399 if (ifr.ifr_flags & IFF_UP)
400 {
401 error = clib_error_return (0, "Skipping PCI device %U as host "
402 "interface %s is up",
Damjan Marioncef87f12017-10-05 15:32:41 +0200403 format_vlib_pci_addr, addr, e->d_name);
Dave Barach9b8ffd92016-07-08 08:13:45 -0400404 close (fd);
Damjan Mariona42cd342016-04-13 18:03:20 +0200405 goto done;
406 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700407 }
408
Damjan Mariona42cd342016-04-13 18:03:20 +0200409 close (fd);
410 vec_reset_length (s);
411
412 s = format (s, "%v/driver/unbind%c", dev_dir_name, 0);
Damjan Marioncef87f12017-10-05 15:32:41 +0200413 clib_sysfs_write ((char *) s, "%U", format_vlib_pci_addr, addr);
Damjan Mariona42cd342016-04-13 18:03:20 +0200414 vec_reset_length (s);
415
Damjan Mariona7f74572017-05-23 18:32:21 +0200416 s = format (s, "%v/driver_override%c", dev_dir_name, 0);
417 if (access ((char *) s, F_OK) == 0)
418 {
Damjan Marioncef87f12017-10-05 15:32:41 +0200419 clib_sysfs_write ((char *) s, "%s", uio_drv_name);
Damjan Mariona7f74572017-05-23 18:32:21 +0200420 clear_driver_override = 1;
421 }
422 else
423 {
424 vec_reset_length (s);
Damjan Marioncef87f12017-10-05 15:32:41 +0200425 s = format (s, "%s/%s/new_id%c", sysfs_pci_drv_path, uio_drv_name, 0);
426 clib_sysfs_write ((char *) s, "0x%04x 0x%04x", di->vendor_id,
427 di->device_id);
Damjan Mariona7f74572017-05-23 18:32:21 +0200428 }
Damjan Mariona42cd342016-04-13 18:03:20 +0200429 vec_reset_length (s);
430
Damjan Marioncef87f12017-10-05 15:32:41 +0200431 s = format (s, "%s/%s/bind%c", sysfs_pci_drv_path, uio_drv_name, 0);
432 clib_sysfs_write ((char *) s, "%U", format_vlib_pci_addr, addr);
Damjan Mariona7f74572017-05-23 18:32:21 +0200433 vec_reset_length (s);
434
435 if (clear_driver_override)
436 {
437 s = format (s, "%v/driver_override%c", dev_dir_name, 0);
Damjan Marion01914ce2017-09-14 19:04:50 +0200438 clib_sysfs_write ((char *) s, "%c", 0);
Damjan Mariona7f74572017-05-23 18:32:21 +0200439 vec_reset_length (s);
440 }
Damjan Mariona42cd342016-04-13 18:03:20 +0200441
442done:
443 closedir (dir);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700444 vec_free (s);
Damjan Mariona42cd342016-04-13 18:03:20 +0200445 vec_free (dev_dir_name);
Damjan Mariona7f74572017-05-23 18:32:21 +0200446 vec_free (driver_name);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700447 return error;
448}
449
Ed Warnickecb9cada2015-12-08 15:45:58 -0700450
451static clib_error_t *
Dave Barach9b8ffd92016-07-08 08:13:45 -0400452scan_uio_dir (void *arg, u8 * path_name, u8 * file_name)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700453{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400454 linux_pci_device_t *l = arg;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700455 unformat_input_t input;
456
457 unformat_init_string (&input, (char *) file_name, vec_len (file_name));
458
Dave Barach9b8ffd92016-07-08 08:13:45 -0400459 if (!unformat (&input, "uio%d", &l->uio_minor))
Ed Warnickecb9cada2015-12-08 15:45:58 -0700460 abort ();
461
462 unformat_free (&input);
463 return 0;
464}
465
Dave Barach9b8ffd92016-07-08 08:13:45 -0400466static clib_error_t *
Damjan Marion56dd5432017-09-08 19:52:02 +0200467linux_pci_uio_read_ready (clib_file_t * uf)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700468{
Damjan Marion5a206ea2016-05-12 22:11:03 +0200469 int __attribute__ ((unused)) rv;
Damjan Marioncef87f12017-10-05 15:32:41 +0200470 vlib_pci_dev_handle_t h = uf->private_data;
471 linux_pci_device_t *p = linux_pci_get_device (h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700472
Damjan Marion5a206ea2016-05-12 22:11:03 +0200473 u32 icount;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400474 rv = read (uf->file_descriptor, &icount, 4);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700475
Damjan Marioncef87f12017-10-05 15:32:41 +0200476 if (p->interrupt_handler)
477 p->interrupt_handler (h);
Damjan Marion5a206ea2016-05-12 22:11:03 +0200478
Damjan Marioncef87f12017-10-05 15:32:41 +0200479 vlib_pci_intr_enable (h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700480
481 return /* no error */ 0;
482}
483
Dave Barach9b8ffd92016-07-08 08:13:45 -0400484static clib_error_t *
Damjan Marioncef87f12017-10-05 15:32:41 +0200485linux_pci_vfio_unmask_intx (linux_pci_device_t * d)
486{
487 clib_error_t *err = 0;
488 struct vfio_irq_set i = {
489 .argsz = sizeof (struct vfio_irq_set),
490 .start = 0,
491 .count = 1,
492 .index = VFIO_PCI_INTX_IRQ_INDEX,
493 .flags = VFIO_IRQ_SET_DATA_NONE | VFIO_IRQ_SET_ACTION_UNMASK,
494 };
495
496 if (ioctl (d->vfio_device_fd, VFIO_DEVICE_SET_IRQS, &i) < 0)
497 {
498 err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_SET_IRQS) '%U'",
499 format_vlib_pci_addr, &d->addr);
500 }
501 return err;
502}
503
504static clib_error_t *
Damjan Marion56dd5432017-09-08 19:52:02 +0200505linux_pci_uio_error_ready (clib_file_t * uf)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700506{
507 u32 error_index = (u32) uf->private_data;
508
509 return clib_error_return (0, "pci device %d: error", error_index);
510}
511
Damjan Marioncef87f12017-10-05 15:32:41 +0200512static clib_error_t *
513linux_pci_vfio_read_ready (clib_file_t * uf)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700514{
Damjan Marioncef87f12017-10-05 15:32:41 +0200515 int __attribute__ ((unused)) rv;
516 vlib_pci_dev_handle_t h = uf->private_data;
517 linux_pci_device_t *p = linux_pci_get_device (h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700518
Damjan Marioncef87f12017-10-05 15:32:41 +0200519 u64 icount;
520 rv = read (uf->file_descriptor, &icount, sizeof (icount));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700521
Damjan Marioncef87f12017-10-05 15:32:41 +0200522 if (p->interrupt_handler)
523 p->interrupt_handler (h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700524
Damjan Marioncef87f12017-10-05 15:32:41 +0200525 linux_pci_vfio_unmask_intx (p);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700526
Damjan Marioncef87f12017-10-05 15:32:41 +0200527 return /* no error */ 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700528}
529
Damjan Marioncef87f12017-10-05 15:32:41 +0200530static clib_error_t *
531linux_pci_vfio_error_ready (clib_file_t * uf)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700532{
Damjan Marioncef87f12017-10-05 15:32:41 +0200533 u32 error_index = (u32) uf->private_data;
534
535 return clib_error_return (0, "pci device %d: error", error_index);
536}
537
538static clib_error_t *
539add_device_uio (vlib_main_t * vm, linux_pci_device_t * p,
540 vlib_pci_device_info_t * di, pci_device_registration_t * r)
541{
542 clib_error_t *err = 0;
543 clib_file_t t = { 0 };
544 u8 *s = 0;
545
546 p->addr.as_u32 = di->addr.as_u32;
547 p->uio_fd = -1;
548
549 s = format (s, "%s/%U/config%c", sysfs_pci_dev_path,
550 format_vlib_pci_addr, &di->addr, 0);
551
552 p->config_fd = open ((char *) s, O_RDWR);
553 vec_reset_length (s);
554
555 if (p->config_fd == -1)
556 {
557 err = clib_error_return_unix (0, "open '%s'", s);
558 goto error;
559 }
560
561 s = format (0, "%s/%U/uio", sysfs_pci_dev_path,
562 format_vlib_pci_addr, &di->addr);
563 foreach_directory_file ((char *) s, scan_uio_dir, p, /* scan_dirs */
564 1);
565 vec_reset_length (s);
566
567 s = format (s, "/dev/uio%d%c", p->uio_minor, 0);
568 p->uio_fd = open ((char *) s, O_RDWR);
569 if (p->uio_fd < 0)
570 {
571 err = clib_error_return_unix (0, "open '%s'", s);
572 goto error;
573 }
574
575 t.read_function = linux_pci_uio_read_ready;
576 t.file_descriptor = p->uio_fd;
577 t.error_function = linux_pci_uio_error_ready;
578 t.private_data = p->handle;
579
580 p->clib_file_index = clib_file_add (&file_main, &t);
581 p->interrupt_handler = r->interrupt_handler;
582 err = r->init_function (vm, p->handle);
583
584error:
585 free (s);
586 if (err)
587 {
Damjan Marion96504182017-12-10 23:54:46 +0100588 if (p->config_fd != -1)
589 close (p->config_fd);
590 if (p->uio_fd != -1)
591 close (p->uio_fd);
Damjan Marioncef87f12017-10-05 15:32:41 +0200592 }
593 return err;
594}
595
596static linux_pci_vfio_iommu_group_t *
597get_vfio_iommu_group (int group)
598{
599 linux_pci_main_t *lpm = &linux_pci_main;
600 uword *p;
601
602 p = hash_get (lpm->iommu_pool_index_by_group, group);
603
604 return p ? pool_elt_at_index (lpm->iommu_groups, p[0]) : 0;
605}
606
607static clib_error_t *
608open_vfio_iommu_group (int group)
609{
610 linux_pci_main_t *lpm = &linux_pci_main;
611 linux_pci_vfio_iommu_group_t *g;
612 clib_error_t *err = 0;
613 struct vfio_group_status group_status;
614 u8 *s = 0;
615 int fd;
616
617 g = get_vfio_iommu_group (group);
618 if (g)
619 {
620 g->refcnt++;
621 return 0;
622 }
623 s = format (s, "/dev/vfio/%u%c", group, 0);
624 fd = open ((char *) s, O_RDWR);
625 if (fd < 0)
Damjan Marion96504182017-12-10 23:54:46 +0100626 return clib_error_return_unix (0, "open '%s'", s);
Damjan Marioncef87f12017-10-05 15:32:41 +0200627
628 group_status.argsz = sizeof (group_status);
629 if (ioctl (fd, VFIO_GROUP_GET_STATUS, &group_status) < 0)
630 {
631 err = clib_error_return_unix (0, "ioctl(VFIO_GROUP_GET_STATUS) '%s'",
632 s);
633 goto error;
634 }
635
636 if (!(group_status.flags & VFIO_GROUP_FLAGS_VIABLE))
637 {
638 err = clib_error_return (0, "iommu group %d is not viable (not all "
639 "devices in this group bound to vfio-pci)",
640 group);
641 goto error;
642 }
643
644 if (ioctl (fd, VFIO_GROUP_SET_CONTAINER, &lpm->vfio_container_fd) < 0)
645 {
646 err = clib_error_return_unix (0, "ioctl(VFIO_GROUP_SET_CONTAINER) '%s'",
647 s);
648 goto error;
649 }
650
651 if (lpm->vfio_iommu_mode == 0)
652 {
653 if (ioctl (lpm->vfio_container_fd, VFIO_SET_IOMMU, VFIO_TYPE1_IOMMU) <
654 0)
655 {
656 err = clib_error_return_unix (0, "ioctl(VFIO_SET_IOMMU) "
657 "'/dev/vfio/vfio'");
658 goto error;
659 }
660 lpm->vfio_iommu_mode = VFIO_TYPE1_IOMMU;
661 }
662
663
664 pool_get (lpm->iommu_groups, g);
665 g->fd = fd;
666 g->refcnt = 1;
667 hash_set (lpm->iommu_pool_index_by_group, group, g - lpm->iommu_groups);
668 vec_free (s);
669 return 0;
670error:
671 close (fd);
672 return err;
673}
674
675static clib_error_t *
676add_device_vfio (vlib_main_t * vm, linux_pci_device_t * p,
677 vlib_pci_device_info_t * di, pci_device_registration_t * r)
678{
679 linux_pci_vfio_iommu_group_t *g;
680 struct vfio_device_info device_info;
681 struct vfio_irq_info irq_info = { 0 };
682 clib_error_t *err = 0;
683 u8 *s = 0;
684 int dfd;
685
686 p->addr.as_u32 = di->addr.as_u32;
687
688 if (di->driver_name == 0 ||
689 (strcmp ("vfio-pci", (char *) di->driver_name) != 0))
690 return clib_error_return (0, "Device '%U' (iommu group %d) not bound to "
691 "vfio-pci", format_vlib_pci_addr, &di->addr,
692 di->iommu_group);
693
694 if ((err = open_vfio_iommu_group (di->iommu_group)))
695 return err;
696
697 g = get_vfio_iommu_group (di->iommu_group);
698
699 s = format (s, "%U%c", format_vlib_pci_addr, &di->addr, 0);
700 if ((dfd = ioctl (g->fd, VFIO_GROUP_GET_DEVICE_FD, (char *) s)) < 0)
701 {
702 err = clib_error_return_unix (0, "ioctl(VFIO_GROUP_GET_DEVICE_FD) '%U'",
703 format_vlib_pci_addr, &di->addr);
704 goto error;
705 }
706 vec_reset_length (s);
707 p->vfio_device_fd = dfd;
708
709 device_info.argsz = sizeof (device_info);
710 if (ioctl (dfd, VFIO_DEVICE_GET_INFO, &device_info) < 0)
711 {
712 err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_INFO) '%U'",
713 format_vlib_pci_addr, &di->addr);
714 goto error;
715 }
716
717 irq_info.argsz = sizeof (struct vfio_irq_info);
718 irq_info.index = VFIO_PCI_INTX_IRQ_INDEX;
719 if (ioctl (dfd, VFIO_DEVICE_GET_IRQ_INFO, &irq_info) < 0)
720 {
721 err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_GET_IRQ_INFO) "
722 "'%U'", format_vlib_pci_addr, &di->addr);
723 goto error;
724 }
725
726 /* reset if device supports it */
727 if (device_info.flags & VFIO_DEVICE_FLAGS_RESET)
728 if (ioctl (dfd, VFIO_DEVICE_RESET) < 0)
729 {
730 err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_RESET) '%U'",
731 format_vlib_pci_addr, &di->addr);
732 goto error;
733 }
734
735 if ((irq_info.flags & VFIO_IRQ_INFO_EVENTFD) && irq_info.count == 1)
736 {
737 u8 buf[sizeof (struct vfio_irq_set) + sizeof (int)] = { 0 };
738 struct vfio_irq_set *irq_set = (struct vfio_irq_set *) buf;
739 clib_file_t t = { 0 };
740 int efd = eventfd (0, EFD_NONBLOCK);
741
742 irq_set->argsz = sizeof (buf);
743 irq_set->count = 1;
744 irq_set->index = VFIO_PCI_INTX_IRQ_INDEX;
745 irq_set->flags =
746 VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER;
747 clib_memcpy (&irq_set->data, &efd, sizeof (int));
748
749 if (ioctl (dfd, VFIO_DEVICE_SET_IRQS, irq_set) < 0)
750 {
751 err = clib_error_return_unix (0, "ioctl(VFIO_DEVICE_SET_IRQS) '%U'",
752 format_vlib_pci_addr, &di->addr);
753 goto error;
754 }
755
756 t.read_function = linux_pci_vfio_read_ready;
757 t.file_descriptor = efd;
758 t.error_function = linux_pci_vfio_error_ready;
759 t.private_data = p->handle;
760 p->clib_file_index = clib_file_add (&file_main, &t);
761
762 /* unmask the interrupt */
763 linux_pci_vfio_unmask_intx (p);
764 }
765
766 p->interrupt_handler = r->interrupt_handler;
767
768 s = format (s, "%s/%U/config%c", sysfs_pci_dev_path,
769 format_vlib_pci_addr, &di->addr, 0);
770
771 p->config_fd = open ((char *) s, O_RDWR);
772 vec_reset_length (s);
773
774 if (p->config_fd == -1)
775 {
776 err = clib_error_return_unix (0, "open '%s'", s);
777 goto error;
778 }
779
780 err = r->init_function (vm, p->handle);
781
782error:
783 vec_free (s);
784 if (err)
785 {
Damjan Marion96504182017-12-10 23:54:46 +0100786 if (dfd != -1)
787 close (dfd);
788 if (p->config_fd != -1)
789 close (p->config_fd);
Damjan Marioncef87f12017-10-05 15:32:41 +0200790 }
791 return err;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700792}
793
794/* Configuration space read/write. */
795clib_error_t *
Damjan Marioncef87f12017-10-05 15:32:41 +0200796vlib_pci_read_write_config (vlib_pci_dev_handle_t h,
Damjan Marion5a206ea2016-05-12 22:11:03 +0200797 vlib_read_or_write_t read_or_write,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400798 uword address, void *data, u32 n_bytes)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700799{
Damjan Marioncef87f12017-10-05 15:32:41 +0200800 linux_pci_device_t *p = linux_pci_get_device (h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700801 int n;
802
Ed Warnickecb9cada2015-12-08 15:45:58 -0700803 if (read_or_write == VLIB_READ)
Damjan Marion5a206ea2016-05-12 22:11:03 +0200804 n = pread (p->config_fd, data, n_bytes, address);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700805 else
Damjan Marion5a206ea2016-05-12 22:11:03 +0200806 n = pwrite (p->config_fd, data, n_bytes, address);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700807
808 if (n != n_bytes)
809 return clib_error_return_unix (0, "%s",
810 read_or_write == VLIB_READ
811 ? "read" : "write");
812
813 return 0;
814}
815
816static clib_error_t *
Damjan Marioncef87f12017-10-05 15:32:41 +0200817vlib_pci_map_resource_int (vlib_pci_dev_handle_t h,
818 u32 resource, u8 * addr, void **result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700819{
Damjan Marioncef87f12017-10-05 15:32:41 +0200820 linux_pci_device_t *p = linux_pci_get_device (h);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700821 struct stat stat_buf;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400822 u8 *file_name;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700823 int fd;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400824 clib_error_t *error;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700825 int flags = MAP_SHARED;
826
827 error = 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700828
Damjan Marioncef87f12017-10-05 15:32:41 +0200829 file_name = format (0, "%s/%U/resource%d%c", sysfs_pci_dev_path,
830 format_vlib_pci_addr, &p->addr, resource, 0);
831
Ed Warnickecb9cada2015-12-08 15:45:58 -0700832 fd = open ((char *) file_name, O_RDWR);
833 if (fd < 0)
834 {
835 error = clib_error_return_unix (0, "open `%s'", file_name);
836 goto done;
837 }
838
839 if (fstat (fd, &stat_buf) < 0)
840 {
841 error = clib_error_return_unix (0, "fstat `%s'", file_name);
842 goto done;
843 }
844
845 vec_validate (p->resource_fds, resource);
846 p->resource_fds[resource] = fd;
847 if (addr != 0)
848 flags |= MAP_FIXED;
849
850 *result = mmap (addr,
851 /* size */ stat_buf.st_size,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400852 PROT_READ | PROT_WRITE, flags,
Ed Warnickecb9cada2015-12-08 15:45:58 -0700853 /* file */ fd,
854 /* offset */ 0);
855 if (*result == (void *) -1)
856 {
857 error = clib_error_return_unix (0, "mmap `%s'", file_name);
858 goto done;
859 }
860
Dave Barach9b8ffd92016-07-08 08:13:45 -0400861done:
Ed Warnickecb9cada2015-12-08 15:45:58 -0700862 if (error)
863 {
Chris Luke370e9e32016-07-07 11:01:17 -0400864 if (fd >= 0)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700865 close (fd);
866 }
867 vec_free (file_name);
868 return error;
869}
870
871clib_error_t *
Damjan Marioncef87f12017-10-05 15:32:41 +0200872vlib_pci_map_resource (vlib_pci_dev_handle_t h, u32 resource, void **result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700873{
Damjan Marioncef87f12017-10-05 15:32:41 +0200874 return (vlib_pci_map_resource_int (h, resource, 0 /* addr */ , result));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700875}
876
877clib_error_t *
Damjan Marioncef87f12017-10-05 15:32:41 +0200878vlib_pci_map_resource_fixed (vlib_pci_dev_handle_t h,
Dave Barach9b8ffd92016-07-08 08:13:45 -0400879 u32 resource, u8 * addr, void **result)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700880{
Damjan Marioncef87f12017-10-05 15:32:41 +0200881 return (vlib_pci_map_resource_int (h, resource, addr, result));
Ed Warnickecb9cada2015-12-08 15:45:58 -0700882}
883
Dave Barach9b8ffd92016-07-08 08:13:45 -0400884void
Damjan Marioncef87f12017-10-05 15:32:41 +0200885init_device_from_registered (vlib_main_t * vm, vlib_pci_device_info_t * di)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700886{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400887 vlib_pci_main_t *pm = &pci_main;
Damjan Marioncef87f12017-10-05 15:32:41 +0200888 linux_pci_main_t *lpm = &linux_pci_main;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400889 pci_device_registration_t *r;
890 pci_device_id_t *i;
Damjan Marioncef87f12017-10-05 15:32:41 +0200891 clib_error_t *err = 0;
892 linux_pci_device_t *p;
893
894 pool_get (lpm->linux_pci_devices, p);
895 p->handle = p - lpm->linux_pci_devices;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700896
Damjan Marion5a206ea2016-05-12 22:11:03 +0200897 r = pm->pci_device_registrations;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700898
899 while (r)
900 {
901 for (i = r->supported_devices; i->vendor_id != 0; i++)
Damjan Marioncef87f12017-10-05 15:32:41 +0200902 if (i->vendor_id == di->config0.header.vendor_id &&
903 i->device_id == di->config0.header.device_id)
Dave Barach9b8ffd92016-07-08 08:13:45 -0400904 {
Damjan Marioncef87f12017-10-05 15:32:41 +0200905 if (di->iommu_group != -1)
906 err = add_device_vfio (vm, p, di, r);
907 else
908 err = add_device_uio (vm, p, di, r);
Damjan Marion5a206ea2016-05-12 22:11:03 +0200909
Damjan Marioncef87f12017-10-05 15:32:41 +0200910 if (err)
911 clib_error_report (err);
912 else
913 return;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400914 }
Ed Warnickecb9cada2015-12-08 15:45:58 -0700915 r = r->next_registration;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400916 }
Damjan Marioncef87f12017-10-05 15:32:41 +0200917
Ed Warnickecb9cada2015-12-08 15:45:58 -0700918 /* No driver, close the PCI config-space FD */
Damjan Marioncef87f12017-10-05 15:32:41 +0200919 memset (p, 0, sizeof (linux_pci_device_t));
920 pool_put (lpm->linux_pci_devices, p);
921}
922
923static clib_error_t *
924scan_pci_addr (void *arg, u8 * dev_dir_name, u8 * ignored)
925{
926 vlib_pci_addr_t addr, **addrv = arg;
927 unformat_input_t input;
928 clib_error_t *err = 0;
929
930 unformat_init_string (&input, (char *) dev_dir_name,
931 vec_len (dev_dir_name));
932
933 if (!unformat (&input, "/sys/bus/pci/devices/%U",
934 unformat_vlib_pci_addr, &addr))
935 err = clib_error_return (0, "unformat error `%v`", dev_dir_name);
936
937 unformat_free (&input);
938
939 if (err)
940 return err;
941
942 vec_add1 (*addrv, addr);
Ed Warnickecb9cada2015-12-08 15:45:58 -0700943 return 0;
944}
945
Damjan Marioncef87f12017-10-05 15:32:41 +0200946static int
947pci_addr_cmp (void *v1, void *v2)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700948{
Damjan Marioncef87f12017-10-05 15:32:41 +0200949 vlib_pci_addr_t *a1 = v1;
950 vlib_pci_addr_t *a2 = v2;
951
952 if (a1->domain > a2->domain)
953 return 1;
954 if (a1->domain < a2->domain)
955 return -1;
956 if (a1->bus > a2->bus)
957 return 1;
958 if (a1->bus < a2->bus)
959 return -1;
960 if (a1->slot > a2->slot)
961 return 1;
962 if (a1->slot < a2->slot)
963 return -1;
964 if (a1->function > a2->function)
965 return 1;
966 if (a1->function < a2->function)
967 return -1;
968 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700969}
970
Damjan Marioncef87f12017-10-05 15:32:41 +0200971vlib_pci_addr_t *
972vlib_pci_get_all_dev_addrs ()
Ed Warnickecb9cada2015-12-08 15:45:58 -0700973{
Damjan Marioncef87f12017-10-05 15:32:41 +0200974 vlib_pci_addr_t *addrs = 0;
975 clib_error_t *err;
976 err = foreach_directory_file ((char *) sysfs_pci_dev_path, scan_pci_addr,
977 &addrs, /* scan_dirs */ 0);
978 if (err)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700979 {
Damjan Marioncef87f12017-10-05 15:32:41 +0200980 vec_free (addrs);
981 return 0;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700982 }
983
Damjan Marioncef87f12017-10-05 15:32:41 +0200984 vec_sort_with_function (addrs, pci_addr_cmp);
Damjan Mariona42cd342016-04-13 18:03:20 +0200985
Damjan Marioncef87f12017-10-05 15:32:41 +0200986 return addrs;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700987}
988
Dave Barach9b8ffd92016-07-08 08:13:45 -0400989clib_error_t *
990linux_pci_init (vlib_main_t * vm)
Ed Warnickecb9cada2015-12-08 15:45:58 -0700991{
Dave Barach9b8ffd92016-07-08 08:13:45 -0400992 vlib_pci_main_t *pm = &pci_main;
Damjan Marioncef87f12017-10-05 15:32:41 +0200993 linux_pci_main_t *lpm = &linux_pci_main;
994 vlib_pci_addr_t *addr = 0, *addrs;
Dave Barach9b8ffd92016-07-08 08:13:45 -0400995 clib_error_t *error;
Damjan Marioncef87f12017-10-05 15:32:41 +0200996 int fd;
Ed Warnickecb9cada2015-12-08 15:45:58 -0700997
998 pm->vlib_main = vm;
999
1000 if ((error = vlib_call_init_function (vm, unix_input_init)))
1001 return error;
1002
Dave Barach9b8ffd92016-07-08 08:13:45 -04001003 ASSERT (sizeof (vlib_pci_addr_t) == sizeof (u32));
Damjan Mariona42cd342016-04-13 18:03:20 +02001004
Damjan Marioncef87f12017-10-05 15:32:41 +02001005 fd = open ("/dev/vfio/vfio", O_RDWR);
Ed Warnickecb9cada2015-12-08 15:45:58 -07001006
Damjan Marioncef87f12017-10-05 15:32:41 +02001007 if ((fd != -1) && (ioctl (fd, VFIO_GET_API_VERSION) != VFIO_API_VERSION))
1008 {
1009 close (fd);
1010 fd = -1;
1011 }
1012
1013 if ((fd != -1) && (ioctl (fd, VFIO_CHECK_EXTENSION, VFIO_TYPE1_IOMMU) == 0))
1014 {
1015 close (fd);
1016 fd = -1;
1017 }
1018
1019 lpm->vfio_container_fd = fd;
1020 lpm->iommu_pool_index_by_group = hash_create (0, sizeof (uword));
1021
1022 addrs = vlib_pci_get_all_dev_addrs ();
1023 /* *INDENT-OFF* */
1024 vec_foreach (addr, addrs)
1025 {
1026 vlib_pci_device_info_t *d;
1027 if ((d = vlib_pci_get_device_info (addr, 0)))
1028 {
1029 init_device_from_registered (vm, d);
1030 vlib_pci_free_device_info (d);
1031 }
1032 }
1033 /* *INDENT-ON* */
Ed Warnickecb9cada2015-12-08 15:45:58 -07001034
1035 return error;
1036}
1037
Damjan Marion5a206ea2016-05-12 22:11:03 +02001038VLIB_INIT_FUNCTION (linux_pci_init);
Dave Barach9b8ffd92016-07-08 08:13:45 -04001039
1040/*
1041 * fd.io coding-style-patch-verification: ON
1042 *
1043 * Local Variables:
1044 * eval: (c-set-style "gnu")
1045 * End:
1046 */