diff options
-rw-r--r-- | docs/misc/xen-command-line.markdown | 14 | ||||
-rw-r--r-- | xen/common/kernel.c | 16 | ||||
-rw-r--r-- | xen/drivers/passthrough/amd/iommu_acpi.c | 88 | ||||
-rw-r--r-- | xen/include/asm-x86/hvm/svm/amd-iommu-proto.h | 1 |
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; |