diff options
author | Yinghai Lu <yhlu.kernel@gmail.com> | 2008-08-19 23:50:07 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2008-10-16 10:52:31 -0400 |
commit | e5a53714acfc7b5f868d07d27c5f02cb00b118db (patch) | |
tree | 087446051c2af229177c1d2aa079d7255077ebb0 /arch/x86/kernel/io_apic_64.c | |
parent | 3ac2de48ed3c998df7f366e039c97eedb27e7c3d (diff) |
x86: put irq_2_pin pointer into irq_cfg
preallocate 32 irq_2_pin entries, and use get_one_free_irq_2_pin() to get
one more and link to irq_cfg if needed.
so don't waste one where no irq is enabled.
Signed-off-by: Yinghai Lu <yhlu.kernel@gmail.com>
Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86/kernel/io_apic_64.c')
-rw-r--r-- | arch/x86/kernel/io_apic_64.c | 161 |
1 files changed, 120 insertions, 41 deletions
diff --git a/arch/x86/kernel/io_apic_64.c b/arch/x86/kernel/io_apic_64.c index 858c37a31a2f..51ef7eb75f2e 100644 --- a/arch/x86/kernel/io_apic_64.c +++ b/arch/x86/kernel/io_apic_64.c | |||
@@ -58,10 +58,11 @@ | |||
58 | #define __apicdebuginit(type) static type __init | 58 | #define __apicdebuginit(type) static type __init |
59 | 59 | ||
60 | struct irq_cfg; | 60 | struct irq_cfg; |
61 | 61 | struct irq_pin_list; | |
62 | struct irq_cfg { | 62 | struct irq_cfg { |
63 | unsigned int irq; | 63 | unsigned int irq; |
64 | struct irq_cfg *next; | 64 | struct irq_cfg *next; |
65 | struct irq_pin_list *irq_2_pin; | ||
65 | cpumask_t domain; | 66 | cpumask_t domain; |
66 | cpumask_t old_domain; | 67 | cpumask_t old_domain; |
67 | unsigned move_cleanup_count; | 68 | unsigned move_cleanup_count; |
@@ -252,13 +253,66 @@ int pin_map_size; | |||
252 | * between pins and IRQs. | 253 | * between pins and IRQs. |
253 | */ | 254 | */ |
254 | 255 | ||
255 | static struct irq_pin_list { | 256 | struct irq_pin_list { |
256 | short apic, pin; | 257 | int apic, pin; |
257 | int next; | 258 | struct irq_pin_list *next; |
258 | } *irq_2_pin; | 259 | }; |
260 | |||
261 | static struct irq_pin_list *irq_2_pin_head; | ||
262 | /* fill one page ? */ | ||
263 | static int nr_irq_2_pin = 0x100; | ||
264 | static struct irq_pin_list *irq_2_pin_ptr; | ||
265 | static void __init irq_2_pin_init_work(void *data) | ||
266 | { | ||
267 | struct dyn_array *da = data; | ||
268 | struct irq_pin_list *pin; | ||
269 | int i; | ||
270 | |||
271 | pin = *da->name; | ||
272 | |||
273 | for (i = 1; i < *da->nr; i++) | ||
274 | pin[i-1].next = &pin[i]; | ||
275 | |||
276 | irq_2_pin_ptr = &pin[0]; | ||
277 | } | ||
278 | DEFINE_DYN_ARRAY(irq_2_pin_head, sizeof(struct irq_pin_list), nr_irq_2_pin, PAGE_SIZE, irq_2_pin_init_work); | ||
279 | |||
280 | static struct irq_pin_list *get_one_free_irq_2_pin(void) | ||
281 | { | ||
282 | struct irq_pin_list *pin; | ||
283 | int i; | ||
284 | |||
285 | pin = irq_2_pin_ptr; | ||
286 | |||
287 | if (pin) { | ||
288 | irq_2_pin_ptr = pin->next; | ||
289 | pin->next = NULL; | ||
290 | return pin; | ||
291 | } | ||
292 | |||
293 | /* | ||
294 | * we run out of pre-allocate ones, allocate more | ||
295 | */ | ||
296 | printk(KERN_DEBUG "try to get more irq_2_pin %d\n", nr_irq_2_pin); | ||
297 | |||
298 | if (after_bootmem) | ||
299 | pin = kzalloc(sizeof(struct irq_pin_list)*nr_irq_2_pin, | ||
300 | GFP_ATOMIC); | ||
301 | else | ||
302 | pin = __alloc_bootmem_nopanic(sizeof(struct irq_pin_list) * | ||
303 | nr_irq_2_pin, PAGE_SIZE, 0); | ||
304 | |||
305 | if (!pin) | ||
306 | panic("can not get more irq_2_pin\n"); | ||
259 | 307 | ||
260 | DEFINE_DYN_ARRAY(irq_2_pin, sizeof(struct irq_pin_list), pin_map_size, sizeof(struct irq_pin_list), NULL); | 308 | for (i = 1; i < nr_irq_2_pin; i++) |
309 | pin[i-1].next = &pin[i]; | ||
261 | 310 | ||
311 | irq_2_pin_ptr = pin->next; | ||
312 | pin->next = NULL; | ||
313 | |||
314 | return pin; | ||
315 | } | ||
262 | 316 | ||
263 | struct io_apic { | 317 | struct io_apic { |
264 | unsigned int index; | 318 | unsigned int index; |
@@ -300,16 +354,17 @@ static bool io_apic_level_ack_pending(unsigned int irq) | |||
300 | { | 354 | { |
301 | struct irq_pin_list *entry; | 355 | struct irq_pin_list *entry; |
302 | unsigned long flags; | 356 | unsigned long flags; |
357 | struct irq_cfg *cfg = irq_cfg(irq); | ||
303 | 358 | ||
304 | spin_lock_irqsave(&ioapic_lock, flags); | 359 | spin_lock_irqsave(&ioapic_lock, flags); |
305 | entry = irq_2_pin + irq; | 360 | entry = cfg->irq_2_pin; |
306 | for (;;) { | 361 | for (;;) { |
307 | unsigned int reg; | 362 | unsigned int reg; |
308 | int pin; | 363 | int pin; |
309 | 364 | ||
310 | pin = entry->pin; | 365 | if (!entry) |
311 | if (pin == -1) | ||
312 | break; | 366 | break; |
367 | pin = entry->pin; | ||
313 | reg = io_apic_read(entry->apic, 0x10 + pin*2); | 368 | reg = io_apic_read(entry->apic, 0x10 + pin*2); |
314 | /* Is the remote IRR bit set? */ | 369 | /* Is the remote IRR bit set? */ |
315 | if (reg & IO_APIC_REDIR_REMOTE_IRR) { | 370 | if (reg & IO_APIC_REDIR_REMOTE_IRR) { |
@@ -318,7 +373,7 @@ static bool io_apic_level_ack_pending(unsigned int irq) | |||
318 | } | 373 | } |
319 | if (!entry->next) | 374 | if (!entry->next) |
320 | break; | 375 | break; |
321 | entry = irq_2_pin + entry->next; | 376 | entry = entry->next; |
322 | } | 377 | } |
323 | spin_unlock_irqrestore(&ioapic_lock, flags); | 378 | spin_unlock_irqrestore(&ioapic_lock, flags); |
324 | 379 | ||
@@ -339,21 +394,24 @@ static inline void io_apic_sync(unsigned int apic) | |||
339 | \ | 394 | \ |
340 | { \ | 395 | { \ |
341 | int pin; \ | 396 | int pin; \ |
342 | struct irq_pin_list *entry = irq_2_pin + irq; \ | 397 | struct irq_cfg *cfg; \ |
398 | struct irq_pin_list *entry; \ | ||
343 | \ | 399 | \ |
344 | BUG_ON(irq >= nr_irqs); \ | 400 | BUG_ON(irq >= nr_irqs); \ |
401 | cfg = irq_cfg(irq); \ | ||
402 | entry = cfg->irq_2_pin; \ | ||
345 | for (;;) { \ | 403 | for (;;) { \ |
346 | unsigned int reg; \ | 404 | unsigned int reg; \ |
347 | pin = entry->pin; \ | 405 | if (!entry) \ |
348 | if (pin == -1) \ | ||
349 | break; \ | 406 | break; \ |
407 | pin = entry->pin; \ | ||
350 | reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \ | 408 | reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \ |
351 | reg ACTION; \ | 409 | reg ACTION; \ |
352 | io_apic_modify(entry->apic, reg); \ | 410 | io_apic_modify(entry->apic, reg); \ |
353 | FINAL; \ | 411 | FINAL; \ |
354 | if (!entry->next) \ | 412 | if (!entry->next) \ |
355 | break; \ | 413 | break; \ |
356 | entry = irq_2_pin + entry->next; \ | 414 | entry = entry->next; \ |
357 | } \ | 415 | } \ |
358 | } | 416 | } |
359 | 417 | ||
@@ -416,15 +474,20 @@ static void ioapic_mask_entry(int apic, int pin) | |||
416 | static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector) | 474 | static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector) |
417 | { | 475 | { |
418 | int apic, pin; | 476 | int apic, pin; |
419 | struct irq_pin_list *entry = irq_2_pin + irq; | 477 | struct irq_cfg *cfg; |
478 | struct irq_pin_list *entry; | ||
420 | 479 | ||
421 | BUG_ON(irq >= nr_irqs); | 480 | BUG_ON(irq >= nr_irqs); |
481 | cfg = irq_cfg(irq); | ||
482 | entry = cfg->irq_2_pin; | ||
422 | for (;;) { | 483 | for (;;) { |
423 | unsigned int reg; | 484 | unsigned int reg; |
485 | |||
486 | if (!entry) | ||
487 | break; | ||
488 | |||
424 | apic = entry->apic; | 489 | apic = entry->apic; |
425 | pin = entry->pin; | 490 | pin = entry->pin; |
426 | if (pin == -1) | ||
427 | break; | ||
428 | /* | 491 | /* |
429 | * With interrupt-remapping, destination information comes | 492 | * With interrupt-remapping, destination information comes |
430 | * from interrupt-remapping table entry. | 493 | * from interrupt-remapping table entry. |
@@ -437,7 +500,7 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector) | |||
437 | io_apic_modify(apic, reg); | 500 | io_apic_modify(apic, reg); |
438 | if (!entry->next) | 501 | if (!entry->next) |
439 | break; | 502 | break; |
440 | entry = irq_2_pin + entry->next; | 503 | entry = entry->next; |
441 | } | 504 | } |
442 | } | 505 | } |
443 | 506 | ||
@@ -480,22 +543,35 @@ static void set_ioapic_affinity_irq(unsigned int irq, cpumask_t mask) | |||
480 | int first_free_entry; | 543 | int first_free_entry; |
481 | static void add_pin_to_irq(unsigned int irq, int apic, int pin) | 544 | static void add_pin_to_irq(unsigned int irq, int apic, int pin) |
482 | { | 545 | { |
483 | struct irq_pin_list *entry = irq_2_pin + irq; | 546 | struct irq_cfg *cfg; |
547 | struct irq_pin_list *entry; | ||
484 | 548 | ||
485 | BUG_ON(irq >= nr_irqs); | 549 | BUG_ON(irq >= nr_irqs); |
486 | irq_cfg_alloc(irq); | 550 | /* first time to refer irq_cfg, so with new */ |
551 | cfg = irq_cfg_alloc(irq); | ||
552 | entry = cfg->irq_2_pin; | ||
553 | if (!entry) { | ||
554 | entry = get_one_free_irq_2_pin(); | ||
555 | cfg->irq_2_pin = entry; | ||
556 | entry->apic = apic; | ||
557 | entry->pin = pin; | ||
558 | printk(KERN_DEBUG " 0 add_pin_to_irq: irq %d --> apic %d pin %d\n", irq, apic, pin); | ||
559 | return; | ||
560 | } | ||
487 | 561 | ||
488 | while (entry->next) | 562 | while (entry->next) { |
489 | entry = irq_2_pin + entry->next; | 563 | /* not again, please */ |
564 | if (entry->apic == apic && entry->pin == pin) | ||
565 | return; | ||
490 | 566 | ||
491 | if (entry->pin != -1) { | 567 | entry = entry->next; |
492 | entry->next = first_free_entry; | ||
493 | entry = irq_2_pin + entry->next; | ||
494 | if (++first_free_entry >= pin_map_size) | ||
495 | panic("io_apic.c: ran out of irq_2_pin entries!"); | ||
496 | } | 568 | } |
569 | |||
570 | entry->next = get_one_free_irq_2_pin(); | ||
571 | entry = entry->next; | ||
497 | entry->apic = apic; | 572 | entry->apic = apic; |
498 | entry->pin = pin; | 573 | entry->pin = pin; |
574 | printk(KERN_DEBUG " x add_pin_to_irq: irq %d --> apic %d pin %d\n", irq, apic, pin); | ||
499 | } | 575 | } |
500 | 576 | ||
501 | /* | 577 | /* |
@@ -505,17 +581,24 @@ static void __init replace_pin_at_irq(unsigned int irq, | |||
505 | int oldapic, int oldpin, | 581 | int oldapic, int oldpin, |
506 | int newapic, int newpin) | 582 | int newapic, int newpin) |
507 | { | 583 | { |
508 | struct irq_pin_list *entry = irq_2_pin + irq; | 584 | struct irq_cfg *cfg = irq_cfg(irq); |
585 | struct irq_pin_list *entry = cfg->irq_2_pin; | ||
586 | int replaced = 0; | ||
509 | 587 | ||
510 | while (1) { | 588 | while (entry) { |
511 | if (entry->apic == oldapic && entry->pin == oldpin) { | 589 | if (entry->apic == oldapic && entry->pin == oldpin) { |
512 | entry->apic = newapic; | 590 | entry->apic = newapic; |
513 | entry->pin = newpin; | 591 | entry->pin = newpin; |
514 | } | 592 | replaced = 1; |
515 | if (!entry->next) | 593 | /* every one is different, right? */ |
516 | break; | 594 | break; |
517 | entry = irq_2_pin + entry->next; | 595 | } |
596 | entry = entry->next; | ||
518 | } | 597 | } |
598 | |||
599 | /* why? call replace before add? */ | ||
600 | if (!replaced) | ||
601 | add_pin_to_irq(irq, newapic, newpin); | ||
519 | } | 602 | } |
520 | 603 | ||
521 | 604 | ||
@@ -1326,15 +1409,16 @@ __apicdebuginit(void) print_IO_APIC(void) | |||
1326 | } | 1409 | } |
1327 | printk(KERN_DEBUG "IRQ to pin mappings:\n"); | 1410 | printk(KERN_DEBUG "IRQ to pin mappings:\n"); |
1328 | for (i = 0; i < nr_irqs; i++) { | 1411 | for (i = 0; i < nr_irqs; i++) { |
1329 | struct irq_pin_list *entry = irq_2_pin + i; | 1412 | struct irq_cfg *cfg = irq_cfg(i); |
1330 | if (entry->pin < 0) | 1413 | struct irq_pin_list *entry = cfg->irq_2_pin; |
1414 | if (!entry) | ||
1331 | continue; | 1415 | continue; |
1332 | printk(KERN_DEBUG "IRQ%d ", i); | 1416 | printk(KERN_DEBUG "IRQ%d ", i); |
1333 | for (;;) { | 1417 | for (;;) { |
1334 | printk("-> %d:%d", entry->apic, entry->pin); | 1418 | printk("-> %d:%d", entry->apic, entry->pin); |
1335 | if (!entry->next) | 1419 | if (!entry->next) |
1336 | break; | 1420 | break; |
1337 | entry = irq_2_pin + entry->next; | 1421 | entry = entry->next; |
1338 | } | 1422 | } |
1339 | printk("\n"); | 1423 | printk("\n"); |
1340 | } | 1424 | } |
@@ -1495,14 +1579,9 @@ void __init enable_IO_APIC(void) | |||
1495 | { | 1579 | { |
1496 | union IO_APIC_reg_01 reg_01; | 1580 | union IO_APIC_reg_01 reg_01; |
1497 | int i8259_apic, i8259_pin; | 1581 | int i8259_apic, i8259_pin; |
1498 | int i, apic; | 1582 | int apic; |
1499 | unsigned long flags; | 1583 | unsigned long flags; |
1500 | 1584 | ||
1501 | for (i = 0; i < pin_map_size; i++) { | ||
1502 | irq_2_pin[i].pin = -1; | ||
1503 | irq_2_pin[i].next = 0; | ||
1504 | } | ||
1505 | |||
1506 | /* | 1585 | /* |
1507 | * The number of IO-APIC IRQ registers (== #pins): | 1586 | * The number of IO-APIC IRQ registers (== #pins): |
1508 | */ | 1587 | */ |