[PATCH] x86_64 io_apic.c: Memorize at bootup where the i8259 isconnected
From: Eric W. Biederman
Date: Fri Jul 29 2005 - 14:36:06 EST
Currently we attempt to restore virtual wire mode on reboot, which
only works if we can figure out where the i8259 is connected. This
is very useful when we kexec another kernel and likely helpful
when dealing with a BIOS that make assumptions about how the system is setup.
Since the acpi MADT table does not provide the location where the i8259
is connected we have to look at the hardware to figure it out.
Most systems have the i8259 connected to the local apic of the cpu so
won't be affected but people running on Opteron and some serverworks chipsets
should be able to use kexec now.
Signed-off-by: Eric W. Biederman <ebiederm@xxxxxxxxxxxx>
---
arch/x86_64/kernel/io_apic.c | 52 ++++++++++++++++++++++++++++++++++++++----
1 files changed, 47 insertions(+), 5 deletions(-)
96c59dd871b00735ef159ddf0d68f338958387fc
diff --git a/arch/x86_64/kernel/io_apic.c b/arch/x86_64/kernel/io_apic.c
--- a/arch/x86_64/kernel/io_apic.c
+++ b/arch/x86_64/kernel/io_apic.c
@@ -45,6 +45,9 @@ int sis_apic_bug; /* not actually suppor
static int no_timer_check;
+/* Where if anywhere is the i8259 connect in external int mode */
+static int ioapic_i8259_pin = -1;
+
static DEFINE_SPINLOCK(ioapic_lock);
/*
@@ -330,7 +333,7 @@ static int find_irq_entry(int apic, int
/*
* Find the pin to which IRQ[irq] (ISA) is connected
*/
-static int find_isa_irq_pin(int irq, int type)
+static int __init find_isa_irq_pin(int irq, int type)
{
int i;
@@ -1096,6 +1099,44 @@ void __apicdebuginit print_PIC(void)
#endif /* 0 */
+static void __init find_i8259_pin(void)
+{
+ struct IO_APIC_route_entry entry;
+ unsigned long flags;
+ int pin, pins;
+
+ ioapic_i8259_pin = -1;
+
+ /* Find the number of pins on the primary ioapic */
+ spin_lock_irqsave(&ioapic_lock, flags);
+ pins = ((io_apic_read(0, 0x01) >> 16) & 0xff) + 1;
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+
+ /* See if any of the pins is in ExtINT mode */
+ for(pin = 0; pin < pins; pin++) {
+ spin_lock_irqsave(&ioapic_lock, flags);
+ *(((int *)&entry) + 0) = io_apic_read(0, 0x10 + 2 * pin);
+ *(((int *)&entry) + 1) = io_apic_read(0, 0x11 + 2 * pin);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+
+ /* If the interrupt line is enabled and in ExtInt mode
+ * I have found the pin where the i8259 is connected.
+ */
+ if ((entry.mask == 0) && (entry.delivery_mode == dest_ExtINT)) {
+ ioapic_i8259_pin = pin;
+ break;
+ }
+ }
+
+ /* If we could not find an appropriate pin by looking at the ioapic
+ * the i8259 probably isn't connected to the ioapic but give
+ * the mptable a chance anyway.
+ */
+ if (ioapic_i8259_pin == -1) {
+ ioapic_i8259_pin = find_isa_irq_pin(0, mp_ExtINT);
+ }
+}
+
static void __init enable_IO_APIC(void)
{
union IO_APIC_reg_01 reg_01;
@@ -1138,11 +1179,11 @@ void disable_IO_APIC(void)
clear_IO_APIC();
/*
- * If the i82559 is routed through an IOAPIC
+ * If the i8259 is routed through an IOAPIC
* Put that IOAPIC in virtual wire mode
* so legacy interrups can be delivered.
*/
- pin = find_isa_irq_pin(0, mp_ExtINT);
+ pin = ioapic_i8259_pin;
if (pin != -1) {
struct IO_APIC_route_entry entry;
unsigned long flags;
@@ -1154,7 +1195,7 @@ void disable_IO_APIC(void)
entry.polarity = 0; /* High */
entry.delivery_status = 0;
entry.dest_mode = 0; /* Physical */
- entry.delivery_mode = 7; /* ExtInt */
+ entry.delivery_mode = dest_ExtINT; /* ExtInt */
entry.vector = 0;
entry.dest.physical.physical_dest = 0;
@@ -1626,7 +1667,7 @@ static inline void check_timer(void)
enable_8259A_irq(0);
pin1 = find_isa_irq_pin(0, mp_INT);
- pin2 = find_isa_irq_pin(0, mp_ExtINT);
+ pin2 = ioapic_i8259_pin;
apic_printk(APIC_VERBOSE,KERN_INFO "..TIMER: vector=0x%02X pin1=%d pin2=%d\n", vector, pin1, pin2);
@@ -1723,6 +1764,7 @@ __setup("no_timer_check", notimercheck);
void __init setup_IO_APIC(void)
{
+ find_i8259_pin();
enable_IO_APIC();
if (acpi_ioapic)
-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/