From a491cc902ca495365e9cd45154b60d8c702d86da Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 9 Jun 2014 16:19:32 +0800 Subject: x86, mpparse: Simplify arch/x86/include/asm/mpspec.h Simplify arch/x86/include/asm/mpspec.h by 1) Change max_physical_apicid to static as it's only used in apic.c. 2) Kill declaration of mpc_default_type, it's never defined. 3) Delete default_acpi_madt_oem_check(), it has already been declared in apic.h. 4) Make default_acpi_madt_oem_check() depends on CONFIG_X86_LOCAL_APIC instead of CONFIG_X86_64 to support i386. 5) Change mp_override_legacy_irq(), mp_config_acpi_legacy_irqs() and mp_register_gsi() as static because they are only used in acpi/boot.c. Signed-off-by: Jiang Liu Acked-by: David Rientjes Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Greg Kroah-Hartman Cc: H. Peter Anvin Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Len Brown Cc: Pavel Machek Cc: Seiji Aguchi Cc: HATAYAMA Daisuke Cc: Paul Gortmaker Cc: Richard Weinberger Cc: Andi Kleen Link: http://lkml.kernel.org/r/1402302011-23642-4-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/acpi/boot.c | 12 +++++++++--- 1 file changed, 9 insertions(+), 3 deletions(-) (limited to 'arch/x86/kernel/acpi/boot.c') diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 86281ffb96d6..b41b47021f53 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -345,6 +345,10 @@ acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long e #endif /*CONFIG_X86_LOCAL_APIC */ #ifdef CONFIG_X86_IO_APIC +static void mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, + u32 gsi); +static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, + int polarity); static int __init acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end) @@ -903,7 +907,8 @@ static int __init acpi_parse_madt_lapic_entries(void) #ifdef CONFIG_X86_IO_APIC #define MP_ISA_BUS 0 -void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi) +static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, + u32 gsi) { int ioapic; int pin; @@ -938,7 +943,7 @@ void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi) isa_irq_to_gsi[bus_irq] = gsi; } -void __init mp_config_acpi_legacy_irqs(void) +static void __init mp_config_acpi_legacy_irqs(void) { int i; struct mpc_intsrc mp_irq; @@ -1040,7 +1045,8 @@ static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger, return 0; } -int mp_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) +static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, + int polarity) { int ioapic; int ioapic_pin; -- cgit v1.2.3 From 8d7cdcb9d8f366c0567b66cce0d5ce37d3311aaf Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 9 Jun 2014 16:19:33 +0800 Subject: x86, acpi: Reorganize code to avoid forward declaration in boot.c Reorganize code to avoid forward declaration in boot.c, no function changes. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Len Brown Cc: Pavel Machek Link: http://lkml.kernel.org/r/1402302011-23642-5-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/acpi/boot.c | 236 ++++++++++++++++++++++---------------------- 1 file changed, 116 insertions(+), 120 deletions(-) (limited to 'arch/x86/kernel/acpi/boot.c') diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index b41b47021f53..ceb3b36f2b2c 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -345,10 +345,123 @@ acpi_parse_lapic_nmi(struct acpi_subtable_header * header, const unsigned long e #endif /*CONFIG_X86_LOCAL_APIC */ #ifdef CONFIG_X86_IO_APIC -static void mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, - u32 gsi); +#define MP_ISA_BUS 0 + +static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, + u32 gsi) +{ + int ioapic; + int pin; + struct mpc_intsrc mp_irq; + + /* + * Convert 'gsi' to 'ioapic.pin'. + */ + ioapic = mp_find_ioapic(gsi); + if (ioapic < 0) + return; + pin = mp_find_ioapic_pin(ioapic, gsi); + + /* + * TBD: This check is for faulty timer entries, where the override + * erroneously sets the trigger to level, resulting in a HUGE + * increase of timer interrupts! + */ + if ((bus_irq == 0) && (trigger == 3)) + trigger = 1; + + mp_irq.type = MP_INTSRC; + mp_irq.irqtype = mp_INT; + mp_irq.irqflag = (trigger << 2) | polarity; + mp_irq.srcbus = MP_ISA_BUS; + mp_irq.srcbusirq = bus_irq; /* IRQ */ + mp_irq.dstapic = mpc_ioapic_id(ioapic); /* APIC ID */ + mp_irq.dstirq = pin; /* INTIN# */ + + mp_save_irq(&mp_irq); + + isa_irq_to_gsi[bus_irq] = gsi; +} + +static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger, + int polarity) +{ +#ifdef CONFIG_X86_MPPARSE + struct mpc_intsrc mp_irq; + struct pci_dev *pdev; + unsigned char number; + unsigned int devfn; + int ioapic; + u8 pin; + + if (!acpi_ioapic) + return 0; + if (!dev || !dev_is_pci(dev)) + return 0; + + pdev = to_pci_dev(dev); + number = pdev->bus->number; + devfn = pdev->devfn; + pin = pdev->pin; + /* print the entry should happen on mptable identically */ + mp_irq.type = MP_INTSRC; + mp_irq.irqtype = mp_INT; + mp_irq.irqflag = (trigger == ACPI_EDGE_SENSITIVE ? 4 : 0x0c) | + (polarity == ACPI_ACTIVE_HIGH ? 1 : 3); + mp_irq.srcbus = number; + mp_irq.srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3); + ioapic = mp_find_ioapic(gsi); + mp_irq.dstapic = mpc_ioapic_id(ioapic); + mp_irq.dstirq = mp_find_ioapic_pin(ioapic, gsi); + + mp_save_irq(&mp_irq); +#endif + return 0; +} + static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, - int polarity); + int polarity) +{ + int ioapic; + int ioapic_pin; + struct io_apic_irq_attr irq_attr; + int ret; + + if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC) + return gsi; + + /* Don't set up the ACPI SCI because it's already set up */ + if (acpi_gbl_FADT.sci_interrupt == gsi) + return gsi; + + ioapic = mp_find_ioapic(gsi); + if (ioapic < 0) { + printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi); + return gsi; + } + + ioapic_pin = mp_find_ioapic_pin(ioapic, gsi); + + if (ioapic_pin > MP_MAX_IOAPIC_PIN) { + printk(KERN_ERR "Invalid reference to IOAPIC pin " + "%d-%d\n", mpc_ioapic_id(ioapic), + ioapic_pin); + return gsi; + } + + if (enable_update_mptable) + mp_config_acpi_gsi(dev, gsi, trigger, polarity); + + set_io_apic_irq_attr(&irq_attr, ioapic, ioapic_pin, + trigger == ACPI_EDGE_SENSITIVE ? 0 : 1, + polarity == ACPI_ACTIVE_HIGH ? 0 : 1); + ret = io_apic_set_pci_routing(dev, gsi_to_irq(gsi), &irq_attr); + if (ret < 0) + gsi = INT_MIN; + + return gsi; +} + static int __init acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end) @@ -905,44 +1018,6 @@ static int __init acpi_parse_madt_lapic_entries(void) #endif /* CONFIG_X86_LOCAL_APIC */ #ifdef CONFIG_X86_IO_APIC -#define MP_ISA_BUS 0 - -static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, - u32 gsi) -{ - int ioapic; - int pin; - struct mpc_intsrc mp_irq; - - /* - * Convert 'gsi' to 'ioapic.pin'. - */ - ioapic = mp_find_ioapic(gsi); - if (ioapic < 0) - return; - pin = mp_find_ioapic_pin(ioapic, gsi); - - /* - * TBD: This check is for faulty timer entries, where the override - * erroneously sets the trigger to level, resulting in a HUGE - * increase of timer interrupts! - */ - if ((bus_irq == 0) && (trigger == 3)) - trigger = 1; - - mp_irq.type = MP_INTSRC; - mp_irq.irqtype = mp_INT; - mp_irq.irqflag = (trigger << 2) | polarity; - mp_irq.srcbus = MP_ISA_BUS; - mp_irq.srcbusirq = bus_irq; /* IRQ */ - mp_irq.dstapic = mpc_ioapic_id(ioapic); /* APIC ID */ - mp_irq.dstirq = pin; /* INTIN# */ - - mp_save_irq(&mp_irq); - - isa_irq_to_gsi[bus_irq] = gsi; -} - static void __init mp_config_acpi_legacy_irqs(void) { int i; @@ -1009,85 +1084,6 @@ static void __init mp_config_acpi_legacy_irqs(void) } } -static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger, - int polarity) -{ -#ifdef CONFIG_X86_MPPARSE - struct mpc_intsrc mp_irq; - struct pci_dev *pdev; - unsigned char number; - unsigned int devfn; - int ioapic; - u8 pin; - - if (!acpi_ioapic) - return 0; - if (!dev || !dev_is_pci(dev)) - return 0; - - pdev = to_pci_dev(dev); - number = pdev->bus->number; - devfn = pdev->devfn; - pin = pdev->pin; - /* print the entry should happen on mptable identically */ - mp_irq.type = MP_INTSRC; - mp_irq.irqtype = mp_INT; - mp_irq.irqflag = (trigger == ACPI_EDGE_SENSITIVE ? 4 : 0x0c) | - (polarity == ACPI_ACTIVE_HIGH ? 1 : 3); - mp_irq.srcbus = number; - mp_irq.srcbusirq = (((devfn >> 3) & 0x1f) << 2) | ((pin - 1) & 3); - ioapic = mp_find_ioapic(gsi); - mp_irq.dstapic = mpc_ioapic_id(ioapic); - mp_irq.dstirq = mp_find_ioapic_pin(ioapic, gsi); - - mp_save_irq(&mp_irq); -#endif - return 0; -} - -static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, - int polarity) -{ - int ioapic; - int ioapic_pin; - struct io_apic_irq_attr irq_attr; - int ret; - - if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC) - return gsi; - - /* Don't set up the ACPI SCI because it's already set up */ - if (acpi_gbl_FADT.sci_interrupt == gsi) - return gsi; - - ioapic = mp_find_ioapic(gsi); - if (ioapic < 0) { - printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi); - return gsi; - } - - ioapic_pin = mp_find_ioapic_pin(ioapic, gsi); - - if (ioapic_pin > MP_MAX_IOAPIC_PIN) { - printk(KERN_ERR "Invalid reference to IOAPIC pin " - "%d-%d\n", mpc_ioapic_id(ioapic), - ioapic_pin); - return gsi; - } - - if (enable_update_mptable) - mp_config_acpi_gsi(dev, gsi, trigger, polarity); - - set_io_apic_irq_attr(&irq_attr, ioapic, ioapic_pin, - trigger == ACPI_EDGE_SENSITIVE ? 0 : 1, - polarity == ACPI_ACTIVE_HIGH ? 0 : 1); - ret = io_apic_set_pci_routing(dev, gsi_to_irq(gsi), &irq_attr); - if (ret < 0) - gsi = INT_MIN; - - return gsi; -} - /* * Parse IOAPIC related entries in MADT * returns 0 on success, < 0 on error -- cgit v1.2.3 From 032329eebba86350849c027fe3a0b672558893d4 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 9 Jun 2014 16:19:35 +0800 Subject: x86, acpi, irq: Kill static function irq_to_gsi() Static function irq_to_gsi() is only called by acpi_isa_irq_to_gsi(), so kill function irq_to_gsi() and simplify acpi_isa_irq_to_gsi(). Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Len Brown Cc: Pavel Machek Link: http://lkml.kernel.org/r/1402302011-23642-7-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/acpi/boot.c | 26 ++++++-------------------- 1 file changed, 6 insertions(+), 20 deletions(-) (limited to 'arch/x86/kernel/acpi/boot.c') diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index ceb3b36f2b2c..09682766d56a 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -120,22 +120,6 @@ static unsigned int gsi_to_irq(unsigned int gsi) return irq; } -static u32 irq_to_gsi(int irq) -{ - unsigned int gsi; - - if (irq < NR_IRQS_LEGACY) - gsi = isa_irq_to_gsi[irq]; - else if (irq < gsi_top) - gsi = irq; - else if (irq < (gsi_top + NR_IRQS_LEGACY)) - gsi = irq - gsi_top; - else - gsi = 0xffffffff; - - return gsi; -} - /* * This is just a simple wrapper around early_ioremap(), * with sanity checks for phys == 0 and size == 0. @@ -640,10 +624,12 @@ EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi) { - if (isa_irq >= 16) - return -1; - *gsi = irq_to_gsi(isa_irq); - return 0; + if (isa_irq < NR_IRQS_LEGACY) { + *gsi = isa_irq_to_gsi[isa_irq]; + return 0; + } + + return -1; } static int acpi_register_gsi_pic(struct device *dev, u32 gsi, -- cgit v1.2.3 From e819813f5cb98030bab38569abffd9354a1c1a82 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 9 Jun 2014 16:19:36 +0800 Subject: x86, ACPI, trivial: Minor improvements to arch/x86/kernel/acpi/boot.c 1) Remove out-of-date comment 2) Kill unused function acpi_set_irq_model_pic() 3) Use NR_IRQS_LEGACY instead of hard-coded 16 4) Trivial syntax improvements Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Len Brown Cc: Pavel Machek Cc: Jiri Kosina Link: http://lkml.kernel.org/r/1402302011-23642-8-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/acpi/boot.c | 50 +++++++++++++++------------------------------ 1 file changed, 16 insertions(+), 34 deletions(-) (limited to 'arch/x86/kernel/acpi/boot.c') diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 09682766d56a..392360c607dc 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -483,11 +483,6 @@ static void __init acpi_sci_ioapic_setup(u8 bus_irq, u16 polarity, u16 trigger, if (acpi_sci_flags & ACPI_MADT_POLARITY_MASK) polarity = acpi_sci_flags & ACPI_MADT_POLARITY_MASK; - /* - * mp_config_acpi_legacy_irqs() already setup IRQs < 16 - * If GSI is < 16, this will update its flags, - * else it will create a new mp_irqs[] entry. - */ mp_override_legacy_irq(bus_irq, polarity, trigger, gsi); /* @@ -686,14 +681,7 @@ void acpi_unregister_gsi(u32 gsi) } EXPORT_SYMBOL_GPL(acpi_unregister_gsi); -void __init acpi_set_irq_model_pic(void) -{ - acpi_irq_model = ACPI_IRQ_MODEL_PIC; - __acpi_register_gsi = acpi_register_gsi_pic; - acpi_ioapic = 0; -} - -void __init acpi_set_irq_model_ioapic(void) +static void __init acpi_set_irq_model_ioapic(void) { acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; __acpi_register_gsi = acpi_register_gsi_ioapic; @@ -932,9 +920,8 @@ static int __init early_acpi_parse_madt_lapic_addr_ovr(void) * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value). */ - count = - acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE, - acpi_parse_lapic_addr_ovr, 0); + count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE, + acpi_parse_lapic_addr_ovr, 0); if (count < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); @@ -959,9 +946,8 @@ static int __init acpi_parse_madt_lapic_entries(void) * and (optionally) overriden by a LAPIC_ADDR_OVR entry (64-bit value). */ - count = - acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE, - acpi_parse_lapic_addr_ovr, 0); + count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_OVERRIDE, + acpi_parse_lapic_addr_ovr, 0); if (count < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC address override entry\n"); @@ -989,11 +975,10 @@ static int __init acpi_parse_madt_lapic_entries(void) return count; } - x2count = - acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_X2APIC_NMI, - acpi_parse_x2apic_nmi, 0); - count = - acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, acpi_parse_lapic_nmi, 0); + x2count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_X2APIC_NMI, + acpi_parse_x2apic_nmi, 0); + count = acpi_table_parse_madt(ACPI_MADT_TYPE_LOCAL_APIC_NMI, + acpi_parse_lapic_nmi, 0); if (count < 0 || x2count < 0) { printk(KERN_ERR PREFIX "Error parsing LAPIC NMI entry\n"); /* TBD: Cleanup to allow fallback to MPS */ @@ -1022,7 +1007,7 @@ static void __init mp_config_acpi_legacy_irqs(void) * Use the default configuration for the IRQs 0-15. Unless * overridden by (MADT) interrupt source override entries. */ - for (i = 0; i < 16; i++) { + for (i = 0; i < NR_IRQS_LEGACY; i++) { int ioapic, pin; unsigned int dstapic; int idx; @@ -1099,9 +1084,8 @@ static int __init acpi_parse_madt_ioapic_entries(void) return -ENODEV; } - count = - acpi_table_parse_madt(ACPI_MADT_TYPE_IO_APIC, acpi_parse_ioapic, - MAX_IO_APICS); + count = acpi_table_parse_madt(ACPI_MADT_TYPE_IO_APIC, acpi_parse_ioapic, + MAX_IO_APICS); if (!count) { printk(KERN_ERR PREFIX "No IOAPIC entries present\n"); return -ENODEV; @@ -1110,9 +1094,8 @@ static int __init acpi_parse_madt_ioapic_entries(void) return count; } - count = - acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr, - nr_irqs); + count = acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, + acpi_parse_int_src_ovr, nr_irqs); if (count < 0) { printk(KERN_ERR PREFIX "Error parsing interrupt source overrides entry\n"); @@ -1131,9 +1114,8 @@ static int __init acpi_parse_madt_ioapic_entries(void) /* Fill in identity legacy mappings where no override */ mp_config_acpi_legacy_irqs(); - count = - acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src, - nr_irqs); + count = acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, + acpi_parse_nmi_src, nr_irqs); if (count < 0) { printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); /* TBD: Cleanup to allow fallback to MPS */ -- cgit v1.2.3 From 2c0a6894df19515baf9d2bf0076a2b57c8b51efb Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 10 Jun 2014 14:11:23 +0800 Subject: x86, ACPI, irq: Enhance error handling in function acpi_register_gsi() Function mp_register_gsi() may return error code when failed to look up or program corresponding IOAPIC pin for GSI, so enhance acpi_register_gsi() to handle possible error cases. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Len Brown Cc: Pavel Machek Link: http://lkml.kernel.org/r/1402380683-32345-1-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/acpi/boot.c | 14 ++++++++------ 1 file changed, 8 insertions(+), 6 deletions(-) (limited to 'arch/x86/kernel/acpi/boot.c') diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 392360c607dc..298f79616f1c 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -97,6 +97,8 @@ static u32 isa_irq_to_gsi[NR_IRQS_LEGACY] __read_mostly = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15 }; +#define ACPI_INVALID_GSI INT_MIN + static unsigned int gsi_to_irq(unsigned int gsi) { unsigned int irq = gsi + NR_IRQS_LEGACY; @@ -441,7 +443,7 @@ static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, polarity == ACPI_ACTIVE_HIGH ? 0 : 1); ret = io_apic_set_pci_routing(dev, gsi_to_irq(gsi), &irq_attr); if (ret < 0) - gsi = INT_MIN; + gsi = ACPI_INVALID_GSI; return gsi; } @@ -666,13 +668,13 @@ int (*acpi_suspend_lowlevel)(void); */ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) { - unsigned int irq; - unsigned int plat_gsi = gsi; + unsigned int plat_gsi; - plat_gsi = (*__acpi_register_gsi)(dev, gsi, trigger, polarity); - irq = gsi_to_irq(plat_gsi); + plat_gsi = __acpi_register_gsi(dev, gsi, trigger, polarity); + if (plat_gsi != ACPI_INVALID_GSI) + return gsi_to_irq(plat_gsi); - return irq; + return -1; } EXPORT_SYMBOL_GPL(acpi_register_gsi); -- cgit v1.2.3 From 2e0ad0e2c13534f1a0e7f63661e666c281e09b66 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 9 Jun 2014 16:19:38 +0800 Subject: x86, ACPI, irq: Fix possible eror in GSI to IRQ mapping for legacy IRQ A default identity mapping between GSI and IRQ is built for legacy IRQs. So when overriding the default identity mapping for legacy IRQs, we should also invalidate isa_irq_to_gsi[gsi] when setting isa_irq_to_gsi[irq] = gsi. Otherwise there may be two entries with the same GSI in the isa_irq_to_gsi array, and acpi_isa_irq_to_gsi() may give wrong result. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Len Brown Cc: Pavel Machek Link: http://lkml.kernel.org/r/1402302011-23642-10-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/acpi/boot.c | 10 +++++++++- 1 file changed, 9 insertions(+), 1 deletion(-) (limited to 'arch/x86/kernel/acpi/boot.c') diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 298f79616f1c..f3bafcd32b98 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -366,6 +366,13 @@ static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, mp_save_irq(&mp_irq); + /* + * Reset default identity mapping if gsi is also an legacy IRQ, + * otherwise there will be more than one entry with the same GSI + * and acpi_isa_irq_to_gsi() may give wrong result. + */ + if (gsi < NR_IRQS_LEGACY && isa_irq_to_gsi[gsi] == gsi) + isa_irq_to_gsi[gsi] = ACPI_INVALID_GSI; isa_irq_to_gsi[bus_irq] = gsi; } @@ -621,7 +628,8 @@ EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi) { - if (isa_irq < NR_IRQS_LEGACY) { + if (isa_irq < NR_IRQS_LEGACY && + isa_irq_to_gsi[isa_irq] != ACPI_INVALID_GSI) { *gsi = isa_irq_to_gsi[isa_irq]; return 0; } -- cgit v1.2.3 From 95d76acc7518d566df18d67c1343bb375b78d1f3 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 9 Jun 2014 16:19:48 +0800 Subject: x86, irq: Count legacy IRQs by legacy_pic->nr_legacy_irqs instead of NR_IRQS_LEGACY Some platforms, such as Intel MID and mshypv, do not support legacy interrupt controllers. So count legacy IRQs by legacy_pic->nr_legacy_irqs instead of hard-coded NR_IRQS_LEGACY. Signed-off-by: Jiang Liu Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: xen-devel@lists.xenproject.org Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Len Brown Cc: Pavel Machek Cc: Konrad Rzeszutek Wilk Cc: Rob Herring Cc: Michal Simek Cc: Tony Lindgren Acked-by: David Vrabel Link: http://lkml.kernel.org/r/1402302011-23642-20-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/i8259.h | 5 +++++ arch/x86/kernel/acpi/boot.c | 13 +++++++------ arch/x86/kernel/apic/io_apic.c | 43 ++++++++++++++++++++++++------------------ arch/x86/kernel/devicetree.c | 13 +++++++------ arch/x86/kernel/irqinit.c | 6 +++--- arch/x86/pci/xen.c | 7 ++++--- 6 files changed, 51 insertions(+), 36 deletions(-) (limited to 'arch/x86/kernel/acpi/boot.c') diff --git a/arch/x86/include/asm/i8259.h b/arch/x86/include/asm/i8259.h index a20365953bf8..ccffa53750a8 100644 --- a/arch/x86/include/asm/i8259.h +++ b/arch/x86/include/asm/i8259.h @@ -67,4 +67,9 @@ struct legacy_pic { extern struct legacy_pic *legacy_pic; extern struct legacy_pic null_legacy_pic; +static inline int nr_legacy_irqs(void) +{ + return legacy_pic->nr_legacy_irqs; +} + #endif /* _ASM_X86_I8259_H */ diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index f3bafcd32b98..b12976590a72 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -43,6 +43,7 @@ #include #include #include +#include #include "sleep.h" /* To include x86_acpi_suspend_lowlevel */ static int __initdata acpi_force = 0; @@ -101,10 +102,10 @@ static u32 isa_irq_to_gsi[NR_IRQS_LEGACY] __read_mostly = { static unsigned int gsi_to_irq(unsigned int gsi) { - unsigned int irq = gsi + NR_IRQS_LEGACY; + unsigned int irq = gsi + nr_legacy_irqs(); unsigned int i; - for (i = 0; i < NR_IRQS_LEGACY; i++) { + for (i = 0; i < nr_legacy_irqs(); i++) { if (isa_irq_to_gsi[i] == gsi) { return i; } @@ -114,7 +115,7 @@ static unsigned int gsi_to_irq(unsigned int gsi) * except on truly weird platforms that have * non isa irqs in the first 16 gsis. */ - if (gsi >= NR_IRQS_LEGACY) + if (gsi >= nr_legacy_irqs()) irq = gsi; else irq = gsi_top + gsi; @@ -371,7 +372,7 @@ static void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, * otherwise there will be more than one entry with the same GSI * and acpi_isa_irq_to_gsi() may give wrong result. */ - if (gsi < NR_IRQS_LEGACY && isa_irq_to_gsi[gsi] == gsi) + if (gsi < nr_legacy_irqs() && isa_irq_to_gsi[gsi] == gsi) isa_irq_to_gsi[gsi] = ACPI_INVALID_GSI; isa_irq_to_gsi[bus_irq] = gsi; } @@ -628,7 +629,7 @@ EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi) { - if (isa_irq < NR_IRQS_LEGACY && + if (isa_irq < nr_legacy_irqs() && isa_irq_to_gsi[isa_irq] != ACPI_INVALID_GSI) { *gsi = isa_irq_to_gsi[isa_irq]; return 0; @@ -1017,7 +1018,7 @@ static void __init mp_config_acpi_legacy_irqs(void) * Use the default configuration for the IRQs 0-15. Unless * overridden by (MADT) interrupt source override entries. */ - for (i = 0; i < NR_IRQS_LEGACY; i++) { + for (i = 0; i < nr_legacy_irqs(); i++) { int ioapic, pin; unsigned int dstapic; int idx; diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 424f795a1c78..4208ea9edc10 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -129,10 +129,17 @@ u32 mp_pin_to_gsi(int ioapic, int pin) return mp_ioapic_gsi_routing(ioapic)->gsi_base + pin; } -/* Initialize all legacy IRQs and all pins on the first IOAPIC at boot */ +/* + * Initialize all legacy IRQs and all pins on the first IOAPIC + * if we have legacy interrupt controller. Kernel boot option "pirq=" + * may rely on non-legacy pins on the first IOAPIC. + */ static inline int mp_init_irq_at_boot(int ioapic, int irq) { - return ioapic == 0 || (irq >= 0 && irq < NR_IRQS_LEGACY); + if (!nr_legacy_irqs()) + return 0; + + return ioapic == 0 || (irq >= 0 && irq < nr_legacy_irqs()); } int nr_ioapics; @@ -216,7 +223,7 @@ int __init arch_early_irq_init(void) struct irq_cfg *cfg; int count, node, i; - if (!legacy_pic->nr_legacy_irqs) + if (!nr_legacy_irqs()) io_apic_irqs = ~0UL; for_each_ioapic(i) { @@ -239,7 +246,7 @@ int __init arch_early_irq_init(void) * For legacy IRQ's, start with assigning irq0 to irq15 to * IRQ0_VECTOR to IRQ15_VECTOR for all cpu's. */ - if (i < legacy_pic->nr_legacy_irqs) { + if (i < nr_legacy_irqs()) { cfg[i].vector = IRQ0_VECTOR + i; cpumask_setall(cfg[i].domain); } @@ -823,7 +830,7 @@ static int __init find_isa_irq_apic(int irq, int type) */ static int EISA_ELCR(unsigned int irq) { - if (irq < legacy_pic->nr_legacy_irqs) { + if (irq < nr_legacy_irqs()) { unsigned int port = 0x4d0 + (irq >> 3); return (inb(port) >> (irq & 7)) & 1; } @@ -980,7 +987,7 @@ static int pin_2_irq(int idx, int apic, int pin) } else { u32 gsi = gsi_cfg->gsi_base + pin; - if (gsi >= NR_IRQS_LEGACY) + if (gsi >= nr_legacy_irqs()) irq = gsi; else irq = gsi_top + gsi; @@ -1357,7 +1364,7 @@ static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg, } ioapic_register_intr(irq, cfg, attr->trigger); - if (irq < legacy_pic->nr_legacy_irqs) + if (irq < nr_legacy_irqs()) legacy_pic->mask(irq); ioapic_write_entry(attr->ioapic, attr->ioapic_pin, entry); @@ -1782,7 +1789,7 @@ __apicdebuginit(void) print_PIC(void) unsigned int v; unsigned long flags; - if (!legacy_pic->nr_legacy_irqs) + if (!nr_legacy_irqs()) return; printk(KERN_DEBUG "\nprinting PIC contents\n"); @@ -1854,7 +1861,7 @@ void __init enable_IO_APIC(void) int i8259_apic, i8259_pin; int apic, pin; - if (!legacy_pic->nr_legacy_irqs) + if (!nr_legacy_irqs()) return; for_each_ioapic_pin(apic, pin) { @@ -1939,7 +1946,7 @@ void disable_IO_APIC(void) */ clear_IO_APIC(); - if (!legacy_pic->nr_legacy_irqs) + if (!nr_legacy_irqs()) return; x86_io_apic_ops.disable(); @@ -2143,7 +2150,7 @@ static unsigned int startup_ioapic_irq(struct irq_data *data) unsigned long flags; raw_spin_lock_irqsave(&ioapic_lock, flags); - if (irq < legacy_pic->nr_legacy_irqs) { + if (irq < nr_legacy_irqs()) { legacy_pic->mask(irq); if (legacy_pic->irq_pending(irq)) was_pending = 1; @@ -2542,7 +2549,7 @@ static inline void init_IO_APIC_traps(void) * so default to an old-fashioned 8259 * interrupt if we can.. */ - if (irq < legacy_pic->nr_legacy_irqs) + if (irq < nr_legacy_irqs()) legacy_pic->make_irq(irq); else /* Strange. Oh, well.. */ @@ -2839,7 +2846,7 @@ void __init setup_IO_APIC(void) /* * calling enable_IO_APIC() is moved to setup_local_APIC for BP */ - io_apic_irqs = legacy_pic->nr_legacy_irqs ? ~PIC_IRQS : ~0UL; + io_apic_irqs = nr_legacy_irqs() ? ~PIC_IRQS : ~0UL; apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); /* @@ -2850,7 +2857,7 @@ void __init setup_IO_APIC(void) sync_Arb_IDs(); setup_IO_APIC_irqs(); init_IO_APIC_traps(); - if (legacy_pic->nr_legacy_irqs) + if (nr_legacy_irqs()) check_timer(); } @@ -3348,7 +3355,7 @@ static int __init io_apic_get_redir_entries(int ioapic) unsigned int arch_dynirq_lower_bound(unsigned int from) { - unsigned int min = gsi_top + NR_IRQS_LEGACY; + unsigned int min = gsi_top + nr_legacy_irqs(); return from < min ? min : from; } @@ -3360,17 +3367,17 @@ int __init arch_probe_nr_irqs(void) if (nr_irqs > (NR_VECTORS * nr_cpu_ids)) nr_irqs = NR_VECTORS * nr_cpu_ids; - nr = (gsi_top + NR_IRQS_LEGACY) + 8 * nr_cpu_ids; + nr = (gsi_top + nr_legacy_irqs()) + 8 * nr_cpu_ids; #if defined(CONFIG_PCI_MSI) || defined(CONFIG_HT_IRQ) /* * for MSI and HT dyn irq */ - nr += (gsi_top + NR_IRQS_LEGACY) * 16; + nr += gsi_top * 16; #endif if (nr < nr_irqs) nr_irqs = nr; - return NR_IRQS_LEGACY; + return nr_legacy_irqs(); } int io_apic_set_pci_routing(struct device *dev, int irq, diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c index 7db54b5d5f86..b4680058db8b 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c @@ -21,6 +21,7 @@ #include #include #include +#include __initdata u64 initial_dtb; char __initdata cmd_line[COMMAND_LINE_SIZE]; @@ -314,7 +315,7 @@ static void dt_add_ioapic_domain(unsigned int ioapic_num, struct irq_domain *id; struct mp_ioapic_gsi *gsi_cfg; int ret; - int num; + int num, legacy_irqs = nr_legacy_irqs(); gsi_cfg = mp_ioapic_gsi_routing(ioapic_num); num = gsi_cfg->gsi_end - gsi_cfg->gsi_base + 1; @@ -324,17 +325,17 @@ static void dt_add_ioapic_domain(unsigned int ioapic_num, BUG_ON(!id); if (gsi_cfg->gsi_base == 0) { /* - * The first NR_IRQS_LEGACY irq descs are allocated in + * The first nr_legacy_irqs() irq descs are allocated in * early_irq_init() and need just a mapping. The * remaining irqs need both. All of them are preallocated * and assigned so we can keep the 1:1 mapping which the ioapic * is having. */ - irq_domain_associate_many(id, 0, 0, NR_IRQS_LEGACY); + irq_domain_associate_many(id, 0, 0, legacy_irqs); - if (num > NR_IRQS_LEGACY) { - ret = irq_create_strict_mappings(id, NR_IRQS_LEGACY, - NR_IRQS_LEGACY, num - NR_IRQS_LEGACY); + if (num > legacy_irqs) { + ret = irq_create_strict_mappings(id, legacy_irqs, + legacy_irqs, num - legacy_irqs); if (ret) pr_err("Error creating mapping for the " "remaining IRQs: %d\n", ret); diff --git a/arch/x86/kernel/irqinit.c b/arch/x86/kernel/irqinit.c index 7f50156542fb..a0111e91eb4b 100644 --- a/arch/x86/kernel/irqinit.c +++ b/arch/x86/kernel/irqinit.c @@ -78,7 +78,7 @@ void __init init_ISA_irqs(void) #endif legacy_pic->init(0); - for (i = 0; i < legacy_pic->nr_legacy_irqs; i++) + for (i = 0; i < nr_legacy_irqs(); i++) irq_set_chip_and_handler_name(i, chip, handle_level_irq, name); } @@ -100,7 +100,7 @@ void __init init_IRQ(void) * then this vector space can be freed and re-used dynamically as the * irq's migrate etc. */ - for (i = 0; i < legacy_pic->nr_legacy_irqs; i++) + for (i = 0; i < nr_legacy_irqs(); i++) per_cpu(vector_irq, 0)[IRQ0_VECTOR + i] = i; x86_init.irqs.intr_init(); @@ -121,7 +121,7 @@ void setup_vector_irq(int cpu) * legacy PIC, for the new cpu that is coming online, setup the static * legacy vector to irq mapping: */ - for (irq = 0; irq < legacy_pic->nr_legacy_irqs; irq++) + for (irq = 0; irq < nr_legacy_irqs(); irq++) per_cpu(vector_irq, cpu)[IRQ0_VECTOR + irq] = irq; #endif diff --git a/arch/x86/pci/xen.c b/arch/x86/pci/xen.c index 905956f16465..093f5f4272d3 100644 --- a/arch/x86/pci/xen.c +++ b/arch/x86/pci/xen.c @@ -23,6 +23,7 @@ #include #include #include +#include static int xen_pcifront_enable_irq(struct pci_dev *dev) { @@ -40,7 +41,7 @@ static int xen_pcifront_enable_irq(struct pci_dev *dev) /* In PV DomU the Xen PCI backend puts the PIRQ in the interrupt line.*/ pirq = gsi; - if (gsi < NR_IRQS_LEGACY) + if (gsi < nr_legacy_irqs()) share = 0; rc = xen_bind_pirq_gsi_to_irq(gsi, pirq, share, "pcifront"); @@ -511,7 +512,7 @@ int __init pci_xen_initial_domain(void) xen_setup_acpi_sci(); __acpi_register_gsi = acpi_register_gsi_xen; /* Pre-allocate legacy irqs */ - for (irq = 0; irq < NR_IRQS_LEGACY; irq++) { + for (irq = 0; irq < nr_legacy_irqs(); irq++) { int trigger, polarity; if (acpi_get_override_irq(irq, &trigger, &polarity) == -1) @@ -522,7 +523,7 @@ int __init pci_xen_initial_domain(void) true /* Map GSI to PIRQ */); } if (0 == nr_ioapics) { - for (irq = 0; irq < NR_IRQS_LEGACY; irq++) + for (irq = 0; irq < nr_legacy_irqs(); irq++) xen_bind_pirq_gsi_to_irq(irq, irq, 0, "xt-pic"); } return 0; -- cgit v1.2.3 From 6b9fb7082409cd4a2c7caf43e3c023ad82dad0d4 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 10 Jun 2014 14:13:25 +0800 Subject: x86, ACPI, irq: Consolidate algorithm of mapping (ioapic, pin) to IRQ number Currently ACPI and ioapic both implement algorithms to map (ioapic, pin) to IRQ number. So consolidate the common part into one place, which is also preparing for irqdomain support. It introduces mp_map_gsi_to_irq(), which will be used to allocate IRQ number IOAPIC pins when irqdomain is enabled. Also rename gsi_to_irq() to map_gsi_to_irq(), later we will introduce unmap_gsi_to_irq() when enabling IOAPIC hotplug. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Len Brown Cc: Pavel Machek Link: http://lkml.kernel.org/r/1402380812-32446-1-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/io_apic.h | 2 ++ arch/x86/kernel/acpi/boot.c | 45 ++++++++++++++++++++---------------------- arch/x86/kernel/apic/io_apic.c | 27 ++++++++++++++----------- 3 files changed, 38 insertions(+), 36 deletions(-) (limited to 'arch/x86/kernel/acpi/boot.c') diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index b775cf3622c3..978e51fdcb59 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h @@ -172,6 +172,7 @@ extern u32 gsi_top; extern int mp_find_ioapic(u32 gsi); extern int mp_find_ioapic_pin(int ioapic, u32 gsi); extern u32 mp_pin_to_gsi(int ioapic, int pin); +extern int mp_map_gsi_to_irq(u32 gsi); extern void __init mp_register_ioapic(int id, u32 address, u32 gsi_base); extern void __init pre_init_apic_IRQ0(void); @@ -214,6 +215,7 @@ static inline void ioapic_insert_resources(void) { } #define gsi_top (NR_IRQS_LEGACY) static inline int mp_find_ioapic(u32 gsi) { return 0; } static inline u32 mp_pin_to_gsi(int ioapic, int pin) { return UINT_MAX; } +static inline int mp_map_gsi_to_irq(u32 gsi) { return gsi; } struct io_apic_irq_attr; static inline int io_apic_set_pci_routing(struct device *dev, int irq, diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index b12976590a72..9965afbd71ca 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -100,27 +100,15 @@ static u32 isa_irq_to_gsi[NR_IRQS_LEGACY] __read_mostly = { #define ACPI_INVALID_GSI INT_MIN -static unsigned int gsi_to_irq(unsigned int gsi) +static int map_gsi_to_irq(unsigned int gsi) { - unsigned int irq = gsi + nr_legacy_irqs(); - unsigned int i; + int i; - for (i = 0; i < nr_legacy_irqs(); i++) { - if (isa_irq_to_gsi[i] == gsi) { + for (i = 0; i < nr_legacy_irqs(); i++) + if (isa_irq_to_gsi[i] == gsi) return i; - } - } - - /* Provide an identity mapping of gsi == irq - * except on truly weird platforms that have - * non isa irqs in the first 16 gsis. - */ - if (gsi >= nr_legacy_irqs()) - irq = gsi; - else - irq = gsi_top + gsi; - return irq; + return mp_map_gsi_to_irq(gsi); } /* @@ -416,6 +404,7 @@ static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger, static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) { + int irq; int ioapic; int ioapic_pin; struct io_apic_irq_attr irq_attr; @@ -428,6 +417,10 @@ static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, if (acpi_gbl_FADT.sci_interrupt == gsi) return gsi; + irq = map_gsi_to_irq(gsi); + if (irq < 0) + return ACPI_INVALID_GSI; + ioapic = mp_find_ioapic(gsi); if (ioapic < 0) { printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi); @@ -449,7 +442,7 @@ static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, set_io_apic_irq_attr(&irq_attr, ioapic, ioapic_pin, trigger == ACPI_EDGE_SENSITIVE ? 0 : 1, polarity == ACPI_ACTIVE_HIGH ? 0 : 1); - ret = io_apic_set_pci_routing(dev, gsi_to_irq(gsi), &irq_attr); + ret = io_apic_set_pci_routing(dev, irq, &irq_attr); if (ret < 0) gsi = ACPI_INVALID_GSI; @@ -614,16 +607,20 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) outb(new >> 8, 0x4d1); } -int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) +int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp) { - *irq = gsi_to_irq(gsi); + int irq = map_gsi_to_irq(gsi); + if (irq >= 0) { #ifdef CONFIG_X86_IO_APIC - if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) - setup_IO_APIC_irq_extra(gsi); + if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) + setup_IO_APIC_irq_extra(gsi); #endif + *irqp = irq; + return 0; + } - return 0; + return -1; } EXPORT_SYMBOL_GPL(acpi_gsi_to_irq); @@ -681,7 +678,7 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) plat_gsi = __acpi_register_gsi(dev, gsi, trigger, polarity); if (plat_gsi != ACPI_INVALID_GSI) - return gsi_to_irq(plat_gsi); + return map_gsi_to_irq(plat_gsi); return -1; } diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index e25e7e315d4f..7fd9f1befe0b 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -959,11 +959,19 @@ static int irq_trigger(int idx) return trigger; } +int mp_map_gsi_to_irq(u32 gsi) +{ + /* + * Provide an identity mapping of gsi == irq except on truly weird + * platforms that have non isa irqs in the first 16 gsis. + */ + return gsi >= nr_legacy_irqs() ? gsi : gsi_top + gsi; +} + static int pin_2_irq(int idx, int apic, int pin) { int irq; int bus = mp_irqs[idx].srcbus; - struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(apic); /* * Debugging check, we are in big trouble if this message pops up! @@ -971,17 +979,6 @@ static int pin_2_irq(int idx, int apic, int pin) if (mp_irqs[idx].dstirq != pin) pr_err("broken BIOS or MPTABLE parser, ayiee!!\n"); - if (test_bit(bus, mp_bus_not_pci)) { - irq = mp_irqs[idx].srcbusirq; - } else { - u32 gsi = gsi_cfg->gsi_base + pin; - - if (gsi >= nr_legacy_irqs()) - irq = gsi; - else - irq = gsi_top + gsi; - } - #ifdef CONFIG_X86_32 /* * PCI IRQ command line redirection. Yes, limits are hardcoded. @@ -996,11 +993,17 @@ static int pin_2_irq(int idx, int apic, int pin) apic_printk(APIC_VERBOSE, KERN_DEBUG "using PIRQ%d -> IRQ %d\n", pin-16, irq); + return irq; } } } #endif + if (test_bit(bus, mp_bus_not_pci)) + irq = mp_irqs[idx].srcbusirq; + else + irq = mp_map_gsi_to_irq(mp_pin_to_gsi(apic, pin)); + return irq; } -- cgit v1.2.3 From 84245af7297ced9e8fe837dc0fc4782438771bd2 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 10 Jun 2014 14:14:47 +0800 Subject: x86, irq, ACPI: Change __acpi_register_gsi to return IRQ number instead of GSI Currently __acpi_register_gsi is defined to return GSI number and may be set to acpi_register_gsi_pic(), acpi_register_gsi_ioapic(), acpi_register_gsi_xen_hvm() and acpi_register_gsi_xen(). Among which, acpi_register_gsi_ioapic() returns GSI number, but acpi_register_gsi_xen_hvm() and acpi_register_gsi_xen() actually returns IRQ number instead of GSI. And for acpi_register_gsi_pic(), GSI number equals to IRQ number. So change acpi_register_gsi_ioapic() to return IRQ number, it also simplifies the code. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Len Brown Cc: Pavel Machek Link: http://lkml.kernel.org/r/1402380887-32512-1-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/acpi/boot.c | 21 ++++++++------------- 1 file changed, 8 insertions(+), 13 deletions(-) (limited to 'arch/x86/kernel/acpi/boot.c') diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 9965afbd71ca..0cf311c72bce 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -419,7 +419,7 @@ static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, irq = map_gsi_to_irq(gsi); if (irq < 0) - return ACPI_INVALID_GSI; + return irq; ioapic = mp_find_ioapic(gsi); if (ioapic < 0) { @@ -444,12 +444,11 @@ static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, polarity == ACPI_ACTIVE_HIGH ? 0 : 1); ret = io_apic_set_pci_routing(dev, irq, &irq_attr); if (ret < 0) - gsi = ACPI_INVALID_GSI; + irq = -1; - return gsi; + return irq; } - static int __init acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end) { @@ -652,11 +651,13 @@ static int acpi_register_gsi_pic(struct device *dev, u32 gsi, static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi, int trigger, int polarity) { + int irq = gsi; + #ifdef CONFIG_X86_IO_APIC - gsi = mp_register_gsi(dev, gsi, trigger, polarity); + irq = mp_register_gsi(dev, gsi, trigger, polarity); #endif - return gsi; + return irq; } int (*__acpi_register_gsi)(struct device *dev, u32 gsi, @@ -674,13 +675,7 @@ int (*acpi_suspend_lowlevel)(void); */ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) { - unsigned int plat_gsi; - - plat_gsi = __acpi_register_gsi(dev, gsi, trigger, polarity); - if (plat_gsi != ACPI_INVALID_GSI) - return map_gsi_to_irq(plat_gsi); - - return -1; + return __acpi_register_gsi(dev, gsi, trigger, polarity); } EXPORT_SYMBOL_GPL(acpi_register_gsi); -- cgit v1.2.3 From d7f3d4781852f5160b939f526afbc21a813a0206 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 9 Jun 2014 16:19:52 +0800 Subject: x86, irq: Introduce mechanisms to support dynamically allocate IRQ for IOAPIC Currently x86 support identity mapping between GSI(IOAPIC pin) and IRQ number, so continous IRQs at low end are statically allocated to IOAPICs at boot time. This design causes trouble to support IOAPIC hotplug. This patch implements basic mechanism to dynamically allocate IRQ on demand for IOAPIC pins by using irqdomain framework. It first adds several fields into struct ioapic to support irqdomain. Then it implements an algorithm to dynamically allocate IRQ number for IOAPIC pins on demand. Currently it supports three types of irqdomain: 1) LEGACY: used to support IOAPIC hosting legacy IRQs and building identity mapping for legacy IRQs. A speical case, we dynamically allocate IRQ number for IOAPIC pin which has GSI number below nr_legacy_irqs() but isn't legacy IRQ. This is for backward compatibility and avoid regression. 2) STRICT: build identity mapping between GSI and IRQ nubmer. 3) DYNAMIC: dynamically allocate IRQ number for IOAPIC pin on demand. Legacy(ISA) IRQs is not managed by irqdomain because there may be multiple pins sharing the same IRQ number and current irqdomain only supports 1:1 mapping between pins and IRQ. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Len Brown Cc: Pavel Machek Link: http://lkml.kernel.org/r/1402302011-23642-24-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/Kconfig | 1 + arch/x86/include/asm/io_apic.h | 21 +++++- arch/x86/kernel/acpi/boot.c | 8 +-- arch/x86/kernel/apic/io_apic.c | 158 ++++++++++++++++++++++++++++++++--------- 4 files changed, 147 insertions(+), 41 deletions(-) (limited to 'arch/x86/kernel/acpi/boot.c') diff --git a/arch/x86/Kconfig b/arch/x86/Kconfig index 9df5c453171e..147a7b788100 100644 --- a/arch/x86/Kconfig +++ b/arch/x86/Kconfig @@ -836,6 +836,7 @@ config X86_IO_APIC def_bool y depends on X86_64 || SMP || X86_32_NON_STANDARD || X86_UP_IOAPIC || PCI_MSI select GENERIC_IRQ_LEGACY_ALLOC_HWIRQ + select IRQ_DOMAIN config X86_REROUTE_FOR_BROKEN_BOOT_IRQS bool "Reroute for broken boot IRQs" diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index 978e51fdcb59..64c6e344399b 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h @@ -98,6 +98,8 @@ struct IR_IO_APIC_route_entry { #define IOAPIC_AUTO -1 #define IOAPIC_EDGE 0 #define IOAPIC_LEVEL 1 +#define IOAPIC_MAP_ALLOC 0x1 +#define IOAPIC_MAP_CHECK 0x2 #ifdef CONFIG_X86_IO_APIC @@ -163,6 +165,21 @@ extern int restore_ioapic_entries(void); extern void setup_ioapic_ids_from_mpc(void); extern void setup_ioapic_ids_from_mpc_nocheck(void); +enum ioapic_domain_type { + IOAPIC_DOMAIN_INVALID, + IOAPIC_DOMAIN_LEGACY, + IOAPIC_DOMAIN_STRICT, + IOAPIC_DOMAIN_DYNAMIC, +}; + +struct device_node; +struct irq_domain_ops; +struct ioapic_domain_cfg { + enum ioapic_domain_type type; + const struct irq_domain_ops *ops; + struct device_node *dev; +}; + struct mp_ioapic_gsi{ u32 gsi_base; u32 gsi_end; @@ -172,7 +189,7 @@ extern u32 gsi_top; extern int mp_find_ioapic(u32 gsi); extern int mp_find_ioapic_pin(int ioapic, u32 gsi); extern u32 mp_pin_to_gsi(int ioapic, int pin); -extern int mp_map_gsi_to_irq(u32 gsi); +extern int mp_map_gsi_to_irq(u32 gsi, unsigned int flags); extern void __init mp_register_ioapic(int id, u32 address, u32 gsi_base); extern void __init pre_init_apic_IRQ0(void); @@ -215,7 +232,7 @@ static inline void ioapic_insert_resources(void) { } #define gsi_top (NR_IRQS_LEGACY) static inline int mp_find_ioapic(u32 gsi) { return 0; } static inline u32 mp_pin_to_gsi(int ioapic, int pin) { return UINT_MAX; } -static inline int mp_map_gsi_to_irq(u32 gsi) { return gsi; } +static inline int mp_map_gsi_to_irq(u32 gsi, unsigned int flags) { return gsi; } struct io_apic_irq_attr; static inline int io_apic_set_pci_routing(struct device *dev, int irq, diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 0cf311c72bce..d6635baf9e3d 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -100,7 +100,7 @@ static u32 isa_irq_to_gsi[NR_IRQS_LEGACY] __read_mostly = { #define ACPI_INVALID_GSI INT_MIN -static int map_gsi_to_irq(unsigned int gsi) +static int map_gsi_to_irq(unsigned int gsi, unsigned int flags) { int i; @@ -108,7 +108,7 @@ static int map_gsi_to_irq(unsigned int gsi) if (isa_irq_to_gsi[i] == gsi) return i; - return mp_map_gsi_to_irq(gsi); + return mp_map_gsi_to_irq(gsi, flags); } /* @@ -417,7 +417,7 @@ static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, if (acpi_gbl_FADT.sci_interrupt == gsi) return gsi; - irq = map_gsi_to_irq(gsi); + irq = map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC); if (irq < 0) return irq; @@ -608,7 +608,7 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp) { - int irq = map_gsi_to_irq(gsi); + int irq = map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC | IOAPIC_MAP_CHECK); if (irq >= 0) { #ifdef CONFIG_X86_IO_APIC diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 7fd9f1befe0b..51ce80004a78 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -83,6 +84,7 @@ int sis_apic_bug = -1; static DEFINE_RAW_SPINLOCK(ioapic_lock); static DEFINE_RAW_SPINLOCK(vector_lock); +static DEFINE_MUTEX(ioapic_mutex); static struct ioapic { /* @@ -97,6 +99,8 @@ static struct ioapic { struct mpc_ioapic mp_config; /* IO APIC gsi routing info */ struct mp_ioapic_gsi gsi_config; + struct ioapic_domain_cfg irqdomain_cfg; + struct irq_domain *irqdomain; DECLARE_BITMAP(pin_programmed, MP_MAX_IOAPIC_PIN + 1); } ioapics[MAX_IO_APICS]; @@ -142,6 +146,11 @@ static inline int mp_init_irq_at_boot(int ioapic, int irq) return ioapic == 0 || (irq >= 0 && irq < nr_legacy_irqs()); } +static inline struct irq_domain *mp_ioapic_irqdomain(int ioapic) +{ + return ioapics[ioapic].irqdomain; +} + int nr_ioapics; /* The one past the highest gsi number used */ @@ -959,19 +968,79 @@ static int irq_trigger(int idx) return trigger; } -int mp_map_gsi_to_irq(u32 gsi) +static int alloc_irq_from_domain(struct irq_domain *domain, u32 gsi, int pin) { + int irq = -1; + int ioapic = (int)(long)domain->host_data; + int type = ioapics[ioapic].irqdomain_cfg.type; + + switch (type) { + case IOAPIC_DOMAIN_LEGACY: + /* + * Dynamically allocate IRQ number for non-ISA IRQs in the first 16 + * GSIs on some weird platforms. + */ + if (gsi < nr_legacy_irqs()) + irq = irq_create_mapping(domain, pin); + else if (irq_create_strict_mappings(domain, gsi, pin, 1) == 0) + irq = gsi; + break; + case IOAPIC_DOMAIN_STRICT: + if (irq_create_strict_mappings(domain, gsi, pin, 1) == 0) + irq = gsi; + break; + case IOAPIC_DOMAIN_DYNAMIC: + irq = irq_create_mapping(domain, pin); + break; + default: + WARN(1, "ioapic: unknown irqdomain type %d\n", type); + break; + } + + return irq > 0 ? irq : -1; +} + +static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin, + unsigned int flags) +{ + int irq; + struct irq_domain *domain = mp_ioapic_irqdomain(ioapic); + /* - * Provide an identity mapping of gsi == irq except on truly weird - * platforms that have non isa irqs in the first 16 gsis. + * Don't use irqdomain to manage ISA IRQs because there may be + * multiple IOAPIC pins sharing the same ISA IRQ number and + * irqdomain only supports 1:1 mapping between IOAPIC pin and + * IRQ number. A typical IOAPIC has 24 pins, pin 0-15 are used + * for legacy IRQs and pin 16-23 are used for PCI IRQs (PIRQ A-H). + * When ACPI is disabled, only legacy IRQ numbers (IRQ0-15) are + * available, and some BIOSes may use MP Interrupt Source records + * to override IRQ numbers for PIRQs instead of reprogramming + * the interrupt routing logic. Thus there may be multiple pins + * sharing the same legacy IRQ number when ACPI is disabled. */ - return gsi >= nr_legacy_irqs() ? gsi : gsi_top + gsi; + if (idx >= 0 && test_bit(mp_irqs[idx].srcbus, mp_bus_not_pci)) + return mp_irqs[idx].srcbusirq; + + if (!domain) { + /* + * Provide an identity mapping of gsi == irq except on truly + * weird platforms that have non isa irqs in the first 16 gsis. + */ + return gsi >= nr_legacy_irqs() ? gsi : gsi_top + gsi; + } + + mutex_lock(&ioapic_mutex); + irq = irq_find_mapping(domain, pin); + if (irq <= 0 && (flags & IOAPIC_MAP_ALLOC)) + irq = alloc_irq_from_domain(domain, gsi, pin); + mutex_unlock(&ioapic_mutex); + + return irq > 0 ? irq : -1; } -static int pin_2_irq(int idx, int apic, int pin) +static int pin_2_irq(int idx, int ioapic, int pin, unsigned int flags) { - int irq; - int bus = mp_irqs[idx].srcbus; + u32 gsi = mp_pin_to_gsi(ioapic, pin); /* * Debugging check, we are in big trouble if this message pops up! @@ -989,7 +1058,7 @@ static int pin_2_irq(int idx, int apic, int pin) apic_printk(APIC_VERBOSE, KERN_DEBUG "disabling PIRQ%d\n", pin-16); } else { - irq = pirq_entries[pin-16]; + int irq = pirq_entries[pin-16]; apic_printk(APIC_VERBOSE, KERN_DEBUG "using PIRQ%d -> IRQ %d\n", pin-16, irq); @@ -999,12 +1068,23 @@ static int pin_2_irq(int idx, int apic, int pin) } #endif - if (test_bit(bus, mp_bus_not_pci)) - irq = mp_irqs[idx].srcbusirq; - else - irq = mp_map_gsi_to_irq(mp_pin_to_gsi(apic, pin)); + return mp_map_pin_to_irq(gsi, idx, ioapic, pin, flags); +} - return irq; +int mp_map_gsi_to_irq(u32 gsi, unsigned int flags) +{ + int ioapic, pin, idx; + + ioapic = mp_find_ioapic(gsi); + if (ioapic < 0) + return -1; + + pin = mp_find_ioapic_pin(ioapic, gsi); + idx = find_irq_entry(ioapic, pin, mp_INT); + if ((flags & IOAPIC_MAP_CHECK) && idx < 0) + return -1; + + return mp_map_pin_to_irq(gsi, idx, ioapic, pin, flags); } /* @@ -1014,7 +1094,7 @@ static int pin_2_irq(int idx, int apic, int pin) int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin, struct io_apic_irq_attr *irq_attr) { - int irq, i, best_guess = -1; + int irq, i, best_ioapic = -1, best_idx = -1; apic_printk(APIC_DEBUG, "querying PCI -> IRQ mapping bus:%d, slot:%d, pin:%d.\n", @@ -1043,30 +1123,37 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pin, continue; /* Skip ISA IRQs */ - irq = pin_2_irq(i, ioapic_idx, mp_irqs[i].dstirq); - if (ioapic_idx == 0 && !IO_APIC_IRQ(irq)) + irq = pin_2_irq(i, ioapic_idx, mp_irqs[i].dstirq, 0); + if (irq > 0 && !IO_APIC_IRQ(irq)) continue; if (pin == (mp_irqs[i].srcbusirq & 3)) { - set_io_apic_irq_attr(irq_attr, ioapic_idx, - mp_irqs[i].dstirq, - irq_trigger(i), - irq_polarity(i)); - return irq; + best_idx = i; + best_ioapic = ioapic_idx; + goto out; } + /* * Use the first all-but-pin matching entry as a * best-guess fuzzy result for broken mptables. */ - if (best_guess < 0) { - set_io_apic_irq_attr(irq_attr, ioapic_idx, - mp_irqs[i].dstirq, - irq_trigger(i), - irq_polarity(i)); - best_guess = irq; + if (best_idx < 0) { + best_idx = i; + best_ioapic = ioapic_idx; } } - return best_guess; + if (best_idx < 0) + return -1; + +out: + irq = pin_2_irq(best_idx, best_ioapic, mp_irqs[best_idx].dstirq, + IOAPIC_MAP_ALLOC); + if (irq > 0) + set_io_apic_irq_attr(irq_attr, best_ioapic, + mp_irqs[best_idx].dstirq, + irq_trigger(best_idx), + irq_polarity(best_idx)); + return irq; } EXPORT_SYMBOL(IO_APIC_get_PCI_irq_vector); @@ -1257,7 +1344,7 @@ static inline int IO_APIC_irq_trigger(int irq) for_each_ioapic_pin(apic, pin) { idx = find_irq_entry(apic, pin, mp_INT); - if ((idx != -1) && (irq == pin_2_irq(idx, apic, pin))) + if ((idx != -1) && (irq == pin_2_irq(idx, apic, pin, 0))) return irq_trigger(idx); } /* @@ -1383,8 +1470,9 @@ static void __init __io_apic_setup_irqs(unsigned int ioapic_idx) if (io_apic_pin_not_connected(idx, ioapic_idx, pin)) continue; - irq = pin_2_irq(idx, ioapic_idx, pin); - if (!mp_init_irq_at_boot(ioapic_idx, irq)) + irq = pin_2_irq(idx, ioapic_idx, pin, + ioapic_idx ? 0 : IOAPIC_MAP_ALLOC); + if (irq < 0 || !mp_init_irq_at_boot(ioapic_idx, irq)) continue; /* @@ -1434,8 +1522,8 @@ void setup_IO_APIC_irq_extra(u32 gsi) if (idx == -1) return; - irq = pin_2_irq(idx, ioapic_idx, pin); - if (mp_init_irq_at_boot(ioapic_idx, irq)) + irq = pin_2_irq(idx, ioapic_idx, pin, IOAPIC_MAP_ALLOC); + if (irq < 0 || mp_init_irq_at_boot(ioapic_idx, irq)) return; set_io_apic_irq_attr(&attr, ioapic_idx, pin, irq_trigger(idx), @@ -3543,8 +3631,8 @@ void __init setup_ioapic_dest(void) if (irq_entry == -1) continue; - irq = pin_2_irq(irq_entry, ioapic, pin); - if (!mp_init_irq_at_boot(ioapic, irq)) + irq = pin_2_irq(irq_entry, ioapic, pin, 0); + if (irq < 0 || !mp_init_irq_at_boot(ioapic, irq)) continue; idata = irq_get_irq_data(irq); -- cgit v1.2.3 From 44767bfaaed782d6d635ecbb13f3980041e6f33e Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 9 Jun 2014 16:19:53 +0800 Subject: x86, irq: Enhance mp_register_ioapic() to support irqdomain Enhance function mp_register_ioapic() to support irqdomain. When registering IOAPIC, caller may provide callbacks and parameters for creating irqdomain. The IOAPIC core will create irqdomain later if caller has passed in corresponding parameters. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: sfi-devel@simplefirmware.org Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Len Brown Cc: Pavel Machek Cc: Rob Herring Cc: Michal Simek Cc: Tony Lindgren Link: http://lkml.kernel.org/r/1402302011-23642-25-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/include/asm/io_apic.h | 3 ++- arch/x86/kernel/acpi/boot.c | 2 +- arch/x86/kernel/apic/io_apic.c | 42 +++++++++++++++++++++++++++++++++++++++++- arch/x86/kernel/devicetree.c | 2 +- arch/x86/kernel/mpparse.c | 2 +- arch/x86/platform/sfi/sfi.c | 2 +- 6 files changed, 47 insertions(+), 6 deletions(-) (limited to 'arch/x86/kernel/acpi/boot.c') diff --git a/arch/x86/include/asm/io_apic.h b/arch/x86/include/asm/io_apic.h index 64c6e344399b..3e4bea3a52b1 100644 --- a/arch/x86/include/asm/io_apic.h +++ b/arch/x86/include/asm/io_apic.h @@ -190,7 +190,8 @@ extern int mp_find_ioapic(u32 gsi); extern int mp_find_ioapic_pin(int ioapic, u32 gsi); extern u32 mp_pin_to_gsi(int ioapic, int pin); extern int mp_map_gsi_to_irq(u32 gsi, unsigned int flags); -extern void __init mp_register_ioapic(int id, u32 address, u32 gsi_base); +extern void __init mp_register_ioapic(int id, u32 address, u32 gsi_base, + struct ioapic_domain_cfg *cfg); extern void __init pre_init_apic_IRQ0(void); extern void mp_save_irq(struct mpc_intsrc *m); diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index d6635baf9e3d..f86b4bae4640 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -462,7 +462,7 @@ acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end) acpi_table_print_madt_entry(header); mp_register_ioapic(ioapic->id, - ioapic->address, ioapic->global_irq_base); + ioapic->address, ioapic->global_irq_base, NULL); return 0; } diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 51ce80004a78..563f4504f54d 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -85,6 +85,7 @@ int sis_apic_bug = -1; static DEFINE_RAW_SPINLOCK(ioapic_lock); static DEFINE_RAW_SPINLOCK(vector_lock); static DEFINE_MUTEX(ioapic_mutex); +static unsigned int ioapic_dynirq_base; static struct ioapic { /* @@ -2920,8 +2921,35 @@ out: */ #define PIC_IRQS (1UL << PIC_CASCADE_IR) +static int mp_irqdomain_create(int ioapic) +{ + int hwirqs = mp_ioapic_pin_count(ioapic); + struct ioapic *ip = &ioapics[ioapic]; + struct ioapic_domain_cfg *cfg = &ip->irqdomain_cfg; + struct mp_ioapic_gsi *gsi_cfg = mp_ioapic_gsi_routing(ioapic); + + if (cfg->type == IOAPIC_DOMAIN_INVALID) + return 0; + + ip->irqdomain = irq_domain_add_linear(cfg->dev, hwirqs, cfg->ops, + (void *)(long)ioapic); + if(!ip->irqdomain) + return -ENOMEM; + + if (cfg->type == IOAPIC_DOMAIN_LEGACY || + cfg->type == IOAPIC_DOMAIN_STRICT) + ioapic_dynirq_base = max(ioapic_dynirq_base, + gsi_cfg->gsi_end + 1); + + if (gsi_cfg->gsi_base == 0) + irq_set_default_host(ip->irqdomain); + + return 0; +} + void __init setup_IO_APIC(void) { + int ioapic; /* * calling enable_IO_APIC() is moved to setup_local_APIC for BP @@ -2929,6 +2957,9 @@ void __init setup_IO_APIC(void) io_apic_irqs = nr_legacy_irqs() ? ~PIC_IRQS : ~0UL; apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); + for_each_ioapic(ioapic) + BUG_ON(mp_irqdomain_create(ioapic)); + /* * Set up IO-APIC IRQ routing. */ @@ -3437,6 +3468,9 @@ unsigned int arch_dynirq_lower_bound(unsigned int from) { unsigned int min = gsi_top + nr_legacy_irqs(); + if (ioapic_dynirq_base) + return ioapic_dynirq_base; + return from < min ? min : from; } @@ -3812,7 +3846,8 @@ static __init int bad_ioapic_register(int idx) return 0; } -void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) +void __init mp_register_ioapic(int id, u32 address, u32 gsi_base, + struct ioapic_domain_cfg *cfg) { int idx = 0; int entries; @@ -3826,6 +3861,11 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) ioapics[idx].mp_config.type = MP_IOAPIC; ioapics[idx].mp_config.flags = MPC_APIC_USABLE; ioapics[idx].mp_config.apicaddr = address; + ioapics[idx].irqdomain = NULL; + if (cfg) + ioapics[idx].irqdomain_cfg = *cfg; + else + ioapics[idx].irqdomain_cfg.type = IOAPIC_DOMAIN_INVALID; set_fixmap_nocache(FIX_IO_APIC_BASE_0 + idx, address); diff --git a/arch/x86/kernel/devicetree.c b/arch/x86/kernel/devicetree.c index b4680058db8b..d2c53feacd77 100644 --- a/arch/x86/kernel/devicetree.c +++ b/arch/x86/kernel/devicetree.c @@ -177,7 +177,7 @@ static void __init dtb_add_ioapic(struct device_node *dn) dn->full_name); return; } - mp_register_ioapic(++ioapic_id, r.start, gsi_top); + mp_register_ioapic(++ioapic_id, r.start, gsi_top, NULL); } static void __init dtb_ioapic_setup(void) diff --git a/arch/x86/kernel/mpparse.c b/arch/x86/kernel/mpparse.c index b10e1132f316..ea8595e4cbd5 100644 --- a/arch/x86/kernel/mpparse.c +++ b/arch/x86/kernel/mpparse.c @@ -115,7 +115,7 @@ static void __init MP_bus_info(struct mpc_bus *m) static void __init MP_ioapic_info(struct mpc_ioapic *m) { if (m->flags & MPC_APIC_USABLE) - mp_register_ioapic(m->apicid, m->apicaddr, gsi_top); + mp_register_ioapic(m->apicid, m->apicaddr, gsi_top, NULL); } static void __init print_mp_irq_info(struct mpc_intsrc *mp_irq) diff --git a/arch/x86/platform/sfi/sfi.c b/arch/x86/platform/sfi/sfi.c index bcd1a703e3e6..8f2f789c6f04 100644 --- a/arch/x86/platform/sfi/sfi.c +++ b/arch/x86/platform/sfi/sfi.c @@ -82,7 +82,7 @@ static int __init sfi_parse_ioapic(struct sfi_table_header *table) pentry = (struct sfi_apic_table_entry *)sb->pentry; for (i = 0; i < num; i++) { - mp_register_ioapic(i, pentry->phys_addr, gsi_top); + mp_register_ioapic(i, pentry->phys_addr, gsi_top, NULL); pentry++; } -- cgit v1.2.3 From ca7e28aa4ff34fdd6622d915682b2765453c5ddd Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 9 Jun 2014 16:19:54 +0800 Subject: x86, ACPI, irq: Provide basic irqdomain support Enhance ACPI driver to provide basic irqdomain support for IOAPIC. We will build identity mapping for IOAPICs hosting legacy IRQs, otherwise dynamically allocate IRQ numbers for IOAPIC pins on demand. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Len Brown Cc: Pavel Machek Link: http://lkml.kernel.org/r/1402302011-23642-26-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/acpi/boot.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'arch/x86/kernel/acpi/boot.c') diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index f86b4bae4640..8d9aee1e67e8 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -31,6 +31,7 @@ #include #include #include +#include #include #include #include @@ -449,10 +450,16 @@ static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, return irq; } +static struct irq_domain_ops acpi_irqdomain_ops; + static int __init acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end) { struct acpi_madt_io_apic *ioapic = NULL; + struct ioapic_domain_cfg cfg = { + .type = IOAPIC_DOMAIN_DYNAMIC, + .ops = &acpi_irqdomain_ops, + }; ioapic = (struct acpi_madt_io_apic *)header; @@ -461,8 +468,12 @@ acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end) acpi_table_print_madt_entry(header); - mp_register_ioapic(ioapic->id, - ioapic->address, ioapic->global_irq_base, NULL); + /* Statically assign IRQ numbers for IOAPICs hosting legacy IRQs */ + if (ioapic->global_irq_base < nr_legacy_irqs()) + cfg.type = IOAPIC_DOMAIN_LEGACY; + + mp_register_ioapic(ioapic->id, ioapic->address, ioapic->global_irq_base, + &cfg); return 0; } -- cgit v1.2.3 From d7b830013f59cf586c1cec3caa1ce7156da59a13 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 9 Jun 2014 16:19:59 +0800 Subject: x86, irq, ACPI: Use common irqdomain map interface to program IOAPIC pins Refine ACPI to use common irqdomain map interface to program IOAPIC pins, so we can unify the callsite to progam IOAPIC pins. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Len Brown Cc: Pavel Machek Link: http://lkml.kernel.org/r/1402302011-23642-31-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/acpi/boot.c | 44 ++++++++++++-------------------------------- 1 file changed, 12 insertions(+), 32 deletions(-) (limited to 'arch/x86/kernel/acpi/boot.c') diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 8d9aee1e67e8..9add76f15cb0 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -405,11 +405,7 @@ static int mp_config_acpi_gsi(struct device *dev, u32 gsi, int trigger, static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity) { - int irq; - int ioapic; - int ioapic_pin; - struct io_apic_irq_attr irq_attr; - int ret; + int irq, node; if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC) return gsi; @@ -418,39 +414,27 @@ static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, if (acpi_gbl_FADT.sci_interrupt == gsi) return gsi; + trigger = trigger == ACPI_EDGE_SENSITIVE ? 0 : 1; + polarity = polarity == ACPI_ACTIVE_HIGH ? 0 : 1; + node = dev ? dev_to_node(dev) : NUMA_NO_NODE; + if (mp_set_gsi_attr(gsi, trigger, polarity, node)) { + pr_warn("Failed to set pin attr for GSI%d\n", gsi); + return -1; + } + irq = map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC); if (irq < 0) return irq; - ioapic = mp_find_ioapic(gsi); - if (ioapic < 0) { - printk(KERN_WARNING "No IOAPIC for GSI %u\n", gsi); - return gsi; - } - - ioapic_pin = mp_find_ioapic_pin(ioapic, gsi); - - if (ioapic_pin > MP_MAX_IOAPIC_PIN) { - printk(KERN_ERR "Invalid reference to IOAPIC pin " - "%d-%d\n", mpc_ioapic_id(ioapic), - ioapic_pin); - return gsi; - } - if (enable_update_mptable) mp_config_acpi_gsi(dev, gsi, trigger, polarity); - set_io_apic_irq_attr(&irq_attr, ioapic, ioapic_pin, - trigger == ACPI_EDGE_SENSITIVE ? 0 : 1, - polarity == ACPI_ACTIVE_HIGH ? 0 : 1); - ret = io_apic_set_pci_routing(dev, irq, &irq_attr); - if (ret < 0) - irq = -1; - return irq; } -static struct irq_domain_ops acpi_irqdomain_ops; +static struct irq_domain_ops acpi_irqdomain_ops = { + .map = mp_irqdomain_map, +}; static int __init acpi_parse_ioapic(struct acpi_subtable_header * header, const unsigned long end) @@ -622,10 +606,6 @@ int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp) int irq = map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC | IOAPIC_MAP_CHECK); if (irq >= 0) { -#ifdef CONFIG_X86_IO_APIC - if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) - setup_IO_APIC_irq_extra(gsi); -#endif *irqp = irq; return 0; } -- cgit v1.2.3 From 16ee7b3dcc56be14b9a813612cff2cc2339cdced Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Mon, 9 Jun 2014 16:20:04 +0800 Subject: x86, irq: Simplify the way to handle ISA IRQ On startup, setup_IO_APIC_irqs() will program all IOAPIC pins for ISA IRQs. Later when mp_map_pin_to_irq() is called, it just returns ISA IRQ number without programming corresponding IOAPIC pin. This patch consolidates the way to program IOAPIC pins for both ISA and non-ISA IRQs into mp_map_pin_to_irq() as below: 1) For ISA IRQs, mp_irqs array is used to map IOAPIC pin to IRQ and mp_irqdomain_map() is used to actually program the pin. 2) For non-ISA IRQs, irqdomain is used to map IOAPIC pin to IRQ, and mp_irqdomain_map() is also used to actually program the pin. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Len Brown Cc: Pavel Machek Link: http://lkml.kernel.org/r/1402302011-23642-36-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/acpi/boot.c | 15 +------ arch/x86/kernel/apic/io_apic.c | 98 ++++++++++++++++-------------------------- 2 files changed, 40 insertions(+), 73 deletions(-) (limited to 'arch/x86/kernel/acpi/boot.c') diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 9add76f15cb0..fd4b6d2e436c 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -101,17 +101,6 @@ static u32 isa_irq_to_gsi[NR_IRQS_LEGACY] __read_mostly = { #define ACPI_INVALID_GSI INT_MIN -static int map_gsi_to_irq(unsigned int gsi, unsigned int flags) -{ - int i; - - for (i = 0; i < nr_legacy_irqs(); i++) - if (isa_irq_to_gsi[i] == gsi) - return i; - - return mp_map_gsi_to_irq(gsi, flags); -} - /* * This is just a simple wrapper around early_ioremap(), * with sanity checks for phys == 0 and size == 0. @@ -422,7 +411,7 @@ static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, return -1; } - irq = map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC); + irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC); if (irq < 0) return irq; @@ -603,7 +592,7 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger) int acpi_gsi_to_irq(u32 gsi, unsigned int *irqp) { - int irq = map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC | IOAPIC_MAP_CHECK); + int irq = mp_map_gsi_to_irq(gsi, IOAPIC_MAP_ALLOC | IOAPIC_MAP_CHECK); if (irq >= 0) { *irqp = irq; diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 6e3d4c771832..8485d904b653 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c @@ -204,8 +204,6 @@ static int __init parse_noapic(char *str) } early_param("noapic", parse_noapic); -static int io_apic_setup_irq_pin(unsigned int irq, int node, - struct io_apic_irq_attr *attr); static struct irq_cfg *alloc_irq_and_cfg_at(unsigned int at, int node); /* Will be called in mpparse/acpi/sfi codes for saving IRQ info */ @@ -1021,6 +1019,16 @@ static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin, struct irq_domain *domain = mp_ioapic_irqdomain(ioapic); struct mp_pin_info *info = mp_pin_info(ioapic, pin); + if (!domain) { + /* + * Provide an identity mapping of gsi == irq except on truly + * weird platforms that have non isa irqs in the first 16 gsis. + */ + return gsi >= nr_legacy_irqs() ? gsi : gsi_top + gsi; + } + + mutex_lock(&ioapic_mutex); + /* * Don't use irqdomain to manage ISA IRQs because there may be * multiple IOAPIC pins sharing the same ISA IRQ number and @@ -1033,28 +1041,30 @@ static int mp_map_pin_to_irq(u32 gsi, int idx, int ioapic, int pin, * the interrupt routing logic. Thus there may be multiple pins * sharing the same legacy IRQ number when ACPI is disabled. */ - if (idx >= 0 && test_bit(mp_irqs[idx].srcbus, mp_bus_not_pci)) - return mp_irqs[idx].srcbusirq; - - if (!domain) { - /* - * Provide an identity mapping of gsi == irq except on truly - * weird platforms that have non isa irqs in the first 16 gsis. - */ - return gsi >= nr_legacy_irqs() ? gsi : gsi_top + gsi; + if (idx >= 0 && test_bit(mp_irqs[idx].srcbus, mp_bus_not_pci)) { + irq = mp_irqs[idx].srcbusirq; + if (flags & IOAPIC_MAP_ALLOC) { + if (info->count == 0 && + mp_irqdomain_map(domain, irq, pin) != 0) + irq = -1; + + /* special handling for timer IRQ0 */ + if (irq == 0) + info->count++; + } + } else { + irq = irq_find_mapping(domain, pin); + if (irq <= 0 && (flags & IOAPIC_MAP_ALLOC)) + irq = alloc_irq_from_domain(domain, gsi, pin); } - mutex_lock(&ioapic_mutex); - irq = irq_find_mapping(domain, pin); - if (irq <= 0 && (flags & IOAPIC_MAP_ALLOC)) - irq = alloc_irq_from_domain(domain, gsi, pin); - if (flags & IOAPIC_MAP_ALLOC) { if (irq > 0) info->count++; else if (info->count == 0) info->set = 0; } + mutex_unlock(&ioapic_mutex); return irq > 0 ? irq : -1; @@ -1471,55 +1481,23 @@ static void setup_ioapic_irq(unsigned int irq, struct irq_cfg *cfg, ioapic_write_entry(attr->ioapic, attr->ioapic_pin, entry); } -static bool __init io_apic_pin_not_connected(int idx, int ioapic_idx, int pin) -{ - if (idx != -1) - return false; - - apic_printk(APIC_VERBOSE, KERN_DEBUG " apic %d pin %d not connected\n", - mpc_ioapic_id(ioapic_idx), pin); - return true; -} - -static void __init __io_apic_setup_irqs(unsigned int ioapic_idx) -{ - int idx, node = cpu_to_node(0); - struct io_apic_irq_attr attr; - unsigned int pin, irq; - - for_each_pin(ioapic_idx, pin) { - idx = find_irq_entry(ioapic_idx, pin, mp_INT); - if (io_apic_pin_not_connected(idx, ioapic_idx, pin)) - continue; - - irq = pin_2_irq(idx, ioapic_idx, pin, - ioapic_idx ? 0 : IOAPIC_MAP_ALLOC); - if (irq < 0 || !mp_init_irq_at_boot(ioapic_idx, irq)) - continue; - - /* - * Skip the timer IRQ if there's a quirk handler - * installed and if it returns 1: - */ - if (apic->multi_timer_check && - apic->multi_timer_check(ioapic_idx, irq)) - continue; - - set_io_apic_irq_attr(&attr, ioapic_idx, pin, irq_trigger(idx), - irq_polarity(idx)); - - io_apic_setup_irq_pin(irq, node, &attr); - } -} - static void __init setup_IO_APIC_irqs(void) { - unsigned int ioapic_idx; + unsigned int ioapic, pin; + int idx; apic_printk(APIC_VERBOSE, KERN_DEBUG "init IO_APIC IRQs\n"); - for_each_ioapic(ioapic_idx) - __io_apic_setup_irqs(ioapic_idx); + for_each_ioapic_pin(ioapic, pin) { + idx = find_irq_entry(ioapic, pin, mp_INT); + if (idx < 0) + apic_printk(APIC_VERBOSE, + KERN_DEBUG " apic %d pin %d not connected\n", + mpc_ioapic_id(ioapic), pin); + else + pin_2_irq(idx, ioapic, pin, + ioapic ? 0 : IOAPIC_MAP_ALLOC); + } } /* -- cgit v1.2.3 From 6a38fa0e3c94dfd1394a71a2d47c9c4d47367374 Mon Sep 17 00:00:00 2001 From: Jiang Liu Date: Tue, 10 Jun 2014 14:16:27 +0800 Subject: x86, irq, ACPI: Release IOAPIC pin when PCI device is disabled Release IOAPIC pin associated with PCI device when the PCI device is disabled. Signed-off-by: Jiang Liu Cc: Konrad Rzeszutek Wilk Cc: Tony Luck Cc: Joerg Roedel Cc: Paul Gortmaker Cc: Greg Kroah-Hartman Cc: Benjamin Herrenschmidt Cc: Grant Likely Cc: Rafael J. Wysocki Cc: Bjorn Helgaas Cc: Randy Dunlap Cc: Yinghai Lu Cc: Len Brown Cc: Pavel Machek Link: http://lkml.kernel.org/r/1402380987-32577-1-git-send-email-jiang.liu@linux.intel.com Signed-off-by: Thomas Gleixner --- arch/x86/kernel/acpi/boot.c | 27 +++++++++++++++++++++++++++ drivers/acpi/pci_irq.c | 3 ++- 2 files changed, 29 insertions(+), 1 deletion(-) (limited to 'arch/x86/kernel/acpi/boot.c') diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index fd4b6d2e436c..8c28023924bf 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -421,8 +421,24 @@ static int mp_register_gsi(struct device *dev, u32 gsi, int trigger, return irq; } +static void mp_unregister_gsi(u32 gsi) +{ + int irq; + + if (acpi_irq_model != ACPI_IRQ_MODEL_IOAPIC) + return; + + if (acpi_gbl_FADT.sci_interrupt == gsi) + return; + + irq = mp_map_gsi_to_irq(gsi, 0); + if (irq > 0) + mp_unmap_irq(irq); +} + static struct irq_domain_ops acpi_irqdomain_ops = { .map = mp_irqdomain_map, + .unmap = mp_irqdomain_unmap, }; static int __init @@ -640,8 +656,16 @@ static int acpi_register_gsi_ioapic(struct device *dev, u32 gsi, return irq; } +static void acpi_unregister_gsi_ioapic(u32 gsi) +{ +#ifdef CONFIG_X86_IO_APIC + mp_unregister_gsi(gsi); +#endif +} + int (*__acpi_register_gsi)(struct device *dev, u32 gsi, int trigger, int polarity) = acpi_register_gsi_pic; +void (*__acpi_unregister_gsi)(u32 gsi) = NULL; #ifdef CONFIG_ACPI_SLEEP int (*acpi_suspend_lowlevel)(void) = x86_acpi_suspend_lowlevel; @@ -661,6 +685,8 @@ EXPORT_SYMBOL_GPL(acpi_register_gsi); void acpi_unregister_gsi(u32 gsi) { + if (__acpi_unregister_gsi) + __acpi_unregister_gsi(gsi); } EXPORT_SYMBOL_GPL(acpi_unregister_gsi); @@ -668,6 +694,7 @@ static void __init acpi_set_irq_model_ioapic(void) { acpi_irq_model = ACPI_IRQ_MODEL_IOAPIC; __acpi_register_gsi = acpi_register_gsi_ioapic; + __acpi_unregister_gsi = acpi_unregister_gsi_ioapic; acpi_ioapic = 1; } diff --git a/drivers/acpi/pci_irq.c b/drivers/acpi/pci_irq.c index 9c62340c2360..6ba463ceccc6 100644 --- a/drivers/acpi/pci_irq.c +++ b/drivers/acpi/pci_irq.c @@ -498,5 +498,6 @@ void acpi_pci_irq_disable(struct pci_dev *dev) */ dev_dbg(&dev->dev, "PCI INT %c disabled\n", pin_name(pin)); - acpi_unregister_gsi(gsi); + if (gsi >= 0 && dev->irq > 0) + acpi_unregister_gsi(gsi); } -- cgit v1.2.3 From b08ee5f7e4135d64b8edd769367f8964a725122e Mon Sep 17 00:00:00 2001 From: Borislav Petkov Date: Fri, 11 Jul 2014 12:43:38 +0200 Subject: x86: Simplify __HAVE_ARCH_CMPXCHG tests Both the 32-bit and 64-bit cmpxchg.h header define __HAVE_ARCH_CMPXCHG and there's ifdeffery which checks it. But since both bitness define it, we can just as well move it up to the main cmpxchg header and simpify a bit of code in doing that. Signed-off-by: Borislav Petkov Link: http://lkml.kernel.org/r/20140711104338.GB17083@pd.tnic Signed-off-by: H. Peter Anvin --- arch/x86/include/asm/cmpxchg.h | 4 ++-- arch/x86/include/asm/cmpxchg_32.h | 2 -- arch/x86/include/asm/cmpxchg_64.h | 2 -- arch/x86/include/asm/mc146818rtc.h | 2 +- arch/x86/include/asm/mutex_32.h | 16 ++-------------- arch/x86/kernel/acpi/boot.c | 4 ---- 6 files changed, 5 insertions(+), 25 deletions(-) (limited to 'arch/x86/kernel/acpi/boot.c') diff --git a/arch/x86/include/asm/cmpxchg.h b/arch/x86/include/asm/cmpxchg.h index d47786acb016..99c105d78b7e 100644 --- a/arch/x86/include/asm/cmpxchg.h +++ b/arch/x86/include/asm/cmpxchg.h @@ -4,6 +4,8 @@ #include #include /* Provides LOCK_PREFIX */ +#define __HAVE_ARCH_CMPXCHG 1 + /* * Non-existant functions to indicate usage errors at link time * (or compile-time if the compiler implements __compiletime_error(). @@ -143,7 +145,6 @@ extern void __add_wrong_size(void) # include #endif -#ifdef __HAVE_ARCH_CMPXCHG #define cmpxchg(ptr, old, new) \ __cmpxchg(ptr, old, new, sizeof(*(ptr))) @@ -152,7 +153,6 @@ extern void __add_wrong_size(void) #define cmpxchg_local(ptr, old, new) \ __cmpxchg_local(ptr, old, new, sizeof(*(ptr))) -#endif /* * xadd() adds "inc" to "*ptr" and atomically returns the previous diff --git a/arch/x86/include/asm/cmpxchg_32.h b/arch/x86/include/asm/cmpxchg_32.h index f8bf2eecab86..f7e142926481 100644 --- a/arch/x86/include/asm/cmpxchg_32.h +++ b/arch/x86/include/asm/cmpxchg_32.h @@ -34,8 +34,6 @@ static inline void set_64bit(volatile u64 *ptr, u64 value) : "memory"); } -#define __HAVE_ARCH_CMPXCHG 1 - #ifdef CONFIG_X86_CMPXCHG64 #define cmpxchg64(ptr, o, n) \ ((__typeof__(*(ptr)))__cmpxchg64((ptr), (unsigned long long)(o), \ diff --git a/arch/x86/include/asm/cmpxchg_64.h b/arch/x86/include/asm/cmpxchg_64.h index 614be87f1a9b..1af94697aae5 100644 --- a/arch/x86/include/asm/cmpxchg_64.h +++ b/arch/x86/include/asm/cmpxchg_64.h @@ -6,8 +6,6 @@ static inline void set_64bit(volatile u64 *ptr, u64 val) *ptr = val; } -#define __HAVE_ARCH_CMPXCHG 1 - #define cmpxchg64(ptr, o, n) \ ({ \ BUILD_BUG_ON(sizeof(*(ptr)) != 8); \ diff --git a/arch/x86/include/asm/mc146818rtc.h b/arch/x86/include/asm/mc146818rtc.h index a55c7efcc4ed..0f555cc31984 100644 --- a/arch/x86/include/asm/mc146818rtc.h +++ b/arch/x86/include/asm/mc146818rtc.h @@ -13,7 +13,7 @@ #define RTC_ALWAYS_BCD 1 /* RTC operates in binary mode */ #endif -#if defined(CONFIG_X86_32) && defined(__HAVE_ARCH_CMPXCHG) +#if defined(CONFIG_X86_32) /* * This lock provides nmi access to the CMOS/RTC registers. It has some * special properties. It is owned by a CPU and stores the index register diff --git a/arch/x86/include/asm/mutex_32.h b/arch/x86/include/asm/mutex_32.h index 0208c3c2cbc6..85e6cda45a02 100644 --- a/arch/x86/include/asm/mutex_32.h +++ b/arch/x86/include/asm/mutex_32.h @@ -100,23 +100,11 @@ do { \ static inline int __mutex_fastpath_trylock(atomic_t *count, int (*fail_fn)(atomic_t *)) { - /* - * We have two variants here. The cmpxchg based one is the best one - * because it never induce a false contention state. It is included - * here because architectures using the inc/dec algorithms over the - * xchg ones are much more likely to support cmpxchg natively. - * - * If not we fall back to the spinlock based variant - that is - * just as efficient (and simpler) as a 'destructive' probing of - * the mutex state would be. - */ -#ifdef __HAVE_ARCH_CMPXCHG + /* cmpxchg because it never induces a false contention state. */ if (likely(atomic_cmpxchg(count, 1, 0) == 1)) return 1; + return 0; -#else - return fail_fn(count); -#endif } #endif /* _ASM_X86_MUTEX_32_H */ diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index 86281ffb96d6..a531f6564ed0 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c @@ -74,10 +74,6 @@ int acpi_fix_pin2_polarity __initdata; static u64 acpi_lapic_addr __initdata = APIC_DEFAULT_PHYS_BASE; #endif -#ifndef __HAVE_ARCH_CMPXCHG -#warning ACPI uses CMPXCHG, i486 and later hardware -#endif - /* -------------------------------------------------------------------------- Boot-time Configuration -------------------------------------------------------------------------- */ -- cgit v1.2.3