ia64/linux-2.6.18-xen.hg

changeset 883:b998614e2e2a

pci/guestdev: enhance guestdev to accept +iomul.

enhance guestdev to accept +iomul and use it.

Signed-off-by: Isaku Yamahata <yamahata@valinux.co.jp>
author Keir Fraser <keir.fraser@citrix.com>
date Thu May 28 09:59:18 2009 +0100 (2009-05-28)
parents 8dec4aa9b8b9
children c7c92f868aa1
files Documentation/kernel-parameters.txt drivers/pci/guestdev.c drivers/pci/iomulti.c drivers/pci/pci.h
line diff
     1.1 --- a/Documentation/kernel-parameters.txt	Thu May 28 09:57:49 2009 +0100
     1.2 +++ b/Documentation/kernel-parameters.txt	Thu May 28 09:59:18 2009 +0100
     1.3 @@ -577,11 +577,15 @@ running once the system is up.
     1.4  
     1.5  	guestdev=	[PCI,ACPI]
     1.6  			Format: {<device path>|<sbdf>}][,{<device path>|<sbdf>}[,...]]
     1.7 -			Format of device path: <hid>[:<uid>]-<dev>.<func>[-<dev>.<func>[,...]]
     1.8 -			Format of sbdf: [<segment>:]<bus>:<dev>.<func>
     1.9 +			Format of device path: <hid>[:<uid>]-<dev>.<func>[-<dev>.<func>[,...]][+iomul]
    1.10 +			Format of sbdf: [<segment>:]<bus>:<dev>.<func>[+iomul]
    1.11  			Specifies PCI device for guest domain.
    1.12  			If PCI-PCI bridge is specified, all PCI devices
    1.13  			behind PCI-PCI bridge are reserved.
    1.14 +			+iomul means that this PCI function will share
    1.15 +			IO ports with other +iomul functions under same
    1.16 +			switch. NOTE: if +iomul is specfied, all the functions
    1.17 +			of the device will share IO ports.
    1.18  
    1.19  	guestiomuldev=	[PCI]
    1.20  			Format: [sbd][,<sbd>][,...]
     2.1 --- a/drivers/pci/guestdev.c	Thu May 28 09:57:49 2009 +0100
     2.2 +++ b/drivers/pci/guestdev.c	Thu May 28 09:59:18 2009 +0100
     2.3 @@ -1,5 +1,7 @@
     2.4  /*
     2.5   * Copyright (c) 2008, 2009 NEC Corporation.
     2.6 + * Copyright (c) 2009 Isaku Yamahata
     2.7 + *                    VA Linux Systems Japan K.K.
     2.8   *
     2.9   * This program is free software; you can redistribute it and/or modify it
    2.10   * under the terms and conditions of the GNU General Public License,
    2.11 @@ -38,8 +40,11 @@
    2.12  #define GUESTDEV_FLAG_DEVICEPATH 0x1
    2.13  #define GUESTDEV_FLAG_SBDF 0x2
    2.14  
    2.15 +#define GUESTDEV_OPT_IOMUL	0x1
    2.16 +
    2.17  struct guestdev {
    2.18  	int flags;
    2.19 +	int options;
    2.20  	struct list_head root_list;
    2.21  	union {
    2.22  		struct devicepath {
    2.23 @@ -276,6 +281,7 @@ struct guestdev __init *pci_copy_guestde
    2.24  	memset(gdev, 0, sizeof(*gdev));
    2.25  	INIT_LIST_HEAD(&gdev->root_list);
    2.26  	gdev->flags = gdev_src->flags;
    2.27 +	gdev->options = gdev_src->options;
    2.28  	strcpy(gdev->u.devicepath.hid, gdev_src->u.devicepath.hid);
    2.29  	strcpy(gdev->u.devicepath.uid, gdev_src->u.devicepath.uid);
    2.30  	gdev->u.devicepath.seg = gdev_src->u.devicepath.seg;
    2.31 @@ -309,7 +315,7 @@ allocate_err_end:
    2.32  }
    2.33  
    2.34  /* Make guestdev from path strings */
    2.35 -static int __init pci_make_devicepath_guestdev(char *path_str)
    2.36 +static int __init pci_make_devicepath_guestdev(char *path_str, int options)
    2.37  {
    2.38  	char hid[HID_LEN + 1], uid[UID_LEN + 1];
    2.39  	char *sp, *ep;
    2.40 @@ -337,6 +343,7 @@ static int __init pci_make_devicepath_gu
    2.41  	memset(gdev_org, 0, sizeof(*gdev_org));
    2.42  	INIT_LIST_HEAD(&gdev_org->root_list);
    2.43  	gdev_org->flags = GUESTDEV_FLAG_DEVICEPATH;
    2.44 +	gdev_org->options = options;
    2.45  	strcpy(gdev_org->u.devicepath.hid, hid);
    2.46  	strcpy(gdev_org->u.devicepath.uid, uid);
    2.47  	gdev_org->u.devicepath.seg = INVALID_SEG;
    2.48 @@ -436,7 +443,7 @@ end:
    2.49  	return ret_val;
    2.50  }
    2.51  
    2.52 -static int __init pci_make_sbdf_guestdev(char* str)
    2.53 +static int __init pci_make_sbdf_guestdev(char* str, int options)
    2.54  {
    2.55  	struct guestdev *gdev;
    2.56  	int seg, bus, dev, func;
    2.57 @@ -453,6 +460,7 @@ static int __init pci_make_sbdf_guestdev
    2.58  	}
    2.59  	INIT_LIST_HEAD(&gdev->root_list);
    2.60  	gdev->flags = GUESTDEV_FLAG_SBDF;
    2.61 +	gdev->options = options;
    2.62  	gdev->u.sbdf.seg = seg;
    2.63  	gdev->u.sbdf.bus = bus;
    2.64  	gdev->u.sbdf.dev = dev;
    2.65 @@ -461,11 +469,31 @@ static int __init pci_make_sbdf_guestdev
    2.66  	return 0;
    2.67  }
    2.68  
    2.69 +static int __init pci_parse_options(const char *str)
    2.70 +{
    2.71 +	int options = 0;
    2.72 +	char *ep;
    2.73 +
    2.74 +	while (str) {
    2.75 +		str++;
    2.76 +		ep = strchr(str, '+');
    2.77 +		if (ep)
    2.78 +			ep = '\0';	/* Chop */
    2.79 +
    2.80 +		if (!strcmp(str, "iomul"))
    2.81 +			options |= GUESTDEV_OPT_IOMUL;
    2.82 +
    2.83 +		str = ep;
    2.84 +	}
    2.85 +	return options;
    2.86 +}
    2.87 +
    2.88  /* Parse guestdev parameter */
    2.89  static int __init pci_parse_guestdev(void)
    2.90  {
    2.91  	int len;
    2.92 -	char *sp, *ep;
    2.93 +	char *sp, *ep, *op;
    2.94 +	int options;
    2.95  	struct list_head *head;
    2.96  	struct guestdev *gdev;
    2.97  	char path_str[GUESTDEV_STR_MAX];
    2.98 @@ -482,16 +510,26 @@ static int __init pci_parse_guestdev(voi
    2.99  		/* Chop */
   2.100  		if (ep)
   2.101  			*ep = '\0';
   2.102 -		ret_val = pci_make_sbdf_guestdev(sp);
   2.103 +		options = 0;
   2.104 +		op = strchr(sp, '+');
   2.105 +		if (op && (!ep || op < ep)) {
   2.106 +			options = pci_parse_options(op);
   2.107 +			*op = '\0';	/* Chop */
   2.108 +		}
   2.109 +		ret_val = pci_make_sbdf_guestdev(sp, options);
   2.110  		if (ret_val == -EINVAL) {
   2.111  			if (pci_check_extended_guestdev_format(sp)) {
   2.112 -				ret_val = pci_make_devicepath_guestdev(sp);
   2.113 +				ret_val = pci_make_devicepath_guestdev(
   2.114 +					sp, options);
   2.115  				if (ret_val && ret_val != -EINVAL)
   2.116  					break;
   2.117  			}
   2.118  		} else if (ret_val)
   2.119  			break;
   2.120 -		sp = ep + 1;
   2.121 +
   2.122 +		if (ep)
   2.123 +			ep++;
   2.124 +		sp = ep;
   2.125  	} while (ep);
   2.126  
   2.127  	list_for_each(head, &guestdev_list) {
   2.128 @@ -532,8 +570,21 @@ static void pci_free_sbdf(struct pcidev_
   2.129  }
   2.130  
   2.131  /* Does PCI device belong to sub tree specified by guestdev with device path? */
   2.132 +typedef int (*pci_node_match_t)(const struct devicepath_node *gdev_node,
   2.133 +				const struct pcidev_sbdf_node *sbdf_node,
   2.134 +				int options);
   2.135 +
   2.136 +static int pci_node_match(const struct devicepath_node *gdev_node,
   2.137 +			  const struct pcidev_sbdf_node *sbdf_node,
   2.138 +			  int options_unused)
   2.139 +{
   2.140 +	return (gdev_node->dev == sbdf_node->dev &&
   2.141 +		gdev_node->func == sbdf_node->func);
   2.142 +}
   2.143 +
   2.144  static int pci_is_in_devicepath_sub_tree(struct guestdev *gdev,
   2.145 -					struct pcidev_sbdf *sbdf)
   2.146 +					 struct pcidev_sbdf *sbdf,
   2.147 +					 pci_node_match_t match)
   2.148  {
   2.149  	int seg, bbn;
   2.150  	struct devicepath_node *gdev_node;
   2.151 @@ -566,8 +617,7 @@ static int pci_is_in_devicepath_sub_tree
   2.152  	while (gdev_node) {
   2.153  		if (!sbdf_node)
   2.154  			return FALSE;
   2.155 -		if (gdev_node->dev != sbdf_node->dev ||
   2.156 -		    gdev_node->func != sbdf_node->func)
   2.157 +		if (!match(gdev_node, sbdf_node, gdev->options))
   2.158  			return FALSE;
   2.159  		gdev_node = gdev_node->child;
   2.160  		sbdf_node = sbdf_node->child;
   2.161 @@ -616,16 +666,29 @@ err_end:
   2.162  }
   2.163  
   2.164  /* Does PCI device belong to sub tree specified by guestdev with sbdf? */
   2.165 -static int pci_is_in_sbdf_sub_tree(struct guestdev *gdev, struct pci_dev *dev)
   2.166 +typedef int (*pci_sbdf_match_t)(const struct guestdev *gdev,
   2.167 +				const  struct pci_dev *dev);
   2.168 +
   2.169 +static int pci_sbdf_match(const struct guestdev *gdev,
   2.170 +			  const struct pci_dev *dev)
   2.171  {
   2.172  	int seg, bus;
   2.173 +
   2.174 +	if (sscanf(dev->dev.bus_id, "%04x:%02x", &seg, &bus) != 2)
   2.175 +		return FALSE;
   2.176 +
   2.177 +	return gdev->u.sbdf.seg == seg &&
   2.178 +		gdev->u.sbdf.bus == bus &&
   2.179 +		gdev->u.sbdf.dev == PCI_SLOT(dev->devfn) &&
   2.180 +		gdev->u.sbdf.func == PCI_FUNC(dev->devfn);
   2.181 +}
   2.182 +
   2.183 +static int pci_is_in_sbdf_sub_tree(struct guestdev *gdev, struct pci_dev *dev,
   2.184 +				   pci_sbdf_match_t match)
   2.185 +{
   2.186  	BUG_ON(!(gdev->flags & GUESTDEV_FLAG_SBDF));
   2.187  	for (;;) {
   2.188 -		if (sscanf(dev->dev.bus_id, "%04x:%02x", &seg, &bus) != 2)
   2.189 -			continue;
   2.190 -		if (gdev->u.sbdf.seg == seg && gdev->u.sbdf.bus == bus &&
   2.191 -			gdev->u.sbdf.dev == PCI_SLOT(dev->devfn) &&
   2.192 -			gdev->u.sbdf.func == PCI_FUNC(dev->devfn))
   2.193 +		if (match(gdev, dev))
   2.194  			return TRUE;
   2.195  		if (!dev->bus || !dev->bus->self)
   2.196  			break;
   2.197 @@ -635,7 +698,8 @@ static int pci_is_in_sbdf_sub_tree(struc
   2.198  }
   2.199  
   2.200  /* Does PCI device belong to sub tree specified by guestdev parameter? */
   2.201 -int pci_is_guestdev(struct pci_dev *dev)
   2.202 +static int __pci_is_guestdev(struct pci_dev *dev, pci_node_match_t node_match,
   2.203 +			     pci_sbdf_match_t sbdf_match)
   2.204  {
   2.205  	struct guestdev *gdev;
   2.206  	struct pcidev_sbdf pcidev_sbdf, *sbdf = NULL;
   2.207 @@ -655,13 +719,14 @@ int pci_is_guestdev(struct pci_dev *dev)
   2.208  				if (!pci_get_sbdf_from_pcidev(dev, sbdf))
   2.209  					goto out;
   2.210  			}
   2.211 -			if (pci_is_in_devicepath_sub_tree(gdev, sbdf)) {
   2.212 +			if (pci_is_in_devicepath_sub_tree(gdev, sbdf,
   2.213 +							  node_match)) {
   2.214  				result = TRUE;
   2.215  				goto out;
   2.216  			}
   2.217  			break;
   2.218  		case GUESTDEV_FLAG_SBDF:
   2.219 -			if (pci_is_in_sbdf_sub_tree(gdev, dev)) {
   2.220 +			if (pci_is_in_sbdf_sub_tree(gdev, dev, sbdf_match)) {
   2.221  				result = TRUE;
   2.222  				goto out;
   2.223  			}
   2.224 @@ -675,6 +740,11 @@ out:
   2.225  		pci_free_sbdf(sbdf);
   2.226  	return result;
   2.227  }
   2.228 +
   2.229 +int pci_is_guestdev(struct pci_dev *dev)
   2.230 +{
   2.231 +	return __pci_is_guestdev(dev, pci_node_match, pci_sbdf_match);
   2.232 +}
   2.233  EXPORT_SYMBOL(pci_is_guestdev);
   2.234  
   2.235  static int __init pci_set_reassign_resources(char *str)
   2.236 @@ -694,6 +764,43 @@ int pci_is_reassigndev(struct pci_dev *d
   2.237  }
   2.238  EXPORT_SYMBOL(pci_is_reassigndev);
   2.239  
   2.240 +#ifdef CONFIG_PCI_IOMULTI
   2.241 +static int pci_iomul_node_match(const struct devicepath_node *gdev_node,
   2.242 +				const struct pcidev_sbdf_node *sbdf_node,
   2.243 +				int options)
   2.244 +{
   2.245 +	return (options & GUESTDEV_OPT_IOMUL) &&
   2.246 +		((gdev_node->child != NULL &&
   2.247 +		  sbdf_node->child != NULL &&
   2.248 +		  gdev_node->dev == sbdf_node->dev &&
   2.249 +		  gdev_node->func == sbdf_node->func) ||
   2.250 +		 (gdev_node->child == NULL &&
   2.251 +		  sbdf_node->child == NULL &&
   2.252 +		  gdev_node->dev == sbdf_node->dev));
   2.253 +}
   2.254 +
   2.255 +static int pci_iomul_sbdf_match(const struct guestdev *gdev,
   2.256 +				const struct pci_dev *dev)
   2.257 +{
   2.258 +	int seg, bus;
   2.259 +
   2.260 +	if (sscanf(dev->dev.bus_id, "%04x:%02x", &seg, &bus) != 2)
   2.261 +		return FALSE;
   2.262 +
   2.263 +	return (gdev->options & GUESTDEV_OPT_IOMUL) &&
   2.264 +		gdev->u.sbdf.seg == seg &&
   2.265 +		gdev->u.sbdf.bus == bus &&
   2.266 +		gdev->u.sbdf.dev == PCI_SLOT(dev->devfn);
   2.267 +}
   2.268 +
   2.269 +int pci_is_iomuldev(struct pci_dev *dev)
   2.270 +{
   2.271 +	return __pci_is_guestdev(dev,
   2.272 +				 pci_iomul_node_match, pci_iomul_sbdf_match);
   2.273 +}
   2.274 +EXPORT_SYMBOL_GPL(pci_is_iomuldev);
   2.275 +#endif /* CONFIG_PCI_IOMULTI */
   2.276 +
   2.277  /* Check whether the devicepath exists under the pci root bus */
   2.278  static int __init pci_check_devicepath_exists(
   2.279  		struct guestdev *gdev, struct pci_bus *bus)
     3.1 --- a/drivers/pci/iomulti.c	Thu May 28 09:57:49 2009 +0100
     3.2 +++ b/drivers/pci/iomulti.c	Thu May 28 09:59:18 2009 +0100
     3.3 @@ -27,6 +27,7 @@
     3.4  #include <asm/setup.h>
     3.5  #include <asm/uaccess.h>
     3.6  
     3.7 +#include "pci.h"
     3.8  #include "iomulti.h"
     3.9  
    3.10  #define PCI_NUM_BARS		6
    3.11 @@ -423,7 +424,8 @@ static int pci_is_iomul_dev_param(struct
    3.12  			break;
    3.13  	}
    3.14  
    3.15 -	return 0;
    3.16 +	/* check guestcev=<device>+iomul option */
    3.17 +	return pci_is_iomuldev(pdev);
    3.18  }
    3.19  
    3.20  /*
     4.1 --- a/drivers/pci/pci.h	Thu May 28 09:57:49 2009 +0100
     4.2 +++ b/drivers/pci/pci.h	Thu May 28 09:59:18 2009 +0100
     4.3 @@ -105,9 +105,13 @@ pci_match_one_device(const struct pci_de
     4.4  extern void pci_disable_bridge_window(struct pci_dev *dev);
     4.5  #endif
     4.6  #ifdef CONFIG_PCI_GUESTDEV
     4.7 +extern int pci_is_guestdev(struct pci_dev *dev);
     4.8  extern int pci_is_reassigndev(struct pci_dev *dev);
     4.9 +extern int pci_is_iomuldev(struct pci_dev *dev);
    4.10  #else
    4.11 -#define pci_is_reassigndev(dev) 0
    4.12 +#define pci_is_guestdev(dev)	0
    4.13 +#define pci_is_reassigndev(dev)	0
    4.14 +#define pci_is_iomuldev(dev)	0
    4.15  #endif
    4.16  
    4.17  #ifdef CONFIG_PCI_GUESTDEV