aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/io_apic_64.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/io_apic_64.c')
-rw-r--r--arch/x86/kernel/io_apic_64.c131
1 files changed, 79 insertions, 52 deletions
diff --git a/arch/x86/kernel/io_apic_64.c b/arch/x86/kernel/io_apic_64.c
index c7c6b005f665..e5ef60303562 100644
--- a/arch/x86/kernel/io_apic_64.c
+++ b/arch/x86/kernel/io_apic_64.c
@@ -61,7 +61,7 @@ struct irq_cfg {
61}; 61};
62 62
63/* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */ 63/* irq_cfg is indexed by the sum of all RTEs in all I/O APICs. */
64struct irq_cfg irq_cfg[NR_IRQS] __read_mostly = { 64static struct irq_cfg irq_cfg[NR_IRQS] __read_mostly = {
65 [0] = { .domain = CPU_MASK_ALL, .vector = IRQ0_VECTOR, }, 65 [0] = { .domain = CPU_MASK_ALL, .vector = IRQ0_VECTOR, },
66 [1] = { .domain = CPU_MASK_ALL, .vector = IRQ1_VECTOR, }, 66 [1] = { .domain = CPU_MASK_ALL, .vector = IRQ1_VECTOR, },
67 [2] = { .domain = CPU_MASK_ALL, .vector = IRQ2_VECTOR, }, 67 [2] = { .domain = CPU_MASK_ALL, .vector = IRQ2_VECTOR, },
@@ -90,7 +90,7 @@ static int no_timer_check;
90 90
91static int disable_timer_pin_1 __initdata; 91static int disable_timer_pin_1 __initdata;
92 92
93int timer_over_8254 __initdata = 1; 93int timer_through_8259 __initdata;
94 94
95/* Where if anywhere is the i8259 connect in external int mode */ 95/* Where if anywhere is the i8259 connect in external int mode */
96static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; 96static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
@@ -183,7 +183,7 @@ static bool io_apic_level_ack_pending(unsigned int irq)
183 break; 183 break;
184 reg = io_apic_read(entry->apic, 0x10 + pin*2); 184 reg = io_apic_read(entry->apic, 0x10 + pin*2);
185 /* Is the remote IRR bit set? */ 185 /* Is the remote IRR bit set? */
186 if ((reg >> 14) & 1) { 186 if (reg & IO_APIC_REDIR_REMOTE_IRR) {
187 spin_unlock_irqrestore(&ioapic_lock, flags); 187 spin_unlock_irqrestore(&ioapic_lock, flags);
188 return true; 188 return true;
189 } 189 }
@@ -298,7 +298,7 @@ static void __target_IO_APIC_irq(unsigned int irq, unsigned int dest, u8 vector)
298 break; 298 break;
299 io_apic_write(apic, 0x11 + pin*2, dest); 299 io_apic_write(apic, 0x11 + pin*2, dest);
300 reg = io_apic_read(apic, 0x10 + pin*2); 300 reg = io_apic_read(apic, 0x10 + pin*2);
301 reg &= ~0x000000ff; 301 reg &= ~IO_APIC_REDIR_VECTOR_MASK;
302 reg |= vector; 302 reg |= vector;
303 io_apic_modify(apic, reg); 303 io_apic_modify(apic, reg);
304 if (!entry->next) 304 if (!entry->next)
@@ -360,16 +360,37 @@ static void add_pin_to_irq(unsigned int irq, int apic, int pin)
360 entry->pin = pin; 360 entry->pin = pin;
361} 361}
362 362
363/*
364 * Reroute an IRQ to a different pin.
365 */
366static void __init replace_pin_at_irq(unsigned int irq,
367 int oldapic, int oldpin,
368 int newapic, int newpin)
369{
370 struct irq_pin_list *entry = irq_2_pin + irq;
371
372 while (1) {
373 if (entry->apic == oldapic && entry->pin == oldpin) {
374 entry->apic = newapic;
375 entry->pin = newpin;
376 }
377 if (!entry->next)
378 break;
379 entry = irq_2_pin + entry->next;
380 }
381}
382
363 383
364#define DO_ACTION(name,R,ACTION, FINAL) \ 384#define DO_ACTION(name,R,ACTION, FINAL) \
365 \ 385 \
366 static void name##_IO_APIC_irq (unsigned int irq) \ 386 static void name##_IO_APIC_irq (unsigned int irq) \
367 __DO_ACTION(R, ACTION, FINAL) 387 __DO_ACTION(R, ACTION, FINAL)
368 388
369DO_ACTION( __mask, 0, |= 0x00010000, io_apic_sync(entry->apic) ) 389/* mask = 1 */
370 /* mask = 1 */ 390DO_ACTION(__mask, 0, |= IO_APIC_REDIR_MASKED, io_apic_sync(entry->apic))
371DO_ACTION( __unmask, 0, &= 0xfffeffff, ) 391
372 /* mask = 0 */ 392/* mask = 0 */
393DO_ACTION(__unmask, 0, &= ~IO_APIC_REDIR_MASKED, )
373 394
374static void mask_IO_APIC_irq (unsigned int irq) 395static void mask_IO_APIC_irq (unsigned int irq)
375{ 396{
@@ -430,20 +451,6 @@ static int __init disable_timer_pin_setup(char *arg)
430} 451}
431__setup("disable_timer_pin_1", disable_timer_pin_setup); 452__setup("disable_timer_pin_1", disable_timer_pin_setup);
432 453
433static int __init setup_disable_8254_timer(char *s)
434{
435 timer_over_8254 = -1;
436 return 1;
437}
438static int __init setup_enable_8254_timer(char *s)
439{
440 timer_over_8254 = 2;
441 return 1;
442}
443
444__setup("disable_8254_timer", setup_disable_8254_timer);
445__setup("enable_8254_timer", setup_enable_8254_timer);
446
447 454
448/* 455/*
449 * Find the IRQ entry number of a certain pin. 456 * Find the IRQ entry number of a certain pin.
@@ -911,26 +918,21 @@ static void __init setup_IO_APIC_irqs(void)
911} 918}
912 919
913/* 920/*
914 * Set up the 8259A-master output pin as broadcast to all 921 * Set up the timer pin, possibly with the 8259A-master behind.
915 * CPUs.
916 */ 922 */
917static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, int vector) 923static void __init setup_timer_IRQ0_pin(unsigned int apic, unsigned int pin,
924 int vector)
918{ 925{
919 struct IO_APIC_route_entry entry; 926 struct IO_APIC_route_entry entry;
920 927
921 memset(&entry, 0, sizeof(entry)); 928 memset(&entry, 0, sizeof(entry));
922 929
923 disable_8259A_irq(0);
924
925 /* mask LVT0 */
926 apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
927
928 /* 930 /*
929 * We use logical delivery to get the timer IRQ 931 * We use logical delivery to get the timer IRQ
930 * to the first CPU. 932 * to the first CPU.
931 */ 933 */
932 entry.dest_mode = INT_DEST_MODE; 934 entry.dest_mode = INT_DEST_MODE;
933 entry.mask = 0; /* unmask IRQ now */ 935 entry.mask = 1; /* mask IRQ now */
934 entry.dest = cpu_mask_to_apicid(TARGET_CPUS); 936 entry.dest = cpu_mask_to_apicid(TARGET_CPUS);
935 entry.delivery_mode = INT_DELIVERY_MODE; 937 entry.delivery_mode = INT_DELIVERY_MODE;
936 entry.polarity = 0; 938 entry.polarity = 0;
@@ -939,7 +941,7 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
939 941
940 /* 942 /*
941 * The timer IRQ doesn't have to know that behind the 943 * The timer IRQ doesn't have to know that behind the
942 * scene we have a 8259A-master in AEOI mode ... 944 * scene we may have a 8259A-master in AEOI mode ...
943 */ 945 */
944 set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge"); 946 set_irq_chip_and_handler_name(0, &ioapic_chip, handle_edge_irq, "edge");
945 947
@@ -947,8 +949,6 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
947 * Add it to the IO-APIC irq-routing table: 949 * Add it to the IO-APIC irq-routing table:
948 */ 950 */
949 ioapic_write_entry(apic, pin, entry); 951 ioapic_write_entry(apic, pin, entry);
950
951 enable_8259A_irq(0);
952} 952}
953 953
954void __apicdebuginit print_IO_APIC(void) 954void __apicdebuginit print_IO_APIC(void)
@@ -1660,6 +1660,7 @@ static inline void __init check_timer(void)
1660 struct irq_cfg *cfg = irq_cfg + 0; 1660 struct irq_cfg *cfg = irq_cfg + 0;
1661 int apic1, pin1, apic2, pin2; 1661 int apic1, pin1, apic2, pin2;
1662 unsigned long flags; 1662 unsigned long flags;
1663 int no_pin1 = 0;
1663 1664
1664 local_irq_save(flags); 1665 local_irq_save(flags);
1665 1666
@@ -1670,16 +1671,11 @@ static inline void __init check_timer(void)
1670 assign_irq_vector(0, TARGET_CPUS); 1671 assign_irq_vector(0, TARGET_CPUS);
1671 1672
1672 /* 1673 /*
1673 * Subtle, code in do_timer_interrupt() expects an AEOI 1674 * As IRQ0 is to be enabled in the 8259A, the virtual
1674 * mode for the 8259A whenever interrupts are routed 1675 * wire has to be disabled in the local APIC.
1675 * through I/O APICs. Also IRQ0 has to be enabled in
1676 * the 8259A which implies the virtual wire has to be
1677 * disabled in the local APIC.
1678 */ 1676 */
1679 apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); 1677 apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
1680 init_8259A(1); 1678 init_8259A(1);
1681 if (timer_over_8254 > 0)
1682 enable_8259A_irq(0);
1683 1679
1684 pin1 = find_isa_irq_pin(0, mp_INT); 1680 pin1 = find_isa_irq_pin(0, mp_INT);
1685 apic1 = find_isa_irq_apic(0, mp_INT); 1681 apic1 = find_isa_irq_apic(0, mp_INT);
@@ -1689,15 +1685,39 @@ static inline void __init check_timer(void)
1689 apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n", 1685 apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
1690 cfg->vector, apic1, pin1, apic2, pin2); 1686 cfg->vector, apic1, pin1, apic2, pin2);
1691 1687
1688 /*
1689 * Some BIOS writers are clueless and report the ExtINTA
1690 * I/O APIC input from the cascaded 8259A as the timer
1691 * interrupt input. So just in case, if only one pin
1692 * was found above, try it both directly and through the
1693 * 8259A.
1694 */
1695 if (pin1 == -1) {
1696 pin1 = pin2;
1697 apic1 = apic2;
1698 no_pin1 = 1;
1699 } else if (pin2 == -1) {
1700 pin2 = pin1;
1701 apic2 = apic1;
1702 }
1703
1704 replace_pin_at_irq(0, 0, 0, apic1, pin1);
1705 apic1 = 0;
1706 pin1 = 0;
1707 setup_timer_IRQ0_pin(apic1, pin1, cfg->vector);
1708
1692 if (pin1 != -1) { 1709 if (pin1 != -1) {
1693 /* 1710 /*
1694 * Ok, does IRQ0 through the IOAPIC work? 1711 * Ok, does IRQ0 through the IOAPIC work?
1695 */ 1712 */
1713 if (no_pin1) {
1714 add_pin_to_irq(0, apic1, pin1);
1715 setup_timer_IRQ0_pin(apic1, pin1, cfg->vector);
1716 }
1696 unmask_IO_APIC_irq(0); 1717 unmask_IO_APIC_irq(0);
1697 if (!no_timer_check && timer_irq_works()) { 1718 if (!no_timer_check && timer_irq_works()) {
1698 nmi_watchdog_default(); 1719 nmi_watchdog_default();
1699 if (nmi_watchdog == NMI_IO_APIC) { 1720 if (nmi_watchdog == NMI_IO_APIC) {
1700 disable_8259A_irq(0);
1701 setup_nmi(); 1721 setup_nmi();
1702 enable_8259A_irq(0); 1722 enable_8259A_irq(0);
1703 } 1723 }
@@ -1706,42 +1726,48 @@ static inline void __init check_timer(void)
1706 goto out; 1726 goto out;
1707 } 1727 }
1708 clear_IO_APIC_pin(apic1, pin1); 1728 clear_IO_APIC_pin(apic1, pin1);
1709 apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: 8254 timer not " 1729 if (!no_pin1)
1710 "connected to IO-APIC\n"); 1730 apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: "
1711 } 1731 "8254 timer not connected to IO-APIC\n");
1712 1732
1713 apic_printk(APIC_VERBOSE,KERN_INFO "...trying to set up timer (IRQ0) " 1733 apic_printk(APIC_VERBOSE,KERN_INFO
1714 "through the 8259A ... "); 1734 "...trying to set up timer (IRQ0) "
1715 if (pin2 != -1) { 1735 "through the 8259A ... ");
1716 apic_printk(APIC_VERBOSE,"\n..... (found apic %d pin %d) ...", 1736 apic_printk(APIC_VERBOSE,"\n..... (found apic %d pin %d) ...",
1717 apic2, pin2); 1737 apic2, pin2);
1718 /* 1738 /*
1719 * legacy devices should be connected to IO APIC #0 1739 * legacy devices should be connected to IO APIC #0
1720 */ 1740 */
1721 setup_ExtINT_IRQ0_pin(apic2, pin2, cfg->vector); 1741 replace_pin_at_irq(0, apic1, pin1, apic2, pin2);
1742 setup_timer_IRQ0_pin(apic2, pin2, cfg->vector);
1743 unmask_IO_APIC_irq(0);
1744 enable_8259A_irq(0);
1722 if (timer_irq_works()) { 1745 if (timer_irq_works()) {
1723 apic_printk(APIC_VERBOSE," works.\n"); 1746 apic_printk(APIC_VERBOSE," works.\n");
1747 timer_through_8259 = 1;
1724 nmi_watchdog_default(); 1748 nmi_watchdog_default();
1725 if (nmi_watchdog == NMI_IO_APIC) { 1749 if (nmi_watchdog == NMI_IO_APIC) {
1750 disable_8259A_irq(0);
1726 setup_nmi(); 1751 setup_nmi();
1752 enable_8259A_irq(0);
1727 } 1753 }
1728 goto out; 1754 goto out;
1729 } 1755 }
1730 /* 1756 /*
1731 * Cleanup, just in case ... 1757 * Cleanup, just in case ...
1732 */ 1758 */
1759 disable_8259A_irq(0);
1733 clear_IO_APIC_pin(apic2, pin2); 1760 clear_IO_APIC_pin(apic2, pin2);
1761 apic_printk(APIC_VERBOSE," failed.\n");
1734 } 1762 }
1735 apic_printk(APIC_VERBOSE," failed.\n");
1736 1763
1737 if (nmi_watchdog == NMI_IO_APIC) { 1764 if (nmi_watchdog == NMI_IO_APIC) {
1738 printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n"); 1765 printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n");
1739 nmi_watchdog = 0; 1766 nmi_watchdog = NMI_NONE;
1740 } 1767 }
1741 1768
1742 apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as Virtual Wire IRQ..."); 1769 apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
1743 1770
1744 disable_8259A_irq(0);
1745 irq_desc[0].chip = &lapic_irq_type; 1771 irq_desc[0].chip = &lapic_irq_type;
1746 apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector); /* Fixed mode */ 1772 apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector); /* Fixed mode */
1747 enable_8259A_irq(0); 1773 enable_8259A_irq(0);
@@ -1750,6 +1776,7 @@ static inline void __init check_timer(void)
1750 apic_printk(APIC_VERBOSE," works.\n"); 1776 apic_printk(APIC_VERBOSE," works.\n");
1751 goto out; 1777 goto out;
1752 } 1778 }
1779 disable_8259A_irq(0);
1753 apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector); 1780 apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector);
1754 apic_printk(APIC_VERBOSE," failed.\n"); 1781 apic_printk(APIC_VERBOSE," failed.\n");
1755 1782