109 lines
3.1 KiB
Diff
109 lines
3.1 KiB
Diff
|
References: bnc#787169
|
||
|
|
||
|
# HG changeset patch
|
||
|
# User Jan Beulich <jbeulich@suse.com>
|
||
|
# Date 1357559889 -3600
|
||
|
# Node ID 23c4bbc0111dd807561b2c62cbc5798220943a0d
|
||
|
# Parent b514b7118958327605e33dd387944832bc8d734a
|
||
|
IOMMU: add option to specify devices behaving like ones using phantom functions
|
||
|
|
||
|
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>
|
||
|
|
||
|
--- a/docs/misc/xen-command-line.markdown
|
||
|
+++ b/docs/misc/xen-command-line.markdown
|
||
|
@@ -672,6 +672,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>`
|
||
|
|
||
|
--- a/xen/drivers/passthrough/pci.c
|
||
|
+++ b/xen/drivers/passthrough/pci.c
|
||
|
@@ -123,6 +123,49 @@ const unsigned long *pci_get_ro_map(u16
|
||
|
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;
|
||
|
@@ -183,6 +226,20 @@ static struct pci_dev *alloc_pdev(struct
|
||
|
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:
|