aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJan Beulich <jbeulich@suse.com>2013-08-29 09:53:07 +0200
committerJan Beulich <jbeulich@suse.com>2013-08-29 09:53:07 +0200
commitfb3f1c1855bd9aca625bc0d040be4cdcc216e958 (patch)
treeeda55e638eae9594ed35e469842a95c082b49d2b
parent3785d30efe8264b899499e0883b10cc434bd0959 (diff)
downloadxen-fb3f1c1855bd9aca625bc0d040be4cdcc216e958.tar.gz
xen-fb3f1c1855bd9aca625bc0d040be4cdcc216e958.tar.bz2
xen-fb3f1c1855bd9aca625bc0d040be4cdcc216e958.zip
AMD IOMMU: allow command line overrides for broken IVRS tables
With there being so many systems with broken ACPI tables, and with it generally being known what's wrong with those tables, give people a handle to overcome the resulting disabling of their IOMMUs. Inspired by Linux side patches providing similar functionality. Suggested-by: Sander Eikelenboom <linux@eikelenboom.it> Signed-off-by: Jan Beulich <jbeulich@suse.com> Tested-By: Sander Eikelenboom <linux@eikelenboom.it> Acked-by: Keir Fraser <keir@xen.org> Acked-by: Suravee Suthikulpanit <suravee.suthikulapanit@amd.com>
-rw-r--r--docs/misc/xen-command-line.markdown14
-rw-r--r--xen/common/kernel.c16
-rw-r--r--xen/drivers/passthrough/amd/iommu_acpi.c88
-rw-r--r--xen/include/asm-x86/hvm/svm/amd-iommu-proto.h1
4 files changed, 101 insertions, 18 deletions
diff --git a/docs/misc/xen-command-line.markdown b/docs/misc/xen-command-line.markdown
index 13c0306c61..a86014b4d6 100644
--- a/docs/misc/xen-command-line.markdown
+++ b/docs/misc/xen-command-line.markdown
@@ -578,6 +578,20 @@ debug hypervisor only).
> `= <integer>`
### irq\_vector\_map
+### ivrs_hpet[`<hpet>`]
+> `=[<seg>:]<bus>:<device>.<func>`
+
+Force the use of `[<seg>:]<bus>:<device>.<func>` as device ID of HPET
+`<hpet>` instead of the one specified by the IVHD sub-tables of the IVRS
+ACPI table.
+
+### ivrs_ioapic[`<ioapic>`]
+> `=[<seg>:]<bus>:<device>.<func>`
+
+Force the use of `[<seg>:]<bus>:<device>.<func>` as device ID of IO-APIC
+`<ioapic>` instead of the one specified by the IVHD sub-tables of the IVRS
+ACPI table.
+
### lapic
Force the use of use of the local APIC on a uniprocessor system, even
diff --git a/xen/common/kernel.c b/xen/common/kernel.c
index 72fb9055b1..b8707d90a1 100644
--- a/xen/common/kernel.c
+++ b/xen/common/kernel.c
@@ -81,9 +81,15 @@ void __init cmdline_parse(const char *cmdline)
/* Search for value part of a key=value option. */
optval = strchr(opt, '=');
if ( optval != NULL )
+ {
*optval++ = '\0'; /* nul-terminate the option value */
+ q = strpbrk(opt, "([{<");
+ }
else
+ {
optval = q; /* default option value is empty string */
+ q = NULL;
+ }
/* Boolean parameters can be inverted with 'no-' prefix. */
bool_assert = !!strncmp("no-", optkey, 3);
@@ -93,7 +99,17 @@ void __init cmdline_parse(const char *cmdline)
for ( param = &__setup_start; param < &__setup_end; param++ )
{
if ( strcmp(param->name, optkey) )
+ {
+ if ( param->type == OPT_CUSTOM && q &&
+ strlen(param->name) == q + 1 - opt &&
+ !strncmp(param->name, opt, q + 1 - opt) )
+ {
+ optval[-1] = '=';
+ ((void (*)(const char *))param->var)(q);
+ optval[-1] = '\0';
+ }
continue;
+ }
switch ( param->type )
{
diff --git a/xen/drivers/passthrough/amd/iommu_acpi.c b/xen/drivers/passthrough/amd/iommu_acpi.c
index c903f9385c..89b359c455 100644
--- a/xen/drivers/passthrough/amd/iommu_acpi.c
+++ b/xen/drivers/passthrough/amd/iommu_acpi.c
@@ -633,6 +633,50 @@ static u16 __init parse_ivhd_device_extended_range(
return dev_length;
}
+static __initdata DECLARE_BITMAP(ioapic_cmdline, ARRAY_SIZE(ioapic_sbdf));
+
+static void __init parse_ivrs_ioapic(char *str)
+{
+ const char *s = str;
+ unsigned long id;
+ unsigned int seg, bus, dev, func;
+
+ ASSERT(*s == '[');
+ id = simple_strtoul(s + 1, &s, 0);
+ if ( id >= ARRAY_SIZE(ioapic_sbdf) || *s != ']' || *++s != '=' )
+ return;
+
+ s = parse_pci(s + 1, &seg, &bus, &dev, &func);
+ if ( !s || *s )
+ return;
+
+ ioapic_sbdf[id].bdf = PCI_BDF(bus, dev, func);
+ ioapic_sbdf[id].seg = seg;
+ __set_bit(id, ioapic_cmdline);
+}
+custom_param("ivrs_ioapic[", parse_ivrs_ioapic);
+
+static void __init parse_ivrs_hpet(char *str)
+{
+ const char *s = str;
+ unsigned long id;
+ unsigned int seg, bus, dev, func;
+
+ ASSERT(*s == '[');
+ id = simple_strtoul(s + 1, &s, 0);
+ if ( id != (typeof(hpet_sbdf.id))id || *s != ']' || *++s != '=' )
+ return;
+
+ s = parse_pci(s + 1, &seg, &bus, &dev, &func);
+ if ( !s || *s )
+ return;
+
+ hpet_sbdf.bdf = PCI_BDF(bus, dev, func);
+ hpet_sbdf.seg = seg;
+ hpet_sbdf.cmdline = 1;
+}
+custom_param("ivrs_hpet[", parse_ivrs_hpet);
+
static u16 __init parse_ivhd_device_special(
const struct acpi_ivrs_device8c *special, u16 seg,
u16 header_length, u16 block_length, struct amd_iommu *iommu)
@@ -681,7 +725,10 @@ static u16 __init parse_ivhd_device_special(
return 0;
}
- if ( ioapic_sbdf[special->handle].pin_2_idx )
+ if ( test_bit(special->handle, ioapic_cmdline) )
+ AMD_IOMMU_DEBUG("IVHD: Command line override present for IO-APIC %#x\n",
+ special->handle);
+ else if ( ioapic_sbdf[special->handle].pin_2_idx )
{
if ( ioapic_sbdf[special->handle].bdf == bdf &&
ioapic_sbdf[special->handle].seg == seg )
@@ -724,14 +771,18 @@ static u16 __init parse_ivhd_device_special(
break;
case ACPI_IVHD_HPET:
/* set device id of hpet */
- if ( hpet_sbdf.iommu )
+ if ( hpet_sbdf.iommu ||
+ (hpet_sbdf.cmdline && hpet_sbdf.id != special->handle) )
{
printk(XENLOG_WARNING "Only one IVHD HPET entry is supported\n");
break;
}
hpet_sbdf.id = special->handle;
- hpet_sbdf.bdf = bdf;
- hpet_sbdf.seg = seg;
+ if ( !hpet_sbdf.cmdline )
+ {
+ hpet_sbdf.bdf = bdf;
+ hpet_sbdf.seg = seg;
+ }
hpet_sbdf.iommu = iommu;
break;
default:
@@ -942,22 +993,23 @@ static int __init parse_ivrs_table(struct acpi_table_header *table)
ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx )
continue;
- printk(XENLOG_ERR "IVHD Error: no information for IO-APIC %#x\n",
- IO_APIC_ID(apic));
- if ( amd_iommu_perdev_intremap )
- error = -ENXIO;
+ if ( !test_bit(IO_APIC_ID(apic), ioapic_cmdline) )
+ {
+ printk(XENLOG_ERR "IVHD Error: no information for IO-APIC %#x\n",
+ IO_APIC_ID(apic));
+ if ( amd_iommu_perdev_intremap )
+ return -ENXIO;
+ }
+
+ ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx = xmalloc_array(
+ u16, nr_ioapic_entries[apic]);
+ if ( ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx )
+ memset(ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx, -1,
+ nr_ioapic_entries[apic] * sizeof(*ioapic_sbdf->pin_2_idx));
else
{
- ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx = xmalloc_array(
- u16, nr_ioapic_entries[apic]);
- if ( ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx )
- memset(ioapic_sbdf[IO_APIC_ID(apic)].pin_2_idx, -1,
- nr_ioapic_entries[apic] * sizeof(*ioapic_sbdf->pin_2_idx));
- else
- {
- printk(XENLOG_ERR "IVHD Error: Out of memory\n");
- error = -ENOMEM;
- }
+ printk(XENLOG_ERR "IVHD Error: Out of memory\n");
+ error = -ENOMEM;
}
}
diff --git a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
index 7736ff4d68..3e6961d5c0 100644
--- a/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
+++ b/xen/include/asm-x86/hvm/svm/amd-iommu-proto.h
@@ -108,6 +108,7 @@ extern struct ioapic_sbdf {
extern struct hpet_sbdf {
u16 bdf, seg, id;
+ bool_t cmdline;
struct amd_iommu *iommu;
} hpet_sbdf;