diff options
author | Suresh Siddha <suresh.b.siddha@intel.com> | 2011-08-25 15:01:13 -0400 |
---|---|---|
committer | Ingo Molnar <mingo@elte.hu> | 2011-09-21 04:26:28 -0400 |
commit | c020570138f5d9cb1fc0a853f9cf9e641178b5c5 (patch) | |
tree | ff696be9affd2e192878c6842452b772e8746d24 | |
parent | e57253a81d9cc7049e9e43bd806ce6cdd297ec1c (diff) |
x86, ioapic: Consolidate the explicit EOI code
Consolidate the io-apic EOI code in clear_IO_APIC_pin() and
eoi_ioapic_irq().
Signed-off-by: Suresh Siddha <suresh.b.siddha@intel.com>
Cc: Thomas Renninger <trenn@suse.de>
Cc: Rafael Wysocki <rjw@novell.com>
Cc: Maciej W. Rozycki <macro@linux-mips.org>
Cc: lchiquitto@novell.com
Cc: jbeulich@novell.com
Cc: yinghai@kernel.org
Link: http://lkml.kernel.org/r/20110825190657.259696697@sbsiddha-desk.sc.intel.com
Signed-off-by: Ingo Molnar <mingo@elte.hu>
-rw-r--r-- | arch/x86/kernel/apic/io_apic.c | 139 |
1 files changed, 65 insertions, 74 deletions
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c index 85050c9ab755..229e19f3eb57 100644 --- a/arch/x86/kernel/apic/io_apic.c +++ b/arch/x86/kernel/apic/io_apic.c | |||
@@ -581,6 +581,66 @@ static void unmask_ioapic_irq(struct irq_data *data) | |||
581 | unmask_ioapic(data->chip_data); | 581 | unmask_ioapic(data->chip_data); |
582 | } | 582 | } |
583 | 583 | ||
584 | /* | ||
585 | * IO-APIC versions below 0x20 don't support EOI register. | ||
586 | * For the record, here is the information about various versions: | ||
587 | * 0Xh 82489DX | ||
588 | * 1Xh I/OAPIC or I/O(x)APIC which are not PCI 2.2 Compliant | ||
589 | * 2Xh I/O(x)APIC which is PCI 2.2 Compliant | ||
590 | * 30h-FFh Reserved | ||
591 | * | ||
592 | * Some of the Intel ICH Specs (ICH2 to ICH5) documents the io-apic | ||
593 | * version as 0x2. This is an error with documentation and these ICH chips | ||
594 | * use io-apic's of version 0x20. | ||
595 | * | ||
596 | * For IO-APIC's with EOI register, we use that to do an explicit EOI. | ||
597 | * Otherwise, we simulate the EOI message manually by changing the trigger | ||
598 | * mode to edge and then back to level, with RTE being masked during this. | ||
599 | */ | ||
600 | static void __eoi_ioapic_pin(int apic, int pin, int vector, struct irq_cfg *cfg) | ||
601 | { | ||
602 | if (mpc_ioapic_ver(apic) >= 0x20) { | ||
603 | /* | ||
604 | * Intr-remapping uses pin number as the virtual vector | ||
605 | * in the RTE. Actual vector is programmed in | ||
606 | * intr-remapping table entry. Hence for the io-apic | ||
607 | * EOI we use the pin number. | ||
608 | */ | ||
609 | if (cfg && irq_remapped(cfg)) | ||
610 | io_apic_eoi(apic, pin); | ||
611 | else | ||
612 | io_apic_eoi(apic, vector); | ||
613 | } else { | ||
614 | struct IO_APIC_route_entry entry, entry1; | ||
615 | |||
616 | entry = entry1 = __ioapic_read_entry(apic, pin); | ||
617 | |||
618 | /* | ||
619 | * Mask the entry and change the trigger mode to edge. | ||
620 | */ | ||
621 | entry1.mask = 1; | ||
622 | entry1.trigger = IOAPIC_EDGE; | ||
623 | |||
624 | __ioapic_write_entry(apic, pin, entry1); | ||
625 | |||
626 | /* | ||
627 | * Restore the previous level triggered entry. | ||
628 | */ | ||
629 | __ioapic_write_entry(apic, pin, entry); | ||
630 | } | ||
631 | } | ||
632 | |||
633 | static void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg) | ||
634 | { | ||
635 | struct irq_pin_list *entry; | ||
636 | unsigned long flags; | ||
637 | |||
638 | raw_spin_lock_irqsave(&ioapic_lock, flags); | ||
639 | for_each_irq_pin(entry, cfg->irq_2_pin) | ||
640 | __eoi_ioapic_pin(entry->apic, entry->pin, cfg->vector, cfg); | ||
641 | raw_spin_unlock_irqrestore(&ioapic_lock, flags); | ||
642 | } | ||
643 | |||
584 | static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) | 644 | static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) |
585 | { | 645 | { |
586 | struct IO_APIC_route_entry entry; | 646 | struct IO_APIC_route_entry entry; |
@@ -601,6 +661,8 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) | |||
601 | } | 661 | } |
602 | 662 | ||
603 | if (entry.irr) { | 663 | if (entry.irr) { |
664 | unsigned long flags; | ||
665 | |||
604 | /* | 666 | /* |
605 | * Make sure the trigger mode is set to level. Explicit EOI | 667 | * Make sure the trigger mode is set to level. Explicit EOI |
606 | * doesn't clear the remote-IRR if the trigger mode is not | 668 | * doesn't clear the remote-IRR if the trigger mode is not |
@@ -611,23 +673,9 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin) | |||
611 | ioapic_write_entry(apic, pin, entry); | 673 | ioapic_write_entry(apic, pin, entry); |
612 | } | 674 | } |
613 | 675 | ||
614 | if (mpc_ioapic_ver(apic) >= 0x20) { | 676 | raw_spin_lock_irqsave(&ioapic_lock, flags); |
615 | unsigned long flags; | 677 | __eoi_ioapic_pin(apic, pin, entry.vector, NULL); |
616 | 678 | raw_spin_unlock_irqrestore(&ioapic_lock, flags); | |
617 | raw_spin_lock_irqsave(&ioapic_lock, flags); | ||
618 | io_apic_eoi(apic, entry.vector); | ||
619 | raw_spin_unlock_irqrestore(&ioapic_lock, flags); | ||
620 | } else { | ||
621 | /* | ||
622 | * Mechanism by which we clear remote-IRR in this | ||
623 | * case is by changing the trigger mode to edge and | ||
624 | * back to level. | ||
625 | */ | ||
626 | entry.trigger = IOAPIC_EDGE; | ||
627 | ioapic_write_entry(apic, pin, entry); | ||
628 | entry.trigger = IOAPIC_LEVEL; | ||
629 | ioapic_write_entry(apic, pin, entry); | ||
630 | } | ||
631 | } | 679 | } |
632 | 680 | ||
633 | /* | 681 | /* |
@@ -2457,63 +2505,6 @@ static void ack_apic_edge(struct irq_data *data) | |||
2457 | 2505 | ||
2458 | atomic_t irq_mis_count; | 2506 | atomic_t irq_mis_count; |
2459 | 2507 | ||
2460 | /* | ||
2461 | * IO-APIC versions below 0x20 don't support EOI register. | ||
2462 | * For the record, here is the information about various versions: | ||
2463 | * 0Xh 82489DX | ||
2464 | * 1Xh I/OAPIC or I/O(x)APIC which are not PCI 2.2 Compliant | ||
2465 | * 2Xh I/O(x)APIC which is PCI 2.2 Compliant | ||
2466 | * 30h-FFh Reserved | ||
2467 | * | ||
2468 | * Some of the Intel ICH Specs (ICH2 to ICH5) documents the io-apic | ||
2469 | * version as 0x2. This is an error with documentation and these ICH chips | ||
2470 | * use io-apic's of version 0x20. | ||
2471 | * | ||
2472 | * For IO-APIC's with EOI register, we use that to do an explicit EOI. | ||
2473 | * Otherwise, we simulate the EOI message manually by changing the trigger | ||
2474 | * mode to edge and then back to level, with RTE being masked during this. | ||
2475 | */ | ||
2476 | static void eoi_ioapic_irq(unsigned int irq, struct irq_cfg *cfg) | ||
2477 | { | ||
2478 | struct irq_pin_list *entry; | ||
2479 | unsigned long flags; | ||
2480 | |||
2481 | raw_spin_lock_irqsave(&ioapic_lock, flags); | ||
2482 | for_each_irq_pin(entry, cfg->irq_2_pin) { | ||
2483 | if (mpc_ioapic_ver(entry->apic) >= 0x20) { | ||
2484 | /* | ||
2485 | * Intr-remapping uses pin number as the virtual vector | ||
2486 | * in the RTE. Actual vector is programmed in | ||
2487 | * intr-remapping table entry. Hence for the io-apic | ||
2488 | * EOI we use the pin number. | ||
2489 | */ | ||
2490 | if (irq_remapped(cfg)) | ||
2491 | io_apic_eoi(entry->apic, entry->pin); | ||
2492 | else | ||
2493 | io_apic_eoi(entry->apic, cfg->vector); | ||
2494 | } else { | ||
2495 | struct IO_APIC_route_entry rte, rte1; | ||
2496 | |||
2497 | rte = rte1 = | ||
2498 | __ioapic_read_entry(entry->apic, entry->pin); | ||
2499 | |||
2500 | /* | ||
2501 | * Mask the entry and change the trigger mode to edge. | ||
2502 | */ | ||
2503 | rte1.mask = 1; | ||
2504 | rte1.trigger = IOAPIC_EDGE; | ||
2505 | |||
2506 | __ioapic_write_entry(apic, pin, rte1); | ||
2507 | |||
2508 | /* | ||
2509 | * Restore the previous level triggered entry. | ||
2510 | */ | ||
2511 | __ioapic_write_entry(apic, pin, rte); | ||
2512 | } | ||
2513 | } | ||
2514 | raw_spin_unlock_irqrestore(&ioapic_lock, flags); | ||
2515 | } | ||
2516 | |||
2517 | static void ack_apic_level(struct irq_data *data) | 2508 | static void ack_apic_level(struct irq_data *data) |
2518 | { | 2509 | { |
2519 | struct irq_cfg *cfg = data->chip_data; | 2510 | struct irq_cfg *cfg = data->chip_data; |