ia64/linux-2.6.18-xen.hg

view drivers/pci/guestdev.c @ 883:b998614e2e2a

pci/guestdev: enhance guestdev to accept +iomul.

enhance guestdev to accept +iomul and use it.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Keir Fraser <keir.fraser@citrix.com>
date Thu May 28 09:59:18 2009 +0100 (2009-05-28)
parents a3ad7a5f2dcd
children 20be7f6d414a
line source
1 /*
2 * Copyright (c) 2008, 2009 NEC Corporation.
3 * Copyright (c) 2009 Isaku Yamahata
4 * VA Linux Systems Japan K.K.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms and conditions of the GNU General Public License,
8 * version 2, as published by the Free Software Foundation.
9 *
10 * This program is distributed in the hope it will be useful, but WITHOUT
11 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
12 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
13 * more details.
14 *
15 * You should have received a copy of the GNU General Public License along with
16 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
17 * Place - Suite 330, Boston, MA 02111-1307 USA.
18 */
20 #include <linux/kernel.h>
21 #include <linux/list.h>
22 #include <linux/mm.h>
23 #include <linux/pci.h>
24 #include <linux/module.h>
25 #include <linux/string.h>
26 #include <linux/acpi.h>
27 #include <asm-x86_64/setup.h>
29 #define HID_LEN 8
30 #define UID_LEN 8
31 #define DEV_LEN 2
32 #define FUNC_LEN 1
33 #define DEV_NUM_MAX 31
34 #define FUNC_NUM_MAX 7
35 #define INVALID_SEG (-1)
36 #define INVALID_BBN (-1)
37 #define GUESTDEV_STR_MAX 128
39 #define GUESTDEV_FLAG_TYPE_MASK 0x3
40 #define GUESTDEV_FLAG_DEVICEPATH 0x1
41 #define GUESTDEV_FLAG_SBDF 0x2
43 #define GUESTDEV_OPT_IOMUL 0x1
45 struct guestdev {
46 int flags;
47 int options;
48 struct list_head root_list;
49 union {
50 struct devicepath {
51 char hid[HID_LEN + 1];
52 char uid[UID_LEN + 1];
53 int seg;
54 int bbn;
55 struct devicepath_node *child;
56 } devicepath;
57 struct sbdf {
58 int seg;
59 int bus;
60 int dev;
61 int func;
62 } sbdf;
63 } u;
64 };
66 struct devicepath_node {
67 int dev;
68 int func;
69 struct devicepath_node *child;
70 };
72 struct pcidev_sbdf {
73 int seg;
74 int bus;
75 struct pcidev_sbdf_node *child;
76 };
78 struct pcidev_sbdf_node {
79 int dev;
80 int func;
81 struct pcidev_sbdf_node *child;
82 };
84 static int reassign_resources = 0;
86 static char guestdev_param[COMMAND_LINE_SIZE];
87 LIST_HEAD(guestdev_list);
89 /* Get hid and uid */
90 static int __init pci_get_hid_uid(char *str, char *hid, char *uid)
91 {
92 char *sp, *ep;
93 int len;
95 sp = str;
96 ep = strchr(sp, ':');
97 if (!ep) {
98 ep = strchr(sp, '-');
99 if (!ep)
100 goto format_err_end;
101 }
102 /* hid length */
103 len = ep - sp;
104 if (len <= 0 || HID_LEN < len)
105 goto format_err_end;
107 strncpy(hid, sp, len);
108 hid[len] = '\0';
110 if (*ep == '-') { /* no uid */
111 uid[0] = '\0';
112 return TRUE;
113 }
115 sp = ep + 1;
116 ep = strchr(sp, '-');
117 if (!ep)
118 ep = strchr(sp, '\0');
120 /* uid length */
121 len = ep - sp;
122 if (len <= 0 || UID_LEN < len)
123 goto format_err_end;
125 strncpy(uid, sp, len);
126 uid[len] = '\0';
127 return TRUE;
129 format_err_end:
130 return FALSE;
131 }
133 /* Get device and function */
134 static int __init pci_get_dev_func(char *str, int *dev, int *func)
135 {
136 if (sscanf(str, "%02x.%01x", dev, func) != 2)
137 goto format_err_end;
139 if (*dev < 0 || DEV_NUM_MAX < *dev)
140 goto format_err_end;
142 if (*func < 0 || FUNC_NUM_MAX < *func)
143 goto format_err_end;
145 return TRUE;
147 format_err_end:
148 return FALSE;
149 }
151 /* Check extended guestdev parameter format error */
152 static int __init pci_check_extended_guestdev_format(char *str)
153 {
154 int flg;
155 char *p;
157 /* Check extended format */
158 if (strpbrk(str, "(|)") == NULL)
159 return TRUE;
161 flg = 0;
162 p = str;
163 while (*p) {
164 switch (*p) {
165 case '(':
166 /* Check nesting error */
167 if (flg != 0)
168 goto format_err_end;
169 flg = 1;
170 /* Check position of '(' is head or
171 previos charactor of '(' is not '-'. */
172 if (p == str || *(p - 1) != '-')
173 goto format_err_end;
174 break;
175 case ')':
176 /* Check nesting error */
177 if (flg != 1)
178 goto format_err_end;
179 flg = 0;
180 /* Check next charactor of ')' is not '\0' */
181 if (*(p + 1) != '\0')
182 goto format_err_end;
183 break;
184 case '|':
185 /* Check position of '|' is outside of '(' and ')' */
186 if (flg != 1)
187 goto format_err_end;
188 break;
189 default:
190 break;
191 }
192 p++;
193 }
194 /* Check number of '(' and ')' are not equal */
195 if (flg != 0)
196 goto format_err_end;
197 return TRUE;
199 format_err_end:
200 printk(KERN_ERR
201 "PCI: The format of the guestdev parameter is illegal. [%s]\n",
202 str);
203 return FALSE;
204 }
206 /* Make guestdev strings */
207 static void pci_make_guestdev_str(struct guestdev *gdev,
208 char *gdev_str, int buf_size)
209 {
210 struct devicepath_node *node;
211 int count;
213 switch (gdev->flags & GUESTDEV_FLAG_TYPE_MASK) {
214 case GUESTDEV_FLAG_DEVICEPATH:
215 memset(gdev_str, 0, buf_size);
217 if (strlen(gdev->u.devicepath.uid))
218 count = snprintf(gdev_str, buf_size, "%s:%s",
219 gdev->u.devicepath.hid,
220 gdev->u.devicepath.uid);
221 else
222 count = snprintf(gdev_str, buf_size, "%s",
223 gdev->u.devicepath.hid);
224 if (count < 0)
225 return;
227 node = gdev->u.devicepath.child;
228 while (node) {
229 gdev_str += count;
230 buf_size -= count;
231 if (buf_size <= 0)
232 return;
233 count = snprintf(gdev_str, buf_size, "-%02x.%01x",
234 node->dev, node->func);
235 if (count < 0)
236 return;
237 node = node->child;
238 }
239 break;
240 case GUESTDEV_FLAG_SBDF:
241 snprintf(gdev_str, buf_size, "%04x:%02x:%02x.%01x",
242 gdev->u.sbdf.seg, gdev->u.sbdf.bus,
243 gdev->u.sbdf.dev, gdev->u.sbdf.func);
244 break;
245 default:
246 BUG();
247 }
248 }
250 /* Free guestdev and nodes */
251 static void __init pci_free_guestdev(struct guestdev *gdev)
252 {
253 struct devicepath_node *node, *next;
255 if (!gdev)
256 return;
257 if (gdev->flags & GUESTDEV_FLAG_DEVICEPATH) {
258 node = gdev->u.devicepath.child;
259 while (node) {
260 next = node->child;
261 kfree(node);
262 node = next;
263 }
264 }
265 list_del(&gdev->root_list);
266 kfree(gdev);
267 }
269 /* Copy guestdev and nodes */
270 struct guestdev __init *pci_copy_guestdev(struct guestdev *gdev_src)
271 {
272 struct guestdev *gdev;
273 struct devicepath_node *node, *node_src, *node_upper;
275 BUG_ON(!(gdev_src->flags & GUESTDEV_FLAG_DEVICEPATH));
277 gdev = kmalloc(sizeof(*gdev), GFP_KERNEL);
278 if (!gdev)
279 goto allocate_err_end;
281 memset(gdev, 0, sizeof(*gdev));
282 INIT_LIST_HEAD(&gdev->root_list);
283 gdev->flags = gdev_src->flags;
284 gdev->options = gdev_src->options;
285 strcpy(gdev->u.devicepath.hid, gdev_src->u.devicepath.hid);
286 strcpy(gdev->u.devicepath.uid, gdev_src->u.devicepath.uid);
287 gdev->u.devicepath.seg = gdev_src->u.devicepath.seg;
288 gdev->u.devicepath.bbn = gdev_src->u.devicepath.bbn;
290 node_upper = NULL;
292 node_src = gdev_src->u.devicepath.child;
293 while (node_src) {
294 node = kmalloc(sizeof(*node), GFP_KERNEL);
295 if (!node)
296 goto allocate_err_end;
297 memset(node, 0, sizeof(*node));
298 node->dev = node_src->dev;
299 node->func = node_src->func;
300 if (!node_upper)
301 gdev->u.devicepath.child = node;
302 else
303 node_upper->child = node;
304 node_upper = node;
305 node_src = node_src->child;
306 }
308 return gdev;
310 allocate_err_end:
311 if (gdev)
312 pci_free_guestdev(gdev);
313 printk(KERN_ERR "PCI: Failed to allocate memory.\n");
314 return NULL;
315 }
317 /* Make guestdev from path strings */
318 static int __init pci_make_devicepath_guestdev(char *path_str, int options)
319 {
320 char hid[HID_LEN + 1], uid[UID_LEN + 1];
321 char *sp, *ep;
322 struct guestdev *gdev, *gdev_org;
323 struct devicepath_node *node, *node_tmp;
324 int dev, func, ret_val;
326 ret_val = 0;
327 gdev = gdev_org = NULL;
328 sp = path_str;
329 /* Look for end of hid:uid'-' */
330 ep = strchr(sp, '-');
331 /* Only hid, uid. (No dev, func) */
332 if (!ep)
333 goto format_err_end;
335 memset(hid, 0 ,sizeof(hid));
336 memset(uid, 0, sizeof(uid));
337 if (!pci_get_hid_uid(sp, hid, uid))
338 goto format_err_end;
340 gdev_org = kmalloc(sizeof(*gdev_org), GFP_KERNEL);
341 if (!gdev_org)
342 goto allocate_err_end;
343 memset(gdev_org, 0, sizeof(*gdev_org));
344 INIT_LIST_HEAD(&gdev_org->root_list);
345 gdev_org->flags = GUESTDEV_FLAG_DEVICEPATH;
346 gdev_org->options = options;
347 strcpy(gdev_org->u.devicepath.hid, hid);
348 strcpy(gdev_org->u.devicepath.uid, uid);
349 gdev_org->u.devicepath.seg = INVALID_SEG;
350 gdev_org->u.devicepath.bbn = INVALID_BBN;
352 gdev = gdev_org;
354 sp = ep + 1;
355 ep = sp;
356 do {
357 if (*sp == '(') {
358 sp++;
359 if (strchr(sp, '|')) {
360 gdev = pci_copy_guestdev(gdev_org);
361 if (!gdev) {
362 ret_val = -ENOMEM;
363 goto end;
364 }
365 }
366 continue;
367 }
368 if (gdev && pci_get_dev_func(sp, &dev, &func)) {
369 node = kmalloc(sizeof(*node), GFP_KERNEL);
370 if (!node)
371 goto allocate_err_end;
372 memset(node, 0, sizeof(*node));
373 node->dev = dev;
374 node->func = func;
375 /* add node to end of guestdev */
376 if (gdev->u.devicepath.child) {
377 node_tmp = gdev->u.devicepath.child;
378 while (node_tmp->child) {
379 node_tmp = node_tmp->child;
380 }
381 node_tmp->child = node;
382 } else
383 gdev->u.devicepath.child = node;
384 } else if (gdev) {
385 printk(KERN_ERR
386 "PCI: Can't obtain dev# and #func# from %s.\n",
387 sp);
388 ret_val = -EINVAL;
389 if (gdev == gdev_org)
390 goto end;
391 pci_free_guestdev(gdev);
392 gdev = NULL;
393 }
395 ep = strpbrk(sp, "-|)");
396 if (!ep)
397 ep = strchr(sp, '\0');
398 /* Is *ep '|' OR ')' OR '\0' ? */
399 if (*ep != '-') {
400 if (gdev)
401 list_add_tail(&gdev->root_list, &guestdev_list);
402 if (*ep == '|') {
403 /* Between '|' and '|' ? */
404 if (strchr(ep + 1, '|')) {
405 gdev = pci_copy_guestdev(gdev_org);
406 if (!gdev) {
407 ret_val = -ENOMEM;
408 goto end;
409 }
410 } else {
411 gdev = gdev_org;
412 gdev_org = NULL;
413 }
414 } else {
415 gdev_org = NULL;
416 gdev = NULL;
417 }
418 }
419 if (*ep == ')')
420 ep++;
421 sp = ep + 1;
422 } while (*ep != '\0');
424 goto end;
426 format_err_end:
427 printk(KERN_ERR
428 "PCI: The format of the guestdev parameter is illegal. [%s]\n",
429 path_str);
430 ret_val = -EINVAL;
431 goto end;
433 allocate_err_end:
434 printk(KERN_ERR "PCI: Failed to allocate memory.\n");
435 ret_val = -ENOMEM;
436 goto end;
438 end:
439 if (gdev_org && (gdev_org != gdev))
440 pci_free_guestdev(gdev_org);
441 if (gdev)
442 pci_free_guestdev(gdev);
443 return ret_val;
444 }
446 static int __init pci_make_sbdf_guestdev(char* str, int options)
447 {
448 struct guestdev *gdev;
449 int seg, bus, dev, func;
451 if (sscanf(str, "%x:%x:%x.%x", &seg, &bus, &dev, &func) != 4) {
452 seg = 0;
453 if (sscanf(str, "%x:%x.%x", &bus, &dev, &func) != 3)
454 return -EINVAL;
455 }
456 gdev = kmalloc(sizeof(*gdev), GFP_KERNEL);
457 if (!gdev) {
458 printk(KERN_ERR "PCI: Failed to allocate memory.\n");
459 return -ENOMEM;
460 }
461 INIT_LIST_HEAD(&gdev->root_list);
462 gdev->flags = GUESTDEV_FLAG_SBDF;
463 gdev->options = options;
464 gdev->u.sbdf.seg = seg;
465 gdev->u.sbdf.bus = bus;
466 gdev->u.sbdf.dev = dev;
467 gdev->u.sbdf.func = func;
468 list_add_tail(&gdev->root_list, &guestdev_list);
469 return 0;
470 }
472 static int __init pci_parse_options(const char *str)
473 {
474 int options = 0;
475 char *ep;
477 while (str) {
478 str++;
479 ep = strchr(str, '+');
480 if (ep)
481 ep = '\0'; /* Chop */
483 if (!strcmp(str, "iomul"))
484 options |= GUESTDEV_OPT_IOMUL;
486 str = ep;
487 }
488 return options;
489 }
491 /* Parse guestdev parameter */
492 static int __init pci_parse_guestdev(void)
493 {
494 int len;
495 char *sp, *ep, *op;
496 int options;
497 struct list_head *head;
498 struct guestdev *gdev;
499 char path_str[GUESTDEV_STR_MAX];
500 int ret_val = 0;
502 len = strlen(guestdev_param);
503 if (len == 0)
504 return 0;
506 sp = guestdev_param;
508 do {
509 ep = strchr(sp, ',');
510 /* Chop */
511 if (ep)
512 *ep = '\0';
513 options = 0;
514 op = strchr(sp, '+');
515 if (op && (!ep || op < ep)) {
516 options = pci_parse_options(op);
517 *op = '\0'; /* Chop */
518 }
519 ret_val = pci_make_sbdf_guestdev(sp, options);
520 if (ret_val == -EINVAL) {
521 if (pci_check_extended_guestdev_format(sp)) {
522 ret_val = pci_make_devicepath_guestdev(
523 sp, options);
524 if (ret_val && ret_val != -EINVAL)
525 break;
526 }
527 } else if (ret_val)
528 break;
530 if (ep)
531 ep++;
532 sp = ep;
533 } while (ep);
535 list_for_each(head, &guestdev_list) {
536 gdev = list_entry(head, struct guestdev, root_list);
537 pci_make_guestdev_str(gdev, path_str, GUESTDEV_STR_MAX);
538 printk(KERN_DEBUG
539 "PCI: %s has been reserved for guest domain.\n",
540 path_str);
541 }
542 return 0;
543 }
545 arch_initcall(pci_parse_guestdev);
547 /* Get command line */
548 static int __init pci_guestdev_setup(char *str)
549 {
550 if (strlen(str) >= COMMAND_LINE_SIZE)
551 return 0;
552 strcpy(guestdev_param, str);
553 return 1;
554 }
556 __setup("guestdev=", pci_guestdev_setup);
558 /* Free sbdf and nodes */
559 static void pci_free_sbdf(struct pcidev_sbdf *sbdf)
560 {
561 struct pcidev_sbdf_node *node, *next;
563 node = sbdf->child;
564 while (node) {
565 next = node->child;
566 kfree(node);
567 node = next;
568 }
569 /* Skip kfree(sbdf) */
570 }
572 /* Does PCI device belong to sub tree specified by guestdev with device path? */
573 typedef int (*pci_node_match_t)(const struct devicepath_node *gdev_node,
574 const struct pcidev_sbdf_node *sbdf_node,
575 int options);
577 static int pci_node_match(const struct devicepath_node *gdev_node,
578 const struct pcidev_sbdf_node *sbdf_node,
579 int options_unused)
580 {
581 return (gdev_node->dev == sbdf_node->dev &&
582 gdev_node->func == sbdf_node->func);
583 }
585 static int pci_is_in_devicepath_sub_tree(struct guestdev *gdev,
586 struct pcidev_sbdf *sbdf,
587 pci_node_match_t match)
588 {
589 int seg, bbn;
590 struct devicepath_node *gdev_node;
591 struct pcidev_sbdf_node *sbdf_node;
593 if (!gdev || !sbdf)
594 return FALSE;
596 BUG_ON(!(gdev->flags & GUESTDEV_FLAG_DEVICEPATH));
598 /* Compare seg and bbn */
599 if (gdev->u.devicepath.seg == INVALID_SEG ||
600 gdev->u.devicepath.bbn == INVALID_BBN) {
601 if (acpi_pci_get_root_seg_bbn(gdev->u.devicepath.hid,
602 gdev->u.devicepath.uid, &seg, &bbn)) {
603 gdev->u.devicepath.seg = seg;
604 gdev->u.devicepath.bbn = bbn;
605 } else
606 return FALSE;
607 }
609 if (gdev->u.devicepath.seg != sbdf->seg ||
610 gdev->u.devicepath.bbn != sbdf->bus)
611 return FALSE;
613 gdev_node = gdev->u.devicepath.child;
614 sbdf_node = sbdf->child;
616 /* Compare dev and func */
617 while (gdev_node) {
618 if (!sbdf_node)
619 return FALSE;
620 if (!match(gdev_node, sbdf_node, gdev->options))
621 return FALSE;
622 gdev_node = gdev_node->child;
623 sbdf_node = sbdf_node->child;
624 }
625 return TRUE;
626 }
628 /* Get sbdf from device */
629 static int pci_get_sbdf_from_pcidev(
630 struct pci_dev *dev, struct pcidev_sbdf *sbdf)
631 {
632 struct pcidev_sbdf_node *node;
634 if (!dev)
635 return FALSE;
637 for(;;) {
638 node = kmalloc(sizeof(*node), GFP_KERNEL);
639 if (!node) {
640 printk(KERN_ERR "PCI: Failed to allocate memory.\n");
641 goto err_end;
642 }
643 memset(node, 0, sizeof(*node));
644 node->dev = PCI_SLOT(dev->devfn);
645 node->func = PCI_FUNC(dev->devfn);
647 if (!sbdf->child)
648 sbdf->child = node;
649 else {
650 node->child = sbdf->child;
651 sbdf->child = node;
652 }
653 if (!dev->bus)
654 goto err_end;
655 if (!dev->bus->self)
656 break;
657 dev = dev->bus->self;
658 }
659 if (sscanf(dev->dev.bus_id, "%04x:%02x", &sbdf->seg, &sbdf->bus) != 2)
660 goto err_end;
661 return TRUE;
663 err_end:
664 pci_free_sbdf(sbdf);
665 return FALSE;
666 }
668 /* Does PCI device belong to sub tree specified by guestdev with sbdf? */
669 typedef int (*pci_sbdf_match_t)(const struct guestdev *gdev,
670 const struct pci_dev *dev);
672 static int pci_sbdf_match(const struct guestdev *gdev,
673 const struct pci_dev *dev)
674 {
675 int seg, bus;
677 if (sscanf(dev->dev.bus_id, "%04x:%02x", &seg, &bus) != 2)
678 return FALSE;
680 return gdev->u.sbdf.seg == seg &&
681 gdev->u.sbdf.bus == bus &&
682 gdev->u.sbdf.dev == PCI_SLOT(dev->devfn) &&
683 gdev->u.sbdf.func == PCI_FUNC(dev->devfn);
684 }
686 static int pci_is_in_sbdf_sub_tree(struct guestdev *gdev, struct pci_dev *dev,
687 pci_sbdf_match_t match)
688 {
689 BUG_ON(!(gdev->flags & GUESTDEV_FLAG_SBDF));
690 for (;;) {
691 if (match(gdev, dev))
692 return TRUE;
693 if (!dev->bus || !dev->bus->self)
694 break;
695 dev = dev->bus->self;
696 }
697 return FALSE;
698 }
700 /* Does PCI device belong to sub tree specified by guestdev parameter? */
701 static int __pci_is_guestdev(struct pci_dev *dev, pci_node_match_t node_match,
702 pci_sbdf_match_t sbdf_match)
703 {
704 struct guestdev *gdev;
705 struct pcidev_sbdf pcidev_sbdf, *sbdf = NULL;
706 struct list_head *head;
707 int result = FALSE;
709 if (!dev)
710 return FALSE;
712 list_for_each(head, &guestdev_list) {
713 gdev = list_entry(head, struct guestdev, root_list);
714 switch (gdev->flags & GUESTDEV_FLAG_TYPE_MASK) {
715 case GUESTDEV_FLAG_DEVICEPATH:
716 if (sbdf == NULL) {
717 sbdf = &pcidev_sbdf;
718 memset(sbdf, 0 ,sizeof(*sbdf));
719 if (!pci_get_sbdf_from_pcidev(dev, sbdf))
720 goto out;
721 }
722 if (pci_is_in_devicepath_sub_tree(gdev, sbdf,
723 node_match)) {
724 result = TRUE;
725 goto out;
726 }
727 break;
728 case GUESTDEV_FLAG_SBDF:
729 if (pci_is_in_sbdf_sub_tree(gdev, dev, sbdf_match)) {
730 result = TRUE;
731 goto out;
732 }
733 break;
734 default:
735 BUG();
736 }
737 }
738 out:
739 if (sbdf)
740 pci_free_sbdf(sbdf);
741 return result;
742 }
744 int pci_is_guestdev(struct pci_dev *dev)
745 {
746 return __pci_is_guestdev(dev, pci_node_match, pci_sbdf_match);
747 }
748 EXPORT_SYMBOL(pci_is_guestdev);
750 static int __init pci_set_reassign_resources(char *str)
751 {
752 reassign_resources = 1;
754 return 1;
755 }
757 __setup("reassign_resources", pci_set_reassign_resources);
759 int pci_is_reassigndev(struct pci_dev *dev)
760 {
761 if (reassign_resources)
762 return pci_is_guestdev(dev);
763 return FALSE;
764 }
765 EXPORT_SYMBOL(pci_is_reassigndev);
767 #ifdef CONFIG_PCI_IOMULTI
768 static int pci_iomul_node_match(const struct devicepath_node *gdev_node,
769 const struct pcidev_sbdf_node *sbdf_node,
770 int options)
771 {
772 return (options & GUESTDEV_OPT_IOMUL) &&
773 ((gdev_node->child != NULL &&
774 sbdf_node->child != NULL &&
775 gdev_node->dev == sbdf_node->dev &&
776 gdev_node->func == sbdf_node->func) ||
777 (gdev_node->child == NULL &&
778 sbdf_node->child == NULL &&
779 gdev_node->dev == sbdf_node->dev));
780 }
782 static int pci_iomul_sbdf_match(const struct guestdev *gdev,
783 const struct pci_dev *dev)
784 {
785 int seg, bus;
787 if (sscanf(dev->dev.bus_id, "%04x:%02x", &seg, &bus) != 2)
788 return FALSE;
790 return (gdev->options & GUESTDEV_OPT_IOMUL) &&
791 gdev->u.sbdf.seg == seg &&
792 gdev->u.sbdf.bus == bus &&
793 gdev->u.sbdf.dev == PCI_SLOT(dev->devfn);
794 }
796 int pci_is_iomuldev(struct pci_dev *dev)
797 {
798 return __pci_is_guestdev(dev,
799 pci_iomul_node_match, pci_iomul_sbdf_match);
800 }
801 EXPORT_SYMBOL_GPL(pci_is_iomuldev);
802 #endif /* CONFIG_PCI_IOMULTI */
804 /* Check whether the devicepath exists under the pci root bus */
805 static int __init pci_check_devicepath_exists(
806 struct guestdev *gdev, struct pci_bus *bus)
807 {
808 struct devicepath_node *node;
809 struct pci_dev *dev;
811 BUG_ON(!(gdev->flags & GUESTDEV_FLAG_DEVICEPATH));
813 node = gdev->u.devicepath.child;
814 while (node) {
815 if (!bus)
816 return FALSE;
817 dev = pci_get_slot(bus, PCI_DEVFN(node->dev, node->func));
818 if (!dev)
819 return FALSE;
820 bus = dev->subordinate;
821 node = node->child;
822 pci_dev_put(dev);
823 }
824 return TRUE;
825 }
827 /* Check whether the guestdev exists in the PCI device tree */
828 static int __init pci_check_guestdev_exists(void)
829 {
830 struct list_head *head;
831 struct guestdev *gdev;
832 int seg, bbn;
833 struct pci_bus *bus;
834 struct pci_dev *dev;
835 char path_str[GUESTDEV_STR_MAX];
837 list_for_each(head, &guestdev_list) {
838 gdev = list_entry(head, struct guestdev, root_list);
839 switch (gdev->flags & GUESTDEV_FLAG_TYPE_MASK) {
840 case GUESTDEV_FLAG_DEVICEPATH:
841 if (gdev->u.devicepath.seg == INVALID_SEG ||
842 gdev->u.devicepath.bbn == INVALID_BBN) {
843 if (acpi_pci_get_root_seg_bbn(
844 gdev->u.devicepath.hid,
845 gdev->u.devicepath.uid, &seg, &bbn)) {
846 gdev->u.devicepath.seg = seg;
847 gdev->u.devicepath.bbn = bbn;
848 } else {
849 pci_make_guestdev_str(gdev,
850 path_str, GUESTDEV_STR_MAX);
851 printk(KERN_INFO
852 "PCI: Device does not exist. %s\n",
853 path_str);
854 continue;
855 }
856 }
858 bus = pci_find_bus(gdev->u.devicepath.seg,
859 gdev->u.devicepath.bbn);
860 if (!bus ||
861 !pci_check_devicepath_exists(gdev, bus)) {
862 pci_make_guestdev_str(gdev, path_str,
863 GUESTDEV_STR_MAX);
864 printk(KERN_INFO
865 "PCI: Device does not exist. %s\n",
866 path_str);
867 }
868 break;
869 case GUESTDEV_FLAG_SBDF:
870 bus = pci_find_bus(gdev->u.sbdf.seg, gdev->u.sbdf.bus);
871 if (bus) {
872 dev = pci_get_slot(bus,
873 PCI_DEVFN(gdev->u.sbdf.dev,
874 gdev->u.sbdf.func));
875 if (dev) {
876 pci_dev_put(dev);
877 continue;
878 }
879 }
880 pci_make_guestdev_str(gdev, path_str, GUESTDEV_STR_MAX);
881 printk(KERN_INFO "PCI: Device does not exist. %s\n",
882 path_str);
883 break;
884 default:
885 BUG();
886 }
887 }
888 return 0;
889 }
891 fs_initcall(pci_check_guestdev_exists);