[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH 3/5] take 2: PCIe IO space multiplexing: Linux part: guestdev kernel paremeter enhance



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

Attachment: guestdev-iomul.patch
Description: Text Data

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel

 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.