aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorEric W. Biederman <ebiederm@xmission.com>2010-03-30 04:07:15 -0400
committerH. Peter Anvin <hpa@zytor.com>2010-05-04 16:35:17 -0400
commit988856ee1623bd37e384105f7bb2b7fe44c009f6 (patch)
tree399f084e7fcddd680b3873a4c9dc6b554405a867
parent4afc51a835d3aeba11c35090f524e05c84586d27 (diff)
x86, acpi/irq: Handle isa irqs that are not identity mapped to gsi's.
ACPI irq source overrides are allowed for the 16 isa irqs and are allowed to map any gsi to any isa irq. A few motherboards have been seen to take advantage of this and put the isa irqs on the 2nd or 3rd ioapic. This causes some problems, most notably the fact that we can not use any gsi < 16. To correct this move the gsis that are not isa irqs and have a gsi number < 16 into the linux irq space just past gsi_end. This is what the es7000 platform is doing today. Moving only the low 16 gsis above the rest of the gsi's only penalizes weird platforms, leaving sane acpi implementations with a 1-1 mapping of gsis and irqs. Signed-off-by: Eric W. Biederman <ebiederm@xmission.com> LKML-Reference: <1269936436-7039-14-git-send-email-ebiederm@xmission.com> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
-rw-r--r--arch/x86/kernel/acpi/boot.c57
-rw-r--r--arch/x86/kernel/apic/io_apic.c8
2 files changed, 59 insertions, 6 deletions
diff --git a/arch/x86/kernel/acpi/boot.c b/arch/x86/kernel/acpi/boot.c
index 07a63ce5811a..325fbbab7f89 100644
--- a/arch/x86/kernel/acpi/boot.c
+++ b/arch/x86/kernel/acpi/boot.c
@@ -94,6 +94,53 @@ enum acpi_irq_model_id acpi_irq_model = ACPI_IRQ_MODEL_PIC;
94 94
95 95
96/* 96/*
97 * ISA irqs by default are the first 16 gsis but can be
98 * any gsi as specified by an interrupt source override.
99 */
100static u32 isa_irq_to_gsi[NR_IRQS_LEGACY] __read_mostly = {
101 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15
102};
103
104static unsigned int gsi_to_irq(unsigned int gsi)
105{
106 unsigned int irq = gsi + NR_IRQS_LEGACY;
107 unsigned int i;
108
109 for (i = 0; i < NR_IRQS_LEGACY; i++) {
110 if (isa_irq_to_gsi[i] == gsi) {
111 return i;
112 }
113 }
114
115 /* Provide an identity mapping of gsi == irq
116 * except on truly weird platforms that have
117 * non isa irqs in the first 16 gsis.
118 */
119 if (gsi >= NR_IRQS_LEGACY)
120 irq = gsi;
121 else
122 irq = gsi_end + 1 + gsi;
123
124 return irq;
125}
126
127static u32 irq_to_gsi(int irq)
128{
129 unsigned int gsi;
130
131 if (irq < NR_IRQS_LEGACY)
132 gsi = isa_irq_to_gsi[irq];
133 else if (irq <= gsi_end)
134 gsi = irq;
135 else if (irq <= (gsi_end + NR_IRQS_LEGACY))
136 gsi = irq - gsi_end;
137 else
138 gsi = 0xffffffff;
139
140 return gsi;
141}
142
143/*
97 * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END, 144 * Temporarily use the virtual area starting from FIX_IO_APIC_BASE_END,
98 * to map the target physical address. The problem is that set_fixmap() 145 * to map the target physical address. The problem is that set_fixmap()
99 * provides a single page, and it is possible that the page is not 146 * provides a single page, and it is possible that the page is not
@@ -449,7 +496,7 @@ void __init acpi_pic_sci_set_trigger(unsigned int irq, u16 trigger)
449 496
450int acpi_gsi_to_irq(u32 gsi, unsigned int *irq) 497int acpi_gsi_to_irq(u32 gsi, unsigned int *irq)
451{ 498{
452 *irq = gsi; 499 *irq = gsi_to_irq(gsi);
453 500
454#ifdef CONFIG_X86_IO_APIC 501#ifdef CONFIG_X86_IO_APIC
455 if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC) 502 if (acpi_irq_model == ACPI_IRQ_MODEL_IOAPIC)
@@ -463,7 +510,7 @@ int acpi_isa_irq_to_gsi(unsigned isa_irq, u32 *gsi)
463{ 510{
464 if (isa_irq >= 16) 511 if (isa_irq >= 16)
465 return -1; 512 return -1;
466 *gsi = isa_irq; 513 *gsi = irq_to_gsi(isa_irq);
467 return 0; 514 return 0;
468} 515}
469 516
@@ -491,7 +538,7 @@ int acpi_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
491 plat_gsi = mp_register_gsi(dev, gsi, trigger, polarity); 538 plat_gsi = mp_register_gsi(dev, gsi, trigger, polarity);
492 } 539 }
493#endif 540#endif
494 irq = plat_gsi; 541 irq = gsi_to_irq(plat_gsi);
495 542
496 return irq; 543 return irq;
497} 544}
@@ -933,6 +980,8 @@ void __init mp_override_legacy_irq(u8 bus_irq, u8 polarity, u8 trigger, u32 gsi)
933 mp_irq.dstirq = pin; /* INTIN# */ 980 mp_irq.dstirq = pin; /* INTIN# */
934 981
935 save_mp_irq(&mp_irq); 982 save_mp_irq(&mp_irq);
983
984 isa_irq_to_gsi[bus_irq] = gsi;
936} 985}
937 986
938void __init mp_config_acpi_legacy_irqs(void) 987void __init mp_config_acpi_legacy_irqs(void)
@@ -1086,7 +1135,7 @@ int mp_register_gsi(struct device *dev, u32 gsi, int trigger, int polarity)
1086 set_io_apic_irq_attr(&irq_attr, ioapic, ioapic_pin, 1135 set_io_apic_irq_attr(&irq_attr, ioapic, ioapic_pin,
1087 trigger == ACPI_EDGE_SENSITIVE ? 0 : 1, 1136 trigger == ACPI_EDGE_SENSITIVE ? 0 : 1,
1088 polarity == ACPI_ACTIVE_HIGH ? 0 : 1); 1137 polarity == ACPI_ACTIVE_HIGH ? 0 : 1);
1089 io_apic_set_pci_routing(dev, gsi, &irq_attr); 1138 io_apic_set_pci_routing(dev, gsi_to_irq(gsi), &irq_attr);
1090 1139
1091 return gsi; 1140 return gsi;
1092} 1141}
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 9f3f6ca86dac..594827c3c615 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -1037,7 +1037,11 @@ static int pin_2_irq(int idx, int apic, int pin)
1037 */ 1037 */
1038 if (ioapic_renumber_irq) 1038 if (ioapic_renumber_irq)
1039 gsi = ioapic_renumber_irq(apic, gsi); 1039 gsi = ioapic_renumber_irq(apic, gsi);
1040 irq = gsi; 1040
1041 if (gsi >= NR_IRQS_LEGACY)
1042 irq = gsi;
1043 else
1044 irq = gsi_end + 1 + gsi;
1041 } 1045 }
1042 1046
1043#ifdef CONFIG_X86_32 1047#ifdef CONFIG_X86_32
@@ -3852,7 +3856,7 @@ void __init probe_nr_irqs_gsi(void)
3852{ 3856{
3853 int nr; 3857 int nr;
3854 3858
3855 nr = gsi_end + 1; 3859 nr = gsi_end + 1 + NR_IRQS_LEGACY;
3856 if (nr > nr_irqs_gsi) 3860 if (nr > nr_irqs_gsi)
3857 nr_irqs_gsi = nr; 3861 nr_irqs_gsi = nr;
3858 3862