diff options
author | Yinghai Lu <yhlu.kernel@gmail.com> | 2008-08-19 23:50:03 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-16 10:52:08 -0400 |
commit | 71f521bbaf375b685aeea20c6b0ed8600cd6edfe (patch) | |
tree | a18b8e8284ff7a68c341de8b1342866b9821ae7f | |
parent | a84488c213a8cfc29200344a6fb6357d48c8ed85 (diff) |
x86, irq: get nr_irqs from madt
Until now, NR_IRQS was derived from black magic defines that had to
be "large enough" to both accomodate NR_CPUS and MAX_NR_IO_APICs.
This resulted in a way too large irq_desc[] array on most x86 systems.
Especially with larger CPU masks, the size of irq_desc can spiral out
of control quickly.
So be smarter about it and use precise allocation instead: determine the
default maximum possible IRQ number from the ACPI MADT. Use a minimum limit
of at least 32 IRQs for broken BIOSes.
Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/kernel/acpi/boot.c | 30 | ||||
-rw-r--r-- | include/asm-x86/mpspec.h | 1 |
2 files changed, 29 insertions, 2 deletions
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c index eb875cdc7367..3e9d163fd92f 100644 --- a/arch/x86/kernel/acpi/boot.c +++ b/arch/x86/kernel/acpi/boot.c | |||
@@ -957,6 +957,29 @@ void __init mp_register_ioapic(int id, u32 address, u32 gsi_base) | |||
957 | nr_ioapics++; | 957 | nr_ioapics++; |
958 | } | 958 | } |
959 | 959 | ||
960 | int get_nr_irqs_via_madt(void) | ||
961 | { | ||
962 | int idx; | ||
963 | int nr = 0; | ||
964 | |||
965 | for (idx = 0; idx < nr_ioapics; idx++) { | ||
966 | if (mp_ioapic_routing[idx].gsi_end > nr) | ||
967 | nr = mp_ioapic_routing[idx].gsi_end; | ||
968 | } | ||
969 | |||
970 | nr++; | ||
971 | |||
972 | /* double it for hotplug and msi and nmi */ | ||
973 | nr <<= 1; | ||
974 | |||
975 | /* something wrong ? */ | ||
976 | if (nr < 32) | ||
977 | nr = 32; | ||
978 | |||
979 | return nr; | ||
980 | |||
981 | } | ||
982 | |||
960 | static void assign_to_mp_irq(struct mp_config_intsrc *m, | 983 | static void assign_to_mp_irq(struct mp_config_intsrc *m, |
961 | struct mp_config_intsrc *mp_irq) | 984 | struct mp_config_intsrc *mp_irq) |
962 | { | 985 | { |
@@ -1254,9 +1277,12 @@ static int __init acpi_parse_madt_ioapic_entries(void) | |||
1254 | return count; | 1277 | return count; |
1255 | } | 1278 | } |
1256 | 1279 | ||
1280 | |||
1281 | nr_irqs = get_nr_irqs_via_madt(); | ||
1282 | |||
1257 | count = | 1283 | count = |
1258 | acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr, | 1284 | acpi_table_parse_madt(ACPI_MADT_TYPE_INTERRUPT_OVERRIDE, acpi_parse_int_src_ovr, |
1259 | NR_IRQ_VECTORS); | 1285 | nr_irqs); |
1260 | if (count < 0) { | 1286 | if (count < 0) { |
1261 | printk(KERN_ERR PREFIX | 1287 | printk(KERN_ERR PREFIX |
1262 | "Error parsing interrupt source overrides entry\n"); | 1288 | "Error parsing interrupt source overrides entry\n"); |
@@ -1276,7 +1302,7 @@ static int __init acpi_parse_madt_ioapic_entries(void) | |||
1276 | 1302 | ||
1277 | count = | 1303 | count = |
1278 | acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src, | 1304 | acpi_table_parse_madt(ACPI_MADT_TYPE_NMI_SOURCE, acpi_parse_nmi_src, |
1279 | NR_IRQ_VECTORS); | 1305 | nr_irqs); |
1280 | if (count < 0) { | 1306 | if (count < 0) { |
1281 | printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); | 1307 | printk(KERN_ERR PREFIX "Error parsing NMI SRC entry\n"); |
1282 | /* TBD: Cleanup to allow fallback to MPS */ | 1308 | /* TBD: Cleanup to allow fallback to MPS */ |
diff --git a/include/asm-x86/mpspec.h b/include/asm-x86/mpspec.h index be2241a818f1..a0748021250b 100644 --- a/include/asm-x86/mpspec.h +++ b/include/asm-x86/mpspec.h | |||
@@ -60,6 +60,7 @@ extern void mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, | |||
60 | u32 gsi); | 60 | u32 gsi); |
61 | extern void mp_config_acpi_legacy_irqs(void); | 61 | extern void mp_config_acpi_legacy_irqs(void); |
62 | extern int mp_register_gsi(u32 gsi, int edge_level, int active_high_low); | 62 | extern int mp_register_gsi(u32 gsi, int edge_level, int active_high_low); |
63 | extern int get_nr_irqs_via_madt(void); | ||
63 | #ifdef CONFIG_X86_IO_APIC | 64 | #ifdef CONFIG_X86_IO_APIC |
64 | extern int mp_config_acpi_gsi(unsigned char number, unsigned int devfn, u8 pin, | 65 | extern int mp_config_acpi_gsi(unsigned char number, unsigned int devfn, u8 pin, |
65 | u32 gsi, int triggering, int polarity); | 66 | u32 gsi, int triggering, int polarity); |