ia64/linux-2.6.18-xen.hg

annotate drivers/pci/guestdev.c @ 769:2fdc121e9b5d

Add "guestdev=" boot parameter.

This patch adds "guestdev=" boot parameter. This boot parameter is
used to reassign page-aligned memory resource and bind PCI back driver.

Signed-off-by: Yuji Shimada <shimada-yxb@necst.nec.co.jp>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Jan 05 10:53:44 2009 +0000 (2009-01-05)
parents
children a3ad7a5f2dcd
rev   line source
keir@769 1 /*
keir@769 2 * Copyright (c) 2008, NEC Corporation.
keir@769 3 *
keir@769 4 * This program is free software; you can redistribute it and/or modify it
keir@769 5 * under the terms and conditions of the GNU General Public License,
keir@769 6 * version 2, as published by the Free Software Foundation.
keir@769 7 *
keir@769 8 * This program is distributed in the hope it will be useful, but WITHOUT
keir@769 9 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
keir@769 10 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
keir@769 11 * more details.
keir@769 12 *
keir@769 13 * You should have received a copy of the GNU General Public License along with
keir@769 14 * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
keir@769 15 * Place - Suite 330, Boston, MA 02111-1307 USA.
keir@769 16 */
keir@769 17
keir@769 18 #include <linux/kernel.h>
keir@769 19 #include <linux/list.h>
keir@769 20 #include <linux/mm.h>
keir@769 21 #include <linux/pci.h>
keir@769 22 #include <linux/module.h>
keir@769 23 #include <linux/string.h>
keir@769 24 #include <linux/acpi.h>
keir@769 25 #include <asm-x86_64/setup.h>
keir@769 26
keir@769 27 #define HID_LEN 8
keir@769 28 #define UID_LEN 8
keir@769 29 #define DEV_LEN 2
keir@769 30 #define FUNC_LEN 1
keir@769 31 #define DEV_NUM_MAX 31
keir@769 32 #define FUNC_NUM_MAX 7
keir@769 33 #define INVALID_SEG (-1)
keir@769 34 #define INVALID_BBN (-1)
keir@769 35 #define PATH_STR_MAX 128
keir@769 36
keir@769 37 struct guestdev {
keir@769 38 struct list_head root_list;
keir@769 39 char hid[HID_LEN + 1];
keir@769 40 char uid[UID_LEN + 1];
keir@769 41 int seg;
keir@769 42 int bbn;
keir@769 43 struct guestdev_node *child;
keir@769 44 };
keir@769 45
keir@769 46 struct guestdev_node {
keir@769 47 int dev;
keir@769 48 int func;
keir@769 49 struct guestdev_node *child;
keir@769 50 };
keir@769 51
keir@769 52 struct pcidev_sbdf {
keir@769 53 int seg;
keir@769 54 int bus;
keir@769 55 struct pcidev_sbdf_node *child;
keir@769 56 };
keir@769 57
keir@769 58 struct pcidev_sbdf_node {
keir@769 59 int dev;
keir@769 60 int func;
keir@769 61 struct pcidev_sbdf_node *child;
keir@769 62 };
keir@769 63
keir@769 64 static int reassign_resources = 0;
keir@769 65
keir@769 66 static char guestdev_param[COMMAND_LINE_SIZE];
keir@769 67 LIST_HEAD(guestdev_list);
keir@769 68
keir@769 69 /* Get hid and uid */
keir@769 70 static int pci_get_hid_uid(char *str, char *hid, char *uid)
keir@769 71 {
keir@769 72 char *sp, *ep;
keir@769 73 int len;
keir@769 74
keir@769 75 sp = str;
keir@769 76 ep = strchr(sp, ':');
keir@769 77 if (!ep) {
keir@769 78 ep = strchr(sp, '-');
keir@769 79 if (!ep)
keir@769 80 goto format_err_end;
keir@769 81 }
keir@769 82 /* hid length */
keir@769 83 len = ep - sp;
keir@769 84 if (len <= 0 || HID_LEN < len)
keir@769 85 goto format_err_end;
keir@769 86
keir@769 87 strncpy(hid, sp, len);
keir@769 88 hid[len] = '\0';
keir@769 89
keir@769 90 if (*ep == '-') { /* no uid */
keir@769 91 uid[0] = '\0';
keir@769 92 return TRUE;
keir@769 93 }
keir@769 94
keir@769 95 sp = ep + 1;
keir@769 96 ep = strchr(sp, '-');
keir@769 97 if (!ep)
keir@769 98 ep = strchr(sp, '\0');
keir@769 99
keir@769 100 /* uid length */
keir@769 101 len = ep - sp;
keir@769 102 if (len <= 0 || UID_LEN < len)
keir@769 103 goto format_err_end;
keir@769 104
keir@769 105 strncpy(uid, sp, len);
keir@769 106 uid[len] = '\0';
keir@769 107 return TRUE;
keir@769 108
keir@769 109 format_err_end:
keir@769 110 return FALSE;
keir@769 111 }
keir@769 112
keir@769 113 /* Get device and function */
keir@769 114 static int pci_get_dev_func(char *str, int *dev, int *func)
keir@769 115 {
keir@769 116 if (sscanf(str, "%02x.%01x", dev, func) != 2)
keir@769 117 goto format_err_end;
keir@769 118
keir@769 119 if (*dev < 0 || DEV_NUM_MAX < *dev)
keir@769 120 goto format_err_end;
keir@769 121
keir@769 122 if (*func < 0 || FUNC_NUM_MAX < *func)
keir@769 123 goto format_err_end;
keir@769 124
keir@769 125 return TRUE;
keir@769 126
keir@769 127 format_err_end:
keir@769 128 return FALSE;
keir@769 129 }
keir@769 130
keir@769 131 /* Check extended guestdev parameter format error */
keir@769 132 static int pci_check_extended_guestdev_format(char *str)
keir@769 133 {
keir@769 134 int flg;
keir@769 135 char *p;
keir@769 136
keir@769 137 /* Check extended format */
keir@769 138 if (strpbrk(str, "(|)") == NULL)
keir@769 139 return TRUE;
keir@769 140
keir@769 141 flg = 0;
keir@769 142 p = str;
keir@769 143 while (*p) {
keir@769 144 switch (*p) {
keir@769 145 case '(':
keir@769 146 /* Check nesting error */
keir@769 147 if (flg != 0)
keir@769 148 goto format_err_end;
keir@769 149 flg = 1;
keir@769 150 /* Check position of '(' is head or
keir@769 151 previos charactor of '(' is not '-'. */
keir@769 152 if (p == str || *(p - 1) != '-')
keir@769 153 goto format_err_end;
keir@769 154 break;
keir@769 155 case ')':
keir@769 156 /* Check nesting error */
keir@769 157 if (flg != 1)
keir@769 158 goto format_err_end;
keir@769 159 flg = 0;
keir@769 160 /* Check next charactor of ')' is not '\0' */
keir@769 161 if (*(p + 1) != '\0')
keir@769 162 goto format_err_end;
keir@769 163 break;
keir@769 164 case '|':
keir@769 165 /* Check position of '|' is outside of '(' and ')' */
keir@769 166 if (flg != 1)
keir@769 167 goto format_err_end;
keir@769 168 break;
keir@769 169 default:
keir@769 170 break;
keir@769 171 }
keir@769 172 p++;
keir@769 173 }
keir@769 174 /* Check number of '(' and ')' are not equal */
keir@769 175 if (flg != 0)
keir@769 176 goto format_err_end;
keir@769 177 return TRUE;
keir@769 178
keir@769 179 format_err_end:
keir@769 180 printk(KERN_ERR
keir@769 181 "PCI: The format of the guestdev parameter is illegal. [%s]\n",
keir@769 182 str);
keir@769 183 return FALSE;
keir@769 184 }
keir@769 185
keir@769 186 /* Make guestdev strings */
keir@769 187 static void pci_make_guestdev_path_str(struct guestdev *gdev,
keir@769 188 char *gdev_str, int buf_size)
keir@769 189 {
keir@769 190 struct guestdev_node *node;
keir@769 191 /* max length for "HID:UID" (hid+uid+':'+'\0') */
keir@769 192 const int hid_uid_len = HID_LEN + UID_LEN + 2;
keir@769 193 /* max length for "-DEV#.FUNC#" (dev+func+'-'+'.'+'\0') */
keir@769 194 const int dev_func_len = DEV_LEN + FUNC_LEN + 3;
keir@769 195
keir@769 196 /* check buffer size for HID:UID */
keir@769 197 if (buf_size < hid_uid_len)
keir@769 198 return;
keir@769 199
keir@769 200 memset(gdev_str, 0, buf_size);
keir@769 201
keir@769 202 if (strlen(gdev->uid))
keir@769 203 sprintf(gdev_str, "%s:%s", gdev->hid, gdev->uid);
keir@769 204 else
keir@769 205 sprintf(gdev_str, "%s", gdev->hid);
keir@769 206 buf_size -= strlen(gdev_str);
keir@769 207
keir@769 208 node = gdev->child;
keir@769 209 while (node) {
keir@769 210 /* check buffer size for -DEV#.FUNC# */
keir@769 211 if (buf_size < dev_func_len)
keir@769 212 return;
keir@769 213 sprintf(gdev_str + strlen(gdev_str), "-%02x.%01x",
keir@769 214 node->dev, node->func);
keir@769 215 buf_size -= dev_func_len;
keir@769 216 node = node->child;
keir@769 217 }
keir@769 218 }
keir@769 219
keir@769 220 /* Free guestdev and nodes */
keir@769 221 static void pci_free_guestdev(struct guestdev *gdev)
keir@769 222 {
keir@769 223 struct guestdev_node *node, *next;
keir@769 224
keir@769 225 if (!gdev)
keir@769 226 return;
keir@769 227
keir@769 228 node = gdev->child;
keir@769 229 while (node) {
keir@769 230 next = node->child;
keir@769 231 kfree(node);
keir@769 232 node = next;
keir@769 233 }
keir@769 234 list_del(&gdev->root_list);
keir@769 235 kfree(gdev);
keir@769 236 }
keir@769 237
keir@769 238 /* Free guestdev_list */
keir@769 239 static void pci_free_guestdev_list(void)
keir@769 240 {
keir@769 241 struct list_head *head, *tmp;
keir@769 242 struct guestdev *gdev;
keir@769 243
keir@769 244 list_for_each_safe(head, tmp, &guestdev_list) {
keir@769 245 gdev = list_entry(head, struct guestdev, root_list);
keir@769 246 pci_free_guestdev(gdev);
keir@769 247 }
keir@769 248 }
keir@769 249
keir@769 250 /* Copy guestdev and nodes */
keir@769 251 struct guestdev *pci_copy_guestdev(struct guestdev *gdev_src)
keir@769 252 {
keir@769 253 struct guestdev *gdev;
keir@769 254 struct guestdev_node *node, *node_src, *node_upper;
keir@769 255
keir@769 256 gdev = kmalloc(sizeof(*gdev), GFP_KERNEL);
keir@769 257 if (!gdev)
keir@769 258 goto allocate_err_end;
keir@769 259
keir@769 260 memset(gdev, 0, sizeof(*gdev));
keir@769 261 INIT_LIST_HEAD(&gdev->root_list);
keir@769 262 strcpy(gdev->hid, gdev_src->hid);
keir@769 263 strcpy(gdev->uid, gdev_src->uid);
keir@769 264 gdev->seg = gdev_src->seg;
keir@769 265 gdev->bbn = gdev_src->bbn;
keir@769 266
keir@769 267 node_upper = NULL;
keir@769 268
keir@769 269 node_src = gdev_src->child;
keir@769 270 while (node_src) {
keir@769 271 node = kmalloc(sizeof(*node), GFP_KERNEL);
keir@769 272 if (!node)
keir@769 273 goto allocate_err_end;
keir@769 274 memset(node, 0, sizeof(*node));
keir@769 275 node->dev = node_src->dev;
keir@769 276 node->func = node_src->func;
keir@769 277 if (!node_upper)
keir@769 278 gdev->child = node;
keir@769 279 else
keir@769 280 node_upper->child = node;
keir@769 281 node_upper = node;
keir@769 282 node_src = node_src->child;
keir@769 283 }
keir@769 284
keir@769 285 return gdev;
keir@769 286
keir@769 287 allocate_err_end:
keir@769 288 if (gdev)
keir@769 289 pci_free_guestdev(gdev);
keir@769 290 printk(KERN_ERR "PCI: Failed to allocate memory.\n");
keir@769 291 return NULL;
keir@769 292 }
keir@769 293
keir@769 294 /* Make guestdev from path strings */
keir@769 295 static int pci_make_guestdev(char *path_str)
keir@769 296 {
keir@769 297 char hid[HID_LEN + 1], uid[UID_LEN + 1];
keir@769 298 char *sp, *ep;
keir@769 299 struct guestdev *gdev, *gdev_org;
keir@769 300 struct guestdev_node *node, *node_tmp;
keir@769 301 int dev, func, ret_val;
keir@769 302
keir@769 303 ret_val = 0;
keir@769 304 gdev = gdev_org = NULL;
keir@769 305 sp = path_str;
keir@769 306 /* Look for end of hid:uid'-' */
keir@769 307 ep = strchr(sp, '-');
keir@769 308 /* Only hid, uid. (No dev, func) */
keir@769 309 if (!ep)
keir@769 310 goto format_err_end;
keir@769 311
keir@769 312 memset(hid, 0 ,sizeof(hid));
keir@769 313 memset(uid, 0, sizeof(uid));
keir@769 314 if (!pci_get_hid_uid(sp, hid, uid))
keir@769 315 goto format_err_end;
keir@769 316
keir@769 317 gdev_org = kmalloc(sizeof(*gdev_org), GFP_KERNEL);
keir@769 318 if (!gdev_org)
keir@769 319 goto allocate_err_end;
keir@769 320 memset(gdev_org, 0, sizeof(*gdev_org));
keir@769 321 INIT_LIST_HEAD(&gdev_org->root_list);
keir@769 322 strcpy(gdev_org->hid, hid);
keir@769 323 strcpy(gdev_org->uid, uid);
keir@769 324 gdev_org->seg = INVALID_SEG;
keir@769 325 gdev_org->bbn = INVALID_BBN;
keir@769 326
keir@769 327 gdev = gdev_org;
keir@769 328
keir@769 329 sp = ep + 1;
keir@769 330 ep = sp;
keir@769 331 do {
keir@769 332 if (*sp == '(') {
keir@769 333 sp++;
keir@769 334 if (strchr(sp, '|')) {
keir@769 335 gdev = pci_copy_guestdev(gdev_org);
keir@769 336 if (!gdev) {
keir@769 337 ret_val = -ENOMEM;
keir@769 338 goto err_end;
keir@769 339 }
keir@769 340 }
keir@769 341 continue;
keir@769 342 }
keir@769 343 if (pci_get_dev_func(sp, &dev, &func)) {
keir@769 344 node = kmalloc(sizeof(*node), GFP_KERNEL);
keir@769 345 if (!node)
keir@769 346 goto allocate_err_end;
keir@769 347 memset(node, 0, sizeof(*node));
keir@769 348 node->dev = dev;
keir@769 349 node->func = func;
keir@769 350 /* add node to end of guestdev */
keir@769 351 if (gdev->child) {
keir@769 352 node_tmp = gdev->child;
keir@769 353 while (node_tmp->child) {
keir@769 354 node_tmp = node_tmp->child;
keir@769 355 }
keir@769 356 node_tmp->child = node;
keir@769 357 } else
keir@769 358 gdev->child = node;
keir@769 359 } else
keir@769 360 goto format_err_end;
keir@769 361
keir@769 362 ep = strpbrk(sp, "-|)");
keir@769 363 if (!ep)
keir@769 364 ep = strchr(sp, '\0');
keir@769 365 /* *ep is '|' OR ')' OR '\0' ? */
keir@769 366 if (*ep != '-') {
keir@769 367 list_add_tail(&gdev->root_list, &guestdev_list);
keir@769 368 if (*ep == '|') {
keir@769 369 /* Between '|' and '|' ? */
keir@769 370 if (strchr(ep + 1, '|')) {
keir@769 371 gdev = pci_copy_guestdev(gdev_org);
keir@769 372 if (!gdev) {
keir@769 373 ret_val = -ENOMEM;
keir@769 374 goto err_end;
keir@769 375 }
keir@769 376 } else
keir@769 377 gdev = gdev_org;
keir@769 378 }
keir@769 379 }
keir@769 380 if (*ep == ')')
keir@769 381 ep++;
keir@769 382 sp = ep + 1;
keir@769 383 } while (*ep != '\0');
keir@769 384
keir@769 385 return ret_val;
keir@769 386
keir@769 387 format_err_end:
keir@769 388 printk(KERN_ERR
keir@769 389 "PCI: The format of the guestdev parameter is illegal. [%s]\n",
keir@769 390 path_str);
keir@769 391 ret_val = -EINVAL;
keir@769 392 goto err_end;
keir@769 393
keir@769 394 allocate_err_end:
keir@769 395 printk(KERN_ERR "PCI: Failed to allocate memory.\n");
keir@769 396 ret_val = -ENOMEM;
keir@769 397 goto err_end;
keir@769 398
keir@769 399 err_end:
keir@769 400 if (gdev_org && (gdev_org != gdev))
keir@769 401 pci_free_guestdev(gdev_org);
keir@769 402 if (gdev)
keir@769 403 pci_free_guestdev(gdev);
keir@769 404 return ret_val;
keir@769 405 }
keir@769 406
keir@769 407 /* Parse guestdev parameter */
keir@769 408 static int __init pci_parse_guestdev(void)
keir@769 409 {
keir@769 410 int len, ret_val;
keir@769 411 char *sp, *ep;
keir@769 412 struct list_head *head;
keir@769 413 struct guestdev *gdev;
keir@769 414 char path_str[PATH_STR_MAX];
keir@769 415
keir@769 416 ret_val = 0;
keir@769 417
keir@769 418 len = strlen(guestdev_param);
keir@769 419 if (len == 0)
keir@769 420 goto end;
keir@769 421
keir@769 422 sp = guestdev_param;
keir@769 423
keir@769 424 do {
keir@769 425 ep = strchr(sp, ',');
keir@769 426 /* Chop */
keir@769 427 if (ep)
keir@769 428 *ep = '\0';
keir@769 429 if (!pci_check_extended_guestdev_format(sp)) {
keir@769 430 pci_free_guestdev_list();
keir@769 431 return -EINVAL;
keir@769 432 }
keir@769 433
keir@769 434 ret_val = pci_make_guestdev(sp);
keir@769 435 if (ret_val) {
keir@769 436 pci_free_guestdev_list();
keir@769 437 return ret_val;
keir@769 438 }
keir@769 439 sp = ep + 1;
keir@769 440 } while (ep);
keir@769 441
keir@769 442 list_for_each(head, &guestdev_list) {
keir@769 443 gdev = list_entry(head, struct guestdev, root_list);
keir@769 444 pci_make_guestdev_path_str(gdev, path_str, PATH_STR_MAX);
keir@769 445 printk(KERN_DEBUG
keir@769 446 "PCI: %s has been reserved for guest domain.\n",
keir@769 447 path_str);
keir@769 448 }
keir@769 449
keir@769 450 end:
keir@769 451 return ret_val;
keir@769 452 }
keir@769 453
keir@769 454 arch_initcall(pci_parse_guestdev);
keir@769 455
keir@769 456 /* Get command line */
keir@769 457 static int __init pci_guestdev_setup(char *str)
keir@769 458 {
keir@769 459 if (strlen(str) >= COMMAND_LINE_SIZE)
keir@769 460 return 0;
keir@769 461 strcpy(guestdev_param, str);
keir@769 462 return 1;
keir@769 463 }
keir@769 464
keir@769 465 __setup("guestdev=", pci_guestdev_setup);
keir@769 466
keir@769 467 /* Free sbdf and nodes */
keir@769 468 static void pci_free_sbdf(struct pcidev_sbdf *sbdf)
keir@769 469 {
keir@769 470 struct pcidev_sbdf_node *node, *next;
keir@769 471
keir@769 472 node = sbdf->child;
keir@769 473 while (node) {
keir@769 474 next = node->child;
keir@769 475 kfree(node);
keir@769 476 node = next;
keir@769 477 }
keir@769 478 /* Skip kfree(sbdf) */
keir@769 479 }
keir@769 480
keir@769 481 /* Is sbdf within guestdev */
keir@769 482 static int pci_sbdf_in_guestdev_sub_tree(struct guestdev *gdev,
keir@769 483 struct pcidev_sbdf *sbdf)
keir@769 484 {
keir@769 485 int seg, bbn;
keir@769 486 struct guestdev_node *gdev_node;
keir@769 487 struct pcidev_sbdf_node *sbdf_node;
keir@769 488
keir@769 489 if (!gdev || !sbdf)
keir@769 490 return FALSE;
keir@769 491
keir@769 492 /* Compare seg and bbn */
keir@769 493 if (gdev->seg == INVALID_SEG ||
keir@769 494 gdev->bbn == INVALID_BBN) {
keir@769 495 if (acpi_pci_get_root_seg_bbn(gdev->hid,
keir@769 496 gdev->uid, &seg, &bbn)) {
keir@769 497 gdev->seg = seg;
keir@769 498 gdev->bbn = bbn;
keir@769 499 } else
keir@769 500 return FALSE;
keir@769 501 }
keir@769 502
keir@769 503 if (gdev->seg != sbdf->seg || gdev->bbn != sbdf->bus)
keir@769 504 return FALSE;
keir@769 505
keir@769 506 gdev_node = gdev->child;
keir@769 507 sbdf_node = sbdf->child;
keir@769 508
keir@769 509 /* Compare dev and func */
keir@769 510 while (gdev_node) {
keir@769 511 if (!sbdf_node)
keir@769 512 return FALSE;
keir@769 513 if (gdev_node->dev != sbdf_node->dev ||
keir@769 514 gdev_node->func != sbdf_node->func)
keir@769 515 return FALSE;
keir@769 516 gdev_node = gdev_node->child;
keir@769 517 sbdf_node = sbdf_node->child;
keir@769 518 }
keir@769 519 return TRUE;
keir@769 520 }
keir@769 521
keir@769 522 /* Get sbdf from device */
keir@769 523 static int pci_get_sbdf_from_pcidev(
keir@769 524 struct pci_dev *dev, struct pcidev_sbdf *sbdf)
keir@769 525 {
keir@769 526 struct pcidev_sbdf_node *node;
keir@769 527
keir@769 528 if (!dev)
keir@769 529 return FALSE;
keir@769 530
keir@769 531 for(;;) {
keir@769 532 node = kmalloc(sizeof(*node), GFP_KERNEL);
keir@769 533 if (!node) {
keir@769 534 printk(KERN_ERR "PCI: Failed to allocate memory.\n");
keir@769 535 goto err_end;
keir@769 536 }
keir@769 537 memset(node, 0, sizeof(*node));
keir@769 538 node->dev = PCI_SLOT(dev->devfn);
keir@769 539 node->func = PCI_FUNC(dev->devfn);
keir@769 540
keir@769 541 if (!sbdf->child)
keir@769 542 sbdf->child = node;
keir@769 543 else {
keir@769 544 node->child = sbdf->child;
keir@769 545 sbdf->child = node;
keir@769 546 }
keir@769 547 if (!dev->bus)
keir@769 548 goto err_end;
keir@769 549 if (!dev->bus->self)
keir@769 550 break;
keir@769 551 dev = dev->bus->self;
keir@769 552 }
keir@769 553 if (sscanf(dev->dev.bus_id, "%04x:%02x", &sbdf->seg, &sbdf->bus) != 2)
keir@769 554 goto err_end;
keir@769 555 return TRUE;
keir@769 556
keir@769 557 err_end:
keir@769 558 pci_free_sbdf(sbdf);
keir@769 559 return FALSE;
keir@769 560 }
keir@769 561
keir@769 562 /* Is PCI device belongs to the subtree of the guestdev parameter */
keir@769 563 int pci_is_guestdev(struct pci_dev *dev)
keir@769 564 {
keir@769 565 struct guestdev *gdev;
keir@769 566 struct pcidev_sbdf sbdf;
keir@769 567 struct list_head *head;
keir@769 568 int result;
keir@769 569
keir@769 570 if (!dev)
keir@769 571 return FALSE;
keir@769 572 memset(&sbdf, 0 ,sizeof(sbdf));
keir@769 573 if (!pci_get_sbdf_from_pcidev(dev, &sbdf))
keir@769 574 return FALSE;
keir@769 575
keir@769 576 result = FALSE;
keir@769 577 list_for_each(head, &guestdev_list) {
keir@769 578 gdev = list_entry(head, struct guestdev, root_list);
keir@769 579 if (pci_sbdf_in_guestdev_sub_tree(gdev, &sbdf)) {
keir@769 580 result = TRUE;
keir@769 581 break;
keir@769 582 }
keir@769 583 }
keir@769 584 pci_free_sbdf(&sbdf);
keir@769 585 return result;
keir@769 586 }
keir@769 587 EXPORT_SYMBOL(pci_is_guestdev);
keir@769 588
keir@769 589 static int __init pci_set_reassign_resources(char *str)
keir@769 590 {
keir@769 591 reassign_resources = 1;
keir@769 592
keir@769 593 return 1;
keir@769 594 }
keir@769 595
keir@769 596 __setup("reassign_resources", pci_set_reassign_resources);
keir@769 597
keir@769 598 int pci_is_guestdev_to_reassign(struct pci_dev *dev)
keir@769 599 {
keir@769 600 if (reassign_resources)
keir@769 601 return pci_is_guestdev(dev);
keir@769 602 return FALSE;
keir@769 603 }
keir@769 604 EXPORT_SYMBOL(pci_is_guestdev_to_reassign);
keir@769 605
keir@769 606 /* Check whether the guestdev exists under the pci root bus */
keir@769 607 static int __init pci_check_guestdev_path_exists(
keir@769 608 struct guestdev *gdev, struct pci_bus *bus)
keir@769 609 {
keir@769 610 struct guestdev_node *node;
keir@769 611 struct pci_dev *dev;
keir@769 612
keir@769 613 node = gdev->child;
keir@769 614 while (node) {
keir@769 615 if (!bus)
keir@769 616 return FALSE;
keir@769 617 dev = pci_get_slot(bus, PCI_DEVFN(node->dev, node->func));
keir@769 618 if (!dev) {
keir@769 619 pci_dev_put(dev);
keir@769 620 return FALSE;
keir@769 621 }
keir@769 622 bus = dev->subordinate;
keir@769 623 node = node->child;
keir@769 624 pci_dev_put(dev);
keir@769 625 }
keir@769 626 return TRUE;
keir@769 627 }
keir@769 628
keir@769 629 /* Check whether the guestdev exists in the PCI device tree */
keir@769 630 static int __init pci_check_guestdev_exists(void)
keir@769 631 {
keir@769 632 struct list_head *head;
keir@769 633 struct guestdev *gdev;
keir@769 634 int seg, bbn;
keir@769 635 struct pci_bus *bus;
keir@769 636 char path_str[PATH_STR_MAX];
keir@769 637
keir@769 638 list_for_each(head, &guestdev_list) {
keir@769 639 gdev = list_entry(head, struct guestdev, root_list);
keir@769 640 if (gdev->seg == INVALID_SEG ||
keir@769 641 gdev->bbn == INVALID_BBN) {
keir@769 642 if (acpi_pci_get_root_seg_bbn(gdev->hid,
keir@769 643 gdev->uid, &seg, &bbn)) {
keir@769 644 gdev->seg = seg;
keir@769 645 gdev->bbn = bbn;
keir@769 646 } else {
keir@769 647 pci_make_guestdev_path_str(gdev, path_str,
keir@769 648 PATH_STR_MAX);
keir@769 649 printk(KERN_INFO
keir@769 650 "PCI: Device does not exist. %s\n",
keir@769 651 path_str);
keir@769 652 continue;
keir@769 653 }
keir@769 654 }
keir@769 655
keir@769 656 bus = pci_find_bus(gdev->seg, gdev->bbn);
keir@769 657 if (!bus || !pci_check_guestdev_path_exists(gdev, bus)) {
keir@769 658 pci_make_guestdev_path_str(gdev, path_str,
keir@769 659 PATH_STR_MAX);
keir@769 660 printk(KERN_INFO
keir@769 661 "PCI: Device does not exist. %s\n", path_str);
keir@769 662 }
keir@769 663 }
keir@769 664 return 0;
keir@769 665 }
keir@769 666
keir@769 667 fs_initcall(pci_check_guestdev_exists);
keir@769 668