]> git.proxmox.com Git - mirror_ubuntu-bionic-kernel.git/blobdiff - arch/x86/kernel/io_apic_64.c
x86: I/O APIC: keep IRQ off when changing LVT registers
[mirror_ubuntu-bionic-kernel.git] / arch / x86 / kernel / io_apic_64.c
index 1627c0d53e0b4f63b927184d40e56145d0012e38..aa45a85c4d11392dcb0ce503ad503418c4f58e8e 100644 (file)
 #include <asm/smp.h>
 #include <asm/desc.h>
 #include <asm/proto.h>
-#include <asm/mach_apic.h>
 #include <asm/acpi.h>
 #include <asm/dma.h>
 #include <asm/nmi.h>
 #include <asm/msidef.h>
 #include <asm/hypertransport.h>
 
+#include <mach_ipi.h>
+#include <mach_apic.h>
+
 struct irq_cfg {
        cpumask_t domain;
        cpumask_t old_domain;
@@ -88,7 +90,6 @@ static int no_timer_check;
 
 static int disable_timer_pin_1 __initdata;
 
-int timer_over_8254 __initdata = 1;
 
 /* Where if anywhere is the i8259 connect in external int mode */
 static struct { int pin, apic; } ioapic_i8259 = { -1, -1 };
@@ -101,6 +102,16 @@ DEFINE_SPINLOCK(vector_lock);
  */
 int nr_ioapic_registers[MAX_IO_APICS];
 
+/* I/O APIC entries */
+struct mpc_config_ioapic mp_ioapics[MAX_IO_APICS];
+int nr_ioapics;
+
+/* MP IRQ source entries */
+struct mpc_config_intsrc mp_irqs[MAX_IRQ_SOURCES];
+
+/* # of MP IRQ source entries */
+int mp_irq_entries;
+
 /*
  * Rough estimation of how many shared IRQs there are, can
  * be changed anytime.
@@ -155,11 +166,10 @@ static inline void io_apic_modify(unsigned int apic, unsigned int value)
        writel(value, &io_apic->data);
 }
 
-static int io_apic_level_ack_pending(unsigned int irq)
+static bool io_apic_level_ack_pending(unsigned int irq)
 {
        struct irq_pin_list *entry;
        unsigned long flags;
-       int pending = 0;
 
        spin_lock_irqsave(&ioapic_lock, flags);
        entry = irq_2_pin + irq;
@@ -172,13 +182,17 @@ static int io_apic_level_ack_pending(unsigned int irq)
                        break;
                reg = io_apic_read(entry->apic, 0x10 + pin*2);
                /* Is the remote IRR bit set? */
-               pending |= (reg >> 14) & 1;
+               if ((reg >> 14) & 1) {
+                       spin_unlock_irqrestore(&ioapic_lock, flags);
+                       return true;
+               }
                if (!entry->next)
                        break;
                entry = irq_2_pin + entry->next;
        }
        spin_unlock_irqrestore(&ioapic_lock, flags);
-       return pending;
+
+       return false;
 }
 
 /*
@@ -415,20 +429,6 @@ static int __init disable_timer_pin_setup(char *arg)
 }
 __setup("disable_timer_pin_1", disable_timer_pin_setup);
 
-static int __init setup_disable_8254_timer(char *s)
-{
-       timer_over_8254 = -1;
-       return 1;
-}
-static int __init setup_enable_8254_timer(char *s)
-{
-       timer_over_8254 = 2;
-       return 1;
-}
-
-__setup("disable_8254_timer", setup_disable_8254_timer);
-__setup("enable_8254_timer", setup_enable_8254_timer);
-
 
 /*
  * Find the IRQ entry number of a certain pin.
@@ -770,7 +770,7 @@ static void __clear_irq_vector(int irq)
                per_cpu(vector_irq, cpu)[vector] = -1;
 
        cfg->vector = 0;
-       cfg->domain = CPU_MASK_NONE;
+       cpus_clear(cfg->domain);
 }
 
 void __setup_vector_irq(int cpu)
@@ -902,9 +902,8 @@ 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));
+       memset(&entry, 0, sizeof(entry));
 
        disable_8259A_irq(0);
 
@@ -932,10 +931,7 @@ static void __init setup_ExtINT_IRQ0_pin(unsigned int apic, unsigned int pin, in
        /*
         * 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);
 }
@@ -1066,8 +1062,7 @@ void __apicdebuginit print_local_APIC(void * dummy)
 
        printk("\n" KERN_DEBUG "printing local APIC contents on CPU#%d/%d:\n",
                smp_processor_id(), hard_smp_processor_id());
-       v = apic_read(APIC_ID);
-       printk(KERN_INFO "... APIC ID:      %08x (%01x)\n", v, GET_APIC_ID(v));
+       printk(KERN_INFO "... APIC ID:      %08x (%01x)\n", v, GET_APIC_ID(read_apic_id()));
        v = apic_read(APIC_LVR);
        printk(KERN_INFO "... APIC VERSION: %08x\n", v);
        ver = GET_APIC_VERSION(v);
@@ -1261,7 +1256,7 @@ void disable_IO_APIC(void)
                entry.dest_mode       = 0; /* Physical */
                entry.delivery_mode   = dest_ExtINT; /* ExtInt */
                entry.vector          = 0;
-               entry.dest          = GET_APIC_ID(apic_read(APIC_ID));
+               entry.dest          = GET_APIC_ID(read_apic_id());
 
                /*
                 * Add it to the IO-APIC irq-routing table:
@@ -1352,9 +1347,7 @@ static int ioapic_retrigger_irq(unsigned int irq)
        unsigned long flags;
 
        spin_lock_irqsave(&vector_lock, flags);
-       cpus_clear(mask);
-       cpu_set(first_cpu(cfg->domain), mask);
-
+       mask = cpumask_of_cpu(first_cpu(cfg->domain));
        send_IPI_mask(mask, cfg->vector);
        spin_unlock_irqrestore(&vector_lock, flags);
 
@@ -1517,8 +1510,7 @@ static inline void init_IO_APIC_traps(void)
         * 0x80, because int 0x80 is hm, kind of importantish. ;)
         */
        for (irq = 0; irq < NR_IRQS ; irq++) {
-               int tmp = irq;
-               if (IO_APIC_IRQ(tmp) && !irq_cfg[tmp].vector) {
+               if (IO_APIC_IRQ(irq) && !irq_cfg[irq].vector) {
                        /*
                         * Hmm.. We don't have an entry for this,
                         * so default to an old-fashioned 8259
@@ -1592,22 +1584,19 @@ static void __init setup_nmi(void)
  * cycles as some i82489DX-based boards have glue logic that keeps the
  * 8259A interrupt line asserted until INTA.  --macro
  */
-static inline void unlock_ExtINT_logic(void)
+static inline void __init 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));
@@ -1620,10 +1609,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);
@@ -1642,10 +1628,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);
 }
 
 /*
@@ -1671,16 +1654,11 @@ static inline void __init check_timer(void)
        assign_irq_vector(0, TARGET_CPUS);
 
        /*
-        * Subtle, code in do_timer_interrupt() expects an AEOI
-        * mode for the 8259A whenever interrupts are routed
-        * through I/O APICs.  Also IRQ0 has to be enabled in
-        * the 8259A which implies the virtual wire has to be
-        * disabled in the local APIC.
+        * As IRQ0 is to be enabled in the 8259A, the virtual
+        * wire has to be disabled in the local APIC.
         */
        apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_EXTINT);
        init_8259A(1);
-       if (timer_over_8254 > 0)
-               enable_8259A_irq(0);
 
        pin1  = find_isa_irq_pin(0, mp_INT);
        apic1 = find_isa_irq_apic(0, mp_INT);
@@ -1698,7 +1676,6 @@ static inline void __init check_timer(void)
                if (!no_timer_check && timer_irq_works()) {
                        nmi_watchdog_default();
                        if (nmi_watchdog == NMI_IO_APIC) {
-                               disable_8259A_irq(0);
                                setup_nmi();
                                enable_8259A_irq(0);
                        }
@@ -1720,17 +1697,21 @@ static inline void __init check_timer(void)
                 * legacy devices should be connected to IO APIC #0
                 */
                setup_ExtINT_IRQ0_pin(apic2, pin2, cfg->vector);
+               enable_8259A_irq(0);
                if (timer_irq_works()) {
                        apic_printk(APIC_VERBOSE," works.\n");
                        nmi_watchdog_default();
                        if (nmi_watchdog == NMI_IO_APIC) {
+                               disable_8259A_irq(0);
                                setup_nmi();
+                               enable_8259A_irq(0);
                        }
                        goto out;
                }
                /*
                 * Cleanup, just in case ...
                 */
+               disable_8259A_irq(0);
                clear_IO_APIC_pin(apic2, pin2);
        }
        apic_printk(APIC_VERBOSE," failed.\n");
@@ -1742,7 +1723,6 @@ static inline void __init check_timer(void)
 
        apic_printk(APIC_VERBOSE, KERN_INFO "...trying to set up timer as Virtual Wire IRQ...");
 
-       disable_8259A_irq(0);
        irq_desc[0].chip = &lapic_irq_type;
        apic_write(APIC_LVT0, APIC_DM_FIXED | cfg->vector);     /* Fixed mode */
        enable_8259A_irq(0);
@@ -1751,6 +1731,7 @@ static inline void __init check_timer(void)
                apic_printk(APIC_VERBOSE," works.\n");
                goto out;
        }
+       disable_8259A_irq(0);
        apic_write(APIC_LVT0, APIC_LVT_MASKED | APIC_DM_FIXED | cfg->vector);
        apic_printk(APIC_VERBOSE," failed.\n");
 
@@ -2314,7 +2295,6 @@ static struct resource * __init ioapic_setup_resources(void)
        res = (void *)mem;
 
        if (mem != NULL) {
-               memset(mem, 0, n);
                mem += sizeof(struct resource) * nr_ioapics;
 
                for (i = 0; i < nr_ioapics; i++) {