diff options
Diffstat (limited to 'arch/i386/kernel/io_apic.c')
-rw-r--r-- | arch/i386/kernel/io_apic.c | 133 |
1 files changed, 90 insertions, 43 deletions
diff --git a/arch/i386/kernel/io_apic.c b/arch/i386/kernel/io_apic.c index 232abf78d..42ebd9643 100644 --- a/arch/i386/kernel/io_apic.c +++ b/arch/i386/kernel/io_apic.c @@ -202,7 +202,7 @@ DO_ACTION( enable, 1, |= 0xff000000, ) /* destination = 0xff */ DO_ACTION( mask, 0, |= 0x00010000, io_apic_sync()) /* mask = 1 */ DO_ACTION( unmask, 0, &= 0xfffeffff, ) /* mask = 0 */ -static void __init clear_IO_APIC_pin(unsigned int pin) +static void clear_IO_APIC_pin(unsigned int pin) { struct IO_APIC_route_entry entry; @@ -215,6 +215,13 @@ static void __init clear_IO_APIC_pin(unsigned int pin) io_apic_write(0x11 + 2 * pin, *(((int *)&entry) + 1)); } +static void clear_IO_APIC (void) +{ + int pin; + + for (pin = 0; pin < nr_ioapic_registers; pin++) + clear_IO_APIC_pin(pin); +} /* * support for broken MP BIOSs, enables hand-redirection of PIRQ0-7 to @@ -286,7 +293,8 @@ static int __init find_timer_pin(int type) 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) && + if ((mp_bus_id_to_type[lbus] == MP_BUS_ISA || + mp_bus_id_to_type[lbus] == MP_BUS_EISA) && (mp_irqs[i].mpc_irqtype == type) && (mp_irqs[i].mpc_srcbusirq == 0x00)) @@ -319,20 +327,7 @@ int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pci_pin) } /* - * Unclear documentation on what a "conforming ISA interrupt" means. - * - * Should we, or should we not, take the ELCR register into account? - * It's part of the EISA specification, but maybe it should only be - * used if the interrupt is actually marked as EISA? - * - * Oh, well. Don't do it until somebody tells us what the right thing - * to do is.. - */ -#undef USE_ELCR_TRIGGER_LEVEL -#ifdef USE_ELCR_TRIGGER_LEVEL - -/* - * ISA Edge/Level control register, ELCR + * EISA Edge/Level control register, ELCR */ static int __init EISA_ELCR(unsigned int irq) { @@ -342,18 +337,22 @@ static int __init EISA_ELCR(unsigned int irq) } printk("Broken MPtable reports ISA irq %d\n", irq); return 0; -} +} -#define default_ISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mpc_dstirq)) -#define default_ISA_polarity(idx) (0) +/* EISA interrupts are always polarity zero and can be edge or level + * trigger depending on the ELCR value. If an interrupt is listed as + * EISA conforming in the MP table, that means its trigger type must + * be read in from the ELCR */ -#else +#define default_EISA_trigger(idx) (EISA_ELCR(mp_irqs[idx].mpc_dstirq)) +#define default_EISA_polarity(idx) (0) + +/* ISA interrupts are always polarity zero edge triggered, even when + * listed as conforming in the MP table. */ #define default_ISA_trigger(idx) (0) #define default_ISA_polarity(idx) (0) -#endif - static int __init MPBIOS_polarity(int idx) { int bus = mp_irqs[idx].mpc_srcbus; @@ -373,6 +372,11 @@ static int __init MPBIOS_polarity(int idx) polarity = default_ISA_polarity(idx); break; } + case MP_BUS_EISA: + { + polarity = default_EISA_polarity(idx); + break; + } case MP_BUS_PCI: /* PCI pin */ { polarity = 1; @@ -432,6 +436,11 @@ static int __init MPBIOS_trigger(int idx) trigger = default_ISA_trigger(idx); break; } + case MP_BUS_EISA: + { + trigger = default_EISA_trigger(idx); + break; + } case MP_BUS_PCI: /* PCI pin, level */ { trigger = 1; @@ -496,6 +505,7 @@ static int __init pin_2_irq(int idx, int pin) switch (mp_bus_id_to_type[bus]) { case MP_BUS_ISA: /* ISA pin */ + case MP_BUS_EISA: { irq = mp_irqs[idx].mpc_srcbusirq; break; @@ -562,6 +572,9 @@ static int __init assign_irq_vector(int irq) 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; } @@ -625,7 +638,7 @@ void __init setup_IO_APIC_irqs(void) /* * Set up a certain pin as ExtINT delivered interrupt */ -void __init setup_ExtINT_pin(unsigned int pin) +void __init setup_ExtINT_pin(unsigned int pin, int irq) { struct IO_APIC_route_entry entry; @@ -635,11 +648,16 @@ void __init setup_ExtINT_pin(unsigned int pin) memset(&entry,0,sizeof(entry)); entry.delivery_mode = dest_ExtINT; - entry.dest_mode = 1; /* logical delivery */ + entry.dest_mode = 0; /* physical delivery */ entry.mask = 0; /* unmask IRQ now */ - entry.dest.logical.logical_dest = 0x01; /* logical CPU #0 */ + /* + * 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; - entry.vector = 0; /* it's ignored */ + entry.vector = assign_irq_vector(irq); entry.polarity = 0; entry.trigger = 0; @@ -681,9 +699,11 @@ void __init print_IO_APIC(void) printk(".... register #01: %08X\n", *(int *)®_01); printk("....... : max redirection entries: %04X\n", reg_01.entries); - if ( (reg_01.entries != 0x0f) && /* ISA-only Neptune boards */ - (reg_01.entries != 0x17) && /* ISA+PCI boards */ - (reg_01.entries != 0x3F) /* Xeon boards */ + if ( (reg_01.entries != 0x0f) && /* older (Neptune) boards */ + (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 */ ) UNEXPECTED_IO_APIC(); if (reg_01.entries == 0x0f) @@ -754,7 +774,7 @@ void __init print_IO_APIC(void) static void __init init_sym_mode(void) { - int i, pin; + int i; for (i = 0; i < PIN_MAP_SIZE; i++) { irq_2_pin[i].pin = -1; @@ -784,8 +804,7 @@ static void __init init_sym_mode(void) /* * Do not trust the IO-APIC being empty at bootup */ - for (pin = 0; pin < nr_ioapic_registers; pin++) - clear_IO_APIC_pin(pin); + clear_IO_APIC(); } /* @@ -793,6 +812,15 @@ static void __init init_sym_mode(void) */ void init_pic_mode(void) { + /* + * Clear the IO-APIC before rebooting: + */ + clear_IO_APIC(); + + /* + * Put it back into PIC mode (has an effect only on + * certain boards) + */ printk("disabling symmetric IO mode... "); outb_p(0x70, 0x22); outb_p(0x00, 0x23); @@ -885,6 +913,8 @@ static void __init setup_ioapic_id(void) static void __init construct_default_ISA_mptable(void) { int i, pos = 0; + const int bus_type = (mpc_default_type == 2 || mpc_default_type == 3 || + mpc_default_type == 6) ? MP_BUS_EISA : MP_BUS_ISA; for (i = 0; i < 16; i++) { if (!IO_APIC_IRQ(i)) @@ -892,14 +922,14 @@ static void __init construct_default_ISA_mptable(void) mp_irqs[pos].mpc_irqtype = mp_INT; mp_irqs[pos].mpc_irqflag = 0; /* default */ - mp_irqs[pos].mpc_srcbus = MP_BUS_ISA; + mp_irqs[pos].mpc_srcbus = 0; mp_irqs[pos].mpc_srcbusirq = i; mp_irqs[pos].mpc_dstapic = 0; mp_irqs[pos].mpc_dstirq = i; pos++; } mp_irq_entries = pos; - mp_bus_id_to_type[0] = MP_BUS_ISA; + mp_bus_id_to_type[0] = bus_type; /* * MP specification 1.4 defines some extra rules for default @@ -1019,7 +1049,7 @@ static void do_edge_ioapic_IRQ(unsigned int irq, struct pt_regs * regs) * and do not need to be masked. */ ack_APIC_irq(); - status = desc->status & ~IRQ_REPLAY; + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); status |= IRQ_PENDING; /* @@ -1030,8 +1060,9 @@ static void do_edge_ioapic_IRQ(unsigned int irq, struct pt_regs * regs) if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { action = desc->action; status &= ~IRQ_PENDING; + status |= IRQ_INPROGRESS; } - desc->status = status | IRQ_INPROGRESS; + desc->status = status; spin_unlock(&irq_controller_lock); /* @@ -1073,7 +1104,7 @@ static void do_level_ioapic_IRQ(unsigned int irq, struct pt_regs * regs) * So this all has to be within the spinlock. */ mask_IO_APIC_irq(irq); - status = desc->status & ~IRQ_REPLAY; + status = desc->status & ~(IRQ_REPLAY | IRQ_WAITING); /* * If the IRQ is disabled for whatever reason, we must @@ -1082,8 +1113,9 @@ static void do_level_ioapic_IRQ(unsigned int irq, struct pt_regs * regs) action = NULL; if (!(status & (IRQ_DISABLED | IRQ_INPROGRESS))) { action = desc->action; + status |= IRQ_INPROGRESS; } - desc->status = status | IRQ_INPROGRESS; + desc->status = status; ack_APIC_irq(); spin_unlock(&irq_controller_lock); @@ -1143,7 +1175,7 @@ static inline void init_IO_APIC_traps(void) * 0x80, because int 0x80 is hm, kind of importantish. ;) */ for (i = 0; i < NR_IRQS ; i++) { - if (IO_APIC_IRQ(i)) { + if (IO_APIC_VECTOR(i) > 0) { if (IO_APIC_irq_trigger(i)) irq_desc[i].handler = &ioapic_level_irq_type; else @@ -1153,8 +1185,25 @@ static inline void init_IO_APIC_traps(void) */ if (i < 16) disable_8259A_irq(i); + } else { + if (!IO_APIC_IRQ(i)) + continue; + + /* + * 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; } } + init_IRQ_SMP(); } /* @@ -1178,7 +1227,7 @@ static inline void check_timer(void) if (pin2 != -1) { printk(".. (found pin %d) ...", pin2); - setup_ExtINT_pin(pin2); + setup_ExtINT_pin(pin2, 0); make_8259A_irq(0); } @@ -1258,14 +1307,12 @@ void __init setup_IO_APIC(void) construct_default_ISA_mptable(); } - init_IO_APIC_traps(); - /* * Set up the IO-APIC IRQ routing table by parsing the MP-BIOS * mptable: */ setup_IO_APIC_irqs(); - init_IRQ_SMP(); + init_IO_APIC_traps(); check_timer(); print_IO_APIC(); |