pci/guestdev: enhance guestdev to accept +iomul.
enhance guestdev to accept +iomul and use it.
Signed-off-by: Isaku Yamahata <yamahata@xxxxxxxxxxxxx>
diff --git a/Documentation/kernel-parameters.txt
b/Documentation/kernel-parameters.txt
--- a/Documentation/kernel-parameters.txt
+++ b/Documentation/kernel-parameters.txt
@@ -577,11 +577,15 @@ running once the system is up.
guestdev= [PCI,ACPI]
Format: {<device path>|<sbdf>}][,{<device
path>|<sbdf>}[,...]]
- Format of device path:
<hid>[:<uid>]-<dev>.<func>[-<dev>.<func>[,...]]
- Format of sbdf: [<segment>:]<bus>:<dev>.<func>
+ Format of device path:
<hid>[:<uid>]-<dev>.<func>[-<dev>.<func>[,...]][+iomul]
+ Format of sbdf: [<segment>:]<bus>:<dev>.<func>[+iomul]
Specifies PCI device for guest domain.
If PCI-PCI bridge is specified, all PCI devices
behind PCI-PCI bridge are reserved.
+ +iomul means that this PCI function will share
+ IO ports with other +iomul functions under same
+ switch. NOTE: if +iomul is specfied, all the functions
+ of the device will share IO ports.
guestiomuldev= [PCI]
Format: [sbd][,<sbd>][,...]
diff --git a/drivers/pci/guestdev.c b/drivers/pci/guestdev.c
--- a/drivers/pci/guestdev.c
+++ b/drivers/pci/guestdev.c
@@ -1,5 +1,7 @@
/*
* Copyright (c) 2008, 2009 NEC Corporation.
+ * Copyright (c) 2009 Isaku Yamahata
+ * VA Linux Systems Japan K.K.
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU General Public License,
@@ -38,8 +40,11 @@
#define GUESTDEV_FLAG_DEVICEPATH 0x1
#define GUESTDEV_FLAG_SBDF 0x2
+#define GUESTDEV_OPT_IOMUL 0x1
+
struct guestdev {
int flags;
+ int options;
struct list_head root_list;
union {
struct devicepath {
@@ -276,6 +281,7 @@ struct guestdev __init *pci_copy_guestde
memset(gdev, 0, sizeof(*gdev));
INIT_LIST_HEAD(&gdev->root_list);
gdev->flags = gdev_src->flags;
+ gdev->options = gdev_src->options;
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;
@@ -309,7 +315,7 @@ allocate_err_end:
}
/* Make guestdev from path strings */
-static int __init pci_make_devicepath_guestdev(char *path_str)
+static int __init pci_make_devicepath_guestdev(char *path_str, int options)
{
char hid[HID_LEN + 1], uid[UID_LEN + 1];
char *sp, *ep;
@@ -337,6 +343,7 @@ static int __init pci_make_devicepath_gu
memset(gdev_org, 0, sizeof(*gdev_org));
INIT_LIST_HEAD(&gdev_org->root_list);
gdev_org->flags = GUESTDEV_FLAG_DEVICEPATH;
+ gdev_org->options = options;
strcpy(gdev_org->u.devicepath.hid, hid);
strcpy(gdev_org->u.devicepath.uid, uid);
gdev_org->u.devicepath.seg = INVALID_SEG;
@@ -436,7 +443,7 @@ end:
return ret_val;
}
-static int __init pci_make_sbdf_guestdev(char* str)
+static int __init pci_make_sbdf_guestdev(char* str, int options)
{
struct guestdev *gdev;
int seg, bus, dev, func;
@@ -453,6 +460,7 @@ static int __init pci_make_sbdf_guestdev
}
INIT_LIST_HEAD(&gdev->root_list);
gdev->flags = GUESTDEV_FLAG_SBDF;
+ gdev->options = options;
gdev->u.sbdf.seg = seg;
gdev->u.sbdf.bus = bus;
gdev->u.sbdf.dev = dev;
@@ -461,11 +469,31 @@ static int __init pci_make_sbdf_guestdev
return 0;
}
+static int __init pci_parse_options(const char *str)
+{
+ int options = 0;
+ char *ep;
+
+ while (str) {
+ str++;
+ ep = strchr(str, '+');
+ if (ep)
+ ep = '\0'; /* Chop */
+
+ if (!strcmp(str, "iomul"))
+ options |= GUESTDEV_OPT_IOMUL;
+
+ str = ep;
+ }
+ return options;
+}
+
/* Parse guestdev parameter */
static int __init pci_parse_guestdev(void)
{
int len;
- char *sp, *ep;
+ char *sp, *ep, *op;
+ int options;
struct list_head *head;
struct guestdev *gdev;
char path_str[GUESTDEV_STR_MAX];
@@ -482,16 +510,26 @@ static int __init pci_parse_guestdev(voi
/* Chop */
if (ep)
*ep = '\0';
- ret_val = pci_make_sbdf_guestdev(sp);
+ options = 0;
+ op = strchr(sp, '+');
+ if (op && (!ep || op < ep)) {
+ options = pci_parse_options(op);
+ *op = '\0'; /* Chop */
+ }
+ ret_val = pci_make_sbdf_guestdev(sp, options);
if (ret_val == -EINVAL) {
if (pci_check_extended_guestdev_format(sp)) {
- ret_val = pci_make_devicepath_guestdev(sp);
+ ret_val = pci_make_devicepath_guestdev(
+ sp, options);
if (ret_val && ret_val != -EINVAL)
break;
}
} else if (ret_val)
break;
- sp = ep + 1;
+
+ if (ep)
+ ep++;
+ sp = ep;
} while (ep);
list_for_each(head, &guestdev_list) {
@@ -532,8 +570,21 @@ static void pci_free_sbdf(struct pcidev_
}
/* Does PCI device belong to sub tree specified by guestdev with device path?
*/
+typedef int (*pci_node_match_t)(const struct devicepath_node *gdev_node,
+ const struct pcidev_sbdf_node *sbdf_node,
+ int options);
+
+static int pci_node_match(const struct devicepath_node *gdev_node,
+ const struct pcidev_sbdf_node *sbdf_node,
+ int options_unused)
+{
+ return (gdev_node->dev == sbdf_node->dev &&
+ gdev_node->func == sbdf_node->func);
+}
+
static int pci_is_in_devicepath_sub_tree(struct guestdev *gdev,
- struct pcidev_sbdf *sbdf)
+ struct pcidev_sbdf *sbdf,
+ pci_node_match_t match)
{
int seg, bbn;
struct devicepath_node *gdev_node;
@@ -566,8 +617,7 @@ static int pci_is_in_devicepath_sub_tree
while (gdev_node) {
if (!sbdf_node)
return FALSE;
- if (gdev_node->dev != sbdf_node->dev ||
- gdev_node->func != sbdf_node->func)
+ if (!match(gdev_node, sbdf_node, gdev->options))
return FALSE;
gdev_node = gdev_node->child;
sbdf_node = sbdf_node->child;
@@ -616,16 +666,29 @@ err_end:
}
/* 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)
+typedef int (*pci_sbdf_match_t)(const struct guestdev *gdev,
+ const struct pci_dev *dev);
+
+static int pci_sbdf_match(const struct guestdev *gdev,
+ const struct pci_dev *dev)
{
int seg, bus;
+
+ if (sscanf(dev->dev.bus_id, "%04x:%02x", &seg, &bus) != 2)
+ return FALSE;
+
+ return 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);
+}
+
+static int pci_is_in_sbdf_sub_tree(struct guestdev *gdev, struct pci_dev *dev,
+ pci_sbdf_match_t match)
+{
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))
+ if (match(gdev, dev))
return TRUE;
if (!dev->bus || !dev->bus->self)
break;
@@ -635,7 +698,8 @@ static int pci_is_in_sbdf_sub_tree(struc
}
/* Does PCI device belong to sub tree specified by guestdev parameter? */
-int pci_is_guestdev(struct pci_dev *dev)
+static int __pci_is_guestdev(struct pci_dev *dev, pci_node_match_t node_match,
+ pci_sbdf_match_t sbdf_match)
{
struct guestdev *gdev;
struct pcidev_sbdf pcidev_sbdf, *sbdf = NULL;
@@ -655,13 +719,14 @@ int pci_is_guestdev(struct pci_dev *dev)
if (!pci_get_sbdf_from_pcidev(dev, sbdf))
goto out;
}
- if (pci_is_in_devicepath_sub_tree(gdev, sbdf)) {
+ if (pci_is_in_devicepath_sub_tree(gdev, sbdf,
+ node_match)) {
result = TRUE;
goto out;
}
break;
case GUESTDEV_FLAG_SBDF:
- if (pci_is_in_sbdf_sub_tree(gdev, dev)) {
+ if (pci_is_in_sbdf_sub_tree(gdev, dev, sbdf_match)) {
result = TRUE;
goto out;
}
@@ -675,6 +740,11 @@ out:
pci_free_sbdf(sbdf);
return result;
}
+
+int pci_is_guestdev(struct pci_dev *dev)
+{
+ return __pci_is_guestdev(dev, pci_node_match, pci_sbdf_match);
+}
EXPORT_SYMBOL(pci_is_guestdev);
static int __init pci_set_reassign_resources(char *str)
@@ -694,6 +764,43 @@ int pci_is_reassigndev(struct pci_dev *d
}
EXPORT_SYMBOL(pci_is_reassigndev);
+#ifdef CONFIG_PCI_IOMULTI
+static int pci_iomul_node_match(const struct devicepath_node *gdev_node,
+ const struct pcidev_sbdf_node *sbdf_node,
+ int options)
+{
+ return (options & GUESTDEV_OPT_IOMUL) &&
+ ((gdev_node->child != NULL &&
+ sbdf_node->child != NULL &&
+ gdev_node->dev == sbdf_node->dev &&
+ gdev_node->func == sbdf_node->func) ||
+ (gdev_node->child == NULL &&
+ sbdf_node->child == NULL &&
+ gdev_node->dev == sbdf_node->dev));
+}
+
+static int pci_iomul_sbdf_match(const struct guestdev *gdev,
+ const struct pci_dev *dev)
+{
+ int seg, bus;
+
+ if (sscanf(dev->dev.bus_id, "%04x:%02x", &seg, &bus) != 2)
+ return FALSE;
+
+ return (gdev->options & GUESTDEV_OPT_IOMUL) &&
+ gdev->u.sbdf.seg == seg &&
+ gdev->u.sbdf.bus == bus &&
+ gdev->u.sbdf.dev == PCI_SLOT(dev->devfn);
+}
+
+int pci_is_iomuldev(struct pci_dev *dev)
+{
+ return __pci_is_guestdev(dev,
+ pci_iomul_node_match, pci_iomul_sbdf_match);
+}
+EXPORT_SYMBOL_GPL(pci_is_iomuldev);
+#endif /* CONFIG_PCI_IOMULTI */
+
/* Check whether the devicepath exists under the pci root bus */
static int __init pci_check_devicepath_exists(
struct guestdev *gdev, struct pci_bus *bus)
diff --git a/drivers/pci/iomulti.c b/drivers/pci/iomulti.c
--- a/drivers/pci/iomulti.c
+++ b/drivers/pci/iomulti.c
@@ -27,6 +27,7 @@
#include <asm/setup.h>
#include <asm/uaccess.h>
+#include "pci.h"
#include "iomulti.h"
#define PCI_NUM_BARS 6
@@ -423,7 +424,8 @@ static int pci_is_iomul_dev_param(struct
break;
}
- return 0;
+ /* check guestcev=<device>+iomul option */
+ return pci_is_iomuldev(pdev);
}
/*
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -105,9 +105,13 @@ pci_match_one_device(const struct pci_de
extern void pci_disable_bridge_window(struct pci_dev *dev);
#endif
#ifdef CONFIG_PCI_GUESTDEV
+extern int pci_is_guestdev(struct pci_dev *dev);
extern int pci_is_reassigndev(struct pci_dev *dev);
+extern int pci_is_iomuldev(struct pci_dev *dev);
#else
-#define pci_is_reassigndev(dev) 0
+#define pci_is_guestdev(dev) 0
+#define pci_is_reassigndev(dev) 0
+#define pci_is_iomuldev(dev) 0
#endif
#ifdef CONFIG_PCI_GUESTDEV
guestdev-iomul.patch
Description: Text Data
_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel
|