aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/io_apic_32.c152
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);
95static int disable_timer_pin_1 __initdata; 95static int disable_timer_pin_1 __initdata;
96 96
97struct irq_cfg; 97struct irq_cfg;
98 98struct irq_pin_list;
99struct irq_cfg { 99struct 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
278static struct irq_pin_list { 279struct irq_pin_list {
279 int apic, pin, next; 280 int apic, pin;
280} *irq_2_pin; 281 struct irq_pin_list *next;
282};
283
284static struct irq_pin_list *irq_2_pin_head;
285/* fill one page ? */
286static int nr_irq_2_pin = 0x100;
287static struct irq_pin_list *irq_2_pin_ptr;
288static 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}
301DEFINE_DYN_ARRAY(irq_2_pin_head, sizeof(struct irq_pin_list), nr_irq_2_pin, PAGE_SIZE, irq_2_pin_init_work);
302
303static 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
282DEFINE_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
284struct io_apic { 340struct 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 */
384static void add_pin_to_irq(unsigned int irq, int apic, int pin) 440static 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
422static void __modify_IO_APIC_irq(unsigned int irq, unsigned long enable, unsigned long disable) 499static 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
510static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t cpumask) 590static 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;