aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Documentation/x86_64/boot-options.txt4
-rw-r--r--arch/x86_64/kernel/early-quirks.c5
-rw-r--r--arch/x86_64/kernel/io_apic.c124
3 files changed, 82 insertions, 51 deletions
diff --git a/Documentation/x86_64/boot-options.txt b/Documentation/x86_64/boot-options.txt
index dbdcaf68e3ea..5c86ed6f0448 100644
--- a/Documentation/x86_64/boot-options.txt
+++ b/Documentation/x86_64/boot-options.txt
@@ -52,6 +52,10 @@ APICs
52 apicmaintimer. Useful when your PIT timer is totally 52 apicmaintimer. Useful when your PIT timer is totally
53 broken. 53 broken.
54 54
55 disable_8254_timer / enable_8254_timer
56 Enable interrupt 0 timer routing over the 8254 in addition to over
57 the IO-APIC. The kernel tries to set a sensible default.
58
55Early Console 59Early Console
56 60
57 syntax: earlyprintk=vga 61 syntax: earlyprintk=vga
diff --git a/arch/x86_64/kernel/early-quirks.c b/arch/x86_64/kernel/early-quirks.c
index 829698f6d049..49802f1bee94 100644
--- a/arch/x86_64/kernel/early-quirks.c
+++ b/arch/x86_64/kernel/early-quirks.c
@@ -69,6 +69,11 @@ static void nvidia_bugs(void)
69 69
70static void ati_bugs(void) 70static void ati_bugs(void)
71{ 71{
72 if (timer_over_8254 == 1) {
73 timer_over_8254 = 0;
74 printk(KERN_INFO
75 "ATI board detected. Disabling timer routing over 8254.\n");
76 }
72} 77}
73 78
74static void intel_bugs(void) 79static void intel_bugs(void)
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
index 2a1dcd5f69c2..d7bad90a5ad8 100644
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -55,6 +55,10 @@ int sis_apic_bug; /* not actually supported, dummy for compile */
55 55
56static int no_timer_check; 56static int no_timer_check;
57 57
58static int disable_timer_pin_1 __initdata;
59
60int timer_over_8254 __initdata = 1;
61
58/* Where if anywhere is the i8259 connect in external int mode */ 62/* Where if anywhere is the i8259 connect in external int mode */
59static struct { int pin, apic; } ioapic_i8259 = { -1, -1 }; 63static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
60 64
@@ -350,6 +354,29 @@ static int __init disable_ioapic_setup(char *str)
350} 354}
351early_param("noapic", disable_ioapic_setup); 355early_param("noapic", disable_ioapic_setup);
352 356
357/* Actually the next is obsolete, but keep it for paranoid reasons -AK */
358static int __init disable_timer_pin_setup(char *arg)
359{
360 disable_timer_pin_1 = 1;
361 return 1;
362}
363__setup("disable_timer_pin_1", disable_timer_pin_setup);
364
365static int __init setup_disable_8254_timer(char *s)
366{
367 timer_over_8254 = -1;
368 return 1;
369}
370static int __init setup_enable_8254_timer(char *s)
371{
372 timer_over_8254 = 2;
373 return 1;
374}
375
376__setup("disable_8254_timer", setup_disable_8254_timer);
377__setup("enable_8254_timer", setup_enable_8254_timer);
378
379
353/* 380/*
354 * Find the IRQ entry number of a certain pin. 381 * Find the IRQ entry number of a certain pin.
355 */ 382 */
@@ -1568,33 +1595,10 @@ static inline void unlock_ExtINT_logic(void)
1568 * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ 1595 * a wide range of boards and BIOS bugs. Fortunately only the timer IRQ
1569 * is so screwy. Thanks to Brian Perkins for testing/hacking this beast 1596 * is so screwy. Thanks to Brian Perkins for testing/hacking this beast
1570 * fanatically on his truly buggy board. 1597 * fanatically on his truly buggy board.
1598 *
1599 * FIXME: really need to revamp this for modern platforms only.
1571 */ 1600 */
1572 1601static inline void check_timer(void)
1573static int try_apic_pin(int apic, int pin, char *msg)
1574{
1575 apic_printk(APIC_VERBOSE, KERN_INFO
1576 "..TIMER: trying IO-APIC=%d PIN=%d %s",
1577 apic, pin, msg);
1578
1579 /*
1580 * Ok, does IRQ0 through the IOAPIC work?
1581 */
1582 if (!no_timer_check && timer_irq_works()) {
1583 nmi_watchdog_default();
1584 if (nmi_watchdog == NMI_IO_APIC) {
1585 disable_8259A_irq(0);
1586 setup_nmi();
1587 enable_8259A_irq(0);
1588 }
1589 return 1;
1590 }
1591 clear_IO_APIC_pin(apic, pin);
1592 apic_printk(APIC_QUIET, KERN_ERR " .. failed\n");
1593 return 0;
1594}
1595
1596/* The function from hell */
1597static void check_timer(void)
1598{ 1602{
1599 int apic1, pin1, apic2, pin2; 1603 int apic1, pin1, apic2, pin2;
1600 int vector; 1604 int vector;
@@ -1615,43 +1619,61 @@ static void check_timer(void)
1615 */ 1619 */
1616 apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT); 1620 apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
1617 init_8259A(1); 1621 init_8259A(1);
1622 if (timer_over_8254 > 0)
1623 enable_8259A_irq(0);
1618 1624
1619 pin1 = find_isa_irq_pin(0, mp_INT); 1625 pin1 = find_isa_irq_pin(0, mp_INT);
1620 apic1 = find_isa_irq_apic(0, mp_INT); 1626 apic1 = find_isa_irq_apic(0, mp_INT);
1621 pin2 = ioapic_i8259.pin; 1627 pin2 = ioapic_i8259.pin;
1622 apic2 = ioapic_i8259.apic; 1628 apic2 = ioapic_i8259.apic;
1623 1629
1624 /* Do this first, otherwise we get double interrupts on ATI boards */ 1630 apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
1625 if ((pin1 != -1) && try_apic_pin(apic1, pin1,"with 8259 IRQ0 disabled")) 1631 vector, apic1, pin1, apic2, pin2);
1626 return;
1627 1632
1628 /* Now try again with IRQ0 8259A enabled. 1633 if (pin1 != -1) {
1629 Assumes timer is on IO-APIC 0 ?!? */ 1634 /*
1630 enable_8259A_irq(0); 1635 * Ok, does IRQ0 through the IOAPIC work?
1631 unmask_IO_APIC_irq(0); 1636 */
1632 if (try_apic_pin(apic1, pin1, "with 8259 IRQ0 enabled")) 1637 unmask_IO_APIC_irq(0);
1633 return; 1638 if (!no_timer_check && timer_irq_works()) {
1634 disable_8259A_irq(0); 1639 nmi_watchdog_default();
1635 1640 if (nmi_watchdog == NMI_IO_APIC) {
1636 /* Always try pin0 and pin2 on APIC 0 to handle buggy timer overrides 1641 disable_8259A_irq(0);
1637 on Nvidia boards */ 1642 setup_nmi();
1638 if (!(apic1 == 0 && pin1 == 0) && 1643 enable_8259A_irq(0);
1639 try_apic_pin(0, 0, "fallback with 8259 IRQ0 disabled")) 1644 }
1640 return; 1645 if (disable_timer_pin_1 > 0)
1641 if (!(apic1 == 0 && pin1 == 2) && 1646 clear_IO_APIC_pin(0, pin1);
1642 try_apic_pin(0, 2, "fallback with 8259 IRQ0 disabled")) 1647 return;
1643 return; 1648 }
1649 clear_IO_APIC_pin(apic1, pin1);
1650 apic_printk(APIC_QUIET,KERN_ERR "..MP-BIOS bug: 8254 timer not "
1651 "connected to IO-APIC\n");
1652 }
1644 1653
1645 /* Then try pure 8259A routing on the 8259 as reported by BIOS*/ 1654 apic_printk(APIC_VERBOSE,KERN_INFO "...trying to set up timer (IRQ0) "
1646 enable_8259A_irq(0); 1655 "through the 8259A ... ");
1647 if (pin2 != -1) { 1656 if (pin2 != -1) {
1657 apic_printk(APIC_VERBOSE,"\n..... (found apic %d pin %d) ...",
1658 apic2, pin2);
1659 /*
1660 * legacy devices should be connected to IO APIC #0
1661 */
1648 setup_ExtINT_IRQ0_pin(apic2, pin2, vector); 1662 setup_ExtINT_IRQ0_pin(apic2, pin2, vector);
1649 if (try_apic_pin(apic2,pin2,"8259A broadcast ExtINT from BIOS")) 1663 if (timer_irq_works()) {
1664 apic_printk(APIC_VERBOSE," works.\n");
1665 nmi_watchdog_default();
1666 if (nmi_watchdog == NMI_IO_APIC) {
1667 setup_nmi();
1668 }
1650 return; 1669 return;
1670 }
1671 /*
1672 * Cleanup, just in case ...
1673 */
1674 clear_IO_APIC_pin(apic2, pin2);
1651 } 1675 }
1652 1676 apic_printk(APIC_VERBOSE," failed.\n");
1653 /* Tried all possibilities to go through the IO-APIC. Now come the
1654 really cheesy fallbacks. */
1655 1677
1656 if (nmi_watchdog == NMI_IO_APIC) { 1678 if (nmi_watchdog == NMI_IO_APIC) {
1657 printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n"); 1679 printk(KERN_WARNING "timer doesn't work through the IO-APIC - disabling NMI Watchdog!\n");