ia64/linux-2.6.18-xen.hg

changeset 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 fad85221407b
children 78d81e85e8cd
files Documentation/kernel-parameters.txt drivers/acpi/pci_root.c drivers/pci/Kconfig drivers/pci/Makefile drivers/pci/guestdev.c drivers/pci/pci.h drivers/pci/reassigndev.c include/asm-x86_64/setup.h include/linux/acpi.h include/linux/pci.h
line diff
     1.1 --- a/Documentation/kernel-parameters.txt	Mon Jan 05 10:53:06 2009 +0000
     1.2 +++ b/Documentation/kernel-parameters.txt	Mon Jan 05 10:53:44 2009 +0000
     1.3 @@ -1240,6 +1240,16 @@ running once the system is up.
     1.4  				bootloader. This is currently used on
     1.5  				IXP2000 systems where the bus has to be
     1.6  				configured a certain way for adjunct CPUs.
     1.7 +		reassign_resources
     1.8 +				Use guestdev parameter to reassign device's
     1.9 +				resources.
    1.10 +		guestdev=
    1.11 +				Format: <device path>[,<device path>[,...]]
    1.12 +				Format of device path: <hid>[:<uid>]-<dev>.<func>[-<dev>.<func>[...]]
    1.13 +				Specifies PCI device for guest domain.
    1.14 +				If PCI-PCI bridge is specified, all
    1.15 +				PCI devices behind PCI-PCI bridge are
    1.16 +				reserved.
    1.17  
    1.18  	pcmv=		[HW,PCMCIA] BadgePAD 4
    1.19  
     2.1 --- a/drivers/acpi/pci_root.c	Mon Jan 05 10:53:06 2009 +0000
     2.2 +++ b/drivers/acpi/pci_root.c	Mon Jan 05 10:53:44 2009 +0000
     2.3 @@ -392,3 +392,32 @@ static int __init acpi_pci_root_init(voi
     2.4  }
     2.5  
     2.6  subsys_initcall(acpi_pci_root_init);
     2.7 +
     2.8 +int acpi_pci_get_root_seg_bbn(char *hid, char *uid, int *seg, int *bbn)
     2.9 +{
    2.10 +	struct list_head *entry;
    2.11 +
    2.12 +	list_for_each(entry, &acpi_pci_roots) {
    2.13 +		struct acpi_pci_root *root;
    2.14 +		root = list_entry(entry, struct acpi_pci_root, node);
    2.15 +		if (!root->device->flags.hardware_id)
    2.16 +			continue;
    2.17 +
    2.18 +		if (strcmp(root->device->pnp.hardware_id, hid))
    2.19 +			continue;
    2.20 +
    2.21 +		if (!root->device->flags.unique_id) {
    2.22 +			if (strlen(uid))
    2.23 +				continue;
    2.24 +		} else {
    2.25 +			if (strcmp(root->device->pnp.unique_id, uid))
    2.26 +				continue;
    2.27 +		}
    2.28 +
    2.29 +		*seg = (int)root->id.segment;
    2.30 +		*bbn = (int)root->id.bus;
    2.31 +		return TRUE;
    2.32 +	}
    2.33 +	return FALSE;
    2.34 +}
    2.35 +EXPORT_SYMBOL(acpi_pci_get_root_seg_bbn);
     3.1 --- a/drivers/pci/Kconfig	Mon Jan 05 10:53:06 2009 +0000
     3.2 +++ b/drivers/pci/Kconfig	Mon Jan 05 10:53:44 2009 +0000
     3.3 @@ -30,3 +30,10 @@ config PCI_DEBUG
     3.4  
     3.5  	  When in doubt, say N.
     3.6  
     3.7 +config PCI_GUESTDEV
     3.8 +	bool "PCI Device Reservation for Passthrough"
     3.9 +	depends on PCI
    3.10 +	default y
    3.11 +	help
    3.12 +	  Say Y here if you want to reserve PCI device for passthrough.
    3.13 +
     4.1 --- a/drivers/pci/Makefile	Mon Jan 05 10:53:06 2009 +0000
     4.2 +++ b/drivers/pci/Makefile	Mon Jan 05 10:53:44 2009 +0000
     4.3 @@ -6,6 +6,7 @@ obj-y		+= access.o bus.o probe.o remove.
     4.4  			pci-driver.o search.o pci-sysfs.o rom.o setup-res.o
     4.5  obj-$(CONFIG_PCI_REASSIGN) += reassigndev.o
     4.6  obj-$(CONFIG_PROC_FS) += proc.o
     4.7 +obj-$(CONFIG_PCI_GUESTDEV) += guestdev.o
     4.8  
     4.9  # Build PCI Express stuff if needed
    4.10  obj-$(CONFIG_PCIEPORTBUS) += pcie/
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/drivers/pci/guestdev.c	Mon Jan 05 10:53:44 2009 +0000
     5.3 @@ -0,0 +1,668 @@
     5.4 +/*
     5.5 + * Copyright (c) 2008, NEC Corporation.
     5.6 + *
     5.7 + * This program is free software; you can redistribute it and/or modify it
     5.8 + * under the terms and conditions of the GNU General Public License,
     5.9 + * version 2, as published by the Free Software Foundation.
    5.10 + *
    5.11 + * This program is distributed in the hope it will be useful, but WITHOUT
    5.12 + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
    5.13 + * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
    5.14 + * more details.
    5.15 + *
    5.16 + * You should have received a copy of the GNU General Public License along with
    5.17 + * this program; if not, write to the Free Software Foundation, Inc., 59 Temple
    5.18 + * Place - Suite 330, Boston, MA 02111-1307 USA.
    5.19 + */
    5.20 +
    5.21 +#include <linux/kernel.h>
    5.22 +#include <linux/list.h>
    5.23 +#include <linux/mm.h>
    5.24 +#include <linux/pci.h>
    5.25 +#include <linux/module.h>
    5.26 +#include <linux/string.h>
    5.27 +#include <linux/acpi.h>
    5.28 +#include <asm-x86_64/setup.h>
    5.29 +
    5.30 +#define HID_LEN 8
    5.31 +#define UID_LEN 8
    5.32 +#define DEV_LEN 2
    5.33 +#define FUNC_LEN 1
    5.34 +#define DEV_NUM_MAX 31
    5.35 +#define FUNC_NUM_MAX 7
    5.36 +#define INVALID_SEG (-1)
    5.37 +#define INVALID_BBN (-1)
    5.38 +#define PATH_STR_MAX 128
    5.39 +
    5.40 +struct guestdev {
    5.41 +	struct list_head root_list;
    5.42 +	char hid[HID_LEN + 1];
    5.43 +	char uid[UID_LEN + 1];
    5.44 +	int seg;
    5.45 +	int bbn;
    5.46 +	struct guestdev_node *child;
    5.47 +};
    5.48 +
    5.49 +struct guestdev_node {
    5.50 +	int dev;
    5.51 +	int func;
    5.52 +	struct guestdev_node *child;
    5.53 +};
    5.54 +
    5.55 +struct pcidev_sbdf {
    5.56 +	int seg;
    5.57 +	int bus;
    5.58 +	struct pcidev_sbdf_node *child;
    5.59 +};
    5.60 +
    5.61 +struct pcidev_sbdf_node {
    5.62 +	int dev;
    5.63 +	int func;
    5.64 +	struct pcidev_sbdf_node *child;
    5.65 +};
    5.66 +
    5.67 +static int reassign_resources = 0;
    5.68 +
    5.69 +static char guestdev_param[COMMAND_LINE_SIZE];
    5.70 +LIST_HEAD(guestdev_list);
    5.71 +
    5.72 +/* Get hid and uid */
    5.73 +static int pci_get_hid_uid(char *str, char *hid, char *uid)
    5.74 +{
    5.75 +	char *sp, *ep;
    5.76 +	int len;
    5.77 +
    5.78 +	sp = str;
    5.79 +	ep = strchr(sp, ':');
    5.80 +	if (!ep) {
    5.81 +		ep = strchr(sp, '-');
    5.82 +		if (!ep)
    5.83 +			goto format_err_end;
    5.84 +	}
    5.85 +	/* hid length */
    5.86 +	len = ep - sp;
    5.87 +	if (len <= 0 || HID_LEN < len)
    5.88 +		goto format_err_end;
    5.89 +
    5.90 +	strncpy(hid, sp, len);
    5.91 +	hid[len] = '\0';
    5.92 +
    5.93 +	if (*ep == '-') { /* no uid */
    5.94 +		uid[0] = '\0';
    5.95 +		return TRUE;
    5.96 +	}
    5.97 +
    5.98 +	sp = ep + 1;
    5.99 +	ep = strchr(sp, '-');
   5.100 +	if (!ep)
   5.101 +		ep = strchr(sp, '\0');
   5.102 +
   5.103 +	/* uid length */
   5.104 +	len = ep - sp;
   5.105 +	if (len <= 0 || UID_LEN < len)
   5.106 +		goto format_err_end;
   5.107 +
   5.108 +	strncpy(uid, sp, len);
   5.109 +	uid[len] = '\0';
   5.110 +	return TRUE;
   5.111 +
   5.112 +format_err_end:
   5.113 +	return FALSE;
   5.114 +}
   5.115 +
   5.116 +/* Get device and function */
   5.117 +static int pci_get_dev_func(char *str, int *dev, int *func)
   5.118 +{
   5.119 +	if (sscanf(str, "%02x.%01x", dev, func) != 2)
   5.120 +		goto format_err_end;
   5.121 +
   5.122 +	if (*dev < 0 || DEV_NUM_MAX < *dev)
   5.123 +		goto format_err_end;
   5.124 +
   5.125 +	if (*func < 0 || FUNC_NUM_MAX < *func)
   5.126 +		goto format_err_end;
   5.127 +
   5.128 +	return TRUE;
   5.129 +
   5.130 +format_err_end:
   5.131 +	return FALSE;
   5.132 +}
   5.133 +
   5.134 +/* Check extended guestdev parameter format error */
   5.135 +static int pci_check_extended_guestdev_format(char *str)
   5.136 +{
   5.137 +	int flg;
   5.138 +	char *p;
   5.139 +
   5.140 +	/* Check extended format */
   5.141 +	if (strpbrk(str, "(|)") == NULL)
   5.142 +		return TRUE;
   5.143 +
   5.144 +	flg = 0;
   5.145 +	p = str;
   5.146 +	while (*p) {
   5.147 +		switch (*p) {
   5.148 +		case '(':
   5.149 +			/* Check nesting error */
   5.150 +			if (flg != 0)
   5.151 +				goto format_err_end;
   5.152 +			flg = 1;
   5.153 +			/* Check position of '(' is head or
   5.154 +			   previos charactor of '(' is not '-'. */
   5.155 +			if (p == str || *(p - 1) != '-')
   5.156 +				goto format_err_end;
   5.157 +			break;
   5.158 +		case ')':
   5.159 +			/* Check nesting error */
   5.160 +			if (flg != 1)
   5.161 +				goto format_err_end;
   5.162 +			flg = 0;
   5.163 +			/* Check next charactor of ')' is not '\0' */
   5.164 +			if (*(p + 1) != '\0')
   5.165 +				goto format_err_end;
   5.166 +			break;
   5.167 +		case '|':
   5.168 +			/* Check position of '|' is outside of '(' and ')' */
   5.169 +			if (flg != 1)
   5.170 +				goto format_err_end;
   5.171 +			break;
   5.172 +		default:
   5.173 +			break;
   5.174 +		}
   5.175 +		p++;
   5.176 +	}
   5.177 +	/* Check number of '(' and ')' are not equal */
   5.178 +	if (flg != 0)
   5.179 +		goto format_err_end;
   5.180 +	return TRUE;
   5.181 +
   5.182 +format_err_end:
   5.183 +	printk(KERN_ERR
   5.184 +		"PCI: The format of the guestdev parameter is illegal. [%s]\n",
   5.185 +		str);
   5.186 +	return FALSE;
   5.187 +}
   5.188 +
   5.189 +/* Make guestdev strings */
   5.190 +static void pci_make_guestdev_path_str(struct guestdev *gdev,
   5.191 +					char *gdev_str, int buf_size)
   5.192 +{
   5.193 +	struct guestdev_node *node;
   5.194 +	/* max length for "HID:UID" (hid+uid+':'+'\0') */
   5.195 +	const int hid_uid_len = HID_LEN + UID_LEN + 2;
   5.196 +	/* max length for "-DEV#.FUNC#" (dev+func+'-'+'.'+'\0') */
   5.197 +	const int dev_func_len = DEV_LEN + FUNC_LEN + 3;
   5.198 +
   5.199 +	/* check buffer size for HID:UID */
   5.200 +	if (buf_size < hid_uid_len)
   5.201 +		return;
   5.202 +
   5.203 +	memset(gdev_str, 0, buf_size);
   5.204 +
   5.205 +	if (strlen(gdev->uid))
   5.206 +		sprintf(gdev_str, "%s:%s", gdev->hid, gdev->uid);
   5.207 +	else
   5.208 +		sprintf(gdev_str, "%s", gdev->hid);
   5.209 +	buf_size -= strlen(gdev_str);
   5.210 +
   5.211 +	node = gdev->child;
   5.212 +	while (node) {
   5.213 +		/* check buffer size for -DEV#.FUNC# */
   5.214 +		if (buf_size < dev_func_len)
   5.215 +			return;
   5.216 +		sprintf(gdev_str + strlen(gdev_str), "-%02x.%01x",
   5.217 +			node->dev, node->func);
   5.218 +		buf_size -= dev_func_len;
   5.219 +		node = node->child;
   5.220 +	}
   5.221 +}
   5.222 +
   5.223 +/* Free guestdev and nodes */
   5.224 +static void pci_free_guestdev(struct guestdev *gdev)
   5.225 +{
   5.226 +	struct guestdev_node *node, *next;
   5.227 +
   5.228 +	if (!gdev)
   5.229 +		return;
   5.230 +
   5.231 +	node = gdev->child;
   5.232 +	while (node) {
   5.233 +		next = node->child;
   5.234 +		kfree(node);
   5.235 +		node = next;
   5.236 +	}
   5.237 +	list_del(&gdev->root_list);
   5.238 +	kfree(gdev);
   5.239 +}
   5.240 +
   5.241 +/* Free guestdev_list */
   5.242 +static void pci_free_guestdev_list(void)
   5.243 +{
   5.244 +	struct list_head *head, *tmp;
   5.245 +	struct guestdev *gdev;
   5.246 +
   5.247 +	list_for_each_safe(head, tmp, &guestdev_list) {
   5.248 +		gdev = list_entry(head, struct guestdev, root_list);
   5.249 +		pci_free_guestdev(gdev);
   5.250 +	}
   5.251 +}
   5.252 +
   5.253 +/* Copy guestdev and nodes */
   5.254 +struct guestdev *pci_copy_guestdev(struct guestdev *gdev_src)
   5.255 +{
   5.256 +	struct guestdev *gdev;
   5.257 +	struct guestdev_node *node, *node_src, *node_upper;
   5.258 +
   5.259 +	gdev = kmalloc(sizeof(*gdev), GFP_KERNEL);
   5.260 +	if (!gdev)
   5.261 +		goto allocate_err_end;
   5.262 +
   5.263 +	memset(gdev, 0, sizeof(*gdev));
   5.264 +	INIT_LIST_HEAD(&gdev->root_list);
   5.265 +	strcpy(gdev->hid, gdev_src->hid);
   5.266 +	strcpy(gdev->uid, gdev_src->uid);
   5.267 +	gdev->seg = gdev_src->seg;
   5.268 +	gdev->bbn = gdev_src->bbn;
   5.269 +
   5.270 +	node_upper = NULL;
   5.271 +
   5.272 +	node_src = gdev_src->child;
   5.273 +	while (node_src) {
   5.274 +		node = kmalloc(sizeof(*node), GFP_KERNEL);
   5.275 +		if (!node)
   5.276 +			goto allocate_err_end;
   5.277 +		memset(node, 0, sizeof(*node));
   5.278 +		node->dev = node_src->dev;
   5.279 +		node->func = node_src->func;
   5.280 +		if (!node_upper)
   5.281 +			gdev->child = node;
   5.282 +		else
   5.283 +			node_upper->child = node;
   5.284 +		node_upper = node;
   5.285 +		node_src = node_src->child;
   5.286 +	}
   5.287 +
   5.288 +	return gdev;
   5.289 +
   5.290 +allocate_err_end:
   5.291 +	if (gdev)
   5.292 +		pci_free_guestdev(gdev);
   5.293 +	printk(KERN_ERR "PCI: Failed to allocate memory.\n");
   5.294 +	return NULL;
   5.295 +}
   5.296 +
   5.297 +/* Make guestdev from path strings */
   5.298 +static int pci_make_guestdev(char *path_str)
   5.299 +{
   5.300 +	char hid[HID_LEN + 1], uid[UID_LEN + 1];
   5.301 +	char *sp, *ep;
   5.302 +	struct guestdev *gdev, *gdev_org;
   5.303 +	struct guestdev_node *node, *node_tmp;
   5.304 +	int dev, func, ret_val;
   5.305 +
   5.306 +	ret_val = 0;
   5.307 +	gdev = gdev_org = NULL;
   5.308 +	sp = path_str;
   5.309 +	/* Look for end of hid:uid'-' */
   5.310 +	ep = strchr(sp, '-');
   5.311 +	/* Only hid, uid. (No dev, func) */
   5.312 +	if (!ep)
   5.313 +		goto format_err_end;
   5.314 +
   5.315 +	memset(hid, 0 ,sizeof(hid));
   5.316 +	memset(uid, 0, sizeof(uid));
   5.317 +	if (!pci_get_hid_uid(sp, hid, uid))
   5.318 +		goto format_err_end;
   5.319 +
   5.320 +	gdev_org = kmalloc(sizeof(*gdev_org), GFP_KERNEL);
   5.321 +	if (!gdev_org)
   5.322 +		goto allocate_err_end;
   5.323 +	memset(gdev_org, 0, sizeof(*gdev_org));
   5.324 +	INIT_LIST_HEAD(&gdev_org->root_list);
   5.325 +	strcpy(gdev_org->hid, hid);
   5.326 +	strcpy(gdev_org->uid, uid);
   5.327 +	gdev_org->seg = INVALID_SEG;
   5.328 +	gdev_org->bbn = INVALID_BBN;
   5.329 +
   5.330 +	gdev = gdev_org;
   5.331 +
   5.332 +	sp = ep + 1;
   5.333 +	ep = sp;
   5.334 +	do {
   5.335 +		if (*sp == '(') {
   5.336 +			sp++;
   5.337 +			if (strchr(sp, '|')) {
   5.338 +				gdev = pci_copy_guestdev(gdev_org);
   5.339 +				if (!gdev) {
   5.340 +					ret_val = -ENOMEM;
   5.341 +					goto err_end;
   5.342 +				}
   5.343 +			}
   5.344 +			continue;
   5.345 +		}
   5.346 +		if (pci_get_dev_func(sp, &dev, &func)) {
   5.347 +			node = kmalloc(sizeof(*node), GFP_KERNEL);
   5.348 +			if (!node)
   5.349 +				goto allocate_err_end;
   5.350 +			memset(node, 0, sizeof(*node));
   5.351 +			node->dev = dev;
   5.352 +			node->func = func;
   5.353 +			/* add node to end of guestdev */
   5.354 +			if (gdev->child) {
   5.355 +				node_tmp = gdev->child;
   5.356 +				while (node_tmp->child) {
   5.357 +					node_tmp = node_tmp->child;
   5.358 +				}
   5.359 +				node_tmp->child = node;
   5.360 +			} else
   5.361 +				gdev->child = node;
   5.362 +		} else
   5.363 +			goto format_err_end;
   5.364 +
   5.365 +		ep = strpbrk(sp, "-|)");
   5.366 +		if (!ep)
   5.367 +			ep = strchr(sp, '\0');
   5.368 +		/* *ep is '|' OR ')' OR '\0' ? */
   5.369 +		if (*ep != '-') {
   5.370 +			list_add_tail(&gdev->root_list, &guestdev_list);
   5.371 +			if (*ep == '|') {
   5.372 +				/* Between '|' and '|' ? */
   5.373 +				if (strchr(ep + 1, '|')) {
   5.374 +					gdev = pci_copy_guestdev(gdev_org);
   5.375 +					if (!gdev) {
   5.376 +						ret_val = -ENOMEM;
   5.377 +						goto err_end;
   5.378 +					}
   5.379 +				} else
   5.380 +					gdev = gdev_org;
   5.381 +			}
   5.382 +		}
   5.383 +		if (*ep == ')')
   5.384 +			ep++;
   5.385 +		sp = ep + 1;
   5.386 +	} while (*ep != '\0');
   5.387 +
   5.388 +	return ret_val;
   5.389 +
   5.390 +format_err_end:
   5.391 +	printk(KERN_ERR
   5.392 +		"PCI: The format of the guestdev parameter is illegal. [%s]\n",
   5.393 +		path_str);
   5.394 +	ret_val = -EINVAL;
   5.395 +	goto err_end;
   5.396 +
   5.397 +allocate_err_end:
   5.398 +	printk(KERN_ERR "PCI: Failed to allocate memory.\n");
   5.399 +	ret_val = -ENOMEM;
   5.400 +	goto err_end;
   5.401 +
   5.402 +err_end:
   5.403 +	if (gdev_org && (gdev_org != gdev))
   5.404 +		pci_free_guestdev(gdev_org);
   5.405 +	if (gdev)
   5.406 +		pci_free_guestdev(gdev);
   5.407 +	return ret_val;
   5.408 +}
   5.409 +
   5.410 +/* Parse guestdev parameter */
   5.411 +static int __init pci_parse_guestdev(void)
   5.412 +{
   5.413 +	int len, ret_val;
   5.414 +	char *sp, *ep;
   5.415 +	struct list_head *head;
   5.416 +	struct guestdev *gdev;
   5.417 +	char path_str[PATH_STR_MAX];
   5.418 +
   5.419 +	ret_val = 0;
   5.420 +
   5.421 +	len = strlen(guestdev_param);
   5.422 +	if (len == 0)
   5.423 +		goto end;
   5.424 +
   5.425 +	sp = guestdev_param;
   5.426 +
   5.427 +	do {
   5.428 +		ep = strchr(sp, ',');
   5.429 +		/* Chop */
   5.430 +		if (ep)
   5.431 +			*ep = '\0';
   5.432 +		if (!pci_check_extended_guestdev_format(sp)) {
   5.433 +			pci_free_guestdev_list();
   5.434 +			return -EINVAL;
   5.435 +		}
   5.436 +
   5.437 +		ret_val = pci_make_guestdev(sp);
   5.438 +		if (ret_val) {
   5.439 +			pci_free_guestdev_list();
   5.440 +			return ret_val;
   5.441 +		}
   5.442 +		sp = ep + 1;
   5.443 +	} while (ep);
   5.444 +
   5.445 +	list_for_each(head, &guestdev_list) {
   5.446 +		gdev = list_entry(head, struct guestdev, root_list);
   5.447 +		pci_make_guestdev_path_str(gdev, path_str, PATH_STR_MAX);
   5.448 +		printk(KERN_DEBUG
   5.449 +			"PCI: %s has been reserved for guest domain.\n",
   5.450 +			path_str);
   5.451 +	}
   5.452 +
   5.453 +end:
   5.454 +	return ret_val;
   5.455 +}
   5.456 +
   5.457 +arch_initcall(pci_parse_guestdev);
   5.458 +
   5.459 +/* Get command line */
   5.460 +static int __init pci_guestdev_setup(char *str)
   5.461 +{
   5.462 +	if (strlen(str) >= COMMAND_LINE_SIZE)
   5.463 +		return 0;
   5.464 +	strcpy(guestdev_param, str);
   5.465 +	return 1;
   5.466 +}
   5.467 +
   5.468 +__setup("guestdev=", pci_guestdev_setup);
   5.469 +
   5.470 +/* Free sbdf and nodes */
   5.471 +static void pci_free_sbdf(struct pcidev_sbdf *sbdf)
   5.472 +{
   5.473 +	struct pcidev_sbdf_node *node, *next;
   5.474 +
   5.475 +	node = sbdf->child;
   5.476 +	while (node) {
   5.477 +		next = node->child;
   5.478 +		kfree(node);
   5.479 +		node = next;
   5.480 +	}
   5.481 +	/* Skip kfree(sbdf) */
   5.482 +}
   5.483 +
   5.484 +/* Is sbdf within guestdev */
   5.485 +static int pci_sbdf_in_guestdev_sub_tree(struct guestdev *gdev, 
   5.486 +					struct pcidev_sbdf *sbdf)
   5.487 +{
   5.488 +	int seg, bbn;
   5.489 +	struct guestdev_node *gdev_node;
   5.490 +	struct pcidev_sbdf_node *sbdf_node;
   5.491 +
   5.492 +	if (!gdev || !sbdf)
   5.493 +		return FALSE;
   5.494 +
   5.495 +	/* Compare seg and bbn */
   5.496 +	if (gdev->seg == INVALID_SEG || 
   5.497 +	    gdev->bbn == INVALID_BBN) {
   5.498 +		if (acpi_pci_get_root_seg_bbn(gdev->hid, 
   5.499 +		    gdev->uid, &seg, &bbn)) {
   5.500 +			gdev->seg = seg;
   5.501 +			gdev->bbn = bbn;
   5.502 +		} else
   5.503 +			return FALSE;
   5.504 +	}
   5.505 +
   5.506 +	if (gdev->seg != sbdf->seg || gdev->bbn != sbdf->bus)
   5.507 +		return FALSE;
   5.508 +
   5.509 +	gdev_node = gdev->child;
   5.510 +	sbdf_node = sbdf->child;
   5.511 +
   5.512 +	/* Compare dev and func */
   5.513 +	while (gdev_node) {
   5.514 +		if (!sbdf_node)
   5.515 +			return FALSE;
   5.516 +		if (gdev_node->dev != sbdf_node->dev ||
   5.517 +		    gdev_node->func != sbdf_node->func)
   5.518 +			return FALSE;
   5.519 +		gdev_node = gdev_node->child;
   5.520 +		sbdf_node = sbdf_node->child;
   5.521 +	}
   5.522 +	return TRUE;
   5.523 +}
   5.524 +
   5.525 +/* Get sbdf from device */
   5.526 +static int pci_get_sbdf_from_pcidev(
   5.527 +	struct pci_dev *dev, struct pcidev_sbdf *sbdf)
   5.528 +{
   5.529 +	struct pcidev_sbdf_node *node;
   5.530 +
   5.531 +	if (!dev)
   5.532 +		return FALSE;
   5.533 +
   5.534 +	for(;;) {
   5.535 +		node = kmalloc(sizeof(*node), GFP_KERNEL);
   5.536 +		if (!node) {
   5.537 +			printk(KERN_ERR "PCI: Failed to allocate memory.\n");
   5.538 +			goto err_end;
   5.539 +		}
   5.540 +		memset(node, 0, sizeof(*node));
   5.541 +		node->dev = PCI_SLOT(dev->devfn);
   5.542 +		node->func = PCI_FUNC(dev->devfn);
   5.543 +
   5.544 +		if (!sbdf->child)
   5.545 +			sbdf->child = node;
   5.546 +		else {
   5.547 +			node->child = sbdf->child;
   5.548 +			sbdf->child = node;
   5.549 +		}
   5.550 +		if (!dev->bus)
   5.551 +			goto err_end;
   5.552 +		if (!dev->bus->self)
   5.553 +			break;
   5.554 +		dev = dev->bus->self;
   5.555 +	}
   5.556 +	if (sscanf(dev->dev.bus_id, "%04x:%02x", &sbdf->seg, &sbdf->bus) != 2)
   5.557 +		goto err_end;
   5.558 +	return TRUE;
   5.559 +
   5.560 +err_end:
   5.561 +	pci_free_sbdf(sbdf);
   5.562 +	return FALSE;
   5.563 +}
   5.564 +
   5.565 +/* Is PCI device belongs to the subtree of the guestdev parameter */
   5.566 +int pci_is_guestdev(struct pci_dev *dev)
   5.567 +{
   5.568 +	struct guestdev *gdev;
   5.569 +	struct pcidev_sbdf sbdf;
   5.570 +	struct list_head *head;
   5.571 +	int result;
   5.572 +
   5.573 +	if (!dev)
   5.574 +		return FALSE;
   5.575 +	memset(&sbdf, 0 ,sizeof(sbdf));
   5.576 +	if (!pci_get_sbdf_from_pcidev(dev, &sbdf))
   5.577 +		return FALSE;
   5.578 +
   5.579 +	result = FALSE;
   5.580 +	list_for_each(head, &guestdev_list) {
   5.581 +		gdev = list_entry(head, struct guestdev, root_list);
   5.582 +		if (pci_sbdf_in_guestdev_sub_tree(gdev, &sbdf)) {
   5.583 +			result = TRUE;
   5.584 +			break;
   5.585 +		}
   5.586 +	}
   5.587 +	pci_free_sbdf(&sbdf);
   5.588 +	return result;
   5.589 +}
   5.590 +EXPORT_SYMBOL(pci_is_guestdev);
   5.591 +
   5.592 +static int __init pci_set_reassign_resources(char *str)
   5.593 +{
   5.594 +	reassign_resources = 1;
   5.595 +
   5.596 +	return 1;
   5.597 +}
   5.598 +
   5.599 +__setup("reassign_resources", pci_set_reassign_resources);
   5.600 +
   5.601 +int pci_is_guestdev_to_reassign(struct pci_dev *dev)
   5.602 +{
   5.603 +	if (reassign_resources)
   5.604 +		return pci_is_guestdev(dev);
   5.605 +	return FALSE;
   5.606 +}
   5.607 +EXPORT_SYMBOL(pci_is_guestdev_to_reassign);
   5.608 +
   5.609 +/* Check whether the guestdev exists under the pci root bus */
   5.610 +static int __init pci_check_guestdev_path_exists(
   5.611 +		struct guestdev *gdev, struct pci_bus *bus)
   5.612 +{
   5.613 +	struct guestdev_node *node;
   5.614 +	struct pci_dev *dev;
   5.615 +
   5.616 +	node = gdev->child;
   5.617 +	while (node) {
   5.618 +		if (!bus)
   5.619 +			return FALSE;
   5.620 +		dev = pci_get_slot(bus, PCI_DEVFN(node->dev, node->func));
   5.621 +		if (!dev) {
   5.622 +			pci_dev_put(dev);
   5.623 +			return FALSE;
   5.624 +		}
   5.625 +		bus = dev->subordinate;
   5.626 +		node = node->child;
   5.627 +		pci_dev_put(dev);
   5.628 +	}
   5.629 +	return TRUE;
   5.630 +}
   5.631 +
   5.632 +/* Check whether the guestdev exists in the PCI device tree */
   5.633 +static int __init pci_check_guestdev_exists(void)
   5.634 +{
   5.635 +	struct list_head *head;
   5.636 +	struct guestdev *gdev;
   5.637 +	int seg, bbn;
   5.638 +	struct pci_bus *bus;
   5.639 +	char path_str[PATH_STR_MAX];
   5.640 +
   5.641 +	list_for_each(head, &guestdev_list) {
   5.642 +		gdev = list_entry(head, struct guestdev, root_list);
   5.643 +		if (gdev->seg == INVALID_SEG ||
   5.644 +			gdev->bbn == INVALID_BBN) {
   5.645 +			if (acpi_pci_get_root_seg_bbn(gdev->hid,
   5.646 +				gdev->uid, &seg, &bbn)) {
   5.647 +				gdev->seg = seg;
   5.648 +				gdev->bbn = bbn;
   5.649 +			} else {
   5.650 +				pci_make_guestdev_path_str(gdev, path_str,
   5.651 +					PATH_STR_MAX);
   5.652 +				printk(KERN_INFO
   5.653 +					"PCI: Device does not exist. %s\n",
   5.654 +					path_str);
   5.655 +				continue;
   5.656 +			}
   5.657 +		}
   5.658 +
   5.659 +		bus = pci_find_bus(gdev->seg, gdev->bbn);
   5.660 +		if (!bus || !pci_check_guestdev_path_exists(gdev, bus)) {
   5.661 +			pci_make_guestdev_path_str(gdev, path_str,
   5.662 +				PATH_STR_MAX);
   5.663 +			printk(KERN_INFO
   5.664 +				"PCI: Device does not exist. %s\n", path_str);
   5.665 +		}
   5.666 +	}
   5.667 +	return 0;
   5.668 +}
   5.669 +
   5.670 +fs_initcall(pci_check_guestdev_exists);
   5.671 +
     6.1 --- a/drivers/pci/pci.h	Mon Jan 05 10:53:06 2009 +0000
     6.2 +++ b/drivers/pci/pci.h	Mon Jan 05 10:53:44 2009 +0000
     6.3 @@ -105,3 +105,7 @@ extern void pci_disable_bridge_window(st
     6.4  #else
     6.5  #define is_reassigndev(dev) 0
     6.6  #endif
     6.7 +
     6.8 +#ifdef CONFIG_PCI_GUESTDEV
     6.9 +int pci_is_guestdev_to_reassign(struct pci_dev *dev);
    6.10 +#endif /* CONFIG_PCI_GUESTDEV */
     7.1 --- a/drivers/pci/reassigndev.c	Mon Jan 05 10:53:06 2009 +0000
     7.2 +++ b/drivers/pci/reassigndev.c	Mon Jan 05 10:53:44 2009 +0000
     7.3 @@ -40,6 +40,13 @@ int is_reassigndev(struct pci_dev *dev)
     7.4  	int seg, bus, slot, func;
     7.5  	int len;
     7.6  	char *p, *next_str;
     7.7 +	int result;
     7.8 +
     7.9 +#ifdef CONFIG_PCI_GUESTDEV
    7.10 +	result = pci_is_guestdev_to_reassign(dev);
    7.11 +	if (result)
    7.12 +		return	result;
    7.13 +#endif /* CONFIG_PCI_GUESTDEV */
    7.14  
    7.15  	p = param_reassigndev;
    7.16  	for (; p; p = next_str + 1) {
     8.1 --- a/include/asm-x86_64/setup.h	Mon Jan 05 10:53:06 2009 +0000
     8.2 +++ b/include/asm-x86_64/setup.h	Mon Jan 05 10:53:44 2009 +0000
     8.3 @@ -1,6 +1,6 @@
     8.4  #ifndef _x8664_SETUP_H
     8.5  #define _x8664_SETUP_H
     8.6  
     8.7 -#define COMMAND_LINE_SIZE	256
     8.8 +#define COMMAND_LINE_SIZE	1024
     8.9  
    8.10  #endif
     9.1 --- a/include/linux/acpi.h	Mon Jan 05 10:53:06 2009 +0000
     9.2 +++ b/include/linux/acpi.h	Mon Jan 05 10:53:44 2009 +0000
     9.3 @@ -406,6 +406,7 @@ int acpi_parse_mcfg (unsigned long phys_
     9.4  void acpi_table_print (struct acpi_table_header *header, unsigned long phys_addr);
     9.5  void acpi_table_print_madt_entry (acpi_table_entry_header *madt);
     9.6  void acpi_table_print_srat_entry (acpi_table_entry_header *srat);
     9.7 +int acpi_pci_get_root_seg_bbn(char *hid, char *uid, int *seg, int *bbn);
     9.8  
     9.9  /* the following four functions are architecture-dependent */
    9.10  #ifdef CONFIG_HAVE_ARCH_PARSE_SRAT
    10.1 --- a/include/linux/pci.h	Mon Jan 05 10:53:06 2009 +0000
    10.2 +++ b/include/linux/pci.h	Mon Jan 05 10:53:44 2009 +0000
    10.3 @@ -804,5 +804,9 @@ extern int pci_pci_problems;
    10.4  #define PCIPCI_VSFX		16
    10.5  #define PCIPCI_ALIMAGIK		32
    10.6  
    10.7 +#ifdef CONFIG_PCI_GUESTDEV
    10.8 +int pci_is_guestdev(struct pci_dev *dev);
    10.9 +#endif /* CONFIG_PCI_GUESTDEV */
   10.10 +
   10.11  #endif /* __KERNEL__ */
   10.12  #endif /* LINUX_PCI_H */