diff options
Diffstat (limited to 'arch/x86/kernel/io_apic.c')
-rw-r--r-- | arch/x86/kernel/io_apic.c | 199 |
1 files changed, 74 insertions, 125 deletions
diff --git a/arch/x86/kernel/io_apic.c b/arch/x86/kernel/io_apic.c index e03bc0f87eef..6f80dc2f137e 100644 --- a/arch/x86/kernel/io_apic.c +++ b/arch/x86/kernel/io_apic.c | |||
@@ -107,7 +107,6 @@ static int __init parse_noapic(char *str) | |||
107 | } | 107 | } |
108 | early_param("noapic", parse_noapic); | 108 | early_param("noapic", parse_noapic); |
109 | 109 | ||
110 | struct irq_cfg; | ||
111 | struct irq_pin_list; | 110 | struct irq_pin_list; |
112 | struct irq_cfg { | 111 | struct irq_cfg { |
113 | unsigned int irq; | 112 | unsigned int irq; |
@@ -120,7 +119,7 @@ struct irq_cfg { | |||
120 | }; | 119 | }; |
121 | 120 | ||
122 | /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */ | 121 | /* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */ |
123 | static struct irq_cfg irq_cfg_legacy[] __initdata = { | 122 | static struct irq_cfg irq_cfgx[NR_IRQS] = { |
124 | [0] = { .irq = 0, .domain = CPU_MASK_ALL, .vector = IRQ0_VECTOR, }, | 123 | [0] = { .irq = 0, .domain = CPU_MASK_ALL, .vector = IRQ0_VECTOR, }, |
125 | [1] = { .irq = 1, .domain = CPU_MASK_ALL, .vector = IRQ1_VECTOR, }, | 124 | [1] = { .irq = 1, .domain = CPU_MASK_ALL, .vector = IRQ1_VECTOR, }, |
126 | [2] = { .irq = 2, .domain = CPU_MASK_ALL, .vector = IRQ2_VECTOR, }, | 125 | [2] = { .irq = 2, .domain = CPU_MASK_ALL, .vector = IRQ2_VECTOR, }, |
@@ -139,49 +138,27 @@ static struct irq_cfg irq_cfg_legacy[] __initdata = { | |||
139 | [15] = { .irq = 15, .domain = CPU_MASK_ALL, .vector = IRQ15_VECTOR, }, | 138 | [15] = { .irq = 15, .domain = CPU_MASK_ALL, .vector = IRQ15_VECTOR, }, |
140 | }; | 139 | }; |
141 | 140 | ||
142 | static struct irq_cfg irq_cfg_init = { .irq = -1U, }; | ||
143 | |||
144 | static void init_one_irq_cfg(struct irq_cfg *cfg) | ||
145 | { | ||
146 | memcpy(cfg, &irq_cfg_init, sizeof(struct irq_cfg)); | ||
147 | } | ||
148 | |||
149 | static struct irq_cfg *irq_cfgx; | ||
150 | |||
151 | static void __init init_work(void *data) | ||
152 | { | ||
153 | struct dyn_array *da = data; | ||
154 | struct irq_cfg *cfg; | ||
155 | int legacy_count; | ||
156 | int i; | ||
157 | |||
158 | cfg = *da->name; | ||
159 | |||
160 | memcpy(cfg, irq_cfg_legacy, sizeof(irq_cfg_legacy)); | ||
161 | |||
162 | legacy_count = ARRAY_SIZE(irq_cfg_legacy); | ||
163 | for (i = legacy_count; i < *da->nr; i++) | ||
164 | init_one_irq_cfg(&cfg[i]); | ||
165 | } | ||
166 | |||
167 | #define for_each_irq_cfg(irq, cfg) \ | 141 | #define for_each_irq_cfg(irq, cfg) \ |
168 | for (irq = 0, cfg = &irq_cfgx[irq]; irq < nr_irqs; irq++, cfg = &irq_cfgx[irq]) | 142 | for (irq = 0, cfg = irq_cfgx; irq < nr_irqs; irq++, cfg++) |
169 | 143 | ||
170 | DEFINE_DYN_ARRAY(irq_cfgx, sizeof(struct irq_cfg), nr_irqs, PAGE_SIZE, init_work); | 144 | static struct irq_cfg *irq_cfg(unsigned int irq) |
171 | |||
172 | struct irq_cfg *irq_cfg(unsigned int irq) | ||
173 | { | 145 | { |
174 | if (irq < nr_irqs) | 146 | return irq < nr_irqs ? irq_cfgx + irq : NULL; |
175 | return &irq_cfgx[irq]; | ||
176 | |||
177 | return NULL; | ||
178 | } | 147 | } |
179 | struct irq_cfg *irq_cfg_alloc(unsigned int irq) | 148 | |
149 | static struct irq_cfg *irq_cfg_alloc(unsigned int irq) | ||
180 | { | 150 | { |
181 | return irq_cfg(irq); | 151 | return irq_cfg(irq); |
182 | } | 152 | } |
183 | 153 | ||
184 | /* | 154 | /* |
155 | * Rough estimation of how many shared IRQs there are, can be changed | ||
156 | * anytime. | ||
157 | */ | ||
158 | #define MAX_PLUS_SHARED_IRQS NR_IRQS | ||
159 | #define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS) | ||
160 | |||
161 | /* | ||
185 | * This is performance-critical, we want to do it O(1) | 162 | * This is performance-critical, we want to do it O(1) |
186 | * | 163 | * |
187 | * the indexing order of this array favors 1:1 mappings | 164 | * the indexing order of this array favors 1:1 mappings |
@@ -193,59 +170,29 @@ struct irq_pin_list { | |||
193 | struct irq_pin_list *next; | 170 | struct irq_pin_list *next; |
194 | }; | 171 | }; |
195 | 172 | ||
196 | static struct irq_pin_list *irq_2_pin_head; | 173 | static struct irq_pin_list irq_2_pin_head[PIN_MAP_SIZE]; |
197 | /* fill one page ? */ | ||
198 | static int nr_irq_2_pin = 0x100; | ||
199 | static struct irq_pin_list *irq_2_pin_ptr; | 174 | static struct irq_pin_list *irq_2_pin_ptr; |
200 | static void __init irq_2_pin_init_work(void *data) | 175 | |
176 | static void __init irq_2_pin_init(void) | ||
201 | { | 177 | { |
202 | struct dyn_array *da = data; | 178 | struct irq_pin_list *pin = irq_2_pin_head; |
203 | struct irq_pin_list *pin; | ||
204 | int i; | 179 | int i; |
205 | 180 | ||
206 | pin = *da->name; | 181 | for (i = 1; i < PIN_MAP_SIZE; i++) |
207 | |||
208 | for (i = 1; i < *da->nr; i++) | ||
209 | pin[i-1].next = &pin[i]; | 182 | pin[i-1].next = &pin[i]; |
210 | 183 | ||
211 | irq_2_pin_ptr = &pin[0]; | 184 | irq_2_pin_ptr = &pin[0]; |
212 | } | 185 | } |
213 | DEFINE_DYN_ARRAY(irq_2_pin_head, sizeof(struct irq_pin_list), nr_irq_2_pin, PAGE_SIZE, irq_2_pin_init_work); | ||
214 | 186 | ||
215 | static struct irq_pin_list *get_one_free_irq_2_pin(void) | 187 | static struct irq_pin_list *get_one_free_irq_2_pin(void) |
216 | { | 188 | { |
217 | struct irq_pin_list *pin; | 189 | struct irq_pin_list *pin = irq_2_pin_ptr; |
218 | int i; | ||
219 | |||
220 | pin = irq_2_pin_ptr; | ||
221 | |||
222 | if (pin) { | ||
223 | irq_2_pin_ptr = pin->next; | ||
224 | pin->next = NULL; | ||
225 | return pin; | ||
226 | } | ||
227 | |||
228 | /* | ||
229 | * we run out of pre-allocate ones, allocate more | ||
230 | */ | ||
231 | printk(KERN_DEBUG "try to get more irq_2_pin %d\n", nr_irq_2_pin); | ||
232 | |||
233 | if (after_bootmem) | ||
234 | pin = kzalloc(sizeof(struct irq_pin_list)*nr_irq_2_pin, | ||
235 | GFP_ATOMIC); | ||
236 | else | ||
237 | pin = __alloc_bootmem_nopanic(sizeof(struct irq_pin_list) * | ||
238 | nr_irq_2_pin, PAGE_SIZE, 0); | ||
239 | 190 | ||
240 | if (!pin) | 191 | if (!pin) |
241 | panic("can not get more irq_2_pin\n"); | 192 | panic("can not get more irq_2_pin\n"); |
242 | 193 | ||
243 | for (i = 1; i < nr_irq_2_pin; i++) | ||
244 | pin[i-1].next = &pin[i]; | ||
245 | |||
246 | irq_2_pin_ptr = pin->next; | 194 | irq_2_pin_ptr = pin->next; |
247 | pin->next = NULL; | 195 | pin->next = NULL; |
248 | |||
249 | return pin; | 196 | return pin; |
250 | } | 197 | } |
251 | 198 | ||
@@ -284,8 +231,9 @@ static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned i | |||
284 | static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value) | 231 | static inline void io_apic_modify(unsigned int apic, unsigned int reg, unsigned int value) |
285 | { | 232 | { |
286 | struct io_apic __iomem *io_apic = io_apic_base(apic); | 233 | struct io_apic __iomem *io_apic = io_apic_base(apic); |
287 | if (sis_apic_bug) | 234 | |
288 | writel(reg, &io_apic->index); | 235 | if (sis_apic_bug) |
236 | writel(reg, &io_apic->index); | ||
289 | writel(value, &io_apic->data); | 237 | writel(value, &io_apic->data); |
290 | } | 238 | } |
291 | 239 | ||
@@ -1044,11 +992,11 @@ static int pin_2_irq(int idx, int apic, int pin) | |||
1044 | while (i < apic) | 992 | while (i < apic) |
1045 | irq += nr_ioapic_registers[i++]; | 993 | irq += nr_ioapic_registers[i++]; |
1046 | irq += pin; | 994 | irq += pin; |
1047 | /* | 995 | /* |
1048 | * For MPS mode, so far only needed by ES7000 platform | 996 | * For MPS mode, so far only needed by ES7000 platform |
1049 | */ | 997 | */ |
1050 | if (ioapic_renumber_irq) | 998 | if (ioapic_renumber_irq) |
1051 | irq = ioapic_renumber_irq(apic, irq); | 999 | irq = ioapic_renumber_irq(apic, irq); |
1052 | } | 1000 | } |
1053 | 1001 | ||
1054 | #ifdef CONFIG_X86_32 | 1002 | #ifdef CONFIG_X86_32 |
@@ -1232,19 +1180,19 @@ static struct irq_chip ir_ioapic_chip; | |||
1232 | #ifdef CONFIG_X86_32 | 1180 | #ifdef CONFIG_X86_32 |
1233 | static inline int IO_APIC_irq_trigger(int irq) | 1181 | static inline int IO_APIC_irq_trigger(int irq) |
1234 | { | 1182 | { |
1235 | int apic, idx, pin; | 1183 | int apic, idx, pin; |
1236 | 1184 | ||
1237 | for (apic = 0; apic < nr_ioapics; apic++) { | 1185 | for (apic = 0; apic < nr_ioapics; apic++) { |
1238 | for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { | 1186 | for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) { |
1239 | idx = find_irq_entry(apic, pin, mp_INT); | 1187 | idx = find_irq_entry(apic, pin, mp_INT); |
1240 | if ((idx != -1) && (irq == pin_2_irq(idx, apic, pin))) | 1188 | if ((idx != -1) && (irq == pin_2_irq(idx, apic, pin))) |
1241 | return irq_trigger(idx); | 1189 | return irq_trigger(idx); |
1242 | } | 1190 | } |
1243 | } | 1191 | } |
1244 | /* | 1192 | /* |
1245 | * nonexistent IRQs are edge default | 1193 | * nonexistent IRQs are edge default |
1246 | */ | 1194 | */ |
1247 | return 0; | 1195 | return 0; |
1248 | } | 1196 | } |
1249 | #else | 1197 | #else |
1250 | static inline int IO_APIC_irq_trigger(int irq) | 1198 | static inline int IO_APIC_irq_trigger(int irq) |
@@ -1509,8 +1457,8 @@ __apicdebuginit(void) print_IO_APIC(void) | |||
1509 | reg_01.raw = io_apic_read(apic, 1); | 1457 | reg_01.raw = io_apic_read(apic, 1); |
1510 | if (reg_01.bits.version >= 0x10) | 1458 | if (reg_01.bits.version >= 0x10) |
1511 | reg_02.raw = io_apic_read(apic, 2); | 1459 | reg_02.raw = io_apic_read(apic, 2); |
1512 | if (reg_01.bits.version >= 0x20) | 1460 | if (reg_01.bits.version >= 0x20) |
1513 | reg_03.raw = io_apic_read(apic, 3); | 1461 | reg_03.raw = io_apic_read(apic, 3); |
1514 | spin_unlock_irqrestore(&ioapic_lock, flags); | 1462 | spin_unlock_irqrestore(&ioapic_lock, flags); |
1515 | 1463 | ||
1516 | printk("\n"); | 1464 | printk("\n"); |
@@ -2089,9 +2037,9 @@ static int ioapic_retrigger_irq(unsigned int irq) | |||
2089 | #else | 2037 | #else |
2090 | static int ioapic_retrigger_irq(unsigned int irq) | 2038 | static int ioapic_retrigger_irq(unsigned int irq) |
2091 | { | 2039 | { |
2092 | send_IPI_self(irq_cfg(irq)->vector); | 2040 | send_IPI_self(irq_cfg(irq)->vector); |
2093 | 2041 | ||
2094 | return 1; | 2042 | return 1; |
2095 | } | 2043 | } |
2096 | #endif | 2044 | #endif |
2097 | 2045 | ||
@@ -2189,7 +2137,7 @@ static int migrate_irq_remapped_level(int irq) | |||
2189 | 2137 | ||
2190 | if (io_apic_level_ack_pending(irq)) { | 2138 | if (io_apic_level_ack_pending(irq)) { |
2191 | /* | 2139 | /* |
2192 | * Interrupt in progress. Migrating irq now will change the | 2140 | * Interrupt in progress. Migrating irq now will change the |
2193 | * vector information in the IO-APIC RTE and that will confuse | 2141 | * vector information in the IO-APIC RTE and that will confuse |
2194 | * the EOI broadcast performed by cpu. | 2142 | * the EOI broadcast performed by cpu. |
2195 | * So, delay the irq migration to the next instance. | 2143 | * So, delay the irq migration to the next instance. |
@@ -2426,28 +2374,28 @@ static void ack_apic_level(unsigned int irq) | |||
2426 | } | 2374 | } |
2427 | 2375 | ||
2428 | static struct irq_chip ioapic_chip __read_mostly = { | 2376 | static struct irq_chip ioapic_chip __read_mostly = { |
2429 | .name = "IO-APIC", | 2377 | .name = "IO-APIC", |
2430 | .startup = startup_ioapic_irq, | 2378 | .startup = startup_ioapic_irq, |
2431 | .mask = mask_IO_APIC_irq, | 2379 | .mask = mask_IO_APIC_irq, |
2432 | .unmask = unmask_IO_APIC_irq, | 2380 | .unmask = unmask_IO_APIC_irq, |
2433 | .ack = ack_apic_edge, | 2381 | .ack = ack_apic_edge, |
2434 | .eoi = ack_apic_level, | 2382 | .eoi = ack_apic_level, |
2435 | #ifdef CONFIG_SMP | 2383 | #ifdef CONFIG_SMP |
2436 | .set_affinity = set_ioapic_affinity_irq, | 2384 | .set_affinity = set_ioapic_affinity_irq, |
2437 | #endif | 2385 | #endif |
2438 | .retrigger = ioapic_retrigger_irq, | 2386 | .retrigger = ioapic_retrigger_irq, |
2439 | }; | 2387 | }; |
2440 | 2388 | ||
2441 | #ifdef CONFIG_INTR_REMAP | 2389 | #ifdef CONFIG_INTR_REMAP |
2442 | static struct irq_chip ir_ioapic_chip __read_mostly = { | 2390 | static struct irq_chip ir_ioapic_chip __read_mostly = { |
2443 | .name = "IR-IO-APIC", | 2391 | .name = "IR-IO-APIC", |
2444 | .startup = startup_ioapic_irq, | 2392 | .startup = startup_ioapic_irq, |
2445 | .mask = mask_IO_APIC_irq, | 2393 | .mask = mask_IO_APIC_irq, |
2446 | .unmask = unmask_IO_APIC_irq, | 2394 | .unmask = unmask_IO_APIC_irq, |
2447 | .ack = ack_x2apic_edge, | 2395 | .ack = ack_x2apic_edge, |
2448 | .eoi = ack_x2apic_level, | 2396 | .eoi = ack_x2apic_level, |
2449 | #ifdef CONFIG_SMP | 2397 | #ifdef CONFIG_SMP |
2450 | .set_affinity = set_ir_ioapic_affinity_irq, | 2398 | .set_affinity = set_ir_ioapic_affinity_irq, |
2451 | #endif | 2399 | #endif |
2452 | .retrigger = ioapic_retrigger_irq, | 2400 | .retrigger = ioapic_retrigger_irq, |
2453 | }; | 2401 | }; |
@@ -2636,8 +2584,8 @@ static inline void __init check_timer(void) | |||
2636 | 2584 | ||
2637 | local_irq_save(flags); | 2585 | local_irq_save(flags); |
2638 | 2586 | ||
2639 | ver = apic_read(APIC_LVR); | 2587 | ver = apic_read(APIC_LVR); |
2640 | ver = GET_APIC_VERSION(ver); | 2588 | ver = GET_APIC_VERSION(ver); |
2641 | 2589 | ||
2642 | /* | 2590 | /* |
2643 | * get/set the timer IRQ vector: | 2591 | * get/set the timer IRQ vector: |
@@ -2822,12 +2770,12 @@ void __init setup_IO_APIC(void) | |||
2822 | io_apic_irqs = ~PIC_IRQS; | 2770 | io_apic_irqs = ~PIC_IRQS; |
2823 | 2771 | ||
2824 | apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); | 2772 | apic_printk(APIC_VERBOSE, "ENABLING IO-APIC IRQs\n"); |
2825 | /* | 2773 | /* |
2826 | * Set up IO-APIC IRQ routing. | 2774 | * Set up IO-APIC IRQ routing. |
2827 | */ | 2775 | */ |
2828 | #ifdef CONFIG_X86_32 | 2776 | #ifdef CONFIG_X86_32 |
2829 | if (!acpi_ioapic) | 2777 | if (!acpi_ioapic) |
2830 | setup_ioapic_ids_from_mpc(); | 2778 | setup_ioapic_ids_from_mpc(); |
2831 | #endif | 2779 | #endif |
2832 | sync_Arb_IDs(); | 2780 | sync_Arb_IDs(); |
2833 | setup_IO_APIC_irqs(); | 2781 | setup_IO_APIC_irqs(); |
@@ -2842,9 +2790,9 @@ void __init setup_IO_APIC(void) | |||
2842 | 2790 | ||
2843 | static int __init io_apic_bug_finalize(void) | 2791 | static int __init io_apic_bug_finalize(void) |
2844 | { | 2792 | { |
2845 | if (sis_apic_bug == -1) | 2793 | if (sis_apic_bug == -1) |
2846 | sis_apic_bug = 0; | 2794 | sis_apic_bug = 0; |
2847 | return 0; | 2795 | return 0; |
2848 | } | 2796 | } |
2849 | 2797 | ||
2850 | late_initcall(io_apic_bug_finalize); | 2798 | late_initcall(io_apic_bug_finalize); |
@@ -3199,7 +3147,7 @@ static int msi_alloc_irte(struct pci_dev *dev, int irq, int nvec) | |||
3199 | if (index < 0) { | 3147 | if (index < 0) { |
3200 | printk(KERN_ERR | 3148 | printk(KERN_ERR |
3201 | "Unable to allocate %d IRTE for PCI %s\n", nvec, | 3149 | "Unable to allocate %d IRTE for PCI %s\n", nvec, |
3202 | pci_name(dev)); | 3150 | pci_name(dev)); |
3203 | return -ENOSPC; | 3151 | return -ENOSPC; |
3204 | } | 3152 | } |
3205 | return index; | 3153 | return index; |
@@ -3885,23 +3833,24 @@ static struct resource * __init ioapic_setup_resources(void) | |||
3885 | void __init ioapic_init_mappings(void) | 3833 | void __init ioapic_init_mappings(void) |
3886 | { | 3834 | { |
3887 | unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; | 3835 | unsigned long ioapic_phys, idx = FIX_IO_APIC_BASE_0; |
3888 | int i; | ||
3889 | struct resource *ioapic_res; | 3836 | struct resource *ioapic_res; |
3837 | int i; | ||
3890 | 3838 | ||
3839 | irq_2_pin_init(); | ||
3891 | ioapic_res = ioapic_setup_resources(); | 3840 | ioapic_res = ioapic_setup_resources(); |
3892 | for (i = 0; i < nr_ioapics; i++) { | 3841 | for (i = 0; i < nr_ioapics; i++) { |
3893 | if (smp_found_config) { | 3842 | if (smp_found_config) { |
3894 | ioapic_phys = mp_ioapics[i].mp_apicaddr; | 3843 | ioapic_phys = mp_ioapics[i].mp_apicaddr; |
3895 | #ifdef CONFIG_X86_32 | 3844 | #ifdef CONFIG_X86_32 |
3896 | if (!ioapic_phys) { | 3845 | if (!ioapic_phys) { |
3897 | printk(KERN_ERR | 3846 | printk(KERN_ERR |
3898 | "WARNING: bogus zero IO-APIC " | 3847 | "WARNING: bogus zero IO-APIC " |
3899 | "address found in MPTABLE, " | 3848 | "address found in MPTABLE, " |
3900 | "disabling IO/APIC support!\n"); | 3849 | "disabling IO/APIC support!\n"); |
3901 | smp_found_config = 0; | 3850 | smp_found_config = 0; |
3902 | skip_ioapic_setup = 1; | 3851 | skip_ioapic_setup = 1; |
3903 | goto fake_ioapic_page; | 3852 | goto fake_ioapic_page; |
3904 | } | 3853 | } |
3905 | #endif | 3854 | #endif |
3906 | } else { | 3855 | } else { |
3907 | #ifdef CONFIG_X86_32 | 3856 | #ifdef CONFIG_X86_32 |