ia64/linux-2.6.18-xen.hg

view drivers/pci/guestdev.c @ 882:8dec4aa9b8b9

PCI pass through: PCIe IO space multiplexing

This is required for more than 16 HVM domain to boot from
PCIe pass through device.

Linux as dom0 exclusively assigns IO space to downstream PCI bridges
and the assignment unit of PCI bridge IO space is 4K. So the only up
to 16 PCIe device can be accessed via IO space within 64K IO ports.
PCI expansion ROM BIOS often uses IO port access to boot from the
device, so on virtualized environment, it means only up to 16 guest
domain can boot from pass-through device.

This patch allows PCIe IO space sharing of pass-through device.
- reassign IO space of PCIe devices specified by
"guestiomuldev=[<segment>:]<bus>:<dev>[,[<segment:><bus>:dev]][,...]"
to be shared.
This is implemented as Linux PCI quirk fixup.

The sharing unit is PCIe switch. Ie IO space of the end point
devices under the same switch will be shared. If there are more than
one switches, two areas of IO space will be used.

- And the driver which arbitrates the accesses to the multiplexed PCIe
IO space. Later qemu-dm will use this.

Limitation:
IO port of IO shared devices can't be accessed from dom0 Linux device
driver. But this wouldn't be a big issue because PCIe specification
discourages the use of IO space and recommends that IO space should be
used only for bootable device with ROM code. OS device driver should
work without IO space access.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Keir Fraser <keir.fraser@citrix.com>
date Thu May 28 09:57:49 2009 +0100 (2009-05-28)
parents a3ad7a5f2dcd
children b998614e2e2a
line source
1 /*
2 * Copyright (c) 2008, 2009 NEC Corporation.
3 *
4 * This program is free software; you can redistribute it and/or modify it
5 * under the terms and conditions of the GNU General Public License,
6 * version 2, as published by the Free Software Foundation.
7 *
8 * This program is distributed in the hope it will be useful, but WITHOUT
9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
11 * more details.
12 *
13 * You should have received a copy of the GNU General Public License along with
14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
15 * Place - Suite 330, Boston, MA 02111-1307 USA.
16 */
18 #include <linux/kernel.h>
19 #include <linux/list.h>
20 #include <linux/mm.h>
21 #include <linux/pci.h>
22 #include <linux/module.h>
23 #include <linux/string.h>
24 #include <linux/acpi.h>
25 #include <asm-x86_64/setup.h>
27 #define HID_LEN 8
28 #define UID_LEN 8
29 #define DEV_LEN 2
30 #define FUNC_LEN 1
31 #define DEV_NUM_MAX 31
32 #define FUNC_NUM_MAX 7
33 #define INVALID_SEG (-1)
34 #define INVALID_BBN (-1)
35 #define GUESTDEV_STR_MAX 128
37 #define GUESTDEV_FLAG_TYPE_MASK 0x3
38 #define GUESTDEV_FLAG_DEVICEPATH 0x1
39 #define GUESTDEV_FLAG_SBDF 0x2
41 struct guestdev {
42 int flags;
43 struct list_head root_list;
44 union {
45 struct devicepath {
46 char hid[HID_LEN + 1];
47 char uid[UID_LEN + 1];
48 int seg;
49 int bbn;
50 struct devicepath_node *child;
51 } devicepath;
52 struct sbdf {
53 int seg;
54 int bus;
55 int dev;
56 int func;
57 } sbdf;
58 } u;
59 };
61 struct devicepath_node {
62 int dev;
63 int func;
64 struct devicepath_node *child;
65 };
67 struct pcidev_sbdf {
68 int seg;
69 int bus;
70 struct pcidev_sbdf_node *child;
71 };
73 struct pcidev_sbdf_node {
74 int dev;
75 int func;
76 struct pcidev_sbdf_node *child;
77 };
79 static int reassign_resources = 0;
81 static char guestdev_param[COMMAND_LINE_SIZE];
82 LIST_HEAD(guestdev_list);
84 /* Get hid and uid */
85 static int __init pci_get_hid_uid(char *str, char *hid, char *uid)
86 {
87 char *sp, *ep;
88 int len;
90 sp = str;
91 ep = strchr(sp, ':');
92 if (!ep) {
93 ep = strchr(sp, '-');
94 if (!ep)
95 goto format_err_end;
96 }
97 /* hid length */
98 len = ep - sp;
99 if (len <= 0 || HID_LEN < len)
100 goto format_err_end;
102 strncpy(hid, sp, len);
103 hid[len] = '\0';
105 if (*ep == '-') { /* no uid */
106 uid[0] = '\0';
107 return TRUE;
108 }
110 sp = ep + 1;
111 ep = strchr(sp, '-');
112 if (!ep)
113 ep = strchr(sp, '\0');
115 /* uid length */
116 len = ep - sp;
117 if (len <= 0 || UID_LEN < len)
118 goto format_err_end;
120 strncpy(uid, sp, len);
121 uid[len] = '\0';
122 return TRUE;
124 format_err_end:
125 return FALSE;
126 }
128 /* Get device and function */
129 static int __init pci_get_dev_func(char *str, int *dev, int *func)
130 {
131 if (sscanf(str, "%02x.%01x", dev, func) != 2)
132 goto format_err_end;
134 if (*dev < 0 || DEV_NUM_MAX < *dev)
135 goto format_err_end;
137 if (*func < 0 || FUNC_NUM_MAX < *func)
138 goto format_err_end;
140 return TRUE;
142 format_err_end:
143 return FALSE;
144 }
146 /* Check extended guestdev parameter format error */
147 static int __init pci_check_extended_guestdev_format(char *str)
148 {
149 int flg;
150 char *p;
152 /* Check extended format */
153 if (strpbrk(str, "(|)") == NULL)
154 return TRUE;
156 flg = 0;
157 p = str;
158 while (*p) {
159 switch (*p) {
160 case '(':
161 /* Check nesting error */
162 if (flg != 0)
163 goto format_err_end;
164 flg = 1;
165 /* Check position of '(' is head or
166 previos charactor of '(' is not '-'. */
167 if (p == str || *(p - 1) != '-')
168 goto format_err_end;
169 break;
170 case ')':
171 /* Check nesting error */
172 if (flg != 1)
173 goto format_err_end;
174 flg = 0;
175 /* Check next charactor of ')' is not '\0' */
176 if (*(p + 1) != '\0')
177 goto format_err_end;
178 break;
179 case '|':
180 /* Check position of '|' is outside of '(' and ')' */
181 if (flg != 1)
182 goto format_err_end;
183 break;
184 default:
185 break;
186 }
187 p++;
188 }
189 /* Check number of '(' and ')' are not equal */
190 if (flg != 0)
191 goto format_err_end;
192 return TRUE;
194 format_err_end:
195 printk(KERN_ERR
196 "PCI: The format of the guestdev parameter is illegal. [%s]\n",
197 str);
198 return FALSE;
199 }
201 /* Make guestdev strings */
202 static void pci_make_guestdev_str(struct guestdev *gdev,
203 char *gdev_str, int buf_size)
204 {
205 struct devicepath_node *node;
206 int count;
208 switch (gdev->flags & GUESTDEV_FLAG_TYPE_MASK) {
209 case GUESTDEV_FLAG_DEVICEPATH:
210 memset(gdev_str, 0, buf_size);
212 if (strlen(gdev->u.devicepath.uid))
213 count = snprintf(gdev_str, buf_size, "%s:%s",
214 gdev->u.devicepath.hid,
215 gdev->u.devicepath.uid);
216 else
217 count = snprintf(gdev_str, buf_size, "%s",
218 gdev->u.devicepath.hid);
219 if (count < 0)
220 return;
222 node = gdev->u.devicepath.child;
223 while (node) {
224 gdev_str += count;
225 buf_size -= count;
226 if (buf_size <= 0)
227 return;
228 count = snprintf(gdev_str, buf_size, "-%02x.%01x",
229 node->dev, node->func);
230 if (count < 0)
231 return;
232 node = node->child;
233 }
234 break;
235 case GUESTDEV_FLAG_SBDF:
236 snprintf(gdev_str, buf_size, "%04x:%02x:%02x.%01x",
237 gdev->u.sbdf.seg, gdev->u.sbdf.bus,
238 gdev->u.sbdf.dev, gdev->u.sbdf.func);
239 break;
240 default:
241 BUG();
242 }
243 }
245 /* Free guestdev and nodes */
246 static void __init pci_free_guestdev(struct guestdev *gdev)
247 {
248 struct devicepath_node *node, *next;
250 if (!gdev)
251 return;
252 if (gdev->flags & GUESTDEV_FLAG_DEVICEPATH) {
253 node = gdev->u.devicepath.child;
254 while (node) {
255 next = node->child;
256 kfree(node);
257 node = next;
258 }
259 }
260 list_del(&gdev->root_list);
261 kfree(gdev);
262 }
264 /* Copy guestdev and nodes */
265 struct guestdev __init *pci_copy_guestdev(struct guestdev *gdev_src)
266 {
267 struct guestdev *gdev;
268 struct devicepath_node *node, *node_src, *node_upper;
270 BUG_ON(!(gdev_src->flags & GUESTDEV_FLAG_DEVICEPATH));
272 gdev = kmalloc(sizeof(*gdev), GFP_KERNEL);
273 if (!gdev)
274 goto allocate_err_end;
276 memset(gdev, 0, sizeof(*gdev));
277 INIT_LIST_HEAD(&gdev->root_list);
278 gdev->flags = gdev_src->flags;
279 strcpy(gdev->u.devicepath.hid, gdev_src->u.devicepath.hid);
280 strcpy(gdev->u.devicepath.uid, gdev_src->u.devicepath.uid);
281 gdev->u.devicepath.seg = gdev_src->u.devicepath.seg;
282 gdev->u.devicepath.bbn = gdev_src->u.devicepath.bbn;
284 node_upper = NULL;
286 node_src = gdev_src->u.devicepath.child;
287 while (node_src) {
288 node = kmalloc(sizeof(*node), GFP_KERNEL);
289 if (!node)
290 goto allocate_err_end;
291 memset(node, 0, sizeof(*node));
292 node->dev = node_src->dev;
293 node->func = node_src->func;
294 if (!node_upper)
295 gdev->u.devicepath.child = node;
296 else
297 node_upper->child = node;
298 node_upper = node;
299 node_src = node_src->child;
300 }
302 return gdev;
304 allocate_err_end:
305 if (gdev)
306 pci_free_guestdev(gdev);
307 printk(KERN_ERR "PCI: Failed to allocate memory.\n");
308 return NULL;
309 }
311 /* Make guestdev from path strings */
312 static int __init pci_make_devicepath_guestdev(char *path_str)
313 {
314 char hid[HID_LEN + 1], uid[UID_LEN + 1];
315 char *sp, *ep;
316 struct guestdev *gdev, *gdev_org;
317 struct devicepath_node *node, *node_tmp;
318 int dev, func, ret_val;
320 ret_val = 0;
321 gdev = gdev_org = NULL;
322 sp = path_str;
323 /* Look for end of hid:uid'-' */
324 ep = strchr(sp, '-');
325 /* Only hid, uid. (No dev, func) */
326 if (!ep)
327 goto format_err_end;
329 memset(hid, 0 ,sizeof(hid));
330 memset(uid, 0, sizeof(uid));
331 if (!pci_get_hid_uid(sp, hid, uid))
332 goto format_err_end;
334 gdev_org = kmalloc(sizeof(*gdev_org), GFP_KERNEL);
335 if (!gdev_org)
336 goto allocate_err_end;
337 memset(gdev_org, 0, sizeof(*gdev_org));
338 INIT_LIST_HEAD(&gdev_org->root_list);
339 gdev_org->flags = GUESTDEV_FLAG_DEVICEPATH;
340 strcpy(gdev_org->u.devicepath.hid, hid);
341 strcpy(gdev_org->u.devicepath.uid, uid);
342 gdev_org->u.devicepath.seg = INVALID_SEG;
343 gdev_org->u.devicepath.bbn = INVALID_BBN;
345 gdev = gdev_org;
347 sp = ep + 1;
348 ep = sp;
349 do {
350 if (*sp == '(') {
351 sp++;
352 if (strchr(sp, '|')) {
353 gdev = pci_copy_guestdev(gdev_org);
354 if (!gdev) {
355 ret_val = -ENOMEM;
356 goto end;
357 }
358 }
359 continue;
360 }
361 if (gdev && pci_get_dev_func(sp, &dev, &func)) {
362 node = kmalloc(sizeof(*node), GFP_KERNEL);
363 if (!node)
364 goto allocate_err_end;
365 memset(node, 0, sizeof(*node));
366 node->dev = dev;
367 node->func = func;
368 /* add node to end of guestdev */
369 if (gdev->u.devicepath.child) {
370 node_tmp = gdev->u.devicepath.child;
371 while (node_tmp->child) {
372 node_tmp = node_tmp->child;
373 }
374 node_tmp->child = node;
375 } else
376 gdev->u.devicepath.child = node;
377 } else if (gdev) {
378 printk(KERN_ERR
379 "PCI: Can't obtain dev# and #func# from %s.\n",
380 sp);
381 ret_val = -EINVAL;
382 if (gdev == gdev_org)
383 goto end;
384 pci_free_guestdev(gdev);
385 gdev = NULL;
386 }
388 ep = strpbrk(sp, "-|)");
389 if (!ep)
390 ep = strchr(sp, '\0');
391 /* Is *ep '|' OR ')' OR '\0' ? */
392 if (*ep != '-') {
393 if (gdev)
394 list_add_tail(&gdev->root_list, &guestdev_list);
395 if (*ep == '|') {
396 /* Between '|' and '|' ? */
397 if (strchr(ep + 1, '|')) {
398 gdev = pci_copy_guestdev(gdev_org);
399 if (!gdev) {
400 ret_val = -ENOMEM;
401 goto end;
402 }
403 } else {
404 gdev = gdev_org;
405 gdev_org = NULL;
406 }
407 } else {
408 gdev_org = NULL;
409 gdev = NULL;
410 }
411 }
412 if (*ep == ')')
413 ep++;
414 sp = ep + 1;
415 } while (*ep != '\0');
417 goto end;
419 format_err_end:
420 printk(KERN_ERR
421 "PCI: The format of the guestdev parameter is illegal. [%s]\n",
422 path_str);
423 ret_val = -EINVAL;
424 goto end;
426 allocate_err_end:
427 printk(KERN_ERR "PCI: Failed to allocate memory.\n");
428 ret_val = -ENOMEM;
429 goto end;
431 end:
432 if (gdev_org && (gdev_org != gdev))
433 pci_free_guestdev(gdev_org);
434 if (gdev)
435 pci_free_guestdev(gdev);
436 return ret_val;
437 }
439 static int __init pci_make_sbdf_guestdev(char* str)
440 {
441 struct guestdev *gdev;
442 int seg, bus, dev, func;
444 if (sscanf(str, "%x:%x:%x.%x", &seg, &bus, &dev, &func) != 4) {
445 seg = 0;
446 if (sscanf(str, "%x:%x.%x", &bus, &dev, &func) != 3)
447 return -EINVAL;
448 }
449 gdev = kmalloc(sizeof(*gdev), GFP_KERNEL);
450 if (!gdev) {
451 printk(KERN_ERR "PCI: Failed to allocate memory.\n");
452 return -ENOMEM;
453 }
454 INIT_LIST_HEAD(&gdev->root_list);
455 gdev->flags = GUESTDEV_FLAG_SBDF;
456 gdev->u.sbdf.seg = seg;
457 gdev->u.sbdf.bus = bus;
458 gdev->u.sbdf.dev = dev;
459 gdev->u.sbdf.func = func;
460 list_add_tail(&gdev->root_list, &guestdev_list);
461 return 0;
462 }
464 /* Parse guestdev parameter */
465 static int __init pci_parse_guestdev(void)
466 {
467 int len;
468 char *sp, *ep;
469 struct list_head *head;
470 struct guestdev *gdev;
471 char path_str[GUESTDEV_STR_MAX];
472 int ret_val = 0;
474 len = strlen(guestdev_param);
475 if (len == 0)
476 return 0;
478 sp = guestdev_param;
480 do {
481 ep = strchr(sp, ',');
482 /* Chop */
483 if (ep)
484 *ep = '\0';
485 ret_val = pci_make_sbdf_guestdev(sp);
486 if (ret_val == -EINVAL) {
487 if (pci_check_extended_guestdev_format(sp)) {
488 ret_val = pci_make_devicepath_guestdev(sp);
489 if (ret_val && ret_val != -EINVAL)
490 break;
491 }
492 } else if (ret_val)
493 break;
494 sp = ep + 1;
495 } while (ep);
497 list_for_each(head, &guestdev_list) {
498 gdev = list_entry(head, struct guestdev, root_list);
499 pci_make_guestdev_str(gdev, path_str, GUESTDEV_STR_MAX);
500 printk(KERN_DEBUG
501 "PCI: %s has been reserved for guest domain.\n",
502 path_str);
503 }
504 return 0;
505 }
507 arch_initcall(pci_parse_guestdev);
509 /* Get command line */
510 static int __init pci_guestdev_setup(char *str)
511 {
512 if (strlen(str) >= COMMAND_LINE_SIZE)
513 return 0;
514 strcpy(guestdev_param, str);
515 return 1;
516 }
518 __setup("guestdev=", pci_guestdev_setup);
520 /* Free sbdf and nodes */
521 static void pci_free_sbdf(struct pcidev_sbdf *sbdf)
522 {
523 struct pcidev_sbdf_node *node, *next;
525 node = sbdf->child;
526 while (node) {
527 next = node->child;
528 kfree(node);
529 node = next;
530 }
531 /* Skip kfree(sbdf) */
532 }
534 /* Does PCI device belong to sub tree specified by guestdev with device path? */
535 static int pci_is_in_devicepath_sub_tree(struct guestdev *gdev,
536 struct pcidev_sbdf *sbdf)
537 {
538 int seg, bbn;
539 struct devicepath_node *gdev_node;
540 struct pcidev_sbdf_node *sbdf_node;
542 if (!gdev || !sbdf)
543 return FALSE;
545 BUG_ON(!(gdev->flags & GUESTDEV_FLAG_DEVICEPATH));
547 /* Compare seg and bbn */
548 if (gdev->u.devicepath.seg == INVALID_SEG ||
549 gdev->u.devicepath.bbn == INVALID_BBN) {
550 if (acpi_pci_get_root_seg_bbn(gdev->u.devicepath.hid,
551 gdev->u.devicepath.uid, &seg, &bbn)) {
552 gdev->u.devicepath.seg = seg;
553 gdev->u.devicepath.bbn = bbn;
554 } else
555 return FALSE;
556 }
558 if (gdev->u.devicepath.seg != sbdf->seg ||
559 gdev->u.devicepath.bbn != sbdf->bus)
560 return FALSE;
562 gdev_node = gdev->u.devicepath.child;
563 sbdf_node = sbdf->child;
565 /* Compare dev and func */
566 while (gdev_node) {
567 if (!sbdf_node)
568 return FALSE;
569 if (gdev_node->dev != sbdf_node->dev ||
570 gdev_node->func != sbdf_node->func)
571 return FALSE;
572 gdev_node = gdev_node->child;
573 sbdf_node = sbdf_node->child;
574 }
575 return TRUE;
576 }
578 /* Get sbdf from device */
579 static int pci_get_sbdf_from_pcidev(
580 struct pci_dev *dev, struct pcidev_sbdf *sbdf)
581 {
582 struct pcidev_sbdf_node *node;
584 if (!dev)
585 return FALSE;
587 for(;;) {
588 node = kmalloc(sizeof(*node), GFP_KERNEL);
589 if (!node) {
590 printk(KERN_ERR "PCI: Failed to allocate memory.\n");
591 goto err_end;
592 }
593 memset(node, 0, sizeof(*node));
594 node->dev = PCI_SLOT(dev->devfn);
595 node->func = PCI_FUNC(dev->devfn);
597 if (!sbdf->child)
598 sbdf->child = node;
599 else {
600 node->child = sbdf->child;
601 sbdf->child = node;
602 }
603 if (!dev->bus)
604 goto err_end;
605 if (!dev->bus->self)
606 break;
607 dev = dev->bus->self;
608 }
609 if (sscanf(dev->dev.bus_id, "%04x:%02x", &sbdf->seg, &sbdf->bus) != 2)
610 goto err_end;
611 return TRUE;
613 err_end:
614 pci_free_sbdf(sbdf);
615 return FALSE;
616 }
618 /* Does PCI device belong to sub tree specified by guestdev with sbdf? */
619 static int pci_is_in_sbdf_sub_tree(struct guestdev *gdev, struct pci_dev *dev)
620 {
621 int seg, bus;
622 BUG_ON(!(gdev->flags & GUESTDEV_FLAG_SBDF));
623 for (;;) {
624 if (sscanf(dev->dev.bus_id, "%04x:%02x", &seg, &bus) != 2)
625 continue;
626 if (gdev->u.sbdf.seg == seg && gdev->u.sbdf.bus == bus &&
627 gdev->u.sbdf.dev == PCI_SLOT(dev->devfn) &&
628 gdev->u.sbdf.func == PCI_FUNC(dev->devfn))
629 return TRUE;
630 if (!dev->bus || !dev->bus->self)
631 break;
632 dev = dev->bus->self;
633 }
634 return FALSE;
635 }
637 /* Does PCI device belong to sub tree specified by guestdev parameter? */
638 int pci_is_guestdev(struct pci_dev *dev)
639 {
640 struct guestdev *gdev;
641 struct pcidev_sbdf pcidev_sbdf, *sbdf = NULL;
642 struct list_head *head;
643 int result = FALSE;
645 if (!dev)
646 return FALSE;
648 list_for_each(head, &guestdev_list) {
649 gdev = list_entry(head, struct guestdev, root_list);
650 switch (gdev->flags & GUESTDEV_FLAG_TYPE_MASK) {
651 case GUESTDEV_FLAG_DEVICEPATH:
652 if (sbdf == NULL) {
653 sbdf = &pcidev_sbdf;
654 memset(sbdf, 0 ,sizeof(*sbdf));
655 if (!pci_get_sbdf_from_pcidev(dev, sbdf))
656 goto out;
657 }
658 if (pci_is_in_devicepath_sub_tree(gdev, sbdf)) {
659 result = TRUE;
660 goto out;
661 }
662 break;
663 case GUESTDEV_FLAG_SBDF:
664 if (pci_is_in_sbdf_sub_tree(gdev, dev)) {
665 result = TRUE;
666 goto out;
667 }
668 break;
669 default:
670 BUG();
671 }
672 }
673 out:
674 if (sbdf)
675 pci_free_sbdf(sbdf);
676 return result;
677 }
678 EXPORT_SYMBOL(pci_is_guestdev);
680 static int __init pci_set_reassign_resources(char *str)
681 {
682 reassign_resources = 1;
684 return 1;
685 }
687 __setup("reassign_resources", pci_set_reassign_resources);
689 int pci_is_reassigndev(struct pci_dev *dev)
690 {
691 if (reassign_resources)
692 return pci_is_guestdev(dev);
693 return FALSE;
694 }
695 EXPORT_SYMBOL(pci_is_reassigndev);
697 /* Check whether the devicepath exists under the pci root bus */
698 static int __init pci_check_devicepath_exists(
699 struct guestdev *gdev, struct pci_bus *bus)
700 {
701 struct devicepath_node *node;
702 struct pci_dev *dev;
704 BUG_ON(!(gdev->flags & GUESTDEV_FLAG_DEVICEPATH));
706 node = gdev->u.devicepath.child;
707 while (node) {
708 if (!bus)
709 return FALSE;
710 dev = pci_get_slot(bus, PCI_DEVFN(node->dev, node->func));
711 if (!dev)
712 return FALSE;
713 bus = dev->subordinate;
714 node = node->child;
715 pci_dev_put(dev);
716 }
717 return TRUE;
718 }
720 /* Check whether the guestdev exists in the PCI device tree */
721 static int __init pci_check_guestdev_exists(void)
722 {
723 struct list_head *head;
724 struct guestdev *gdev;
725 int seg, bbn;
726 struct pci_bus *bus;
727 struct pci_dev *dev;
728 char path_str[GUESTDEV_STR_MAX];
730 list_for_each(head, &guestdev_list) {
731 gdev = list_entry(head, struct guestdev, root_list);
732 switch (gdev->flags & GUESTDEV_FLAG_TYPE_MASK) {
733 case GUESTDEV_FLAG_DEVICEPATH:
734 if (gdev->u.devicepath.seg == INVALID_SEG ||
735 gdev->u.devicepath.bbn == INVALID_BBN) {
736 if (acpi_pci_get_root_seg_bbn(
737 gdev->u.devicepath.hid,
738 gdev->u.devicepath.uid, &seg, &bbn)) {
739 gdev->u.devicepath.seg = seg;
740 gdev->u.devicepath.bbn = bbn;
741 } else {
742 pci_make_guestdev_str(gdev,
743 path_str, GUESTDEV_STR_MAX);
744 printk(KERN_INFO
745 "PCI: Device does not exist. %s\n",
746 path_str);
747 continue;
748 }
749 }
751 bus = pci_find_bus(gdev->u.devicepath.seg,
752 gdev->u.devicepath.bbn);
753 if (!bus ||
754 !pci_check_devicepath_exists(gdev, bus)) {
755 pci_make_guestdev_str(gdev, path_str,
756 GUESTDEV_STR_MAX);
757 printk(KERN_INFO
758 "PCI: Device does not exist. %s\n",
759 path_str);
760 }
761 break;
762 case GUESTDEV_FLAG_SBDF:
763 bus = pci_find_bus(gdev->u.sbdf.seg, gdev->u.sbdf.bus);
764 if (bus) {
765 dev = pci_get_slot(bus,
766 PCI_DEVFN(gdev->u.sbdf.dev,
767 gdev->u.sbdf.func));
768 if (dev) {
769 pci_dev_put(dev);
770 continue;
771 }
772 }
773 pci_make_guestdev_str(gdev, path_str, GUESTDEV_STR_MAX);
774 printk(KERN_INFO "PCI: Device does not exist. %s\n",
775 path_str);
776 break;
777 default:
778 BUG();
779 }
780 }
781 return 0;
782 }
784 fs_initcall(pci_check_guestdev_exists);