Merge branch 'upstream-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/ieee13...
[pandora-kernel.git] / arch / i386 / kernel / io_apic.c
index 72ae414..fd0df75 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/init.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
-#include <linux/config.h>
 #include <linux/smp_lock.h>
 #include <linux/mc146818rtc.h>
 #include <linux/compiler.h>
@@ -41,6 +40,7 @@
 #include <asm/nmi.h>
 
 #include <mach_apic.h>
+#include <mach_apicdef.h>
 
 #include "io_ports.h"
 
@@ -66,7 +66,7 @@ int sis_apic_bug = -1;
  */
 int nr_ioapic_registers[MAX_IO_APICS];
 
-int disable_timer_pin_1 __initdata;
+static int disable_timer_pin_1 __initdata;
 
 /*
  * Rough estimation of how many shared IRQs there are, can
@@ -94,6 +94,34 @@ int vector_irq[NR_VECTORS] __read_mostly = { [0 ... NR_VECTORS - 1] = -1};
 #define vector_to_irq(vector)  (vector)
 #endif
 
+
+union entry_union {
+       struct { u32 w1, w2; };
+       struct IO_APIC_route_entry entry;
+};
+
+static struct IO_APIC_route_entry ioapic_read_entry(int apic, int pin)
+{
+       union entry_union eu;
+       unsigned long flags;
+       spin_lock_irqsave(&ioapic_lock, flags);
+       eu.w1 = io_apic_read(apic, 0x10 + 2 * pin);
+       eu.w2 = io_apic_read(apic, 0x11 + 2 * pin);
+       spin_unlock_irqrestore(&ioapic_lock, flags);
+       return eu.entry;
+}
+
+static void ioapic_write_entry(int apic, int pin, struct IO_APIC_route_entry e)
+{
+       unsigned long flags;
+       union entry_union eu;
+       eu.entry = e;
+       spin_lock_irqsave(&ioapic_lock, flags);
+       io_apic_write(apic, 0x10 + 2*pin, eu.w1);
+       io_apic_write(apic, 0x11 + 2*pin, eu.w2);
+       spin_unlock_irqrestore(&ioapic_lock, flags);
+}
+
 /*
  * The common case is 1:1 IRQ<->pin mappings. Sometimes there are
  * shared ISA-space IRQs, so we have to support them. We are super
@@ -201,13 +229,9 @@ static void unmask_IO_APIC_irq (unsigned int irq)
 static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
 {
        struct IO_APIC_route_entry entry;
-       unsigned long flags;
        
        /* Check delivery_mode to be sure we're not clearing an SMI pin */
-       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);
+       entry = ioapic_read_entry(apic, pin);
        if (entry.delivery_mode == dest_SMI)
                return;
 
@@ -216,10 +240,7 @@ static void clear_IO_APIC_pin(unsigned int apic, unsigned int pin)
         */
        memset(&entry, 0, sizeof(entry));
        entry.mask = 1;
-       spin_lock_irqsave(&ioapic_lock, flags);
-       io_apic_write(apic, 0x10 + 2 * pin, *(((int *)&entry) + 0));
-       io_apic_write(apic, 0x11 + 2 * pin, *(((int *)&entry) + 1));
-       spin_unlock_irqrestore(&ioapic_lock, flags);
+       ioapic_write_entry(apic, pin, entry);
 }
 
 static void clear_IO_APIC (void)
@@ -581,7 +602,7 @@ static int balanced_irq(void *unused)
        
        /* push everything to CPU 0 to give us a starting point.  */
        for (i = 0 ; i < NR_IRQS ; i++) {
-               pending_irq_cpumask[i] = cpumask_of_cpu(0);
+               irq_desc[i].pending_mask = cpumask_of_cpu(0);
                set_pending_irq(i, cpumask_of_cpu(0));
        }
 
@@ -1205,15 +1226,17 @@ static struct hw_interrupt_type ioapic_edge_type;
 #define IOAPIC_EDGE    0
 #define IOAPIC_LEVEL   1
 
-static inline void ioapic_register_intr(int irq, int vector, unsigned long trigger)
+static void ioapic_register_intr(int irq, int vector, unsigned long trigger)
 {
-       unsigned idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
+       unsigned idx;
+
+       idx = use_pci_vector() && !platform_legacy_irq(irq) ? vector : irq;
 
        if ((trigger == IOAPIC_AUTO && IO_APIC_irq_trigger(irq)) ||
                        trigger == IOAPIC_LEVEL)
-               irq_desc[idx].handler = &ioapic_level_type;
+               irq_desc[idx].chip = &ioapic_level_type;
        else
-               irq_desc[idx].handler = &ioapic_edge_type;
+               irq_desc[idx].chip = &ioapic_edge_type;
        set_intr_gate(vector, interrupt[idx]);
 }
 
@@ -1282,9 +1305,8 @@ static void __init setup_IO_APIC_irqs(void)
                        if (!apic && (irq < 16))
                                disable_8259A_irq(irq);
                }
+               ioapic_write_entry(apic, pin, entry);
                spin_lock_irqsave(&ioapic_lock, flags);
-               io_apic_write(apic, 0x11+2*pin, *(((int *)&entry)+1));
-               io_apic_write(apic, 0x10+2*pin, *(((int *)&entry)+0));
                set_native_irq_info(irq, TARGET_CPUS);
                spin_unlock_irqrestore(&ioapic_lock, flags);
        }
@@ -1300,7 +1322,6 @@ static void __init setup_IO_APIC_irqs(void)
 static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, int vector)
 {
        struct IO_APIC_route_entry entry;
-       unsigned long flags;
 
        memset(&entry,0,sizeof(entry));
 
@@ -1325,15 +1346,12 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
         * The timer IRQ doesn't have to know that behind the
         * scene we have a 8259A-master in AEOI mode ...
         */
-       irq_desc[0].handler = &ioapic_edge_type;
+       irq_desc[0].chip = &ioapic_edge_type;
 
        /*
         * Add it to the IO-APIC irq-routing table:
         */
-       spin_lock_irqsave(&ioapic_lock, flags);
-       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);
+       ioapic_write_entry(apic, pin, entry);
 
        enable_8259A_irq(0);
 }
@@ -1443,10 +1461,7 @@ void __init print_IO_APIC(void)
        for (i = 0; i <= reg_01.bits.entries; i++) {
                struct IO_APIC_route_entry entry;
 
-               spin_lock_irqsave(&ioapic_lock, flags);
-               *(((int *)&entry)+0) = io_apic_read(apic, 0x10+i*2);
-               *(((int *)&entry)+1) = io_apic_read(apic, 0x11+i*2);
-               spin_unlock_irqrestore(&ioapic_lock, flags);
+               entry = ioapic_read_entry(apic, i);
 
                printk(KERN_DEBUG " %02x %03X %02X  ",
                        i,
@@ -1665,10 +1680,7 @@ static void __init enable_IO_APIC(void)
                /* See if any of the pins is in ExtINT mode */
                for (pin = 0; pin < nr_ioapic_registers[apic]; 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);
+                       entry = ioapic_read_entry(apic, pin);
 
 
                        /* If the interrupt line is enabled and in ExtInt mode
@@ -1725,7 +1737,6 @@ void disable_IO_APIC(void)
         */
        if (ioapic_i8259.pin != -1) {
                struct IO_APIC_route_entry entry;
-               unsigned long flags;
 
                memset(&entry, 0, sizeof(entry));
                entry.mask            = 0; /* Enabled */
@@ -1742,12 +1753,7 @@ void disable_IO_APIC(void)
                /*
                 * Add it to the IO-APIC irq-routing table:
                 */
-               spin_lock_irqsave(&ioapic_lock, flags);
-               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);
+               ioapic_write_entry(ioapic_i8259.apic, ioapic_i8259.pin, entry);
        }
        disconnect_bsp_APIC(ioapic_i8259.pin != -1);
 }
@@ -2069,6 +2075,13 @@ static void set_ioapic_affinity_vector (unsigned int vector,
 #endif
 #endif
 
+static int ioapic_retrigger(unsigned int irq)
+{
+       send_IPI_self(IO_APIC_VECTOR(irq));
+
+       return 1;
+}
+
 /*
  * Level and edge triggered IO-APIC interrupts need different handling,
  * so we use two separate IRQ descriptors. Edge triggered IRQs can be
@@ -2088,6 +2101,7 @@ static struct hw_interrupt_type ioapic_edge_type __read_mostly = {
 #ifdef CONFIG_SMP
        .set_affinity   = set_ioapic_affinity,
 #endif
+       .retrigger      = ioapic_retrigger,
 };
 
 static struct hw_interrupt_type ioapic_level_type __read_mostly = {
@@ -2101,6 +2115,7 @@ static struct hw_interrupt_type ioapic_level_type __read_mostly = {
 #ifdef CONFIG_SMP
        .set_affinity   = set_ioapic_affinity,
 #endif
+       .retrigger      = ioapic_retrigger,
 };
 
 static inline void init_IO_APIC_traps(void)
@@ -2135,7 +2150,7 @@ static inline void init_IO_APIC_traps(void)
                                make_8259A_irq(irq);
                        else
                                /* Strange. Oh, well.. */
-                               irq_desc[irq].handler = &no_irq_type;
+                               irq_desc[irq].chip = &no_irq_type;
                }
        }
 }
@@ -2203,17 +2218,13 @@ static inline void unlock_ExtINT_logic(void)
        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);
        apic = find_isa_irq_apic(8, mp_INT);
        if (pin == -1)
                return;
 
-       spin_lock_irqsave(&ioapic_lock, flags);
-       *(((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);
+       entry0 = ioapic_read_entry(apic, pin);
        clear_IO_APIC_pin(apic, pin);
 
        memset(&entry1, 0, sizeof(entry1));
@@ -2226,10 +2237,7 @@ static inline void unlock_ExtINT_logic(void)
        entry1.trigger = 0;
        entry1.vector = 0;
 
-       spin_lock_irqsave(&ioapic_lock, flags);
-       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);
+       ioapic_write_entry(apic, pin, entry1);
 
        save_control = CMOS_READ(RTC_CONTROL);
        save_freq_select = CMOS_READ(RTC_FREQ_SELECT);
@@ -2248,10 +2256,7 @@ static inline void unlock_ExtINT_logic(void)
        CMOS_WRITE(save_freq_select, RTC_FREQ_SELECT);
        clear_IO_APIC_pin(apic, pin);
 
-       spin_lock_irqsave(&ioapic_lock, flags);
-       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);
+       ioapic_write_entry(apic, pin, entry0);
 }
 
 int timer_uses_ioapic_pin_0;
@@ -2351,7 +2356,7 @@ static inline void check_timer(void)
        printk(KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
 
        disable_8259A_irq(0);
-       irq_desc[0].handler = &lapic_irq_type;
+       irq_desc[0].chip = &lapic_irq_type;
        apic_write_around(APIC_LVT0, APIC_DM_FIXED | vector);   /* Fixed mode */
        enable_8259A_irq(0);
 
@@ -2451,17 +2456,12 @@ static int ioapic_suspend(struct sys_device *dev, pm_message_t state)
 {
        struct IO_APIC_route_entry *entry;
        struct sysfs_ioapic_data *data;
-       unsigned long flags;
        int i;
        
        data = container_of(dev, struct sysfs_ioapic_data, dev);
        entry = data->entry;
-       spin_lock_irqsave(&ioapic_lock, flags);
-       for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) {
-               *(((int *)entry) + 1) = io_apic_read(dev->id, 0x11 + 2 * i);
-               *(((int *)entry) + 0) = io_apic_read(dev->id, 0x10 + 2 * i);
-       }
-       spin_unlock_irqrestore(&ioapic_lock, flags);
+       for (i = 0; i < nr_ioapic_registers[dev->id]; i ++)
+               entry[i] = ioapic_read_entry(dev->id, i);
 
        return 0;
 }
@@ -2483,11 +2483,9 @@ static int ioapic_resume(struct sys_device *dev)
                reg_00.bits.ID = mp_ioapics[dev->id].mpc_apicid;
                io_apic_write(dev->id, 0, reg_00.raw);
        }
-       for (i = 0; i < nr_ioapic_registers[dev->id]; i ++, entry ++ ) {
-               io_apic_write(dev->id, 0x11+2*i, *(((int *)entry)+1));
-               io_apic_write(dev->id, 0x10+2*i, *(((int *)entry)+0));
-       }
        spin_unlock_irqrestore(&ioapic_lock, flags);
+       for (i = 0; i < nr_ioapic_registers[dev->id]; i ++)
+               ioapic_write_entry(dev->id, i, entry[i]);
 
        return 0;
 }
@@ -2684,9 +2682,8 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a
        if (!ioapic && (irq < 16))
                disable_8259A_irq(irq);
 
+       ioapic_write_entry(ioapic, pin, entry);
        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));
        set_native_irq_info(use_pci_vector() ? entry.vector : irq, TARGET_CPUS);
        spin_unlock_irqrestore(&ioapic_lock, flags);
 
@@ -2694,3 +2691,25 @@ int io_apic_set_pci_routing (int ioapic, int pin, int irq, int edge_level, int a
 }
 
 #endif /* CONFIG_ACPI */
+
+static int __init parse_disable_timer_pin_1(char *arg)
+{
+       disable_timer_pin_1 = 1;
+       return 0;
+}
+early_param("disable_timer_pin_1", parse_disable_timer_pin_1);
+
+static int __init parse_enable_timer_pin_1(char *arg)
+{
+       disable_timer_pin_1 = -1;
+       return 0;
+}
+early_param("enable_timer_pin_1", parse_enable_timer_pin_1);
+
+static int __init parse_noapic(char *arg)
+{
+       /* disable IO-APIC */
+       disable_ioapic_setup();
+       return 0;
+}
+early_param("noapic", parse_noapic);