|
@@ -46,6 +46,9 @@
|
|
int (*ioapic_renumber_irq)(int ioapic, int irq);
|
|
int (*ioapic_renumber_irq)(int ioapic, int irq);
|
|
atomic_t irq_mis_count;
|
|
atomic_t irq_mis_count;
|
|
|
|
|
|
|
|
+/* Where if anywhere is the i8259 connect in external int mode */
|
|
|
|
+static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
|
|
|
|
+
|
|
static DEFINE_SPINLOCK(ioapic_lock);
|
|
static DEFINE_SPINLOCK(ioapic_lock);
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -738,7 +741,7 @@ static int find_irq_entry(int apic, int pin, int type)
|
|
/*
|
|
/*
|
|
* Find the pin to which IRQ[irq] (ISA) is connected
|
|
* 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;
|
|
int i;
|
|
|
|
|
|
@@ -758,6 +761,33 @@ static int find_isa_irq_pin(int irq, int type)
|
|
return -1;
|
|
return -1;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+static int __init find_isa_irq_apic(int irq, int type)
|
|
|
|
+{
|
|
|
|
+ int i;
|
|
|
|
+
|
|
|
|
+ for (i = 0; i < mp_irq_entries; i++) {
|
|
|
|
+ int lbus = mp_irqs[i].mpc_srcbus;
|
|
|
|
+
|
|
|
|
+ if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA ||
|
|
|
|
+ mp_bus_id_to_type[lbus] == MP_BUS_EISA ||
|
|
|
|
+ mp_bus_id_to_type[lbus] == MP_BUS_MCA ||
|
|
|
|
+ mp_bus_id_to_type[lbus] == MP_BUS_NEC98
|
|
|
|
+ ) &&
|
|
|
|
+ (mp_irqs[i].mpc_irqtype == type) &&
|
|
|
|
+ (mp_irqs[i].mpc_srcbusirq == irq))
|
|
|
|
+ break;
|
|
|
|
+ }
|
|
|
|
+ if (i < mp_irq_entries) {
|
|
|
|
+ int apic;
|
|
|
|
+ for(apic = 0; apic < nr_ioapics; apic++) {
|
|
|
|
+ if (mp_ioapics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic)
|
|
|
|
+ return apic;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
|
|
+ return -1;
|
|
|
|
+}
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* Find a specific PCI IRQ entry.
|
|
* Find a specific PCI IRQ entry.
|
|
* Not an __init, possibly needed by modules
|
|
* Not an __init, possibly needed by modules
|
|
@@ -1253,7 +1283,7 @@ static void __init setup_IO_APIC_irqs(void)
|
|
/*
|
|
/*
|
|
* Set up the 8259A-master output pin:
|
|
* Set up the 8259A-master output pin:
|
|
*/
|
|
*/
|
|
-static void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector)
|
|
|
|
|
|
+static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, int vector)
|
|
{
|
|
{
|
|
struct IO_APIC_route_entry entry;
|
|
struct IO_APIC_route_entry entry;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
@@ -1287,8 +1317,8 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int pin, int vector)
|
|
* Add it to the IO-APIC irq-routing table:
|
|
* Add it to the IO-APIC irq-routing table:
|
|
*/
|
|
*/
|
|
spin_lock_irqsave(&ioapic_lock, flags);
|
|
spin_lock_irqsave(&ioapic_lock, flags);
|
|
- io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
|
|
|
|
- io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
|
|
|
|
|
|
+ io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
|
|
|
|
+ io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
|
|
spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
|
|
|
|
enable_8259A_irq(0);
|
|
enable_8259A_irq(0);
|
|
@@ -1595,7 +1625,8 @@ void /*__init*/ print_PIC(void)
|
|
static void __init enable_IO_APIC(void)
|
|
static void __init enable_IO_APIC(void)
|
|
{
|
|
{
|
|
union IO_APIC_reg_01 reg_01;
|
|
union IO_APIC_reg_01 reg_01;
|
|
- int i;
|
|
|
|
|
|
+ int i8259_apic, i8259_pin;
|
|
|
|
+ int i, apic;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
|
|
|
|
for (i = 0; i < PIN_MAP_SIZE; i++) {
|
|
for (i = 0; i < PIN_MAP_SIZE; i++) {
|
|
@@ -1609,11 +1640,52 @@ static void __init enable_IO_APIC(void)
|
|
/*
|
|
/*
|
|
* The number of IO-APIC IRQ registers (== #pins):
|
|
* The number of IO-APIC IRQ registers (== #pins):
|
|
*/
|
|
*/
|
|
- for (i = 0; i < nr_ioapics; i++) {
|
|
|
|
|
|
+ for (apic = 0; apic < nr_ioapics; apic++) {
|
|
spin_lock_irqsave(&ioapic_lock, flags);
|
|
spin_lock_irqsave(&ioapic_lock, flags);
|
|
- reg_01.raw = io_apic_read(i, 1);
|
|
|
|
|
|
+ reg_01.raw = io_apic_read(apic, 1);
|
|
spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
- nr_ioapic_registers[i] = reg_01.bits.entries+1;
|
|
|
|
|
|
+ nr_ioapic_registers[apic] = reg_01.bits.entries+1;
|
|
|
|
+ }
|
|
|
|
+ for(apic = 0; apic < nr_ioapics; apic++) {
|
|
|
|
+ int pin;
|
|
|
|
+ /* See if any of the pins is in ExtINT mode */
|
|
|
|
+ for(pin = 0; pin < nr_ioapic_registers[i]; pin++) {
|
|
|
|
+ struct IO_APIC_route_entry entry;
|
|
|
|
+ spin_lock_irqsave(&ioapic_lock, flags);
|
|
|
|
+ *(((int *)&entry) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
|
|
|
|
+ *(((int *)&entry) + 1) = io_apic_read(apic, 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.apic = apic;
|
|
|
|
+ ioapic_i8259.pin = pin;
|
|
|
|
+ goto found_i8259;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+ found_i8259:
|
|
|
|
+ /* Look to see what if the MP table has reported the ExtINT */
|
|
|
|
+ /* If we could not find the appropriate pin by looking at the ioapic
|
|
|
|
+ * the i8259 probably is not connected the ioapic but give the
|
|
|
|
+ * mptable a chance anyway.
|
|
|
|
+ */
|
|
|
|
+ i8259_pin = find_isa_irq_pin(0, mp_ExtINT);
|
|
|
|
+ i8259_apic = find_isa_irq_apic(0, mp_ExtINT);
|
|
|
|
+ /* Trust the MP table if nothing is setup in the hardware */
|
|
|
|
+ if ((ioapic_i8259.pin == -1) && (i8259_pin >= 0)) {
|
|
|
|
+ printk(KERN_WARNING "ExtINT not setup in hardware but reported by MP table\n");
|
|
|
|
+ ioapic_i8259.pin = i8259_pin;
|
|
|
|
+ ioapic_i8259.apic = i8259_apic;
|
|
|
|
+ }
|
|
|
|
+ /* Complain if the MP table and the hardware disagree */
|
|
|
|
+ if (((ioapic_i8259.apic != i8259_apic) || (ioapic_i8259.pin != i8259_pin)) &&
|
|
|
|
+ (i8259_pin >= 0) && (ioapic_i8259.pin >= 0))
|
|
|
|
+ {
|
|
|
|
+ printk(KERN_WARNING "ExtINT in hardware and MP table differ\n");
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -1627,7 +1699,6 @@ static void __init enable_IO_APIC(void)
|
|
*/
|
|
*/
|
|
void disable_IO_APIC(void)
|
|
void disable_IO_APIC(void)
|
|
{
|
|
{
|
|
- int pin;
|
|
|
|
/*
|
|
/*
|
|
* Clear the IO-APIC before rebooting:
|
|
* Clear the IO-APIC before rebooting:
|
|
*/
|
|
*/
|
|
@@ -1638,8 +1709,7 @@ void disable_IO_APIC(void)
|
|
* Put that IOAPIC in virtual wire mode
|
|
* Put that IOAPIC in virtual wire mode
|
|
* so legacy interrupts can be delivered.
|
|
* so legacy interrupts can be delivered.
|
|
*/
|
|
*/
|
|
- pin = find_isa_irq_pin(0, mp_ExtINT);
|
|
|
|
- if (pin != -1) {
|
|
|
|
|
|
+ if (ioapic_i8259.pin != -1) {
|
|
struct IO_APIC_route_entry entry;
|
|
struct IO_APIC_route_entry entry;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
|
|
|
|
@@ -1650,7 +1720,7 @@ void disable_IO_APIC(void)
|
|
entry.polarity = 0; /* High */
|
|
entry.polarity = 0; /* High */
|
|
entry.delivery_status = 0;
|
|
entry.delivery_status = 0;
|
|
entry.dest_mode = 0; /* Physical */
|
|
entry.dest_mode = 0; /* Physical */
|
|
- entry.delivery_mode = 7; /* ExtInt */
|
|
|
|
|
|
+ entry.delivery_mode = dest_ExtINT; /* ExtInt */
|
|
entry.vector = 0;
|
|
entry.vector = 0;
|
|
entry.dest.physical.physical_dest = 0;
|
|
entry.dest.physical.physical_dest = 0;
|
|
|
|
|
|
@@ -1659,11 +1729,13 @@ void disable_IO_APIC(void)
|
|
* Add it to the IO-APIC irq-routing table:
|
|
* Add it to the IO-APIC irq-routing table:
|
|
*/
|
|
*/
|
|
spin_lock_irqsave(&ioapic_lock, flags);
|
|
spin_lock_irqsave(&ioapic_lock, flags);
|
|
- io_apic_write(0, 0x11+2*pin, *(((int *)&entry)+1));
|
|
|
|
- io_apic_write(0, 0x10+2*pin, *(((int *)&entry)+0));
|
|
|
|
|
|
+ io_apic_write(ioapic_i8259.apic, 0x11+2*ioapic_i8259.pin,
|
|
|
|
+ *(((int *)&entry)+1));
|
|
|
|
+ io_apic_write(ioapic_i8259.apic, 0x10+2*ioapic_i8259.pin,
|
|
|
|
+ *(((int *)&entry)+0));
|
|
spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
}
|
|
}
|
|
- disconnect_bsp_APIC(pin != -1);
|
|
|
|
|
|
+ disconnect_bsp_APIC(ioapic_i8259.pin != -1);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -2113,20 +2185,21 @@ static void setup_nmi (void)
|
|
*/
|
|
*/
|
|
static inline void unlock_ExtINT_logic(void)
|
|
static inline void unlock_ExtINT_logic(void)
|
|
{
|
|
{
|
|
- int pin, i;
|
|
|
|
|
|
+ int apic, pin, i;
|
|
struct IO_APIC_route_entry entry0, entry1;
|
|
struct IO_APIC_route_entry entry0, entry1;
|
|
unsigned char save_control, save_freq_select;
|
|
unsigned char save_control, save_freq_select;
|
|
unsigned long flags;
|
|
unsigned long flags;
|
|
|
|
|
|
- pin = find_isa_irq_pin(8, mp_INT);
|
|
|
|
|
|
+ pin = find_isa_irq_pin(8, mp_INT);
|
|
|
|
+ apic = find_isa_irq_apic(8, mp_INT);
|
|
if (pin == -1)
|
|
if (pin == -1)
|
|
return;
|
|
return;
|
|
|
|
|
|
spin_lock_irqsave(&ioapic_lock, flags);
|
|
spin_lock_irqsave(&ioapic_lock, flags);
|
|
- *(((int *)&entry0) + 1) = io_apic_read(0, 0x11 + 2 * pin);
|
|
|
|
- *(((int *)&entry0) + 0) = io_apic_read(0, 0x10 + 2 * pin);
|
|
|
|
|
|
+ *(((int *)&entry0) + 1) = io_apic_read(apic, 0x11 + 2 * pin);
|
|
|
|
+ *(((int *)&entry0) + 0) = io_apic_read(apic, 0x10 + 2 * pin);
|
|
spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
- clear_IO_APIC_pin(0, pin);
|
|
|
|
|
|
+ clear_IO_APIC_pin(apic, pin);
|
|
|
|
|
|
memset(&entry1, 0, sizeof(entry1));
|
|
memset(&entry1, 0, sizeof(entry1));
|
|
|
|
|
|
@@ -2139,8 +2212,8 @@ static inline void unlock_ExtINT_logic(void)
|
|
entry1.vector = 0;
|
|
entry1.vector = 0;
|
|
|
|
|
|
spin_lock_irqsave(&ioapic_lock, flags);
|
|
spin_lock_irqsave(&ioapic_lock, flags);
|
|
- io_apic_write(0, 0x11 + 2 * pin, *(((int *)&entry1) + 1));
|
|
|
|
- io_apic_write(0, 0x10 + 2 * pin, *(((int *)&entry1) + 0));
|
|
|
|
|
|
+ io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry1) + 1));
|
|
|
|
+ io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry1) + 0));
|
|
spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
|
|
|
|
save_control = CMOS_READ(RTC_CONTROL);
|
|
save_control = CMOS_READ(RTC_CONTROL);
|
|
@@ -2158,11 +2231,11 @@ static inline void unlock_ExtINT_logic(void)
|
|
|
|
|
|
CMOS_WRITE(save_control, RTC_CONTROL);
|
|
CMOS_WRITE(save_control, RTC_CONTROL);
|
|
CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
|
|
CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
|
|
- clear_IO_APIC_pin(0, pin);
|
|
|
|
|
|
+ clear_IO_APIC_pin(apic, pin);
|
|
|
|
|
|
spin_lock_irqsave(&ioapic_lock, flags);
|
|
spin_lock_irqsave(&ioapic_lock, flags);
|
|
- io_apic_write(0, 0x11 + 2 * pin, *(((int *)&entry0) + 1));
|
|
|
|
- io_apic_write(0, 0x10 + 2 * pin, *(((int *)&entry0) + 0));
|
|
|
|
|
|
+ io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry0) + 1));
|
|
|
|
+ io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry0) + 0));
|
|
spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
spin_unlock_irqrestore(&ioapic_lock, flags);
|
|
}
|
|
}
|
|
|
|
|
|
@@ -2174,7 +2247,7 @@ static inline void unlock_ExtINT_logic(void)
|
|
*/
|
|
*/
|
|
static inline void check_timer(void)
|
|
static inline void check_timer(void)
|
|
{
|
|
{
|
|
- int pin1, pin2;
|
|
|
|
|
|
+ int apic1, pin1, apic2, pin2;
|
|
int vector;
|
|
int vector;
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -2196,10 +2269,13 @@ static inline void check_timer(void)
|
|
timer_ack = 1;
|
|
timer_ack = 1;
|
|
enable_8259A_irq(0);
|
|
enable_8259A_irq(0);
|
|
|
|
|
|
- pin1 = find_isa_irq_pin(0, mp_INT);
|
|
|
|
- pin2 = find_isa_irq_pin(0, mp_ExtINT);
|
|
|
|
|
|
+ pin1 = find_isa_irq_pin(0, mp_INT);
|
|
|
|
+ apic1 = find_isa_irq_apic(0, mp_INT);
|
|
|
|
+ pin2 = ioapic_i8259.pin;
|
|
|
|
+ apic2 = ioapic_i8259.apic;
|
|
|
|
|
|
- printk(KERN_INFO "..TIMER: vector=0x%02X pin1=%d pin2=%d\n", vector, pin1, pin2);
|
|
|
|
|
|
+ printk(KERN_INFO "..TIMER: vector=0x%02X apic1=%d pin1=%d apic2=%d pin2=%d\n",
|
|
|
|
+ vector, apic1, pin1, apic2, pin2);
|
|
|
|
|
|
if (pin1 != -1) {
|
|
if (pin1 != -1) {
|
|
/*
|
|
/*
|
|
@@ -2216,8 +2292,9 @@ static inline void check_timer(void)
|
|
clear_IO_APIC_pin(0, pin1);
|
|
clear_IO_APIC_pin(0, pin1);
|
|
return;
|
|
return;
|
|
}
|
|
}
|
|
- clear_IO_APIC_pin(0, pin1);
|
|
|
|
- printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to IO-APIC\n");
|
|
|
|
|
|
+ clear_IO_APIC_pin(apic1, pin1);
|
|
|
|
+ printk(KERN_ERR "..MP-BIOS bug: 8254 timer not connected to "
|
|
|
|
+ "IO-APIC\n");
|
|
}
|
|
}
|
|
|
|
|
|
printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... ");
|
|
printk(KERN_INFO "...trying to set up timer (IRQ0) through the 8259A ... ");
|
|
@@ -2226,13 +2303,13 @@ static inline void check_timer(void)
|
|
/*
|
|
/*
|
|
* legacy devices should be connected to IO APIC #0
|
|
* legacy devices should be connected to IO APIC #0
|
|
*/
|
|
*/
|
|
- setup_ExtINT_IRQ0_pin(pin2, vector);
|
|
|
|
|
|
+ setup_ExtINT_IRQ0_pin(apic2, pin2, vector);
|
|
if (timer_irq_works()) {
|
|
if (timer_irq_works()) {
|
|
printk("works.\n");
|
|
printk("works.\n");
|
|
if (pin1 != -1)
|
|
if (pin1 != -1)
|
|
- replace_pin_at_irq(0, 0, pin1, 0, pin2);
|
|
|
|
|
|
+ replace_pin_at_irq(0, apic1, pin1, apic2, pin2);
|
|
else
|
|
else
|
|
- add_pin_to_irq(0, 0, pin2);
|
|
|
|
|
|
+ add_pin_to_irq(0, apic2, pin2);
|
|
if (nmi_watchdog == NMI_IO_APIC) {
|
|
if (nmi_watchdog == NMI_IO_APIC) {
|
|
setup_nmi();
|
|
setup_nmi();
|
|
}
|
|
}
|
|
@@ -2241,7 +2318,7 @@ static inline void check_timer(void)
|
|
/*
|
|
/*
|
|
* Cleanup, just in case ...
|
|
* Cleanup, just in case ...
|
|
*/
|
|
*/
|
|
- clear_IO_APIC_pin(0, pin2);
|
|
|
|
|
|
+ clear_IO_APIC_pin(apic2, pin2);
|
|
}
|
|
}
|
|
printk(" failed.\n");
|
|
printk(" failed.\n");
|
|
|
|
|