diff options
-rw-r--r-- | arch/x86/kernel/io_apic_32.c | 152 |
1 files changed, 117 insertions, 35 deletions
diff --git a/arch/x86/kernel/io_apic_32.c b/arch/x86/kernel/io_apic_32.c index 5a83d7f5b147..59d2e8a273e3 100644 --- a/arch/x86/kernel/io_apic_32.c +++ b/arch/x86/kernel/io_apic_32.c | |||
@@ -95,10 +95,11 @@ DECLARE_BITMAP(mp_bus_not_pci, MAX_MP_BUSSES); | |||
95 | static int disable_timer_pin_1 __initdata; | 95 | static int disable_timer_pin_1 __initdata; |
96 | 96 | ||
97 | struct irq_cfg; | 97 | struct irq_cfg; |
98 | 98 | struct irq_pin_list; | |
99 | struct irq_cfg { | 99 | struct irq_cfg { |
100 | unsigned int irq; | 100 | unsigned int irq; |
101 | struct irq_cfg *next; | 101 | struct irq_cfg *next; |
102 | struct irq_pin_list *irq_2_pin; | ||
102 | u8 vector; | 103 | u8 vector; |
103 | }; | 104 | }; |
104 | 105 | ||
@@ -275,11 +276,66 @@ int pin_map_size; | |||
275 | * between pins and IRQs. | 276 | * between pins and IRQs. |
276 | */ | 277 | */ |
277 | 278 | ||
278 | static struct irq_pin_list { | 279 | struct irq_pin_list { |
279 | int apic, pin, next; | 280 | int apic, pin; |
280 | } *irq_2_pin; | 281 | struct irq_pin_list *next; |
282 | }; | ||
283 | |||
284 | static struct irq_pin_list *irq_2_pin_head; | ||
285 | /* fill one page ? */ | ||
286 | static int nr_irq_2_pin = 0x100; | ||
287 | static struct irq_pin_list *irq_2_pin_ptr; | ||
288 | static void __init irq_2_pin_init_work(void *data) | ||
289 | { | ||
290 | struct dyn_array *da = data; | ||
291 | struct irq_pin_list *pin; | ||
292 | int i; | ||
293 | |||
294 | pin = *da->name; | ||
295 | |||
296 | for (i = 1; i < *da->nr; i++) | ||
297 | pin[i-1].next = &pin[i]; | ||
298 | |||
299 | irq_2_pin_ptr = &pin[0]; | ||
300 | } | ||
301 | DEFINE_DYN_ARRAY(irq_2_pin_head, sizeof(struct irq_pin_list), nr_irq_2_pin, PAGE_SIZE, irq_2_pin_init_work); | ||
302 | |||
303 | static struct irq_pin_list *get_one_free_irq_2_pin(void) | ||
304 | { | ||
305 | struct irq_pin_list *pin; | ||
306 | int i; | ||
307 | |||
308 | pin = irq_2_pin_ptr; | ||
309 | |||
310 | if (pin) { | ||
311 | irq_2_pin_ptr = pin->next; | ||
312 | pin->next = NULL; | ||
313 | return pin; | ||
314 | } | ||
315 | |||
316 | /* | ||
317 | * we run out of pre-allocate ones, allocate more | ||
318 | */ | ||
319 | printk(KERN_DEBUG "try to get more irq_2_pin %d\n", nr_irq_2_pin); | ||
320 | |||
321 | if (after_bootmem) | ||
322 | pin = kzalloc(sizeof(struct irq_pin_list)*nr_irq_2_pin, | ||
323 | GFP_ATOMIC); | ||
324 | else | ||
325 | pin = __alloc_bootmem_nopanic(sizeof(struct irq_pin_list) * | ||
326 | nr_irq_2_pin, PAGE_SIZE, 0); | ||
327 | |||
328 | if (!pin) | ||
329 | panic("can not get more irq_2_pin\n"); | ||
281 | 330 | ||
282 | DEFINE_DYN_ARRAY(irq_2_pin, sizeof(struct irq_pin_list), pin_map_size, 16, NULL); | 331 | for (i = 1; i < nr_irq_2_pin; i++) |
332 | pin[i-1].next = &pin[i]; | ||
333 | |||
334 | irq_2_pin_ptr = pin->next; | ||
335 | pin->next = NULL; | ||
336 | |||
337 | return pin; | ||
338 | } | ||
283 | 339 | ||
284 | struct io_apic { | 340 | struct io_apic { |
285 | unsigned int index; | 341 | unsigned int index; |
@@ -383,20 +439,34 @@ static void ioapic_mask_entry(int apic, int pin) | |||
383 | */ | 439 | */ |
384 | static void add_pin_to_irq(unsigned int irq, int apic, int pin) | 440 | static void add_pin_to_irq(unsigned int irq, int apic, int pin) |
385 | { | 441 | { |
386 | struct irq_pin_list *entry = irq_2_pin + irq; | 442 | struct irq_cfg *cfg; |
443 | struct irq_pin_list *entry; | ||
444 | |||
445 | /* first time to refer irq_cfg, so with new */ | ||
446 | cfg = irq_cfg_alloc(irq); | ||
447 | entry = cfg->irq_2_pin; | ||
448 | if (!entry) { | ||
449 | entry = get_one_free_irq_2_pin(); | ||
450 | cfg->irq_2_pin = entry; | ||
451 | entry->apic = apic; | ||
452 | entry->pin = pin; | ||
453 | printk(KERN_DEBUG " 0 add_pin_to_irq: irq %d --> apic %d pin %d\n", irq, apic, pin); | ||
454 | return; | ||
455 | } | ||
387 | 456 | ||
388 | irq_cfg_alloc(irq); | 457 | while (entry->next) { |
389 | while (entry->next) | 458 | /* not again, please */ |
390 | entry = irq_2_pin + entry->next; | 459 | if (entry->apic == apic && entry->pin == pin) |
460 | return; | ||
391 | 461 | ||
392 | if (entry->pin != -1) { | 462 | entry = entry->next; |
393 | entry->next = first_free_entry; | ||
394 | entry = irq_2_pin + entry->next; | ||
395 | if (++first_free_entry >= pin_map_size) | ||
396 | panic("io_apic.c: whoops"); | ||
397 | } | 463 | } |
464 | |||
465 | entry->next = get_one_free_irq_2_pin(); | ||
466 | entry = entry->next; | ||
398 | entry->apic = apic; | 467 | entry->apic = apic; |
399 | entry->pin = pin; | 468 | entry->pin = pin; |
469 | printk(KERN_DEBUG " x add_pin_to_irq: irq %d --> apic %d pin %d\n", irq, apic, pin); | ||
400 | } | 470 | } |
401 | 471 | ||
402 | /* | 472 | /* |
@@ -406,35 +476,45 @@ static void __init replace_pin_at_irq(unsigned int irq, | |||
406 | int oldapic, int oldpin, | 476 | int oldapic, int oldpin, |
407 | int newapic, int newpin) | 477 | int newapic, int newpin) |
408 | { | 478 | { |
409 | struct irq_pin_list *entry = irq_2_pin + irq; | 479 | struct irq_cfg *cfg = irq_cfg(irq); |
480 | struct irq_pin_list *entry = cfg->irq_2_pin; | ||
481 | int replaced = 0; | ||
410 | 482 | ||
411 | while (1) { | 483 | while (entry) { |
412 | if (entry->apic == oldapic && entry->pin == oldpin) { | 484 | if (entry->apic == oldapic && entry->pin == oldpin) { |
413 | entry->apic = newapic; | 485 | entry->apic = newapic; |
414 | entry->pin = newpin; | 486 | entry->pin = newpin; |
415 | } | 487 | replaced = 1; |
416 | if (!entry->next) | 488 | /* every one is different, right? */ |
417 | break; | 489 | break; |
418 | entry = irq_2_pin + entry->next; | 490 | } |
491 | entry = entry->next; | ||
419 | } | 492 | } |
493 | |||
494 | /* why? call replace before add? */ | ||
495 | if (!replaced) | ||
496 | add_pin_to_irq(irq, newapic, newpin); | ||
420 | } | 497 | } |
421 | 498 | ||
422 | static void __modify_IO_APIC_irq(unsigned int irq, unsigned long enable, unsigned long disable) | 499 | static void __modify_IO_APIC_irq(unsigned int irq, unsigned long enable, unsigned long disable) |
423 | { | 500 | { |
424 | struct irq_pin_list *entry = irq_2_pin + irq; | 501 | struct irq_cfg *cfg; |
502 | struct irq_pin_list *entry; | ||
425 | unsigned int pin, reg; | 503 | unsigned int pin, reg; |
426 | 504 | ||
505 | cfg = irq_cfg(irq); | ||
506 | entry = cfg->irq_2_pin; | ||
427 | for (;;) { | 507 | for (;;) { |
428 | pin = entry->pin; | 508 | if (!entry) |
429 | if (pin == -1) | ||
430 | break; | 509 | break; |
510 | pin = entry->pin; | ||
431 | reg = io_apic_read(entry->apic, 0x10 + pin*2); | 511 | reg = io_apic_read(entry->apic, 0x10 + pin*2); |
432 | reg &= ~disable; | 512 | reg &= ~disable; |
433 | reg |= enable; | 513 | reg |= enable; |
434 | io_apic_modify(entry->apic, 0x10 + pin*2, reg); | 514 | io_apic_modify(entry->apic, 0x10 + pin*2, reg); |
435 | if (!entry->next) | 515 | if (!entry->next) |
436 | break; | 516 | break; |
437 | entry = irq_2_pin + entry->next; | 517 | entry = entry->next; |
438 | } | 518 | } |
439 | } | 519 | } |
440 | 520 | ||
@@ -509,13 +589,18 @@ static void clear_IO_APIC(void) | |||
509 | #ifdef CONFIG_SMP | 589 | #ifdef CONFIG_SMP |
510 | static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) | 590 | static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) |
511 | { | 591 | { |
592 | struct irq_cfg *cfg; | ||
512 | unsigned long flags; | 593 | unsigned long flags; |
513 | int pin; | 594 | int pin; |
514 | struct irq_pin_list *entry = irq_2_pin + irq; | 595 | struct irq_pin_list *entry; |
515 | unsigned int apicid_value; | 596 | unsigned int apicid_value; |
516 | cpumask_t tmp; | 597 | cpumask_t tmp; |
517 | struct irq_desc *desc; | 598 | struct irq_desc *desc; |
518 | 599 | ||
600 | |||
601 | cfg = irq_cfg(irq); | ||
602 | entry = cfg->irq_2_pin; | ||
603 | |||
519 | cpus_and(tmp, cpumask, cpu_online_map); | 604 | cpus_and(tmp, cpumask, cpu_online_map); |
520 | if (cpus_empty(tmp)) | 605 | if (cpus_empty(tmp)) |
521 | tmp = TARGET_CPUS; | 606 | tmp = TARGET_CPUS; |
@@ -527,13 +612,13 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) | |||
527 | apicid_value = apicid_value << 24; | 612 | apicid_value = apicid_value << 24; |
528 | spin_lock_irqsave(&ioapic_lock, flags); | 613 | spin_lock_irqsave(&ioapic_lock, flags); |
529 | for (;;) { | 614 | for (;;) { |
530 | pin = entry->pin; | 615 | if (!entry) |
531 | if (pin == -1) | ||
532 | break; | 616 | break; |
617 | pin = entry->pin; | ||
533 | io_apic_write(entry->apic, 0x10 + 1 + pin*2, apicid_value); | 618 | io_apic_write(entry->apic, 0x10 + 1 + pin*2, apicid_value); |
534 | if (!entry->next) | 619 | if (!entry->next) |
535 | break; | 620 | break; |
536 | entry = irq_2_pin + entry->next; | 621 | entry = entry->next; |
537 | } | 622 | } |
538 | desc = irq_to_desc(irq); | 623 | desc = irq_to_desc(irq); |
539 | desc->affinity = cpumask; | 624 | desc->affinity = cpumask; |
@@ -1152,6 +1237,7 @@ __apicdebuginit(void) print_IO_APIC(void) | |||
1152 | union IO_APIC_reg_02 reg_02; | 1237 | union IO_APIC_reg_02 reg_02; |
1153 | union IO_APIC_reg_03 reg_03; | 1238 | union IO_APIC_reg_03 reg_03; |
1154 | unsigned long flags; | 1239 | unsigned long flags; |
1240 | struct irq_cfg *cfg; | ||
1155 | 1241 | ||
1156 | if (apic_verbosity == APIC_QUIET) | 1242 | if (apic_verbosity == APIC_QUIET) |
1157 | return; | 1243 | return; |
@@ -1240,16 +1326,16 @@ __apicdebuginit(void) print_IO_APIC(void) | |||
1240 | } | 1326 | } |
1241 | } | 1327 | } |
1242 | printk(KERN_DEBUG "IRQ to pin mappings:\n"); | 1328 | printk(KERN_DEBUG "IRQ to pin mappings:\n"); |
1243 | for (i = 0; i < nr_irqs; i++) { | 1329 | for_each_irq_cfg(cfg) { |
1244 | struct irq_pin_list *entry = irq_2_pin + i; | 1330 | struct irq_pin_list *entry = cfg->irq_2_pin; |
1245 | if (entry->pin < 0) | 1331 | if (!entry) |
1246 | continue; | 1332 | continue; |
1247 | printk(KERN_DEBUG "IRQ%d ", i); | 1333 | printk(KERN_DEBUG "IRQ%d ", i); |
1248 | for (;;) { | 1334 | for (;;) { |
1249 | printk("-> %d:%d", entry->apic, entry->pin); | 1335 | printk("-> %d:%d", entry->apic, entry->pin); |
1250 | if (!entry->next) | 1336 | if (!entry->next) |
1251 | break; | 1337 | break; |
1252 | entry = irq_2_pin + entry->next; | 1338 | entry = entry->next; |
1253 | } | 1339 | } |
1254 | printk("\n"); | 1340 | printk("\n"); |
1255 | } | 1341 | } |
@@ -1420,10 +1506,6 @@ static void __init enable_IO_APIC(void) | |||
1420 | int i, apic; | 1506 | int i, apic; |
1421 | unsigned long flags; | 1507 | unsigned long flags; |
1422 | 1508 | ||
1423 | for (i = 0; i < pin_map_size; i++) { | ||
1424 | irq_2_pin[i].pin = -1; | ||
1425 | irq_2_pin[i].next = 0; | ||
1426 | } | ||
1427 | if (!pirqs_enabled) | 1509 | if (!pirqs_enabled) |
1428 | for (i = 0; i < MAX_PIRQS; i++) | 1510 | for (i = 0; i < MAX_PIRQS; i++) |
1429 | pirq_entries[i] = -1; | 1511 | pirq_entries[i] = -1; |