patch-2.4.22 linux-2.4.22/arch/i386/kernel/io_apic.c
Next file: linux-2.4.22/arch/i386/kernel/mpparse.c
Previous file: linux-2.4.22/arch/i386/kernel/i387.c
Back to the patch index
Back to the overall index
- Lines: 293
- Date:
2003-08-25 04:44:39.000000000 -0700
- Orig file:
linux-2.4.21/arch/i386/kernel/io_apic.c
- Orig date:
2003-06-13 07:51:29.000000000 -0700
diff -urN linux-2.4.21/arch/i386/kernel/io_apic.c linux-2.4.22/arch/i386/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>
@@ -123,7 +125,7 @@
break; \
reg = io_apic_read(entry->apic, 0x10 + R + pin*2); \
reg ACTION; \
- io_apic_modify(entry->apic, reg); \
+ io_apic_write(entry->apic, 0x10 + R + pin*2, reg); \
if (!entry->next) \
break; \
entry = irq_2_pin + entry->next; \
@@ -750,6 +752,7 @@
struct IO_APIC_reg_00 reg_00;
struct IO_APIC_reg_01 reg_01;
struct IO_APIC_reg_02 reg_02;
+ struct IO_APIC_reg_03 reg_03;
unsigned long flags;
printk(KERN_DEBUG "number of MP IRQ sources: %d.\n", mp_irq_entries);
@@ -770,6 +773,8 @@
*(int *)®_01 = io_apic_read(apic, 1);
if (reg_01.version >= 0x10)
*(int *)®_02 = io_apic_read(apic, 2);
+ if (reg_01.version >= 0x20)
+ *(int *)®_03 = io_apic_read(apic, 3);
spin_unlock_irqrestore(&ioapic_lock, flags);
printk("\n");
@@ -807,13 +812,31 @@
if (reg_01.__reserved_1 || reg_01.__reserved_2)
UNEXPECTED_IO_APIC();
- if (reg_01.version >= 0x10) {
+ /*
+ * Some Intel chipsets with IO APIC VERSION of 0x1? don't have reg_02,
+ * but the value of reg_02 is read as the previous read register
+ * value, so ignore it if reg_02 == reg_01.
+ */
+ if (reg_01.version >= 0x10 && *(int *)®_02 != *(int *)®_01) {
printk(KERN_DEBUG ".... register #02: %08X\n", *(int *)®_02);
printk(KERN_DEBUG "....... : arbitration: %02X\n", reg_02.arbitration);
if (reg_02.__reserved_1 || reg_02.__reserved_2)
UNEXPECTED_IO_APIC();
}
+ /*
+ * Some Intel chipsets with IO APIC VERSION of 0x2? don't have reg_02
+ * or reg_03, but the value of reg_0[23] is read as the previous read
+ * register value, so ignore it if reg_03 == reg_0[12].
+ */
+ if (reg_01.version >= 0x20 && *(int *)®_03 != *(int *)®_02 &&
+ *(int *)®_03 != *(int *)®_01) {
+ printk(KERN_DEBUG ".... register #03: %08X\n", *(int *)®_03);
+ printk(KERN_DEBUG "....... : Boot DT : %X\n", reg_03.boot_DT);
+ if (reg_03.__reserved_1)
+ UNEXPECTED_IO_APIC();
+ }
+
printk(KERN_DEBUG ".... IRQ redirection table:\n");
printk(KERN_DEBUG " NR Log Phy Mask Trig IRR Pol"
@@ -1057,6 +1080,10 @@
unsigned char old_id;
unsigned long flags;
+ if (acpi_ioapic)
+ /* This gets done during IOAPIC enumeration for ACPI. */
+ return;
+
if (clustered_apic_mode)
/* We don't have a good way to do this yet - hack */
phys_id_present_map = (u_long) 0xf;
@@ -1316,6 +1343,25 @@
static void mask_and_ack_level_ioapic_irq (unsigned int irq) { /* nothing */ }
+#ifndef CONFIG_SMP
+
+void send_IPI_self(int vector)
+{
+ unsigned int cfg;
+
+ /*
+ * Wait for idle.
+ */
+ apic_wait_icr_idle();
+ cfg = APIC_DM_FIXED | APIC_DEST_SELF | vector | APIC_DEST_LOGICAL;
+ /*
+ * Send the IPI. The write to APIC_ICR fires this off.
+ */
+ apic_write_around(APIC_ICR, cfg);
+}
+
+#endif /* CONFIG_SMP */
+
static void set_ioapic_affinity (unsigned int irq, unsigned long mask)
{
unsigned long flags;
@@ -1657,8 +1703,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();
@@ -1667,3 +1712,170 @@
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;
+ }
+
+ /* XAPICs do not need unique IDs */
+ if (clustered_apic_mode == CLUSTERED_APIC_XAPIC){
+ printk(KERN_INFO "IOAPIC[%d]: Assigned apic_id %d\n",
+ ioapic, apic_id);
+ return apic_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, int edge_level, int active_high_low)
+{
+ 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 = edge_level;
+ entry.polarity = active_high_low;
+
+ 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 Mode:%i Active:%i)\n", ioapic,
+ mp_ioapics[ioapic].mpc_apicid, pin, entry.vector, irq, edge_level, active_high_low);
+
+ if (edge_level) {
+ irq_desc[irq].handler = &ioapic_level_irq_type;
+ } else {
+ irq_desc[irq].handler = &ioapic_edge_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 0;
+}
+
+#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)