patch-2.3.12 linux/arch/i386/kernel/io_apic.c
Next file: linux/arch/i386/kernel/irq.h
Previous file: linux/arch/i386/kernel/init_task.c
Back to the patch index
Back to the overall index
- Lines: 543
- Date:
Sun Jul 25 10:26:01 1999
- Orig file:
v2.3.11/linux/arch/i386/kernel/io_apic.c
- Orig date:
Thu May 6 16:07:03 1999
diff -u --recursive --new-file v2.3.11/linux/arch/i386/kernel/io_apic.c linux/arch/i386/kernel/io_apic.c
@@ -5,6 +5,12 @@
*
* Many thanks to Stig Venaas for trying out countless experimental
* patches and reporting/debugging problems patiently!
+ *
+ * (c) 1999, Multiple IO-APIC support, developed by
+ * Ken-ichi Yaku <yaku@css1.kbnes.nec.co.jp> and
+ * Hidemi Kishimoto <kisimoto@css1.kbnes.nec.co.jp>,
+ * further tested and cleaned up by Zach Brown <zab@redhat.com>
+ * and Ingo Molnar <mingo@redhat.com>
*/
#include <linux/sched.h>
@@ -19,7 +25,7 @@
* volatile is justified in this case, IO-APIC register contents
* might change spontaneously, GCC should not cache it
*/
-#define IO_APIC_BASE ((volatile int *)fix_to_virt(FIX_IO_APIC_BASE))
+#define IO_APIC_BASE(idx) ((volatile int *)__fix_to_virt(FIX_IO_APIC_BASE_0 + idx))
/*
* The structure of the IO-APIC:
@@ -45,9 +51,10 @@
} __attribute__ ((packed));
/*
- * # of IRQ routing registers
+ * # of IO-APICs and # of IRQ routing registers
*/
-int nr_ioapic_registers = 0;
+int nr_ioapics = 0;
+int nr_ioapic_registers[MAX_IO_APICS];
enum ioapic_irq_destination_types {
dest_Fixed = 0,
@@ -94,6 +101,7 @@
mp_ExtINT = 3
};
+struct mpc_config_ioapic mp_apics[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 */
@@ -108,34 +116,34 @@
* between pins and IRQs.
*/
-static inline unsigned int io_apic_read(unsigned int reg)
+static inline unsigned int io_apic_read(unsigned int apic, unsigned int reg)
{
- *IO_APIC_BASE = reg;
- return *(IO_APIC_BASE+4);
+ *IO_APIC_BASE(apic) = reg;
+ return *(IO_APIC_BASE(apic)+4);
}
-static inline void io_apic_write(unsigned int reg, unsigned int value)
+static inline void io_apic_write(unsigned int apic, unsigned int reg, unsigned int value)
{
- *IO_APIC_BASE = reg;
- *(IO_APIC_BASE+4) = value;
+ *IO_APIC_BASE(apic) = reg;
+ *(IO_APIC_BASE(apic)+4) = value;
}
/*
* Re-write a value: to be used for read-modify-write
* cycles where the read already set up the index register.
*/
-static inline void io_apic_modify(unsigned int value)
+static inline void io_apic_modify(unsigned int apic, unsigned int value)
{
- *(IO_APIC_BASE+4) = value;
+ *(IO_APIC_BASE(apic)+4) = value;
}
/*
* Synchronize the IO-APIC and the CPU by doing
* a dummy read from the IO-APIC
*/
-static inline void io_apic_sync(void)
+static inline void io_apic_sync(unsigned int apic)
{
- (void) *(IO_APIC_BASE+4);
+ (void) *(IO_APIC_BASE(apic)+4);
}
/*
@@ -146,7 +154,7 @@
#define PIN_MAP_SIZE (MAX_PLUS_SHARED_IRQS + NR_IRQS)
static struct irq_pin_list {
- int pin, next;
+ int apic, pin, next;
} irq_2_pin[PIN_MAP_SIZE];
/*
@@ -154,7 +162,7 @@
* shared ISA-space IRQs, so we have to support them. We are super
* fast in the common case, and fast for shared ISA-space IRQs.
*/
-static void add_pin_to_irq(unsigned int irq, int pin)
+static void add_pin_to_irq(unsigned int irq, int apic, int pin)
{
static int first_free_entry = NR_IRQS;
struct irq_pin_list *entry = irq_2_pin + irq;
@@ -168,6 +176,7 @@
if (++first_free_entry >= PIN_MAP_SIZE)
panic("io_apic.c: whoops");
}
+ entry->apic = apic;
entry->pin = pin;
}
@@ -183,9 +192,9 @@
pin = entry->pin; \
if (pin == -1) \
break; \
- reg = io_apic_read(0x10 + R + pin*2); \
+ reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \
reg ACTION; \
- io_apic_modify(reg); \
+ io_apic_modify(entry->apic, reg); \
if (!entry->next) \
break; \
entry = irq_2_pin + entry->next; \
@@ -197,12 +206,12 @@
* 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()) /* destination = 0x00 */
+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()) /* mask = 1 */
+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 pin)
+static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
{
struct IO_APIC_route_entry entry;
@@ -211,16 +220,17 @@
*/
memset(&entry, 0, sizeof(entry));
entry.mask = 1;
- io_apic_write(0x10 + 2 * pin, *(((int *)&entry) + 0));
- io_apic_write(0x11 + 2 * pin, *(((int *)&entry) + 1));
+ io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
+ io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
}
static void clear_IO_APIC (void)
{
- int pin;
+ int apic, pin;
- for (pin = 0; pin < nr_ioapic_registers; pin++)
- clear_IO_APIC_pin(pin);
+ for (apic = 0; apic < nr_ioapics; apic++)
+ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++)
+ clear_IO_APIC_pin(apic, pin);
}
/*
@@ -270,12 +280,13 @@
/*
* Find the IRQ entry number of a certain pin.
*/
-static int __init find_irq_entry(int pin, int type)
+static int __init find_irq_entry(int apic, int pin, int type)
{
int i;
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_dstirq == pin))
return i;
@@ -307,21 +318,26 @@
* Find a specific PCI IRQ entry.
* Not an initfunc, possibly needed by modules
*/
+static int __init pin_2_irq(int idx, int apic, int pin);
int IO_APIC_get_PCI_irq_vector(int bus, int slot, int pci_pin)
{
- int i;
+ int apic, i;
for (i = 0; i < mp_irq_entries; i++) {
int lbus = mp_irqs[i].mpc_srcbus;
- if (IO_APIC_IRQ(mp_irqs[i].mpc_dstirq) &&
+ for (apic = 0; apic < nr_ioapics; apic++)
+ if (mp_apics[apic].mpc_apicid == mp_irqs[i].mpc_dstapic)
+ break;
+
+ if ((apic || IO_APIC_IRQ(mp_irqs[i].mpc_dstirq)) &&
(mp_bus_id_to_type[lbus] == MP_BUS_PCI) &&
!mp_irqs[i].mpc_irqtype &&
(bus == mp_bus_id_to_pci_bus[mp_irqs[i].mpc_srcbus]) &&
(slot == ((mp_irqs[i].mpc_srcbusirq >> 2) & 0x1f)) &&
(pci_pin == (mp_irqs[i].mpc_srcbusirq & 3)))
- return mp_irqs[i].mpc_dstirq;
+ return pin_2_irq(i,apic,mp_irqs[i].mpc_dstirq);
}
return -1;
}
@@ -491,9 +507,9 @@
return MPBIOS_trigger(idx);
}
-static int __init pin_2_irq(int idx, int pin)
+static int __init pin_2_irq(int idx, int apic, int pin)
{
- int irq;
+ int irq, i;
int bus = mp_irqs[idx].mpc_srcbus;
/*
@@ -513,9 +529,12 @@
case MP_BUS_PCI: /* PCI pin */
{
/*
- * PCI IRQs are 'directly mapped'
+ * PCI IRQs are mapped in order
*/
- irq = pin;
+ i = irq = 0;
+ while (i < apic)
+ irq += nr_ioapic_registers[i++];
+ irq += pin;
break;
}
default:
@@ -545,12 +564,14 @@
static inline int IO_APIC_irq_trigger(int irq)
{
- int idx, pin;
+ int apic, idx, pin;
- for (pin = 0; pin < nr_ioapic_registers; pin++) {
- idx = find_irq_entry(pin,mp_INT);
- if ((idx != -1) && (irq == pin_2_irq(idx,pin)))
- return irq_trigger(idx);
+ for (apic = 0; apic < nr_ioapics; apic++) {
+ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
+ idx = find_irq_entry(apic,pin,mp_INT);
+ if ((idx != -1) && (irq == pin_2_irq(idx,apic,pin)))
+ return irq_trigger(idx);
+ }
}
/*
* nonexistent IRQs are edge default
@@ -582,11 +603,12 @@
void __init setup_IO_APIC_irqs(void)
{
struct IO_APIC_route_entry entry;
- int pin, idx, bus, irq, first_notcon = 1;
+ int apic, pin, idx, irq, first_notcon = 1;
printk("init IO_APIC IRQs\n");
- for (pin = 0; pin < nr_ioapic_registers; pin++) {
+ for (apic = 0; apic < nr_ioapics; apic++) {
+ for (pin = 0; pin < nr_ioapic_registers[apic]; pin++) {
/*
* add it to the IO-APIC irq-routing table:
@@ -598,13 +620,13 @@
entry.mask = 0; /* enable IRQ */
entry.dest.logical.logical_dest = 0; /* but no route */
- idx = find_irq_entry(pin,mp_INT);
+ idx = find_irq_entry(apic,pin,mp_INT);
if (idx == -1) {
if (first_notcon) {
- printk(" IO-APIC pin %d", pin);
+ printk(" IO-APIC (apicid-pin) %d-%d", mp_apics[apic].mpc_apicid, pin);
first_notcon = 0;
} else
- printk(", %d", pin);
+ printk(", %d-%d", mp_apics[apic].mpc_apicid, pin);
continue;
}
@@ -617,18 +639,17 @@
entry.dest.logical.logical_dest = 0xff;
}
- irq = pin_2_irq(idx,pin);
- add_pin_to_irq(irq, pin);
+ irq = pin_2_irq(idx,apic,pin);
+ add_pin_to_irq(irq, apic, pin);
- if (!IO_APIC_IRQ(irq))
+ if (!apic && !IO_APIC_IRQ(irq))
continue;
entry.vector = assign_irq_vector(irq);
- bus = mp_irqs[idx].mpc_srcbus;
-
- io_apic_write(0x11+2*pin, *(((int *)&entry)+1));
- io_apic_write(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));
+ }
}
if (!first_notcon)
@@ -638,7 +659,7 @@
/*
* Set up a certain pin as ExtINT delivered interrupt
*/
-void __init setup_ExtINT_pin(unsigned int pin, int irq)
+void __init setup_ExtINT_pin(unsigned int apic, unsigned int pin, int irq)
{
struct IO_APIC_route_entry entry;
@@ -662,8 +683,8 @@
entry.polarity = 0;
entry.trigger = 0;
- io_apic_write(0x10+2*pin, *(((int *)&entry)+0));
- io_apic_write(0x11+2*pin, *(((int *)&entry)+1));
+ io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
+ io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
}
void __init UNEXPECTED_IO_APIC(void)
@@ -674,17 +695,14 @@
void __init print_IO_APIC(void)
{
- int i;
+ int apic, i;
struct IO_APIC_reg_00 reg_00;
struct IO_APIC_reg_01 reg_01;
struct IO_APIC_reg_02 reg_02;
printk("number of MP IRQ sources: %d.\n", mp_irq_entries);
- printk("number of IO-APIC registers: %d.\n", nr_ioapic_registers);
-
- *(int *)®_00 = io_apic_read(0);
- *(int *)®_01 = io_apic_read(1);
- *(int *)®_02 = io_apic_read(2);
+ 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]);
/*
* We are a bit conservative about what we expect. We have to
@@ -692,6 +710,12 @@
*/
printk("testing the IO APIC.......................\n");
+ for (apic = 0; apic < nr_ioapics; apic++) {
+
+ *(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);
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)
@@ -706,8 +730,6 @@
(reg_01.entries != 0x3F) /* bigger Xeon boards */
)
UNEXPECTED_IO_APIC();
- if (reg_01.entries == 0x0f)
- printk("....... [IO-APIC cannot route PCI PIRQ 0-3]\n");
printk("....... : IO APIC version: %04X\n", reg_01.version);
if ( (reg_01.version != 0x10) && /* oldest IO-APICs */
@@ -731,8 +753,8 @@
for (i = 0; i <= reg_01.entries; i++) {
struct IO_APIC_route_entry entry;
- *(((int *)&entry)+0) = io_apic_read(0x10+i*2);
- *(((int *)&entry)+1) = io_apic_read(0x11+i*2);
+ *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2);
+ *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2);
printk(" %02x %03X %02X ",
i,
@@ -751,7 +773,7 @@
entry.vector
);
}
-
+ }
printk(KERN_DEBUG "IRQ to pin mappings:\n");
for (i = 0; i < NR_IRQS; i++) {
struct irq_pin_list *entry = irq_2_pin + i;
@@ -796,9 +818,12 @@
*/
{
struct IO_APIC_reg_01 reg_01;
+ int i;
- *(int *)®_01 = io_apic_read(1);
- nr_ioapic_registers = 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;
+ }
}
/*
@@ -827,55 +852,6 @@
printk("...done.\n");
}
-char ioapic_OEM_ID [16];
-char ioapic_Product_ID [16];
-
-struct ioapic_list_entry {
- char * oem_id;
- char * product_id;
-};
-
-struct ioapic_list_entry __initdata ioapic_whitelist [] = {
-
- { "INTEL " , "PR440FX " },
- { "INTEL " , "82440FX " },
- { "AIR " , "KDI " },
- { 0 , 0 }
-};
-
-struct ioapic_list_entry __initdata ioapic_blacklist [] = {
-
- { "OEM00000" , "PROD00000000" },
- { 0 , 0 }
-};
-
-static int __init in_ioapic_list(struct ioapic_list_entry * table)
-{
- for ( ; table->oem_id ; table++)
- if ((!strcmp(table->oem_id,ioapic_OEM_ID)) &&
- (!strcmp(table->product_id,ioapic_Product_ID)))
- return 1;
- return 0;
-}
-
-static int __init ioapic_whitelisted(void)
-{
-/*
- * Right now, whitelist everything to see whether the new parsing
- * routines really do work for everybody.
- */
-#if 1
- return 1;
-#else
- return in_ioapic_list(ioapic_whitelist);
-#endif
-}
-
-static int __init ioapic_blacklisted(void)
-{
- return in_ioapic_list(ioapic_blacklist);
-}
-
static void __init setup_ioapic_id(void)
{
struct IO_APIC_reg_00 reg_00;
@@ -897,15 +873,15 @@
/*
* Set the ID
*/
- *(int *)®_00 = io_apic_read(0);
+ *(int *)®_00 = io_apic_read(0, 0);
printk("...changing IO-APIC physical APIC ID to 2...\n");
reg_00.ID = 0x2;
- io_apic_write(0, *(int *)®_00);
+ io_apic_write(0, 0, *(int *)®_00);
/*
* Sanity check
*/
- *(int *)®_00 = io_apic_read(0);
+ *(int *)®_00 = io_apic_read(0, 0);
if (reg_00.ID != 0x2)
panic("could not set ID");
}
@@ -1227,7 +1203,10 @@
if (pin2 != -1) {
printk(".. (found pin %d) ...", pin2);
- setup_ExtINT_pin(pin2, 0);
+ /*
+ * legacy devices should be connected to IO APIC #0
+ */
+ setup_ExtINT_pin(0, pin2, 0);
make_8259A_irq(0);
}
@@ -1238,9 +1217,9 @@
* Just in case ...
*/
if (pin1 != -1)
- clear_IO_APIC_pin(pin1);
+ clear_IO_APIC_pin(0, pin1);
if (pin2 != -1)
- clear_IO_APIC_pin(pin2);
+ clear_IO_APIC_pin(0, pin2);
make_8259A_irq(0);
@@ -1273,29 +1252,8 @@
{
init_sym_mode();
- /*
- * Determine the range of IRQs handled by the IO-APIC. The
- * following boards can be fully enabled:
- *
- * - whitelisted ones
- * - those which have no PCI pins connected
- * - those for which the user has specified a pirq= parameter
- */
- if ( ioapic_whitelisted() ||
- (nr_ioapic_registers == 16) ||
- pirqs_enabled)
- {
- printk("ENABLING IO-APIC IRQs\n");
- io_apic_irqs = ~PIC_IRQS;
- } else {
- if (ioapic_blacklisted())
- printk(" blacklisted board, DISABLING IO-APIC IRQs\n");
- else
- printk(" unlisted board, DISABLING IO-APIC IRQs\n");
-
- printk(" see Documentation/IO-APIC.txt to enable them\n");
- io_apic_irqs = 0;
- }
+ printk("ENABLING IO-APIC IRQs\n");
+ io_apic_irqs = ~PIC_IRQS;
/*
* If there are no explicit MP IRQ entries, it's either one of the
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)