]> xenbits.xensource.com Git - people/aperard/xen-arm.git/commitdiff
IOMMU: add option to specify devices behaving like ones using phantom functions
authorJan Beulich <jbeulich@suse.com>
Mon, 7 Jan 2013 11:58:09 +0000 (12:58 +0100)
committerJan Beulich <jbeulich@suse.com>
Mon, 7 Jan 2013 11:58:09 +0000 (12:58 +0100)
At least certain Marvell SATA controllers are known to issue bus master
requests with a non-zero function as origin, despite themselves being
single function devices.

Signed-off-by: Jan Beulich <jbeulich@suse.com>
Acked-by: "Zhang, Xiantao" <xiantao.zhang@intel.com>
docs/misc/xen-command-line.markdown
xen/drivers/passthrough/pci.c

index 443685e904df708bbbaf18d54f2da00e960dd23f..6ad63094b2a01a1300afc8e3d9c0424341d33ed4 100644 (file)
@@ -703,6 +703,16 @@ Defaults to booting secondary processors.
 
 Default: `on`
 
+### pci-phantom
+> `=[<seg>:]<bus>:<device>,<stride>`
+
+Mark a group of PCI devices as using phantom functions without actually
+advertising so, so the IOMMU can create translation contexts for them.
+
+All numbers specified must be hexadecimal ones.
+
+This option can be specified more than once (up to 8 times at present).
+
 ### ple\_gap
 > `= <integer>`
 
index cd708f342782d6df0d09bc560fe3d9a82d1419d0..49d4709a477d3341a797742dbe4123f64ad50f96 100644 (file)
@@ -121,6 +121,49 @@ const unsigned long *pci_get_ro_map(u16 seg)
     return pseg ? pseg->ro_map : NULL;
 }
 
+static struct phantom_dev {
+    u16 seg;
+    u8 bus, slot, stride;
+} phantom_devs[8];
+static unsigned int nr_phantom_devs;
+
+static void __init parse_phantom_dev(char *str) {
+    const char *s = str;
+    struct phantom_dev phantom;
+
+    if ( !s || !*s || nr_phantom_devs >= ARRAY_SIZE(phantom_devs) )
+        return;
+
+    phantom.seg = simple_strtol(s, &s, 16);
+    if ( *s != ':' )
+        return;
+
+    phantom.bus = simple_strtol(s + 1, &s, 16);
+    if ( *s == ',' )
+    {
+        phantom.slot = phantom.bus;
+        phantom.bus = phantom.seg;
+        phantom.seg = 0;
+    }
+    else if ( *s == ':' )
+        phantom.slot = simple_strtol(s + 1, &s, 16);
+    else
+        return;
+
+    if ( *s != ',' )
+        return;
+    switch ( phantom.stride = simple_strtol(s + 1, &s, 0) )
+    {
+    case 1: case 2: case 4:
+        if ( *s )
+    default:
+            return;
+    }
+
+    phantom_devs[nr_phantom_devs++] = phantom;
+}
+custom_param("pci-phantom", parse_phantom_dev);
+
 static struct pci_dev *alloc_pdev(struct pci_seg *pseg, u8 bus, u8 devfn)
 {
     struct pci_dev *pdev;
@@ -181,6 +224,20 @@ static struct pci_dev *alloc_pdev(struct pci_seg *pseg, u8 bus, u8 devfn)
                 if ( PCI_FUNC(devfn) >= pdev->phantom_stride )
                     pdev->phantom_stride = 0;
             }
+            else
+            {
+                unsigned int i;
+
+                for ( i = 0; i < nr_phantom_devs; ++i )
+                    if ( phantom_devs[i].seg == pseg->nr &&
+                         phantom_devs[i].bus == bus &&
+                         phantom_devs[i].slot == PCI_SLOT(devfn) &&
+                         phantom_devs[i].stride > PCI_FUNC(devfn) )
+                    {
+                        pdev->phantom_stride = phantom_devs[i].stride;
+                        break;
+                    }
+            }
             break;
 
         case DEV_TYPE_PCI: