Skip to content

Commit

Permalink
---
Browse files Browse the repository at this point in the history
yaml
---
r: 11765
b: refs/heads/master
c: fcfd636
h: refs/heads/master
i:
  11763: 50a2a18
v: v3
  • Loading branch information
Eric W. Biederman authored and Linus Torvalds committed Oct 31, 2005
1 parent b124f6e commit 372f22e
Show file tree
Hide file tree
Showing 2 changed files with 113 additions and 36 deletions.
2 changes: 1 addition & 1 deletion [refs]
Original file line number Diff line number Diff line change
@@ -1,2 +1,2 @@
---
refs/heads/master: 9338316c9323682d32270d83b106472a50ab6da4
refs/heads/master: fcfd636a728fe2b8fb8c8fd8c557302059580577
147 changes: 112 additions & 35 deletions trunk/arch/i386/kernel/io_apic.c
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,9 @@
int (*ioapic_renumber_irq)(int ioapic, int irq);
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);

/*
Expand Down Expand Up @@ -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
*/
static int find_isa_irq_pin(int irq, int type)
static int __init find_isa_irq_pin(int irq, int type)
{
int i;

Expand All @@ -758,6 +761,33 @@ static int find_isa_irq_pin(int irq, int type)
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.
* Not an __init, possibly needed by modules
Expand Down Expand Up @@ -1253,7 +1283,7 @@ static void __init setup_IO_APIC_irqs(void)
/*
* 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;
unsigned long flags;
Expand Down Expand Up @@ -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:
*/
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);

enable_8259A_irq(0);
Expand Down Expand Up @@ -1595,7 +1625,8 @@ void /*__init*/ print_PIC(void)
static void __init enable_IO_APIC(void)
{
union IO_APIC_reg_01 reg_01;
int i;
int i8259_apic, i8259_pin;
int i, apic;
unsigned long flags;

for (i = 0; i < PIN_MAP_SIZE; i++) {
Expand All @@ -1609,11 +1640,52 @@ static void __init enable_IO_APIC(void)
/*
* 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);
reg_01.raw = io_apic_read(i, 1);
reg_01.raw = io_apic_read(apic, 1);
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");
}

/*
Expand All @@ -1627,7 +1699,6 @@ static void __init enable_IO_APIC(void)
*/
void disable_IO_APIC(void)
{
int pin;
/*
* Clear the IO-APIC before rebooting:
*/
Expand All @@ -1638,8 +1709,7 @@ void disable_IO_APIC(void)
* Put that IOAPIC in virtual wire mode
* 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;
unsigned long flags;

Expand All @@ -1650,7 +1720,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;

Expand All @@ -1659,11 +1729,13 @@ void disable_IO_APIC(void)
* Add it to the IO-APIC irq-routing table:
*/
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);
}
disconnect_bsp_APIC(pin != -1);
disconnect_bsp_APIC(ioapic_i8259.pin != -1);
}

/*
Expand Down Expand Up @@ -2113,20 +2185,21 @@ static void setup_nmi (void)
*/
static inline void unlock_ExtINT_logic(void)
{
int pin, i;
int apic, pin, i;
struct IO_APIC_route_entry entry0, entry1;
unsigned char save_control, save_freq_select;
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)
return;

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);
clear_IO_APIC_pin(0, pin);
clear_IO_APIC_pin(apic, pin);

memset(&entry1, 0, sizeof(entry1));

Expand All @@ -2139,8 +2212,8 @@ static inline void unlock_ExtINT_logic(void)
entry1.vector = 0;

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);

save_control = CMOS_READ(RTC_CONTROL);
Expand All @@ -2158,11 +2231,11 @@ static inline void unlock_ExtINT_logic(void)

CMOS_WRITE(save_control, RTC_CONTROL);
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);
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);
}

Expand All @@ -2174,7 +2247,7 @@ static inline void unlock_ExtINT_logic(void)
*/
static inline void check_timer(void)
{
int pin1, pin2;
int apic1, pin1, apic2, pin2;
int vector;

/*
Expand All @@ -2196,10 +2269,13 @@ static inline void check_timer(void)
timer_ack = 1;
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) {
/*
Expand All @@ -2216,8 +2292,9 @@ static inline void check_timer(void)
clear_IO_APIC_pin(0, pin1);
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 ... ");
Expand All @@ -2226,13 +2303,13 @@ static inline void check_timer(void)
/*
* 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()) {
printk("works.\n");
if (pin1 != -1)
replace_pin_at_irq(0, 0, pin1, 0, pin2);
replace_pin_at_irq(0, apic1, pin1, apic2, pin2);
else
add_pin_to_irq(0, 0, pin2);
add_pin_to_irq(0, apic2, pin2);
if (nmi_watchdog == NMI_IO_APIC) {
setup_nmi();
}
Expand All @@ -2241,7 +2318,7 @@ static inline void check_timer(void)
/*
* Cleanup, just in case ...
*/
clear_IO_APIC_pin(0, pin2);
clear_IO_APIC_pin(apic2, pin2);
}
printk(" failed.\n");

Expand Down

0 comments on commit 372f22e

Please sign in to comment.