aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/apic/io_apic.c48
1 files changed, 47 insertions, 1 deletions
diff --git a/arch/x86/kernel/apic/io_apic.c b/arch/x86/kernel/apic/io_apic.c
index 620da6fed6b7..913d4bd2913a 100644
--- a/arch/x86/kernel/apic/io_apic.c
+++ b/arch/x86/kernel/apic/io_apic.c
@@ -593,10 +593,56 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
593 entry = ioapic_read_entry(apic, pin); 593 entry = ioapic_read_entry(apic, pin);
594 if (entry.delivery_mode == dest_SMI) 594 if (entry.delivery_mode == dest_SMI)
595 return; 595 return;
596
597 /*
598 * Make sure the entry is masked and re-read the contents to check
599 * if it is a level triggered pin and if the remote-IRR is set.
600 */
601 if (!entry.mask) {
602 entry.mask = 1;
603 ioapic_write_entry(apic, pin, entry);
604 entry = ioapic_read_entry(apic, pin);
605 }
606
607 if (entry.irr) {
608 /*
609 * Make sure the trigger mode is set to level. Explicit EOI
610 * doesn't clear the remote-IRR if the trigger mode is not
611 * set to level.
612 */
613 if (!entry.trigger) {
614 entry.trigger = IOAPIC_LEVEL;
615 ioapic_write_entry(apic, pin, entry);
616 }
617
618 if (mpc_ioapic_ver(apic) >= 0x20) {
619 unsigned long flags;
620
621 raw_spin_lock_irqsave(&ioapic_lock, flags);
622 io_apic_eoi(apic, entry.vector);
623 raw_spin_unlock_irqrestore(&ioapic_lock, flags);
624 } else {
625 /*
626 * Mechanism by which we clear remote-IRR in this
627 * case is by changing the trigger mode to edge and
628 * back to level.
629 */
630 entry.trigger = IOAPIC_EDGE;
631 ioapic_write_entry(apic, pin, entry);
632 entry.trigger = IOAPIC_LEVEL;
633 ioapic_write_entry(apic, pin, entry);
634 }
635 }
636
596 /* 637 /*
597 * Disable it in the IO-APIC irq-routing table: 638 * Clear the rest of the bits in the IO-APIC RTE except for the mask
639 * bit.
598 */ 640 */
599 ioapic_mask_entry(apic, pin); 641 ioapic_mask_entry(apic, pin);
642 entry = ioapic_read_entry(apic, pin);
643 if (entry.irr)
644 printk(KERN_ERR "Unable to reset IRR for apic: %d, pin :%d\n",
645 mpc_ioapic_id(apic), pin);
600} 646}
601 647
602static void clear_IO_APIC (void) 648static void clear_IO_APIC (void)