ia64/linux-2.6.18-xen.hg

view drivers/pci/guestdev.c @ 857:a3ad7a5f2dcd

dom0 linux: support SBDF with "guestdev=" and remove "reassigndev="

When we don't need to reassign resources and use device path,
pciback.hide= boot parameter can be used. The parameter is also needed
for backward compatibility.

pciback.hide=(00:01.0)(00:02.0)

When we need to reassign resources or use device path, guestdev= boot
parameter can be used. reassign_resources boot parameter is needed to
reassign resources, too.

guestdev=00:01.0,00:02.0 reassign_resources
guestdev=PNP0A08:0-1.0,PNP0A08:0-2.0
guestdev=PNP0A08:0-1.0,PNP0A08:0-2.0 reassign_resources

Signed-off-by: Yuji Shimada <shimada-yxb@necst.nec.co.jp>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Apr 09 08:44:25 2009 +0100 (2009-04-09)
parents 2fdc121e9b5d
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);