diff -r e5d3f2fa3428 Documentation/kernel-parameters.txt --- a/Documentation/kernel-parameters.txt Tue Apr 07 10:29:30 2009 +0100 +++ b/Documentation/kernel-parameters.txt Wed Apr 08 16:14:56 2009 +0900 @@ -576,8 +576,9 @@ running once the system is up. gt96100eth= [NET] MIPS GT96100 Advanced Communication Controller guestdev= [PCI,ACPI] - Format: [,[,...]] - Format of device path: [:]-.[-.[...]] + Format: {|}][,{|}[,...]] + Format of device path: [:]-.[-.[,...]] + Format of sbdf: [:]:. Specifies PCI device for guest domain. If PCI-PCI bridge is specified, all PCI devices behind PCI-PCI bridge are reserved. @@ -1364,12 +1365,6 @@ running once the system is up. Run specified binary instead of /init from the ramdisk, used for early userspace startup. See initrd. - reassigndev= [PCI] - Format: [:]:.[,[:]:.[,...]] - Specifies device to reassign page-aligned memory - resources. PCI-PCI bridge can be specified, if - resource windows need to be expanded. - reassign_resources [PCI,ACPI] Use guestdev parameter to reassign device's resources. diff -r e5d3f2fa3428 drivers/pci/Makefile --- a/drivers/pci/Makefile Tue Apr 07 10:29:30 2009 +0100 +++ b/drivers/pci/Makefile Wed Apr 08 16:14:56 2009 +0900 @@ -4,7 +4,6 @@ obj-y += access.o bus.o probe.o remove.o pci.o quirks.o \ pci-driver.o search.o pci-sysfs.o rom.o setup-res.o -obj-$(CONFIG_PCI_REASSIGN) += reassigndev.o obj-$(CONFIG_PROC_FS) += proc.o obj-$(CONFIG_PCI_GUESTDEV) += guestdev.o diff -r e5d3f2fa3428 drivers/pci/guestdev.c --- a/drivers/pci/guestdev.c Tue Apr 07 10:29:30 2009 +0100 +++ b/drivers/pci/guestdev.c Wed Apr 08 16:14:56 2009 +0900 @@ -1,5 +1,5 @@ /* - * Copyright (c) 2008, NEC Corporation. + * Copyright (c) 2008, 2009 NEC Corporation. * * This program is free software; you can redistribute it and/or modify it * under the terms and conditions of the GNU General Public License, @@ -32,21 +32,36 @@ #define FUNC_NUM_MAX 7 #define INVALID_SEG (-1) #define INVALID_BBN (-1) -#define PATH_STR_MAX 128 +#define GUESTDEV_STR_MAX 128 + +#define GUESTDEV_FLAG_TYPE_MASK 0x3 +#define GUESTDEV_FLAG_DEVICEPATH 0x1 +#define GUESTDEV_FLAG_SBDF 0x2 struct guestdev { + int flags; struct list_head root_list; - char hid[HID_LEN + 1]; - char uid[UID_LEN + 1]; - int seg; - int bbn; - struct guestdev_node *child; + union { + struct devicepath { + char hid[HID_LEN + 1]; + char uid[UID_LEN + 1]; + int seg; + int bbn; + struct devicepath_node *child; + } devicepath; + struct sbdf { + int seg; + int bus; + int dev; + int func; + } sbdf; + } u; }; -struct guestdev_node { +struct devicepath_node { int dev; int func; - struct guestdev_node *child; + struct devicepath_node *child; }; struct pcidev_sbdf { @@ -67,7 +82,7 @@ LIST_HEAD(guestdev_list); LIST_HEAD(guestdev_list); /* Get hid and uid */ -static int pci_get_hid_uid(char *str, char *hid, char *uid) +static int __init pci_get_hid_uid(char *str, char *hid, char *uid) { char *sp, *ep; int len; @@ -111,7 +126,7 @@ format_err_end: } /* Get device and function */ -static int pci_get_dev_func(char *str, int *dev, int *func) +static int __init pci_get_dev_func(char *str, int *dev, int *func) { if (sscanf(str, "%02x.%01x", dev, func) != 2) goto format_err_end; @@ -129,7 +144,7 @@ format_err_end: } /* Check extended guestdev parameter format error */ -static int pci_check_extended_guestdev_format(char *str) +static int __init pci_check_extended_guestdev_format(char *str) { int flg; char *p; @@ -184,74 +199,75 @@ format_err_end: } /* Make guestdev strings */ -static void pci_make_guestdev_path_str(struct guestdev *gdev, +static void pci_make_guestdev_str(struct guestdev *gdev, char *gdev_str, int buf_size) { - struct guestdev_node *node; - /* max length for "HID:UID" (hid+uid+':'+'\0') */ - const int hid_uid_len = HID_LEN + UID_LEN + 2; - /* max length for "-DEV#.FUNC#" (dev+func+'-'+'.'+'\0') */ - const int dev_func_len = DEV_LEN + FUNC_LEN + 3; + struct devicepath_node *node; + int count; - /* check buffer size for HID:UID */ - if (buf_size < hid_uid_len) - return; + switch (gdev->flags & GUESTDEV_FLAG_TYPE_MASK) { + case GUESTDEV_FLAG_DEVICEPATH: + memset(gdev_str, 0, buf_size); - memset(gdev_str, 0, buf_size); + if (strlen(gdev->u.devicepath.uid)) + count = snprintf(gdev_str, buf_size, "%s:%s", + gdev->u.devicepath.hid, + gdev->u.devicepath.uid); + else + count = snprintf(gdev_str, buf_size, "%s", + gdev->u.devicepath.hid); + if (count < 0) + return; - if (strlen(gdev->uid)) - sprintf(gdev_str, "%s:%s", gdev->hid, gdev->uid); - else - sprintf(gdev_str, "%s", gdev->hid); - buf_size -= strlen(gdev_str); - - node = gdev->child; - while (node) { - /* check buffer size for -DEV#.FUNC# */ - if (buf_size < dev_func_len) - return; - sprintf(gdev_str + strlen(gdev_str), "-%02x.%01x", - node->dev, node->func); - buf_size -= dev_func_len; - node = node->child; + node = gdev->u.devicepath.child; + while (node) { + gdev_str += count; + buf_size -= count; + if (buf_size <= 0) + return; + count = snprintf(gdev_str, buf_size, "-%02x.%01x", + node->dev, node->func); + if (count < 0) + return; + node = node->child; + } + break; + case GUESTDEV_FLAG_SBDF: + snprintf(gdev_str, buf_size, "%04x:%02x:%02x.%01x", + gdev->u.sbdf.seg, gdev->u.sbdf.bus, + gdev->u.sbdf.dev, gdev->u.sbdf.func); + break; + default: + BUG(); } } /* Free guestdev and nodes */ -static void pci_free_guestdev(struct guestdev *gdev) +static void __init pci_free_guestdev(struct guestdev *gdev) { - struct guestdev_node *node, *next; + struct devicepath_node *node, *next; if (!gdev) return; - - node = gdev->child; - while (node) { - next = node->child; - kfree(node); - node = next; + if (gdev->flags & GUESTDEV_FLAG_DEVICEPATH) { + node = gdev->u.devicepath.child; + while (node) { + next = node->child; + kfree(node); + node = next; + } } list_del(&gdev->root_list); kfree(gdev); } -/* Free guestdev_list */ -static void pci_free_guestdev_list(void) -{ - struct list_head *head, *tmp; - struct guestdev *gdev; - - list_for_each_safe(head, tmp, &guestdev_list) { - gdev = list_entry(head, struct guestdev, root_list); - pci_free_guestdev(gdev); - } -} - /* Copy guestdev and nodes */ -struct guestdev *pci_copy_guestdev(struct guestdev *gdev_src) +struct guestdev __init *pci_copy_guestdev(struct guestdev *gdev_src) { struct guestdev *gdev; - struct guestdev_node *node, *node_src, *node_upper; + struct devicepath_node *node, *node_src, *node_upper; + + BUG_ON(!(gdev_src->flags & GUESTDEV_FLAG_DEVICEPATH)); gdev = kmalloc(sizeof(*gdev), GFP_KERNEL); if (!gdev) @@ -259,14 +275,15 @@ struct guestdev *pci_copy_guestdev(struc memset(gdev, 0, sizeof(*gdev)); INIT_LIST_HEAD(&gdev->root_list); - strcpy(gdev->hid, gdev_src->hid); - strcpy(gdev->uid, gdev_src->uid); - gdev->seg = gdev_src->seg; - gdev->bbn = gdev_src->bbn; + gdev->flags = gdev_src->flags; + strcpy(gdev->u.devicepath.hid, gdev_src->u.devicepath.hid); + strcpy(gdev->u.devicepath.uid, gdev_src->u.devicepath.uid); + gdev->u.devicepath.seg = gdev_src->u.devicepath.seg; + gdev->u.devicepath.bbn = gdev_src->u.devicepath.bbn; node_upper = NULL; - node_src = gdev_src->child; + node_src = gdev_src->u.devicepath.child; while (node_src) { node = kmalloc(sizeof(*node), GFP_KERNEL); if (!node) @@ -275,7 +292,7 @@ struct guestdev *pci_copy_guestdev(struc node->dev = node_src->dev; node->func = node_src->func; if (!node_upper) - gdev->child = node; + gdev->u.devicepath.child = node; else node_upper->child = node; node_upper = node; @@ -292,12 +309,12 @@ allocate_err_end: } /* Make guestdev from path strings */ -static int pci_make_guestdev(char *path_str) +static int __init pci_make_devicepath_guestdev(char *path_str) { char hid[HID_LEN + 1], uid[UID_LEN + 1]; char *sp, *ep; struct guestdev *gdev, *gdev_org; - struct guestdev_node *node, *node_tmp; + struct devicepath_node *node, *node_tmp; int dev, func, ret_val; ret_val = 0; @@ -319,10 +336,11 @@ static int pci_make_guestdev(char *path_ goto allocate_err_end; memset(gdev_org, 0, sizeof(*gdev_org)); INIT_LIST_HEAD(&gdev_org->root_list); - strcpy(gdev_org->hid, hid); - strcpy(gdev_org->uid, uid); - gdev_org->seg = INVALID_SEG; - gdev_org->bbn = INVALID_BBN; + gdev_org->flags = GUESTDEV_FLAG_DEVICEPATH; + strcpy(gdev_org->u.devicepath.hid, hid); + strcpy(gdev_org->u.devicepath.uid, uid); + gdev_org->u.devicepath.seg = INVALID_SEG; + gdev_org->u.devicepath.bbn = INVALID_BBN; gdev = gdev_org; @@ -335,12 +353,12 @@ static int pci_make_guestdev(char *path_ gdev = pci_copy_guestdev(gdev_org); if (!gdev) { ret_val = -ENOMEM; - goto err_end; + goto end; } } continue; } - if (pci_get_dev_func(sp, &dev, &func)) { + if (gdev && pci_get_dev_func(sp, &dev, &func)) { node = kmalloc(sizeof(*node), GFP_KERNEL); if (!node) goto allocate_err_end; @@ -348,33 +366,47 @@ static int pci_make_guestdev(char *path_ node->dev = dev; node->func = func; /* add node to end of guestdev */ - if (gdev->child) { - node_tmp = gdev->child; + if (gdev->u.devicepath.child) { + node_tmp = gdev->u.devicepath.child; while (node_tmp->child) { node_tmp = node_tmp->child; } node_tmp->child = node; } else - gdev->child = node; - } else - goto format_err_end; + gdev->u.devicepath.child = node; + } else if (gdev) { + printk(KERN_ERR + "PCI: Can't obtain dev# and #func# from %s.\n", + sp); + ret_val = -EINVAL; + if (gdev == gdev_org) + goto end; + pci_free_guestdev(gdev); + gdev = NULL; + } ep = strpbrk(sp, "-|)"); if (!ep) ep = strchr(sp, '\0'); - /* *ep is '|' OR ')' OR '\0' ? */ + /* Is *ep '|' OR ')' OR '\0' ? */ if (*ep != '-') { - list_add_tail(&gdev->root_list, &guestdev_list); + if (gdev) + list_add_tail(&gdev->root_list, &guestdev_list); if (*ep == '|') { /* Between '|' and '|' ? */ if (strchr(ep + 1, '|')) { gdev = pci_copy_guestdev(gdev_org); if (!gdev) { ret_val = -ENOMEM; - goto err_end; + goto end; } - } else + } else { gdev = gdev_org; + gdev_org = NULL; + } + } else { + gdev_org = NULL; + gdev = NULL; } } if (*ep == ')') @@ -382,21 +414,21 @@ static int pci_make_guestdev(char *path_ sp = ep + 1; } while (*ep != '\0'); - return ret_val; + goto end; format_err_end: printk(KERN_ERR "PCI: The format of the guestdev parameter is illegal. [%s]\n", path_str); ret_val = -EINVAL; - goto err_end; + goto end; allocate_err_end: printk(KERN_ERR "PCI: Failed to allocate memory.\n"); ret_val = -ENOMEM; - goto err_end; + goto end; -err_end: +end: if (gdev_org && (gdev_org != gdev)) pci_free_guestdev(gdev_org); if (gdev) @@ -404,20 +436,44 @@ err_end: return ret_val; } +static int __init pci_make_sbdf_guestdev(char* str) +{ + struct guestdev *gdev; + int seg, bus, dev, func; + + if (sscanf(str, "%x:%x:%x.%x", &seg, &bus, &dev, &func) != 4) { + seg = 0; + if (sscanf(str, "%x:%x.%x", &bus, &dev, &func) != 3) + return -EINVAL; + } + gdev = kmalloc(sizeof(*gdev), GFP_KERNEL); + if (!gdev) { + printk(KERN_ERR "PCI: Failed to allocate memory.\n"); + return -ENOMEM; + } + INIT_LIST_HEAD(&gdev->root_list); + gdev->flags = GUESTDEV_FLAG_SBDF; + gdev->u.sbdf.seg = seg; + gdev->u.sbdf.bus = bus; + gdev->u.sbdf.dev = dev; + gdev->u.sbdf.func = func; + list_add_tail(&gdev->root_list, &guestdev_list); + return 0; +} + /* Parse guestdev parameter */ static int __init pci_parse_guestdev(void) { - int len, ret_val; + int len; char *sp, *ep; struct list_head *head; struct guestdev *gdev; - char path_str[PATH_STR_MAX]; - - ret_val = 0; + char path_str[GUESTDEV_STR_MAX]; + int ret_val = 0; len = strlen(guestdev_param); if (len == 0) - goto end; + return 0; sp = guestdev_param; @@ -426,29 +482,26 @@ static int __init pci_parse_guestdev(voi /* Chop */ if (ep) *ep = '\0'; - if (!pci_check_extended_guestdev_format(sp)) { - pci_free_guestdev_list(); - return -EINVAL; - } - - ret_val = pci_make_guestdev(sp); - if (ret_val) { - pci_free_guestdev_list(); - return ret_val; - } + ret_val = pci_make_sbdf_guestdev(sp); + if (ret_val == -EINVAL) { + if (pci_check_extended_guestdev_format(sp)) { + ret_val = pci_make_devicepath_guestdev(sp); + if (ret_val && ret_val != -EINVAL) + break; + } + } else if (ret_val) + break; sp = ep + 1; } while (ep); list_for_each(head, &guestdev_list) { gdev = list_entry(head, struct guestdev, root_list); - pci_make_guestdev_path_str(gdev, path_str, PATH_STR_MAX); + pci_make_guestdev_str(gdev, path_str, GUESTDEV_STR_MAX); printk(KERN_DEBUG "PCI: %s has been reserved for guest domain.\n", path_str); } - -end: - return ret_val; + return 0; } arch_initcall(pci_parse_guestdev); @@ -478,32 +531,35 @@ static void pci_free_sbdf(struct pcidev_ /* Skip kfree(sbdf) */ } -/* Is sbdf within guestdev */ -static int pci_sbdf_in_guestdev_sub_tree(struct guestdev *gdev, +/* Does PCI device belong to sub tree specified by guestdev with device path? */ +static int pci_is_in_devicepath_sub_tree(struct guestdev *gdev, struct pcidev_sbdf *sbdf) { int seg, bbn; - struct guestdev_node *gdev_node; + struct devicepath_node *gdev_node; struct pcidev_sbdf_node *sbdf_node; if (!gdev || !sbdf) return FALSE; + BUG_ON(!(gdev->flags & GUESTDEV_FLAG_DEVICEPATH)); + /* Compare seg and bbn */ - if (gdev->seg == INVALID_SEG || - gdev->bbn == INVALID_BBN) { - if (acpi_pci_get_root_seg_bbn(gdev->hid, - gdev->uid, &seg, &bbn)) { - gdev->seg = seg; - gdev->bbn = bbn; + if (gdev->u.devicepath.seg == INVALID_SEG || + gdev->u.devicepath.bbn == INVALID_BBN) { + if (acpi_pci_get_root_seg_bbn(gdev->u.devicepath.hid, + gdev->u.devicepath.uid, &seg, &bbn)) { + gdev->u.devicepath.seg = seg; + gdev->u.devicepath.bbn = bbn; } else return FALSE; } - if (gdev->seg != sbdf->seg || gdev->bbn != sbdf->bus) + if (gdev->u.devicepath.seg != sbdf->seg || + gdev->u.devicepath.bbn != sbdf->bus) return FALSE; - gdev_node = gdev->child; + gdev_node = gdev->u.devicepath.child; sbdf_node = sbdf->child; /* Compare dev and func */ @@ -559,29 +615,64 @@ err_end: return FALSE; } -/* Is PCI device belongs to the subtree of the guestdev parameter */ +/* Does PCI device belong to sub tree specified by guestdev with sbdf? */ +static int pci_is_in_sbdf_sub_tree(struct guestdev *gdev, struct pci_dev *dev) +{ + int seg, bus; + BUG_ON(!(gdev->flags & GUESTDEV_FLAG_SBDF)); + for (;;) { + if (sscanf(dev->dev.bus_id, "%04x:%02x", &seg, &bus) != 2) + continue; + if (gdev->u.sbdf.seg == seg && gdev->u.sbdf.bus == bus && + gdev->u.sbdf.dev == PCI_SLOT(dev->devfn) && + gdev->u.sbdf.func == PCI_FUNC(dev->devfn)) + return TRUE; + if (!dev->bus || !dev->bus->self) + break; + dev = dev->bus->self; + } + return FALSE; +} + +/* Does PCI device belong to sub tree specified by guestdev parameter? */ int pci_is_guestdev(struct pci_dev *dev) { struct guestdev *gdev; - struct pcidev_sbdf sbdf; + struct pcidev_sbdf pcidev_sbdf, *sbdf = NULL; struct list_head *head; - int result; + int result = FALSE; if (!dev) return FALSE; - memset(&sbdf, 0 ,sizeof(sbdf)); - if (!pci_get_sbdf_from_pcidev(dev, &sbdf)) - return FALSE; - result = FALSE; list_for_each(head, &guestdev_list) { gdev = list_entry(head, struct guestdev, root_list); - if (pci_sbdf_in_guestdev_sub_tree(gdev, &sbdf)) { - result = TRUE; + switch (gdev->flags & GUESTDEV_FLAG_TYPE_MASK) { + case GUESTDEV_FLAG_DEVICEPATH: + if (sbdf == NULL) { + sbdf = &pcidev_sbdf; + memset(sbdf, 0 ,sizeof(*sbdf)); + if (!pci_get_sbdf_from_pcidev(dev, sbdf)) + goto out; + } + if (pci_is_in_devicepath_sub_tree(gdev, sbdf)) { + result = TRUE; + goto out; + } break; + case GUESTDEV_FLAG_SBDF: + if (pci_is_in_sbdf_sub_tree(gdev, dev)) { + result = TRUE; + goto out; + } + break; + default: + BUG(); } } - pci_free_sbdf(&sbdf); +out: + if (sbdf) + pci_free_sbdf(sbdf); return result; } EXPORT_SYMBOL(pci_is_guestdev); @@ -595,30 +686,30 @@ static int __init pci_set_reassign_resou __setup("reassign_resources", pci_set_reassign_resources); -int pci_is_guestdev_to_reassign(struct pci_dev *dev) +int pci_is_reassigndev(struct pci_dev *dev) { if (reassign_resources) return pci_is_guestdev(dev); return FALSE; } -EXPORT_SYMBOL(pci_is_guestdev_to_reassign); +EXPORT_SYMBOL(pci_is_reassigndev); -/* Check whether the guestdev exists under the pci root bus */ -static int __init pci_check_guestdev_path_exists( +/* Check whether the devicepath exists under the pci root bus */ +static int __init pci_check_devicepath_exists( struct guestdev *gdev, struct pci_bus *bus) { - struct guestdev_node *node; + struct devicepath_node *node; struct pci_dev *dev; - node = gdev->child; + BUG_ON(!(gdev->flags & GUESTDEV_FLAG_DEVICEPATH)); + + node = gdev->u.devicepath.child; while (node) { if (!bus) return FALSE; dev = pci_get_slot(bus, PCI_DEVFN(node->dev, node->func)); - if (!dev) { - pci_dev_put(dev); + if (!dev) return FALSE; - } bus = dev->subordinate; node = node->child; pci_dev_put(dev); @@ -633,32 +724,58 @@ static int __init pci_check_guestdev_exi struct guestdev *gdev; int seg, bbn; struct pci_bus *bus; - char path_str[PATH_STR_MAX]; + struct pci_dev *dev; + char path_str[GUESTDEV_STR_MAX]; list_for_each(head, &guestdev_list) { gdev = list_entry(head, struct guestdev, root_list); - if (gdev->seg == INVALID_SEG || - gdev->bbn == INVALID_BBN) { - if (acpi_pci_get_root_seg_bbn(gdev->hid, - gdev->uid, &seg, &bbn)) { - gdev->seg = seg; - gdev->bbn = bbn; - } else { - pci_make_guestdev_path_str(gdev, path_str, - PATH_STR_MAX); + switch (gdev->flags & GUESTDEV_FLAG_TYPE_MASK) { + case GUESTDEV_FLAG_DEVICEPATH: + if (gdev->u.devicepath.seg == INVALID_SEG || + gdev->u.devicepath.bbn == INVALID_BBN) { + if (acpi_pci_get_root_seg_bbn( + gdev->u.devicepath.hid, + gdev->u.devicepath.uid, &seg, &bbn)) { + gdev->u.devicepath.seg = seg; + gdev->u.devicepath.bbn = bbn; + } else { + pci_make_guestdev_str(gdev, + path_str, GUESTDEV_STR_MAX); + printk(KERN_INFO + "PCI: Device does not exist. %s\n", + path_str); + continue; + } + } + + bus = pci_find_bus(gdev->u.devicepath.seg, + gdev->u.devicepath.bbn); + if (!bus || + !pci_check_devicepath_exists(gdev, bus)) { + pci_make_guestdev_str(gdev, path_str, + GUESTDEV_STR_MAX); printk(KERN_INFO "PCI: Device does not exist. %s\n", path_str); - continue; } - } - - bus = pci_find_bus(gdev->seg, gdev->bbn); - if (!bus || !pci_check_guestdev_path_exists(gdev, bus)) { - pci_make_guestdev_path_str(gdev, path_str, - PATH_STR_MAX); - printk(KERN_INFO - "PCI: Device does not exist. %s\n", path_str); + break; + case GUESTDEV_FLAG_SBDF: + bus = pci_find_bus(gdev->u.sbdf.seg, gdev->u.sbdf.bus); + if (bus) { + dev = pci_get_slot(bus, + PCI_DEVFN(gdev->u.sbdf.dev, + gdev->u.sbdf.func)); + if (dev) { + pci_dev_put(dev); + continue; + } + } + pci_make_guestdev_str(gdev, path_str, GUESTDEV_STR_MAX); + printk(KERN_INFO "PCI: Device does not exist. %s\n", + path_str); + break; + default: + BUG(); } } return 0; diff -r e5d3f2fa3428 drivers/pci/pci.h --- a/drivers/pci/pci.h Tue Apr 07 10:29:30 2009 +0100 +++ b/drivers/pci/pci.h Wed Apr 08 16:14:56 2009 +0900 @@ -102,8 +102,10 @@ pci_match_one_device(const struct pci_de } #ifdef CONFIG_PCI_REASSIGN +extern void pci_disable_bridge_window(struct pci_dev *dev); +#endif +#ifdef CONFIG_PCI_GUESTDEV extern int pci_is_reassigndev(struct pci_dev *dev); -extern void pci_disable_bridge_window(struct pci_dev *dev); #else #define pci_is_reassigndev(dev) 0 #endif diff -r e5d3f2fa3428 drivers/pci/reassigndev.c --- a/drivers/pci/reassigndev.c Tue Apr 07 10:29:30 2009 +0100 +++ /dev/null Thu Jan 01 00:00:00 1970 +0000 @@ -1,87 +0,0 @@ -/* - * Copyright (c) 2008, NEC Corporation. - * - * This program is free software; you can redistribute it and/or modify it - * under the terms and conditions of the GNU General Public License, - * version 2, as published by the Free Software Foundation. - * - * This program is distributed in the hope it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or - * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for - * more details. - * - * You should have received a copy of the GNU General Public License along with - * this program; if not, write to the Free Software Foundation, Inc., 59 Temple - * Place - Suite 330, Boston, MA 02111-1307 USA. - */ - -#include -#include -#include -#include "pci.h" - - -#define REASSIGNDEV_PARAM_MAX (2048) -#define TOKEN_MAX (12) /* "SSSS:BB:DD.F" length is 12 */ - -static char param_reassigndev[REASSIGNDEV_PARAM_MAX] = {0}; - -static int __init pci_reassigndev_setup(char *str) -{ - strncpy(param_reassigndev, str, REASSIGNDEV_PARAM_MAX); - param_reassigndev[REASSIGNDEV_PARAM_MAX - 1] = '\0'; - return 1; -} -__setup("reassigndev=", pci_reassigndev_setup); - -int pci_is_reassigndev(struct pci_dev *dev) -{ - char dev_str[TOKEN_MAX+1]; - int seg, bus, slot, func; - int len; - char *p, *next_str; - int result; - -#ifdef CONFIG_PCI_GUESTDEV - result = pci_is_guestdev_to_reassign(dev); - if (result) - return result; -#endif /* CONFIG_PCI_GUESTDEV */ - - p = param_reassigndev; - for (; p; p = next_str + 1) { - next_str = strpbrk(p, ","); - if (next_str) { - len = next_str - p; - } else { - len = strlen(p); - } - if (len > 0 && len <= TOKEN_MAX) { - strncpy(dev_str, p, len); - *(dev_str + len) = '\0'; - - if (sscanf(dev_str, "%x:%x:%x.%x", - &seg, &bus, &slot, &func) != 4) { - if (sscanf(dev_str, "%x:%x.%x", - &bus, &slot, &func) == 3) { - seg = 0; - } else { - /* failed to scan strings */ - seg = -1; - bus = -1; - } - } - if (seg == pci_domain_nr(dev->bus) && - bus == dev->bus->number && - slot == PCI_SLOT(dev->devfn) && - func == PCI_FUNC(dev->devfn)) { - /* It's a target device */ - return 1; - } - } - if (!next_str) - break; - } - - return 0; -}