patch-2.3.20 linux/arch/i386/kernel/io_apic.c
Next file: linux/arch/i386/kernel/irq.c
Previous file: linux/arch/i386/kernel/i8259.c
Back to the patch index
Back to the overall index
- Lines: 804
- Date:
Thu Oct 7 10:17:08 1999
- Orig file:
v2.3.19/linux/arch/i386/kernel/io_apic.c
- Orig date:
Tue Aug 31 17:29:12 1999
diff -u --recursive --new-file v2.3.19/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
@@ -1,7 +1,7 @@
/*
* Intel IO-APIC support for multi-Pentium hosts.
*
- * Copyright (C) 1997, 1998 Ingo Molnar, Hajnalka Szabo
+ * Copyright (C) 1997, 1998, 1999 Ingo Molnar, Hajnalka Szabo
*
* Many thanks to Stig Venaas for trying out countless experimental
* patches and reporting/debugging problems patiently!
@@ -18,15 +18,21 @@
#include <linux/init.h>
#include <linux/delay.h>
#include <asm/io.h>
+#include <asm/desc.h>
#include <linux/irq.h>
+#undef __init
+#define __init
+
/*
* volatile is justified in this case, IO-APIC register contents
* might change spontaneously, GCC should not cache it
*/
#define IO_APIC_BASE(idx) ((volatile int *)__fix_to_virt(FIX_IO_APIC_BASE_0 + idx))
+extern int nmi_watchdog;
+
/*
* The structure of the IO-APIC:
*/
@@ -59,6 +65,11 @@
enum ioapic_irq_destination_types {
dest_Fixed = 0,
dest_LowestPrio = 1,
+ dest_SMI = 2,
+ dest__reserved_1 = 3,
+ dest_NMI = 4,
+ dest_INIT = 5,
+ dest__reserved_2 = 6,
dest_ExtINT = 7
};
@@ -94,14 +105,7 @@
* MP-BIOS irq configuration table structures:
*/
-enum mp_irq_source_types {
- mp_INT = 0,
- mp_NMI = 1,
- mp_SMI = 2,
- mp_ExtINT = 3
-};
-
-struct mpc_config_ioapic mp_apics[MAX_IO_APICS];/* I/O APIC entries */
+struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];/* I/O APIC entries */
int mp_irq_entries = 0; /* # of MP IRQ source entries */
struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
/* MP IRQ source entries */
@@ -202,16 +206,10 @@
FINAL; \
}
-/*
- * We disable IO-APIC IRQs by setting their 'destination CPU mask' to
- * zero. Trick by Ramesh Nalluri.
- */
-DO_ACTION( disable, 1, &= 0x00ffffff, io_apic_sync(entry->apic))/* destination = 0x00 */
-DO_ACTION( enable, 1, |= 0xff000000, ) /* destination = 0xff */
DO_ACTION( mask, 0, |= 0x00010000, io_apic_sync(entry->apic))/* mask = 1 */
DO_ACTION( unmask, 0, &= 0xfffeffff, ) /* mask = 0 */
-static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
+void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
{
struct IO_APIC_route_entry entry;
@@ -289,7 +287,7 @@
for (i = 0; i < mp_irq_entries; i++)
if ( (mp_irqs[i].mpc_irqtype == type) &&
- (mp_irqs[i].mpc_dstapic == mp_apics[apic].mpc_apicid) &&
+ (mp_irqs[i].mpc_dstapic == mp_ioapics[apic].mpc_apicid) &&
(mp_irqs[i].mpc_dstirq == pin))
return i;
@@ -330,7 +328,7 @@
int lbus = mp_irqs[i].mpc_srcbus;
for (apic = 0; apic < nr_ioapics; apic++)
- if (mp_apics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic)
+ if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic)
break;
if ((apic || IO_APIC_IRQ(mp_irqs[i].mpc_dstirq)) &&
@@ -589,24 +587,30 @@
static int current_vector = IRQ0_TRAP_VECTOR, offset = 0;
if (IO_APIC_VECTOR(irq) > 0)
return IO_APIC_VECTOR(irq);
+ if (current_vector == 0xFF)
+ panic("ran out of interrupt sources!");
+next:
current_vector += 8;
- if (current_vector > 0xFE) {
+ if (current_vector == SYSCALL_VECTOR)
+ goto next;
+
+ if (current_vector > 0xFF) {
offset++;
current_vector = IRQ0_TRAP_VECTOR + offset;
- printk("WARNING: ASSIGN_IRQ_VECTOR wrapped back to %02X\n",
- current_vector);
}
- if (current_vector == SYSCALL_VECTOR)
- panic("ran out of interrupt sources!");
IO_APIC_VECTOR(irq) = current_vector;
return current_vector;
}
+extern void (*interrupt[NR_IRQS])(void);
+static struct hw_interrupt_type ioapic_level_irq_type;
+static struct hw_interrupt_type ioapic_edge_irq_type;
+
void __init setup_IO_APIC_irqs(void)
{
struct IO_APIC_route_entry entry;
- int apic, pin, idx, irq, first_notcon = 1;
+ int apic, pin, idx, irq, first_notcon = 1, vector;
printk("init IO_APIC IRQs\n");
@@ -621,15 +625,15 @@
entry.delivery_mode = dest_LowestPrio;
entry.dest_mode = 1; /* logical delivery */
entry.mask = 0; /* enable IRQ */
- entry.dest.logical.logical_dest = 0; /* but no route */
+ entry.dest.logical.logical_dest = APIC_ALL_CPUS; /* all CPUs */
idx = find_irq_entry(apic,pin,mp_INT);
if (idx == -1) {
if (first_notcon) {
- printk(" IO-APIC (apicid-pin) %d-%d", mp_apics[apic].mpc_apicid, pin);
+ printk(" IO-APIC (apicid-pin) %d-%d", mp_ioapics[apic].mpc_apicid, pin);
first_notcon = 0;
} else
- printk(", %d-%d", mp_apics[apic].mpc_apicid, pin);
+ printk(", %d-%d", mp_ioapics[apic].mpc_apicid, pin);
continue;
}
@@ -639,17 +643,29 @@
if (irq_trigger(idx)) {
entry.trigger = 1;
entry.mask = 1;
- entry.dest.logical.logical_dest = 0xff;
+ entry.dest.logical.logical_dest = APIC_ALL_CPUS;
}
- irq = pin_2_irq(idx,apic,pin);
+ irq = pin_2_irq(idx, apic, pin);
add_pin_to_irq(irq, apic, pin);
if (!apic && !IO_APIC_IRQ(irq))
continue;
- entry.vector = assign_irq_vector(irq);
+ if (IO_APIC_IRQ(irq)) {
+ vector = assign_irq_vector(irq);
+ entry.vector = vector;
+
+ if (IO_APIC_irq_trigger(irq))
+ irq_desc[irq].handler = &ioapic_level_irq_type;
+ else
+ irq_desc[irq].handler = &ioapic_edge_irq_type;
+ set_intr_gate(vector, interrupt[irq]);
+
+ if (!apic && (irq < 16))
+ disable_8259A_irq(irq);
+ }
io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
}
@@ -660,34 +676,47 @@
}
/*
- * Set up a certain pin as ExtINT delivered interrupt
+ * Set up the 8259A-master output pin as broadcast to all
+ * CPUs.
*/
-void __init setup_ExtINT_pin(unsigned int apic, unsigned int pin, int irq)
+void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector)
{
struct IO_APIC_route_entry entry;
- /*
- * add it to the IO-APIC irq-routing table:
- */
memset(&entry,0,sizeof(entry));
- entry.delivery_mode = dest_ExtINT;
- entry.dest_mode = 0; /* physical delivery */
- entry.mask = 0; /* unmask IRQ now */
- /*
- * We use physical delivery to get the timer IRQ
- * to the boot CPU. 'boot_cpu_id' is the physical
- * APIC ID of the boot CPU.
- */
- entry.dest.physical.physical_dest = boot_cpu_id;
+ disable_8259A_irq(0);
+
+ apic_readaround(APIC_LVT0);
+ apic_write(APIC_LVT0, 0x00010700); // mask LVT0
- entry.vector = assign_irq_vector(irq);
+ init_8259A(1);
+ /*
+ * We use logical delivery to get the timer IRQ
+ * to the first CPU.
+ */
+ entry.dest_mode = 1; /* logical delivery */
+ entry.mask = 0; /* unmask IRQ now */
+ entry.dest.logical.logical_dest = APIC_ALL_CPUS;
+ entry.delivery_mode = dest_LowestPrio;
entry.polarity = 0;
entry.trigger = 0;
+ entry.vector = vector;
+
+ /*
+ * The timer IRQ doesnt have to know that behind the
+ * scene we have a 8259A-master in AEOI mode ...
+ */
+ irq_desc[0].handler = &ioapic_edge_irq_type;
- io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
- io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
+ /*
+ * Add it to the IO-APIC irq-routing table:
+ */
+ io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
+ io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
+
+ enable_8259A_irq(0);
}
void __init UNEXPECTED_IO_APIC(void)
@@ -705,7 +734,7 @@
printk("number of MP IRQ sources: %d.\n", mp_irq_entries);
for (i = 0; i < nr_ioapics; i++)
- printk("number of IO-APIC #%d registers: %d.\n", mp_apics[i].mpc_apicid, nr_ioapic_registers[i]);
+ printk("number of IO-APIC #%d registers: %d.\n", mp_ioapics[i].mpc_apicid, nr_ioapic_registers[i]);
/*
* We are a bit conservative about what we expect. We have to
@@ -717,8 +746,10 @@
*(int *)®_00 = io_apic_read(apic, 0);
*(int *)®_01 = io_apic_read(apic, 1);
- *(int *)®_02 = io_apic_read(apic, 2);
- printk("\nIO APIC #%d......\n", mp_apics[apic].mpc_apicid);
+ if (reg_01.version >= 0x10)
+ *(int *)®_02 = io_apic_read(apic, 2);
+
+ printk("\nIO APIC #%d......\n", mp_ioapics[apic].mpc_apicid);
printk(".... register #00: %08X\n", *(int *)®_00);
printk("....... : physical APIC id: %02X\n", reg_00.ID);
if (reg_00.__reserved_1 || reg_00.__reserved_2)
@@ -730,12 +761,15 @@
(reg_01.entries != 0x17) && /* typical ISA+PCI boards */
(reg_01.entries != 0x1b) && /* Compaq Proliant boards */
(reg_01.entries != 0x1f) && /* dual Xeon boards */
- (reg_01.entries != 0x3F) /* bigger Xeon boards */
+ (reg_01.entries != 0x22) && /* bigger Xeon boards */
+ (reg_01.entries != 0x2E) &&
+ (reg_01.entries != 0x3F)
)
UNEXPECTED_IO_APIC();
printk("....... : IO APIC version: %04X\n", reg_01.version);
- if ( (reg_01.version != 0x10) && /* oldest IO-APICs */
+ if ( (reg_01.version != 0x01) && /* 82489DX IO-APICs */
+ (reg_01.version != 0x10) && /* oldest IO-APICs */
(reg_01.version != 0x11) && /* Pentium/Pro IO-APICs */
(reg_01.version != 0x13) /* Xeon IO-APICs */
)
@@ -743,10 +777,12 @@
if (reg_01.__reserved_1 || reg_01.__reserved_2)
UNEXPECTED_IO_APIC();
- printk(".... register #02: %08X\n", *(int *)®_02);
- printk("....... : arbitration: %02X\n", reg_02.arbitration);
- if (reg_02.__reserved_1 || reg_02.__reserved_2)
- UNEXPECTED_IO_APIC();
+ if (reg_01.version >= 0x10) {
+ printk(".... register #02: %08X\n", *(int *)®_02);
+ printk("....... : arbitration: %02X\n", reg_02.arbitration);
+ if (reg_02.__reserved_1 || reg_02.__reserved_2)
+ UNEXPECTED_IO_APIC();
+ }
printk(".... IRQ redirection table:\n");
@@ -797,8 +833,116 @@
return;
}
+static void print_APIC_bitfield (int base)
+{
+ unsigned int v;
+ int i, j;
+
+ printk("0123456789abcdef0123456789abcdef\n");
+ for (i = 0; i < 8; i++) {
+ v = apic_read(base + i*0x10);
+ for (j = 0; j < 32; j++) {
+ if (v & (1<<j))
+ printk("1");
+ else
+ printk("0");
+ }
+ printk("\n");
+ }
+}
+
+void /*__init*/ print_local_APIC(void * dummy)
+{
+ unsigned int v, ver, maxlvt;
+
+ printk("\nprinting local APIC contents on CPU#%d/%d:\n",
+ smp_processor_id(), hard_smp_processor_id());
+ v = apic_read(APIC_ID);
+ printk("... APIC ID: %08x (%01x)\n", v, GET_APIC_ID(v));
+ v = apic_read(APIC_LVR);
+ printk("... APIC VERSION: %08x\n", v);
+ ver = GET_APIC_VERSION(v);
+ maxlvt = get_maxlvt();
+
+ v = apic_read(APIC_TASKPRI);
+ printk("... APIC TASKPRI: %08x (%02x)\n", v, v & APIC_TPRI_MASK);
+
+ if (APIC_INTEGRATED(ver)) { /* !82489DX */
+ v = apic_read(APIC_ARBPRI);
+ printk("... APIC ARBPRI: %08x (%02x)\n", v,
+ v & APIC_ARBPRI_MASK);
+ v = apic_read(APIC_PROCPRI);
+ printk("... APIC PROCPRI: %08x\n", v);
+ }
+
+ v = apic_read(APIC_EOI);
+ printk("... APIC EOI: %08x\n", v);
+ v = apic_read(APIC_LDR);
+ printk("... APIC LDR: %08x\n", v);
+ v = apic_read(APIC_DFR);
+ printk("... APIC DFR: %08x\n", v);
+ v = apic_read(APIC_SPIV);
+ printk("... APIC SPIV: %08x\n", v);
+
+ printk("... APIC ISR field:\n");
+ print_APIC_bitfield(APIC_ISR);
+ printk("... APIC TMR field:\n");
+ print_APIC_bitfield(APIC_TMR);
+ printk("... APIC IRR field:\n");
+ print_APIC_bitfield(APIC_IRR);
+
+ if (APIC_INTEGRATED(ver)) { /* !82489DX */
+ /*
+ * Due to the Pentium erratum 3AP.
+ */
+ if (maxlvt > 3) {
+ apic_readaround(APIC_SPIV); // not strictly necessery
+ apic_write(APIC_ESR, 0);
+ }
+ v = apic_read(APIC_ESR);
+ printk("... APIC ESR: %08x\n", v);
+ }
+
+ v = apic_read(APIC_ICR);
+ printk("... APIC ICR: %08x\n", v);
+ v = apic_read(APIC_ICR2);
+ printk("... APIC ICR2: %08x\n", v);
+
+ v = apic_read(APIC_LVTT);
+ printk("... APIC LVTT: %08x\n", v);
+
+ if (maxlvt > 3) { /* PC is LVT#4. */
+ v = apic_read(APIC_LVTPC);
+ printk("... APIC LVTPC: %08x\n", v);
+ }
+ v = apic_read(APIC_LVT0);
+ printk("... APIC LVT0: %08x\n", v);
+ v = apic_read(APIC_LVT1);
+ printk("... APIC LVT1: %08x\n", v);
+
+ if (maxlvt > 2) { /* ERR is LVT#3. */
+ v = apic_read(APIC_LVTERR);
+ printk("... APIC LVTERR: %08x\n", v);
+ }
+
+ v = apic_read(APIC_TMICT);
+ printk("... APIC TMICT: %08x\n", v);
+ v = apic_read(APIC_TMCCT);
+ printk("... APIC TMCCT: %08x\n", v);
+ v = apic_read(APIC_TDCR);
+ printk("... APIC TDCR: %08x\n", v);
+ printk("\n");
+}
+
+void print_all_local_APICs (void)
+{
+ smp_call_function(print_local_APIC, NULL, 1, 1);
+ print_local_APIC(NULL);
+}
+
static void __init init_sym_mode(void)
{
+ struct IO_APIC_reg_01 reg_01;
int i;
for (i = 0; i < PIN_MAP_SIZE; i++) {
@@ -809,24 +953,21 @@
for (i = 0; i < MAX_PIRQS; i++)
pirq_entries[i] =- 1;
- printk("enabling symmetric IO mode... ");
-
- outb(0x70, 0x22);
- outb(0x01, 0x23);
-
- printk("...done.\n");
+ if (pic_mode) {
+ /*
+ * PIC mode, enable symmetric IO mode in the IMCR.
+ */
+ printk("leaving PIC mode, enabling symmetric IO mode.\n");
+ outb(0x70, 0x22);
+ outb(0x01, 0x23);
+ }
/*
* The number of IO-APIC IRQ registers (== #pins):
*/
- {
- struct IO_APIC_reg_01 reg_01;
- int i;
-
- for (i = 0; i < nr_ioapics; i++) {
- *(int *)®_01 = io_apic_read(i, 1);
- nr_ioapic_registers[i] = reg_01.entries+1;
- }
+ for (i = 0; i < nr_ioapics; i++) {
+ *(int *)®_01 = io_apic_read(i, 1);
+ nr_ioapic_registers[i] = reg_01.entries+1;
}
/*
@@ -835,24 +976,41 @@
clear_IO_APIC();
}
+static void clear_lapic_ints (void * dummy)
+{
+ int maxlvt;
+
+ maxlvt = get_maxlvt();
+ apic_write_around(APIC_LVTT, 0x00010000);
+ apic_write_around(APIC_LVT0, 0x00010000);
+ apic_write_around(APIC_LVT1, 0x00010000);
+ if (maxlvt >= 3)
+ apic_write_around(APIC_LVTERR, 0x00010000);
+ if (maxlvt >= 4)
+ apic_write_around(APIC_LVTPC, 0x00010000);
+}
+
/*
* Not an __init, needed by the reboot code
*/
void init_pic_mode(void)
{
/*
- * Clear the IO-APIC before rebooting:
+ * Clear the IO-APIC and local APICs before rebooting:
*/
clear_IO_APIC();
+ smp_call_function(clear_lapic_ints, NULL, 1, 1);
+ clear_lapic_ints(NULL);
/*
* Put it back into PIC mode (has an effect only on
- * certain boards)
+ * certain older boards)
*/
- printk("disabling symmetric IO mode... ");
+ if (pic_mode) {
+ printk("disabling symmetric IO mode, entering PIC mode.\n");
outb_p(0x70, 0x22);
outb_p(0x00, 0x23);
- printk("...done.\n");
+ }
}
static void __init setup_ioapic_id(void)
@@ -914,10 +1072,13 @@
* MP specification 1.4 defines some extra rules for default
* configurations, fix them up here:
*/
-
switch (mpc_default_type)
{
case 2:
+ /*
+ * IRQ0 is not connected:
+ */
+ mp_irqs[0].mpc_irqtype = mp_ExtINT;
break;
default:
/*
@@ -942,7 +1103,7 @@
unsigned int t1 = jiffies;
sti();
- mdelay(100);
+ mdelay(40);
if (jiffies-t1>1)
return 1;
@@ -950,6 +1111,27 @@
return 0;
}
+extern atomic_t nmi_counter[NR_CPUS];
+
+static int __init nmi_irq_works(void)
+{
+ atomic_t tmp[NR_CPUS];
+ int j, cpu;
+
+ memcpy(tmp, nmi_counter, sizeof(tmp));
+ sti();
+ mdelay(50);
+
+ for (j = 0; j < smp_num_cpus; j++) {
+ cpu = cpu_logical_map(j);
+ if (atomic_read(nmi_counter+cpu) - atomic_read(tmp+cpu) <= 3) {
+ printk("CPU#%d NMI appears to be stuck.\n", cpu);
+ return 0;
+ }
+ }
+ return 1;
+}
+
/*
* In the SMP+IOAPIC case it might happen that there are an unspecified
* number of pending IRQ events unhandled. These cases are very rare,
@@ -964,12 +1146,11 @@
*/
static void enable_edge_ioapic_irq(unsigned int irq)
{
- enable_IO_APIC_irq(irq);
+ unmask_IO_APIC_irq(irq);
}
static void disable_edge_ioapic_irq(unsigned int irq)
{
- disable_IO_APIC_irq(irq);
}
/*
@@ -995,8 +1176,17 @@
}
#define shutdown_edge_ioapic_irq disable_edge_ioapic_irq
-void static ack_edge_ioapic_irq(unsigned int i)
-{
+
+/*
+ * Once we have recorded IRQ_PENDING already, we can mask the
+ * interrupt for real. This prevents IRQ storms from unhandled
+ * devices.
+ */
+void static ack_edge_ioapic_irq(unsigned int irq)
+{
+ if ((irq_desc[irq].status & (IRQ_PENDING | IRQ_DISABLED))
+ == (IRQ_PENDING | IRQ_DISABLED))
+ mask_IO_APIC_irq(irq);
ack_APIC_irq();
}
void static end_edge_ioapic_irq(unsigned int i){}
@@ -1055,7 +1245,8 @@
static inline void init_IO_APIC_traps(void)
{
- int i;
+ int irq;
+
/*
* NOTE! The local APIC isn't very good at handling
* multiple interrupts at the same interrupt level.
@@ -1067,36 +1258,62 @@
* Also, we've got to be careful not to trash gate
* 0x80, because int 0x80 is hm, kind of importantish. ;)
*/
- for (i = 0; i < NR_IRQS ; i++) {
- if (IO_APIC_VECTOR(i) > 0) {
- if (IO_APIC_irq_trigger(i))
- irq_desc[i].handler = &ioapic_level_irq_type;
- else
- irq_desc[i].handler = &ioapic_edge_irq_type;
- /*
- * disable it in the 8259A:
- */
- if (i < 16)
- disable_8259A_irq(i);
- } else {
- if (!IO_APIC_IRQ(i))
- continue;
-
+ for (irq = 0; irq < NR_IRQS ; irq++) {
+ if (IO_APIC_IRQ(irq) && !IO_APIC_VECTOR(irq)) {
/*
* Hmm.. We don't have an entry for this,
* so default to an old-fashioned 8259
* interrupt if we can..
*/
- if (i < 16) {
- make_8259A_irq(i);
- continue;
- }
-
- /* Strange. Oh, well.. */
- irq_desc[i].handler = &no_irq_type;
+ if (irq < 16)
+ make_8259A_irq(irq);
+ else
+ /* Strange. Oh, well.. */
+ irq_desc[irq].handler = &no_irq_type;
}
}
- init_IRQ_SMP();
+}
+
+void static ack_lapic_irq (unsigned int irq)
+{
+ ack_APIC_irq();
+}
+
+void static end_lapic_irq (unsigned int i) { /* nothing */ }
+
+static struct hw_interrupt_type lapic_irq_type = {
+ "local-APIC-edge",
+ NULL, /* startup_irq() not used for IRQ0 */
+ NULL, /* shutdown_irq() not used for IRQ0 */
+ NULL, /* enable_irq() not used for IRQ0 */
+ NULL, /* disable_irq() not used for IRQ0 */
+ ack_lapic_irq,
+ end_lapic_irq
+};
+
+static void enable_NMI_through_LVT0 (void * dummy)
+{
+ apic_readaround(APIC_LVT0);
+ apic_write(APIC_LVT0, 0x00000400); // unmask and set to NMI
+}
+
+static void setup_nmi (void)
+{
+ /*
+ * Dirty trick to enable the NMI watchdog ...
+ * We put the 8259A master into AEOI mode and
+ * unmask on all local APICs LVT0 as NMI.
+ *
+ * The idea to use the 8259A in AEOI mode ('8259A Virtual Wire')
+ * is from Maciej W. Rozycki - so we do not have to EOI from
+ * the NMI handler or the timer interrupt.
+ */
+ printk("activating NMI Watchdog ...");
+
+ smp_call_function(enable_NMI_through_LVT0, NULL, 1, 1);
+ enable_NMI_through_LVT0(NULL);
+
+ printk(" done.\n");
}
/*
@@ -1108,45 +1325,78 @@
static inline void check_timer(void)
{
int pin1, pin2;
+ int vector;
+
+ /*
+ * get/set the timer IRQ vector:
+ */
+ vector = assign_irq_vector(0);
+ set_intr_gate(vector, interrupt[0]);
pin1 = find_timer_pin(mp_INT);
pin2 = find_timer_pin(mp_ExtINT);
- enable_IO_APIC_irq(0);
- if (!timer_irq_works()) {
- if (pin1 != -1)
- printk("..MP-BIOS bug: 8254 timer not connected to IO-APIC\n");
- printk("...trying to set up timer as ExtINT... ");
-
- if (pin2 != -1) {
- printk(".. (found pin %d) ...", pin2);
- /*
- * legacy devices should be connected to IO APIC #0
- */
- setup_ExtINT_pin(0, pin2, 0);
- make_8259A_irq(0);
+ /*
+ * Ok, does IRQ0 through the IOAPIC work?
+ */
+ if (timer_irq_works()) {
+ if (nmi_watchdog) {
+ disable_8259A_irq(0);
+ init_8259A(1);
+ setup_nmi();
+ enable_8259A_irq(0);
+ if (nmi_irq_works())
+ return;
+ } else
+ return;
+ }
+
+ if (pin1 != -1) {
+ printk("..MP-BIOS bug: 8254 timer not connected to IO-APIC\n");
+ clear_IO_APIC_pin(0, pin1);
+ }
+
+ printk("...trying to set up timer (IRQ0) through the 8259A ... ");
+ if (pin2 != -1) {
+ printk("\n..... (found pin %d) ...", pin2);
+ /*
+ * legacy devices should be connected to IO APIC #0
+ */
+ setup_ExtINT_IRQ0_pin(pin2, vector);
+ if (timer_irq_works()) {
+ printk("works.\n");
+ if (nmi_watchdog) {
+ setup_nmi();
+ if (nmi_irq_works())
+ return;
+ } else
+ return;
}
+ /*
+ * Cleanup, just in case ...
+ */
+ clear_IO_APIC_pin(0, pin2);
+ }
+ printk(" failed.\n");
- if (!timer_irq_works()) {
- printk(" failed.\n");
- printk("...trying to set up timer as BP IRQ...");
- /*
- * Just in case ...
- */
- if (pin1 != -1)
- clear_IO_APIC_pin(0, pin1);
- if (pin2 != -1)
- clear_IO_APIC_pin(0, pin2);
-
- make_8259A_irq(0);
-
- if (!timer_irq_works()) {
- printk(" failed.\n");
- panic("IO-APIC + timer doesn't work!");
- }
- }
+ if (nmi_watchdog)
+ printk("timer doesnt work through the IO-APIC - cannot activate NMI Watchdog!\n");
+
+ printk("...trying to set up timer as Virtual Wire IRQ...");
+
+ disable_8259A_irq(0);
+ irq_desc[0].handler = &lapic_irq_type;
+ init_8259A(1); // AEOI mode
+ apic_readaround(APIC_LVT0);
+ apic_write(APIC_LVT0, 0x00000000 | vector); // Fixed mode
+ enable_8259A_irq(0);
+
+ if (timer_irq_works()) {
printk(" works.\n");
+ return;
}
+ printk(" failed :(.\n");
+ panic("IO-APIC + timer doesn't work! pester mingo@redhat.com");
}
/*
@@ -1189,6 +1439,5 @@
setup_IO_APIC_irqs();
init_IO_APIC_traps();
check_timer();
-
print_IO_APIC();
}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)