patch-2.4.22 linux-2.4.22/arch/x86_64/kernel/io_apic.c
Next file: linux-2.4.22/arch/x86_64/kernel/mpparse.c
Previous file: linux-2.4.22/arch/x86_64/kernel/head.S
Back to the patch index
Back to the overall index
- Lines: 197
- Date:
2003-08-25 04:44:40.000000000 -0700
- Orig file:
linux-2.4.21/arch/x86_64/kernel/io_apic.c
- Orig date:
2003-06-13 07:51:32.000000000 -0700
diff -urN linux-2.4.21/arch/x86_64/kernel/io_apic.c linux-2.4.22/arch/x86_64/kernel/io_apic.c
@@ -17,6 +17,7 @@
* thanks to Eric Gilmore
* and Rolf G. Tews
* for testing these extensively
+ * Paul Diefenbaugh : Added full ACPI support
*/
#include <linux/mm.h>
@@ -28,6 +29,7 @@
#include <linux/config.h>
#include <linux/smp_lock.h>
#include <linux/mc146818rtc.h>
+#include <linux/acpi.h>
#include <asm/io.h>
#include <asm/smp.h>
@@ -1046,6 +1048,10 @@
unsigned char old_id;
unsigned long flags;
+ if (acpi_ioapic)
+ /* This gets done during IOAPIC enumeration for ACPI. */
+ return;
+
/*
* Set the IOAPIC ID to the value stored in the MPC table.
*/
@@ -1641,8 +1647,7 @@
printk("ENABLING IO-APIC IRQs\n");
/*
- * Set up the IO-APIC IRQ routing table by parsing the MP-BIOS
- * mptable:
+ * Set up IO-APIC IRQ routing.
*/
setup_ioapic_ids_from_mpc();
sync_Arb_IDs();
@@ -1651,3 +1656,159 @@
check_timer();
print_IO_APIC();
}
+
+
+/* --------------------------------------------------------------------------
+ ACPI-based IOAPIC Configuration
+ -------------------------------------------------------------------------- */
+
+#ifdef CONFIG_ACPI_BOOT
+
+#define IO_APIC_MAX_ID 15
+
+int __init io_apic_get_unique_id (int ioapic, int apic_id)
+{
+ struct IO_APIC_reg_00 reg_00;
+ static unsigned long apic_id_map = 0;
+ unsigned long flags;
+ int i = 0;
+
+ /*
+ * The P4 platform supports up to 256 APIC IDs on two separate APIC
+ * buses (one for LAPICs, one for IOAPICs), where predecessors only
+ * supports up to 16 on one shared APIC bus.
+ *
+ * TBD: Expand LAPIC/IOAPIC support on P4-class systems to take full
+ * advantage of new APIC bus architecture.
+ */
+
+ if (!apic_id_map)
+ apic_id_map = phys_cpu_present_map;
+
+ spin_lock_irqsave(&ioapic_lock, flags);
+ *(int *)®_00 = io_apic_read(ioapic, 0);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+
+ if (apic_id >= IO_APIC_MAX_ID) {
+ printk(KERN_WARNING "IOAPIC[%d]: Invalid apic_id %d, trying "
+ "%d\n", ioapic, apic_id, reg_00.ID);
+ apic_id = reg_00.ID;
+ }
+
+ /*
+ * Every APIC in a system must have a unique ID or we get lots of nice
+ * 'stuck on smp_invalidate_needed IPI wait' messages.
+ */
+ if (apic_id_map & (1 << apic_id)) {
+
+ for (i = 0; i < IO_APIC_MAX_ID; i++) {
+ if (!(apic_id_map & (1 << i)))
+ break;
+ }
+
+ if (i == IO_APIC_MAX_ID)
+ panic("Max apic_id exceeded!\n");
+
+ printk(KERN_WARNING "IOAPIC[%d]: apic_id %d already used, "
+ "trying %d\n", ioapic, apic_id, i);
+
+ apic_id = i;
+ }
+
+ apic_id_map |= (1 << apic_id);
+
+ if (reg_00.ID != apic_id) {
+ reg_00.ID = apic_id;
+
+ spin_lock_irqsave(&ioapic_lock, flags);
+ io_apic_write(ioapic, 0, *(int *)®_00);
+ *(int *)®_00 = io_apic_read(ioapic, 0);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+
+ /* Sanity check */
+ if (reg_00.ID != apic_id)
+ panic("IOAPIC[%d]: Unable change apic_id!\n", ioapic);
+ }
+
+ printk(KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n", ioapic, apic_id);
+
+ return apic_id;
+}
+
+
+int __init io_apic_get_version (int ioapic)
+{
+ struct IO_APIC_reg_01 reg_01;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioapic_lock, flags);
+ *(int *)®_01 = io_apic_read(ioapic, 1);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+
+ return reg_01.version;
+}
+
+
+int __init io_apic_get_redir_entries (int ioapic)
+{
+ struct IO_APIC_reg_01 reg_01;
+ unsigned long flags;
+
+ spin_lock_irqsave(&ioapic_lock, flags);
+ *(int *)®_01 = io_apic_read(ioapic, 1);
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+
+ return reg_01.entries;
+}
+
+
+int io_apic_set_pci_routing (int ioapic, int pin, int irq)
+{
+ struct IO_APIC_route_entry entry;
+ unsigned long flags;
+
+ if (!IO_APIC_IRQ(irq)) {
+ printk(KERN_ERR "IOAPIC[%d]: Invalid reference to IRQ 0/n",
+ ioapic);
+ return -EINVAL;
+ }
+
+ /*
+ * Generate a PCI IRQ routing entry and program the IOAPIC accordingly.
+ * Note that we mask (disable) IRQs now -- these get enabled when the
+ * corresponding device driver registers for this IRQ.
+ */
+
+ memset(&entry,0,sizeof(entry));
+
+ entry.delivery_mode = dest_LowestPrio;
+ entry.dest_mode = INT_DELIVERY_MODE;
+ entry.dest.logical.logical_dest = TARGET_CPUS;
+ entry.mask = 1; /* Disabled (masked) */
+ entry.trigger = 1; /* Level sensitive */
+ entry.polarity = 1; /* Low active */
+
+ add_pin_to_irq(irq, ioapic, pin);
+
+ entry.vector = assign_irq_vector(irq);
+
+ printk(KERN_DEBUG "IOAPIC[%d]: Set PCI routing entry (%d-%d -> 0x%x -> "
+ "IRQ %d)\n", ioapic,
+ mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq);
+
+ irq_desc[irq].handler = &ioapic_level_irq_type;
+
+ set_intr_gate(entry.vector, interrupt[irq]);
+
+ if (!ioapic && (irq < 16))
+ disable_8259A_irq(irq);
+
+ spin_lock_irqsave(&ioapic_lock, flags);
+ io_apic_write(ioapic, 0x11+2*pin, *(((int *)&entry)+1));
+ io_apic_write(ioapic, 0x10+2*pin, *(((int *)&entry)+0));
+ spin_unlock_irqrestore(&ioapic_lock, flags);
+
+ return entry.vector;
+}
+
+#endif /*CONFIG_ACPI_BOOT*/
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)