ia64/linux-2.6.18-xen.hg

view drivers/pci/guestdev.c @ 897:329ea0ccb344

balloon: try harder to balloon up under memory pressure.

Currently if the balloon driver is unable to increase the guest's
reservation it assumes the failure was due to reaching its full
allocation, gives up on the ballooning operation and records the limit
it reached as the "hard limit". The driver will not try again until
the target is set again (even to the same value).

However it is possible that ballooning has in fact failed due to
memory pressure in the host and therefore it is desirable to keep
attempting to reach the target in case memory becomes available. The
most likely scenario is that some guests are ballooning down while
others are ballooning up and therefore there is temporary memory
pressure while things stabilise. You would not expect a well behaved
toolstack to ask a domain to balloon to more than its allocation nor
would you expect it to deliberately over-commit memory by setting
balloon targets which exceed the total host memory.

This patch drops the concept of a hard limit and causes the balloon
driver to retry increasing the reservation on a timer in the same
manner as when decreasing the reservation.

Also if we partially succeed in increasing the reservation
(i.e. receive less pages than we asked for) then we may as well keep
those pages rather than returning them to Xen.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Fri Jun 05 14:01:20 2009 +0100 (2009-06-05)
parents 20be7f6d414a
children
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 strlcpy(hid, sp, len);
109 if (*ep == '-') { /* no uid */
110 uid[0] = '\0';
111 return TRUE;
112 }
114 sp = ep + 1;
115 ep = strchr(sp, '-');
116 if (!ep)
117 ep = strchr(sp, '\0');
119 /* uid length */
120 len = ep - sp;
121 if (len <= 0 || UID_LEN < len)
122 goto format_err_end;
124 strlcpy(uid, sp, len);
125 return TRUE;
127 format_err_end:
128 return FALSE;
129 }
131 /* Get device and function */
132 static int __init pci_get_dev_func(char *str, int *dev, int *func)
133 {
134 if (sscanf(str, "%02x.%01x", dev, func) != 2)
135 goto format_err_end;
137 if (*dev < 0 || DEV_NUM_MAX < *dev)
138 goto format_err_end;
140 if (*func < 0 || FUNC_NUM_MAX < *func)
141 goto format_err_end;
143 return TRUE;
145 format_err_end:
146 return FALSE;
147 }
149 /* Check extended guestdev parameter format error */
150 static int __init pci_check_extended_guestdev_format(char *str)
151 {
152 int flg;
153 char *p;
155 /* Check extended format */
156 if (strpbrk(str, "(|)") == NULL)
157 return TRUE;
159 flg = 0;
160 p = str;
161 while (*p) {
162 switch (*p) {
163 case '(':
164 /* Check nesting error */
165 if (flg != 0)
166 goto format_err_end;
167 flg = 1;
168 /* Check position of '(' is head or
169 previos charactor of '(' is not '-'. */
170 if (p == str || *(p - 1) != '-')
171 goto format_err_end;
172 break;
173 case ')':
174 /* Check nesting error */
175 if (flg != 1)
176 goto format_err_end;
177 flg = 0;
178 /* Check next charactor of ')' is not '\0' */
179 if (*(p + 1) != '\0')
180 goto format_err_end;
181 break;
182 case '|':
183 /* Check position of '|' is outside of '(' and ')' */
184 if (flg != 1)
185 goto format_err_end;
186 break;
187 default:
188 break;
189 }
190 p++;
191 }
192 /* Check number of '(' and ')' are not equal */
193 if (flg != 0)
194 goto format_err_end;
195 return TRUE;
197 format_err_end:
198 printk(KERN_ERR
199 "PCI: The format of the guestdev parameter is illegal. [%s]\n",
200 str);
201 return FALSE;
202 }
204 /* Make guestdev strings */
205 static void pci_make_guestdev_str(struct guestdev *gdev,
206 char *gdev_str, int buf_size)
207 {
208 struct devicepath_node *node;
209 int count;
211 switch (gdev->flags & GUESTDEV_FLAG_TYPE_MASK) {
212 case GUESTDEV_FLAG_DEVICEPATH:
213 memset(gdev_str, 0, buf_size);
215 if (strlen(gdev->u.devicepath.uid))
216 count = snprintf(gdev_str, buf_size, "%s:%s",
217 gdev->u.devicepath.hid,
218 gdev->u.devicepath.uid);
219 else
220 count = snprintf(gdev_str, buf_size, "%s",
221 gdev->u.devicepath.hid);
222 if (count < 0)
223 return;
225 node = gdev->u.devicepath.child;
226 while (node) {
227 gdev_str += count;
228 buf_size -= count;
229 if (buf_size <= 0)
230 return;
231 count = snprintf(gdev_str, buf_size, "-%02x.%01x",
232 node->dev, node->func);
233 if (count < 0)
234 return;
235 node = node->child;
236 }
237 break;
238 case GUESTDEV_FLAG_SBDF:
239 snprintf(gdev_str, buf_size, "%04x:%02x:%02x.%01x",
240 gdev->u.sbdf.seg, gdev->u.sbdf.bus,
241 gdev->u.sbdf.dev, gdev->u.sbdf.func);
242 break;
243 default:
244 BUG();
245 }
246 }
248 /* Free guestdev and nodes */
249 static void __init pci_free_guestdev(struct guestdev *gdev)
250 {
251 struct devicepath_node *node, *next;
253 if (!gdev)
254 return;
255 if (gdev->flags & GUESTDEV_FLAG_DEVICEPATH) {
256 node = gdev->u.devicepath.child;
257 while (node) {
258 next = node->child;
259 kfree(node);
260 node = next;
261 }
262 }
263 list_del(&gdev->root_list);
264 kfree(gdev);
265 }
267 /* Copy guestdev and nodes */
268 struct guestdev __init *pci_copy_guestdev(struct guestdev *gdev_src)
269 {
270 struct guestdev *gdev;
271 struct devicepath_node *node, *node_src, *node_upper;
273 BUG_ON(!(gdev_src->flags & GUESTDEV_FLAG_DEVICEPATH));
275 gdev = kmalloc(sizeof(*gdev), GFP_KERNEL);
276 if (!gdev)
277 goto allocate_err_end;
279 memset(gdev, 0, sizeof(*gdev));
280 INIT_LIST_HEAD(&gdev->root_list);
281 gdev->flags = gdev_src->flags;
282 gdev->options = gdev_src->options;
283 strcpy(gdev->u.devicepath.hid, gdev_src->u.devicepath.hid);
284 strcpy(gdev->u.devicepath.uid, gdev_src->u.devicepath.uid);
285 gdev->u.devicepath.seg = gdev_src->u.devicepath.seg;
286 gdev->u.devicepath.bbn = gdev_src->u.devicepath.bbn;
288 node_upper = NULL;
290 node_src = gdev_src->u.devicepath.child;
291 while (node_src) {
292 node = kmalloc(sizeof(*node), GFP_KERNEL);
293 if (!node)
294 goto allocate_err_end;
295 memset(node, 0, sizeof(*node));
296 node->dev = node_src->dev;
297 node->func = node_src->func;
298 if (!node_upper)
299 gdev->u.devicepath.child = node;
300 else
301 node_upper->child = node;
302 node_upper = node;
303 node_src = node_src->child;
304 }
306 return gdev;
308 allocate_err_end:
309 if (gdev)
310 pci_free_guestdev(gdev);
311 printk(KERN_ERR "PCI: Failed to allocate memory.\n");
312 return NULL;
313 }
315 /* Make guestdev from path strings */
316 static int __init pci_make_devicepath_guestdev(char *path_str, int options)
317 {
318 char hid[HID_LEN + 1], uid[UID_LEN + 1];
319 char *sp, *ep;
320 struct guestdev *gdev, *gdev_org;
321 struct devicepath_node *node, *node_tmp;
322 int dev, func, ret_val;
324 ret_val = 0;
325 gdev = gdev_org = NULL;
326 sp = path_str;
327 /* Look for end of hid:uid'-' */
328 ep = strchr(sp, '-');
329 /* Only hid, uid. (No dev, func) */
330 if (!ep)
331 goto format_err_end;
333 memset(hid, 0 ,sizeof(hid));
334 memset(uid, 0, sizeof(uid));
335 if (!pci_get_hid_uid(sp, hid, uid))
336 goto format_err_end;
338 gdev_org = kmalloc(sizeof(*gdev_org), GFP_KERNEL);
339 if (!gdev_org)
340 goto allocate_err_end;
341 memset(gdev_org, 0, sizeof(*gdev_org));
342 INIT_LIST_HEAD(&gdev_org->root_list);
343 gdev_org->flags = GUESTDEV_FLAG_DEVICEPATH;
344 gdev_org->options = options;
345 strcpy(gdev_org->u.devicepath.hid, hid);
346 strcpy(gdev_org->u.devicepath.uid, uid);
347 gdev_org->u.devicepath.seg = INVALID_SEG;
348 gdev_org->u.devicepath.bbn = INVALID_BBN;
350 gdev = gdev_org;
352 sp = ep + 1;
353 ep = sp;
354 do {
355 if (*sp == '(') {
356 sp++;
357 if (strchr(sp, '|')) {
358 gdev = pci_copy_guestdev(gdev_org);
359 if (!gdev) {
360 ret_val = -ENOMEM;
361 goto end;
362 }
363 }
364 continue;
365 }
366 if (gdev && pci_get_dev_func(sp, &dev, &func)) {
367 node = kmalloc(sizeof(*node), GFP_KERNEL);
368 if (!node)
369 goto allocate_err_end;
370 memset(node, 0, sizeof(*node));
371 node->dev = dev;
372 node->func = func;
373 /* add node to end of guestdev */
374 if (gdev->u.devicepath.child) {
375 node_tmp = gdev->u.devicepath.child;
376 while (node_tmp->child) {
377 node_tmp = node_tmp->child;
378 }
379 node_tmp->child = node;
380 } else
381 gdev->u.devicepath.child = node;
382 } else if (gdev) {
383 printk(KERN_ERR
384 "PCI: Can't obtain dev# and #func# from %s.\n",
385 sp);
386 ret_val = -EINVAL;
387 if (gdev == gdev_org)
388 goto end;
389 pci_free_guestdev(gdev);
390 gdev = NULL;
391 }
393 ep = strpbrk(sp, "-|)");
394 if (!ep)
395 ep = strchr(sp, '\0');
396 /* Is *ep '|' OR ')' OR '\0' ? */
397 if (*ep != '-') {
398 if (gdev)
399 list_add_tail(&gdev->root_list, &guestdev_list);
400 if (*ep == '|') {
401 /* Between '|' and '|' ? */
402 if (strchr(ep + 1, '|')) {
403 gdev = pci_copy_guestdev(gdev_org);
404 if (!gdev) {
405 ret_val = -ENOMEM;
406 goto end;
407 }
408 } else {
409 gdev = gdev_org;
410 gdev_org = NULL;
411 }
412 } else {
413 gdev_org = NULL;
414 gdev = NULL;
415 }
416 }
417 if (*ep == ')')
418 ep++;
419 sp = ep + 1;
420 } while (*ep != '\0');
422 goto end;
424 format_err_end:
425 printk(KERN_ERR
426 "PCI: The format of the guestdev parameter is illegal. [%s]\n",
427 path_str);
428 ret_val = -EINVAL;
429 goto end;
431 allocate_err_end:
432 printk(KERN_ERR "PCI: Failed to allocate memory.\n");
433 ret_val = -ENOMEM;
434 goto end;
436 end:
437 if (gdev_org && (gdev_org != gdev))
438 pci_free_guestdev(gdev_org);
439 if (gdev)
440 pci_free_guestdev(gdev);
441 return ret_val;
442 }
444 static int __init pci_make_sbdf_guestdev(char* str, int options)
445 {
446 struct guestdev *gdev;
447 int seg, bus, dev, func;
449 if (sscanf(str, "%x:%x:%x.%x", &seg, &bus, &dev, &func) != 4) {
450 seg = 0;
451 if (sscanf(str, "%x:%x.%x", &bus, &dev, &func) != 3)
452 return -EINVAL;
453 }
454 gdev = kmalloc(sizeof(*gdev), GFP_KERNEL);
455 if (!gdev) {
456 printk(KERN_ERR "PCI: Failed to allocate memory.\n");
457 return -ENOMEM;
458 }
459 INIT_LIST_HEAD(&gdev->root_list);
460 gdev->flags = GUESTDEV_FLAG_SBDF;
461 gdev->options = options;
462 gdev->u.sbdf.seg = seg;
463 gdev->u.sbdf.bus = bus;
464 gdev->u.sbdf.dev = dev;
465 gdev->u.sbdf.func = func;
466 list_add_tail(&gdev->root_list, &guestdev_list);
467 return 0;
468 }
470 static int __init pci_parse_options(const char *str)
471 {
472 int options = 0;
473 char *ep;
475 while (str) {
476 str++;
477 ep = strchr(str, '+');
478 if (ep)
479 ep = '\0'; /* Chop */
481 if (!strcmp(str, "iomul"))
482 options |= GUESTDEV_OPT_IOMUL;
484 str = ep;
485 }
486 return options;
487 }
489 /* Parse guestdev parameter */
490 static int __init pci_parse_guestdev(void)
491 {
492 int len;
493 char *sp, *ep, *op;
494 int options;
495 struct list_head *head;
496 struct guestdev *gdev;
497 char path_str[GUESTDEV_STR_MAX];
498 int ret_val = 0;
500 len = strlen(guestdev_param);
501 if (len == 0)
502 return 0;
504 sp = guestdev_param;
506 do {
507 ep = strchr(sp, ',');
508 /* Chop */
509 if (ep)
510 *ep = '\0';
511 options = 0;
512 op = strchr(sp, '+');
513 if (op && (!ep || op < ep)) {
514 options = pci_parse_options(op);
515 *op = '\0'; /* Chop */
516 }
517 ret_val = pci_make_sbdf_guestdev(sp, options);
518 if (ret_val == -EINVAL) {
519 if (pci_check_extended_guestdev_format(sp)) {
520 ret_val = pci_make_devicepath_guestdev(
521 sp, options);
522 if (ret_val && ret_val != -EINVAL)
523 break;
524 }
525 } else if (ret_val)
526 break;
528 if (ep)
529 ep++;
530 sp = ep;
531 } while (ep);
533 list_for_each(head, &guestdev_list) {
534 gdev = list_entry(head, struct guestdev, root_list);
535 pci_make_guestdev_str(gdev, path_str, GUESTDEV_STR_MAX);
536 printk(KERN_DEBUG
537 "PCI: %s has been reserved for guest domain.\n",
538 path_str);
539 }
540 return 0;
541 }
543 arch_initcall(pci_parse_guestdev);
545 /* Get command line */
546 static int __init pci_guestdev_setup(char *str)
547 {
548 if (strlen(str) >= COMMAND_LINE_SIZE)
549 return 0;
550 strlcpy(guestdev_param, str, sizeof(guestdev_param));
551 return 1;
552 }
554 __setup("guestdev=", pci_guestdev_setup);
556 /* Free sbdf and nodes */
557 static void pci_free_sbdf(struct pcidev_sbdf *sbdf)
558 {
559 struct pcidev_sbdf_node *node, *next;
561 node = sbdf->child;
562 while (node) {
563 next = node->child;
564 kfree(node);
565 node = next;
566 }
567 /* Skip kfree(sbdf) */
568 }
570 /* Does PCI device belong to sub tree specified by guestdev with device path? */
571 typedef int (*pci_node_match_t)(const struct devicepath_node *gdev_node,
572 const struct pcidev_sbdf_node *sbdf_node,
573 int options);
575 static int pci_node_match(const struct devicepath_node *gdev_node,
576 const struct pcidev_sbdf_node *sbdf_node,
577 int options_unused)
578 {
579 return (gdev_node->dev == sbdf_node->dev &&
580 gdev_node->func == sbdf_node->func);
581 }
583 static int pci_is_in_devicepath_sub_tree(struct guestdev *gdev,
584 struct pcidev_sbdf *sbdf,
585 pci_node_match_t match)
586 {
587 int seg, bbn;
588 struct devicepath_node *gdev_node;
589 struct pcidev_sbdf_node *sbdf_node;
591 if (!gdev || !sbdf)
592 return FALSE;
594 BUG_ON(!(gdev->flags & GUESTDEV_FLAG_DEVICEPATH));
596 /* Compare seg and bbn */
597 if (gdev->u.devicepath.seg == INVALID_SEG ||
598 gdev->u.devicepath.bbn == INVALID_BBN) {
599 if (acpi_pci_get_root_seg_bbn(gdev->u.devicepath.hid,
600 gdev->u.devicepath.uid, &seg, &bbn)) {
601 gdev->u.devicepath.seg = seg;
602 gdev->u.devicepath.bbn = bbn;
603 } else
604 return FALSE;
605 }
607 if (gdev->u.devicepath.seg != sbdf->seg ||
608 gdev->u.devicepath.bbn != sbdf->bus)
609 return FALSE;
611 gdev_node = gdev->u.devicepath.child;
612 sbdf_node = sbdf->child;
614 /* Compare dev and func */
615 while (gdev_node) {
616 if (!sbdf_node)
617 return FALSE;
618 if (!match(gdev_node, sbdf_node, gdev->options))
619 return FALSE;
620 gdev_node = gdev_node->child;
621 sbdf_node = sbdf_node->child;
622 }
623 return TRUE;
624 }
626 /* Get sbdf from device */
627 static int pci_get_sbdf_from_pcidev(
628 struct pci_dev *dev, struct pcidev_sbdf *sbdf)
629 {
630 struct pcidev_sbdf_node *node;
632 if (!dev)
633 return FALSE;
635 for(;;) {
636 node = kmalloc(sizeof(*node), GFP_KERNEL);
637 if (!node) {
638 printk(KERN_ERR "PCI: Failed to allocate memory.\n");
639 goto err_end;
640 }
641 memset(node, 0, sizeof(*node));
642 node->dev = PCI_SLOT(dev->devfn);
643 node->func = PCI_FUNC(dev->devfn);
645 if (!sbdf->child)
646 sbdf->child = node;
647 else {
648 node->child = sbdf->child;
649 sbdf->child = node;
650 }
651 if (!dev->bus)
652 goto err_end;
653 if (!dev->bus->self)
654 break;
655 dev = dev->bus->self;
656 }
657 if (sscanf(dev->dev.bus_id, "%04x:%02x", &sbdf->seg, &sbdf->bus) != 2)
658 goto err_end;
659 return TRUE;
661 err_end:
662 pci_free_sbdf(sbdf);
663 return FALSE;
664 }
666 /* Does PCI device belong to sub tree specified by guestdev with sbdf? */
667 typedef int (*pci_sbdf_match_t)(const struct guestdev *gdev,
668 const struct pci_dev *dev);
670 static int pci_sbdf_match(const struct guestdev *gdev,
671 const struct pci_dev *dev)
672 {
673 int seg, bus;
675 if (sscanf(dev->dev.bus_id, "%04x:%02x", &seg, &bus) != 2)
676 return FALSE;
678 return gdev->u.sbdf.seg == seg &&
679 gdev->u.sbdf.bus == bus &&
680 gdev->u.sbdf.dev == PCI_SLOT(dev->devfn) &&
681 gdev->u.sbdf.func == PCI_FUNC(dev->devfn);
682 }
684 static int pci_is_in_sbdf_sub_tree(struct guestdev *gdev, struct pci_dev *dev,
685 pci_sbdf_match_t match)
686 {
687 BUG_ON(!(gdev->flags & GUESTDEV_FLAG_SBDF));
688 for (;;) {
689 if (match(gdev, dev))
690 return TRUE;
691 if (!dev->bus || !dev->bus->self)
692 break;
693 dev = dev->bus->self;
694 }
695 return FALSE;
696 }
698 /* Does PCI device belong to sub tree specified by guestdev parameter? */
699 static int __pci_is_guestdev(struct pci_dev *dev, pci_node_match_t node_match,
700 pci_sbdf_match_t sbdf_match)
701 {
702 struct guestdev *gdev;
703 struct pcidev_sbdf pcidev_sbdf, *sbdf = NULL;
704 struct list_head *head;
705 int result = FALSE;
707 if (!dev)
708 return FALSE;
710 list_for_each(head, &guestdev_list) {
711 gdev = list_entry(head, struct guestdev, root_list);
712 switch (gdev->flags & GUESTDEV_FLAG_TYPE_MASK) {
713 case GUESTDEV_FLAG_DEVICEPATH:
714 if (sbdf == NULL) {
715 sbdf = &pcidev_sbdf;
716 memset(sbdf, 0 ,sizeof(*sbdf));
717 if (!pci_get_sbdf_from_pcidev(dev, sbdf))
718 goto out;
719 }
720 if (pci_is_in_devicepath_sub_tree(gdev, sbdf,
721 node_match)) {
722 result = TRUE;
723 goto out;
724 }
725 break;
726 case GUESTDEV_FLAG_SBDF:
727 if (pci_is_in_sbdf_sub_tree(gdev, dev, sbdf_match)) {
728 result = TRUE;
729 goto out;
730 }
731 break;
732 default:
733 BUG();
734 }
735 }
736 out:
737 if (sbdf)
738 pci_free_sbdf(sbdf);
739 return result;
740 }
742 int pci_is_guestdev(struct pci_dev *dev)
743 {
744 return __pci_is_guestdev(dev, pci_node_match, pci_sbdf_match);
745 }
746 EXPORT_SYMBOL(pci_is_guestdev);
748 static int __init pci_set_reassign_resources(char *str)
749 {
750 reassign_resources = 1;
752 return 1;
753 }
755 __setup("reassign_resources", pci_set_reassign_resources);
757 int pci_is_reassigndev(struct pci_dev *dev)
758 {
759 if (reassign_resources)
760 return pci_is_guestdev(dev);
761 return FALSE;
762 }
763 EXPORT_SYMBOL(pci_is_reassigndev);
765 #ifdef CONFIG_PCI_IOMULTI
766 static int pci_iomul_node_match(const struct devicepath_node *gdev_node,
767 const struct pcidev_sbdf_node *sbdf_node,
768 int options)
769 {
770 return (options & GUESTDEV_OPT_IOMUL) &&
771 ((gdev_node->child != NULL &&
772 sbdf_node->child != NULL &&
773 gdev_node->dev == sbdf_node->dev &&
774 gdev_node->func == sbdf_node->func) ||
775 (gdev_node->child == NULL &&
776 sbdf_node->child == NULL &&
777 gdev_node->dev == sbdf_node->dev));
778 }
780 static int pci_iomul_sbdf_match(const struct guestdev *gdev,
781 const struct pci_dev *dev)
782 {
783 int seg, bus;
785 if (sscanf(dev->dev.bus_id, "%04x:%02x", &seg, &bus) != 2)
786 return FALSE;
788 return (gdev->options & GUESTDEV_OPT_IOMUL) &&
789 gdev->u.sbdf.seg == seg &&
790 gdev->u.sbdf.bus == bus &&
791 gdev->u.sbdf.dev == PCI_SLOT(dev->devfn);
792 }
794 int pci_is_iomuldev(struct pci_dev *dev)
795 {
796 return __pci_is_guestdev(dev,
797 pci_iomul_node_match, pci_iomul_sbdf_match);
798 }
799 EXPORT_SYMBOL_GPL(pci_is_iomuldev);
800 #endif /* CONFIG_PCI_IOMULTI */
802 /* Check whether the devicepath exists under the pci root bus */
803 static int __init pci_check_devicepath_exists(
804 struct guestdev *gdev, struct pci_bus *bus)
805 {
806 struct devicepath_node *node;
807 struct pci_dev *dev;
809 BUG_ON(!(gdev->flags & GUESTDEV_FLAG_DEVICEPATH));
811 node = gdev->u.devicepath.child;
812 while (node) {
813 if (!bus)
814 return FALSE;
815 dev = pci_get_slot(bus, PCI_DEVFN(node->dev, node->func));
816 if (!dev)
817 return FALSE;
818 bus = dev->subordinate;
819 node = node->child;
820 pci_dev_put(dev);
821 }
822 return TRUE;
823 }
825 /* Check whether the guestdev exists in the PCI device tree */
826 static int __init pci_check_guestdev_exists(void)
827 {
828 struct list_head *head;
829 struct guestdev *gdev;
830 int seg, bbn;
831 struct pci_bus *bus;
832 struct pci_dev *dev;
833 char path_str[GUESTDEV_STR_MAX];
835 list_for_each(head, &guestdev_list) {
836 gdev = list_entry(head, struct guestdev, root_list);
837 switch (gdev->flags & GUESTDEV_FLAG_TYPE_MASK) {
838 case GUESTDEV_FLAG_DEVICEPATH:
839 if (gdev->u.devicepath.seg == INVALID_SEG ||
840 gdev->u.devicepath.bbn == INVALID_BBN) {
841 if (acpi_pci_get_root_seg_bbn(
842 gdev->u.devicepath.hid,
843 gdev->u.devicepath.uid, &seg, &bbn)) {
844 gdev->u.devicepath.seg = seg;
845 gdev->u.devicepath.bbn = bbn;
846 } else {
847 pci_make_guestdev_str(gdev,
848 path_str, GUESTDEV_STR_MAX);
849 printk(KERN_INFO
850 "PCI: Device does not exist. %s\n",
851 path_str);
852 continue;
853 }
854 }
856 bus = pci_find_bus(gdev->u.devicepath.seg,
857 gdev->u.devicepath.bbn);
858 if (!bus ||
859 !pci_check_devicepath_exists(gdev, bus)) {
860 pci_make_guestdev_str(gdev, path_str,
861 GUESTDEV_STR_MAX);
862 printk(KERN_INFO
863 "PCI: Device does not exist. %s\n",
864 path_str);
865 }
866 break;
867 case GUESTDEV_FLAG_SBDF:
868 bus = pci_find_bus(gdev->u.sbdf.seg, gdev->u.sbdf.bus);
869 if (bus) {
870 dev = pci_get_slot(bus,
871 PCI_DEVFN(gdev->u.sbdf.dev,
872 gdev->u.sbdf.func));
873 if (dev) {
874 pci_dev_put(dev);
875 continue;
876 }
877 }
878 pci_make_guestdev_str(gdev, path_str, GUESTDEV_STR_MAX);
879 printk(KERN_INFO "PCI: Device does not exist. %s\n",
880 path_str);
881 break;
882 default:
883 BUG();
884 }
885 }
886 return 0;
887 }
889 fs_initcall(pci_check_guestdev_exists);