[PATCH] genirq: add ->retrigger() irq op to consolidate hw_irq_resend()
[safe/jmp/linux-2.6] / arch / i386 / kernel / apic.c
index 8d81b7b..7ce0949 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/kernel_stat.h>
 #include <linux/sysdev.h>
 #include <linux/cpu.h>
+#include <linux/module.h>
 
 #include <asm/atomic.h>
 #include <asm/smp.h>
 #include <asm/arch_hooks.h>
 #include <asm/hpet.h>
 #include <asm/i8253.h>
+#include <asm/nmi.h>
 
 #include <mach_apic.h>
+#include <mach_apicdef.h>
+#include <mach_ipi.h>
 
 #include "io_ports.h"
 
 /*
+ * cpu_mask that denotes the CPUs that needs timer interrupt coming in as
+ * IPIs in place of local APIC timers
+ */
+static cpumask_t timer_bcast_ipi;
+
+/*
  * Knob to control our willingness to enable the local APIC.
  */
 int enable_local_apic __initdata = 0; /* -1=force-disable, +1=force-enable */
@@ -53,6 +63,18 @@ int apic_verbosity;
 
 static void apic_pm_activate(void);
 
+static int modern_apic(void)
+{
+       unsigned int lvr, version;
+       /* AMD systems use old APIC versions, so check the CPU */
+       if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
+               boot_cpu_data.x86 >= 0xf)
+               return 1;
+       lvr = apic_read(APIC_LVR);
+       version = GET_APIC_VERSION(lvr);
+       return version >= 0x14;
+}
+
 /*
  * 'what should we do if we get a hw irq event on an illegal vector'.
  * each architecture has to answer this themselves.
@@ -67,8 +89,10 @@ void ack_bad_irq(unsigned int irq)
         * holds up an irq slot - in excessive cases (when multiple
         * unexpected vectors occur) that might lock up the APIC
         * completely.
+        * But only ack when the APIC is enabled -AK
         */
-       ack_APIC_irq();
+       if (cpu_has_apic)
+               ack_APIC_irq();
 }
 
 void __init apic_intr_init(void)
@@ -90,11 +114,7 @@ void __init apic_intr_init(void)
 }
 
 /* Using APIC to generate smp_local_timer_interrupt? */
-int using_apic_timer = 0;
-
-static DEFINE_PER_CPU(int, prof_multiplier) = 1;
-static DEFINE_PER_CPU(int, prof_old_multiplier) = 1;
-static DEFINE_PER_CPU(int, prof_counter) = 1;
+int using_apic_timer __read_mostly = 0;
 
 static int enabled_via_apicbase;
 
@@ -112,10 +132,7 @@ void enable_NMI_through_LVT0 (void * dummy)
 
 int get_physical_broadcast(void)
 {
-       unsigned int lvr, version;
-       lvr = apic_read(APIC_LVR);
-       version = GET_APIC_VERSION(lvr);
-       if (!APIC_INTEGRATED(version) || version >= 0x14)
+       if (modern_apic())
                return 0xff;
        else
                return 0xf;
@@ -140,7 +157,7 @@ void clear_local_APIC(void)
        maxlvt = get_maxlvt();
 
        /*
-        * Masking an LVT entry on a P6 can trigger a local APIC error
+        * Masking an LVT entry can trigger a local APIC error
         * if the vector is zero. Mask LVTERR first to prevent this.
         */
        if (maxlvt >= 3) {
@@ -342,9 +359,9 @@ int __init verify_local_APIC(void)
 
 void __init sync_Arb_IDs(void)
 {
-       /* Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1 */
-       unsigned int ver = GET_APIC_VERSION(apic_read(APIC_LVR));
-       if (ver >= 0x14)        /* P4 or higher */
+       /* Unsupported on P4 - see Intel Dev. Manual Vol. 3, Ch. 8.6.1
+          And not needed on AMD */
+       if (modern_apic())
                return;
        /*
         * Wait for idle.
@@ -408,6 +425,7 @@ void __init init_bsp_APIC(void)
 void __devinit setup_local_APIC(void)
 {
        unsigned long oldvalue, value, ver, maxlvt;
+       int i, j;
 
        /* Pound the ESR really hard over the head with a big hammer - mbligh */
        if (esr_disable) {
@@ -445,6 +463,25 @@ void __devinit setup_local_APIC(void)
        apic_write_around(APIC_TASKPRI, value);
 
        /*
+        * After a crash, we no longer service the interrupts and a pending
+        * interrupt from previous kernel might still have ISR bit set.
+        *
+        * Most probably by now CPU has serviced that pending interrupt and
+        * it might not have done the ack_APIC_irq() because it thought,
+        * interrupt came from i8259 as ExtInt. LAPIC did not get EOI so it
+        * does not clear the ISR bit and cpu thinks it has already serivced
+        * the interrupt. Hence a vector might get locked. It was noticed
+        * for timer irq (vector 0x31). Issue an extra EOI to clear ISR.
+        */
+       for (i = APIC_ISR_NR - 1; i >= 0; i--) {
+               value = apic_read(APIC_ISR + i*0x10);
+               for (j = 31; j >= 0; j--) {
+                       if (value & (1<<j))
+                               ack_APIC_irq();
+               }
+       }
+
+       /*
         * Now that we are all set up, enable the APIC
         */
        value = apic_read(APIC_SPIV);
@@ -559,15 +596,23 @@ void __devinit setup_local_APIC(void)
  * If Linux enabled the LAPIC against the BIOS default
  * disable it down before re-entering the BIOS on shutdown.
  * Otherwise the BIOS may get confused and not power-off.
+ * Additionally clear all LVT entries before disable_local_APIC
+ * for the case where Linux didn't enable the LAPIC.
  */
 void lapic_shutdown(void)
 {
-       if (!cpu_has_apic || !enabled_via_apicbase)
+       unsigned long flags;
+
+       if (!cpu_has_apic)
                return;
 
-       local_irq_disable();
-       disable_local_APIC();
-       local_irq_enable();
+       local_irq_save(flags);
+       clear_local_APIC();
+
+       if (enabled_via_apicbase)
+               disable_local_APIC();
+
+       local_irq_restore(flags);
 }
 
 #ifdef CONFIG_PM
@@ -713,11 +758,7 @@ static int __init apic_set_verbosity(char *str)
                apic_verbosity = APIC_DEBUG;
        else if (strcmp("verbose", str) == 0)
                apic_verbosity = APIC_VERBOSE;
-       else
-               printk(KERN_WARNING "APIC Verbosity level %s not recognised"
-                               " use apic=verbose or apic=debug", str);
-
-       return 0;
+       return 1;
 }
 
 __setup("apic=", apic_set_verbosity);
@@ -803,7 +844,6 @@ no_apic:
 
 void __init init_apic_mappings(void)
 {
-       unsigned int orig_apicid;
        unsigned long apic_phys;
 
        /*
@@ -825,11 +865,8 @@ void __init init_apic_mappings(void)
         * Fetch the APIC ID of the BSP in case we have a
         * default configuration (or the MP table is broken).
         */
-       orig_apicid = boot_cpu_physical_apicid;
-       boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
-       if ((orig_apicid != -1U) && (orig_apicid != boot_cpu_physical_apicid))
-               printk(KERN_WARNING "Boot APIC ID in local APIC unexpected (%d vs %d)",
-                       orig_apicid, boot_cpu_physical_apicid);
+       if (boot_cpu_physical_apicid == -1U)
+               boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
 
 #ifdef CONFIG_X86_IO_APIC
        {
@@ -933,11 +970,16 @@ void (*wait_timer_tick)(void) __devinitdata = wait_8254_wraparound;
 static void __setup_APIC_LVTT(unsigned int clocks)
 {
        unsigned int lvtt_value, tmp_value, ver;
+       int cpu = smp_processor_id();
 
        ver = GET_APIC_VERSION(apic_read(APIC_LVR));
        lvtt_value = APIC_LVT_TIMER_PERIODIC | LOCAL_TIMER_VECTOR;
        if (!APIC_INTEGRATED(ver))
                lvtt_value |= SET_APIC_TIMER_BASE(APIC_TIMER_BASE_DIV);
+
+       if (cpu_isset(cpu, timer_bcast_ipi))
+               lvtt_value |= APIC_LVT_MASKED;
+
        apic_write_around(APIC_LVTT, lvtt_value);
 
        /*
@@ -1055,7 +1097,6 @@ void __init setup_boot_APIC_clock(void)
        using_apic_timer = 1;
 
        local_irq_save(flags);
-       local_irq_disable();
 
        calibration_result = calibrate_APIC_clock();
        /*
@@ -1071,19 +1112,33 @@ void __devinit setup_secondary_APIC_clock(void)
        setup_APIC_timer(calibration_result);
 }
 
-void __devinit disable_APIC_timer(void)
+void disable_APIC_timer(void)
 {
        if (using_apic_timer) {
                unsigned long v;
 
                v = apic_read(APIC_LVTT);
-               apic_write_around(APIC_LVTT, v | APIC_LVT_MASKED);
+               /*
+                * When an illegal vector value (0-15) is written to an LVT
+                * entry and delivery mode is Fixed, the APIC may signal an
+                * illegal vector error, with out regard to whether the mask
+                * bit is set or whether an interrupt is actually seen on input.
+                *
+                * Boot sequence might call this function when the LVTT has
+                * '0' vector value. So make sure vector field is set to
+                * valid value.
+                */
+               v |= (APIC_LVT_MASKED | LOCAL_TIMER_VECTOR);
+               apic_write_around(APIC_LVTT, v);
        }
 }
 
 void enable_APIC_timer(void)
 {
-       if (using_apic_timer) {
+       int cpu = smp_processor_id();
+
+       if (using_apic_timer &&
+           !cpu_isset(cpu, timer_bcast_ipi)) {
                unsigned long v;
 
                v = apic_read(APIC_LVTT);
@@ -1091,33 +1146,31 @@ void enable_APIC_timer(void)
        }
 }
 
-/*
- * the frequency of the profiling timer can be changed
- * by writing a multiplier value into /proc/profile.
- */
-int setup_profiling_timer(unsigned int multiplier)
+void switch_APIC_timer_to_ipi(void *cpumask)
 {
-       int i;
+       cpumask_t mask = *(cpumask_t *)cpumask;
+       int cpu = smp_processor_id();
 
-       /*
-        * Sanity check. [at least 500 APIC cycles should be
-        * between APIC interrupts as a rule of thumb, to avoid
-        * irqs flooding us]
-        */
-       if ( (!multiplier) || (calibration_result/multiplier < 500))
-               return -EINVAL;
-
-       /* 
-        * Set the new multiplier for each CPU. CPUs don't start using the
-        * new values until the next timer interrupt in which they do process
-        * accounting. At that time they also adjust their APIC timers
-        * accordingly.
-        */
-       for (i = 0; i < NR_CPUS; ++i)
-               per_cpu(prof_multiplier, i) = multiplier;
+       if (cpu_isset(cpu, mask) &&
+           !cpu_isset(cpu, timer_bcast_ipi)) {
+               disable_APIC_timer();
+               cpu_set(cpu, timer_bcast_ipi);
+       }
+}
+EXPORT_SYMBOL(switch_APIC_timer_to_ipi);
 
-       return 0;
+void switch_ipi_to_APIC_timer(void *cpumask)
+{
+       cpumask_t mask = *(cpumask_t *)cpumask;
+       int cpu = smp_processor_id();
+
+       if (cpu_isset(cpu, mask) &&
+           cpu_isset(cpu, timer_bcast_ipi)) {
+               cpu_clear(cpu, timer_bcast_ipi);
+               enable_APIC_timer();
+       }
 }
+EXPORT_SYMBOL(switch_ipi_to_APIC_timer);
 
 #undef APIC_DIVISOR
 
@@ -1133,32 +1186,10 @@ int setup_profiling_timer(unsigned int multiplier)
 
 inline void smp_local_timer_interrupt(struct pt_regs * regs)
 {
-       int cpu = smp_processor_id();
-
        profile_tick(CPU_PROFILING, regs);
-       if (--per_cpu(prof_counter, cpu) <= 0) {
-               /*
-                * The multiplier may have changed since the last time we got
-                * to this point as a result of the user writing to
-                * /proc/profile. In this case we need to adjust the APIC
-                * timer accordingly.
-                *
-                * Interrupts are already masked off at this point.
-                */
-               per_cpu(prof_counter, cpu) = per_cpu(prof_multiplier, cpu);
-               if (per_cpu(prof_counter, cpu) !=
-                                       per_cpu(prof_old_multiplier, cpu)) {
-                       __setup_APIC_LVTT(
-                                       calibration_result/
-                                       per_cpu(prof_counter, cpu));
-                       per_cpu(prof_old_multiplier, cpu) =
-                                               per_cpu(prof_counter, cpu);
-               }
-
 #ifdef CONFIG_SMP
-               update_process_times(user_mode_vm(regs));
+       update_process_times(user_mode_vm(regs));
 #endif
-       }
 
        /*
         * We take the 'long' return path, and there every subsystem
@@ -1205,6 +1236,43 @@ fastcall void smp_apic_timer_interrupt(struct pt_regs *regs)
        irq_exit();
 }
 
+#ifndef CONFIG_SMP
+static void up_apic_timer_interrupt_call(struct pt_regs *regs)
+{
+       int cpu = smp_processor_id();
+
+       /*
+        * the NMI deadlock-detector uses this.
+        */
+       per_cpu(irq_stat, cpu).apic_timer_irqs++;
+
+       smp_local_timer_interrupt(regs);
+}
+#endif
+
+void smp_send_timer_broadcast_ipi(struct pt_regs *regs)
+{
+       cpumask_t mask;
+
+       cpus_and(mask, cpu_online_map, timer_bcast_ipi);
+       if (!cpus_empty(mask)) {
+#ifdef CONFIG_SMP
+               send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
+#else
+               /*
+                * We can directly call the apic timer interrupt handler
+                * in UP case. Minus all irq related functions
+                */
+               up_apic_timer_interrupt_call(regs);
+#endif
+       }
+}
+
+int setup_profiling_timer(unsigned int multiplier)
+{
+       return -EINVAL;
+}
+
 /*
  * This interrupt should _never_ happen with our APIC/SMP architecture
  */
@@ -1260,81 +1328,49 @@ fastcall void smp_error_interrupt(struct pt_regs *regs)
 }
 
 /*
- * This initializes the IO-APIC and APIC hardware.
+ * This initializes the IO-APIC and APIC hardware if this is
+ * a UP kernel.
  */
-int __init APIC_init(void)
+int __init APIC_init_uniprocessor (void)
 {
-       if (enable_local_apic < 0) {
-               printk(KERN_INFO "APIC disabled\n");
-               return -1;
-       }
+       if (enable_local_apic < 0)
+               clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
 
-       /* See if we have a SMP configuration or have forced enabled
-        * the local apic.
-        */
-       if (!smp_found_config && !acpi_lapic && !cpu_has_apic) {
-               enable_local_apic = -1;
+       if (!smp_found_config && !cpu_has_apic)
                return -1;
-       }
 
        /*
-        * Complain if the BIOS pretends there is an apic.
-        * Then get out because we don't have an a local apic.
+        * Complain if the BIOS pretends there is one.
         */
        if (!cpu_has_apic && APIC_INTEGRATED(apic_version[boot_cpu_physical_apicid])) {
                printk(KERN_ERR "BIOS bug, local APIC #%d not detected!...\n",
                        boot_cpu_physical_apicid);
-               printk(KERN_ERR "... forcing use of dummy APIC emulation. (tell your hw vendor)\n");
-               enable_local_apic = -1;
+               clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
                return -1;
        }
 
        verify_local_APIC();
 
-       /*
-        * Should not be necessary because the MP table should list the boot
-        * CPU too, but we do it for the sake of robustness anyway.
-        * Makes no sense to do this check in clustered apic mode, so skip it
-        */
-       if (!check_phys_apicid_present(boot_cpu_physical_apicid)) {
-               printk("weird, boot CPU (#%d) not listed by the BIOS.\n",
-                               boot_cpu_physical_apicid);
-               physid_set(hard_smp_processor_id(), phys_cpu_present_map);
-       }
-
-       /*
-        * Switch from PIC to APIC mode.
-        */
        connect_bsp_APIC();
-       setup_local_APIC();
 
-#ifdef CONFIG_X86_IO_APIC
        /*
-        * Now start the IO-APICs
+        * Hack: In case of kdump, after a crash, kernel might be booting
+        * on a cpu with non-zero lapic id. But boot_cpu_physical_apicid
+        * might be zero if read from MP tables. Get it from LAPIC.
         */
-       if (smp_found_config && !skip_ioapic_setup && nr_ioapics)
-               setup_IO_APIC();
+#ifdef CONFIG_CRASH_DUMP
+       boot_cpu_physical_apicid = GET_APIC_ID(apic_read(APIC_ID));
 #endif
-       return 0;
-}
+       phys_cpu_present_map = physid_mask_of_physid(boot_cpu_physical_apicid);
 
-void __init APIC_late_time_init(void)
-{
-       /* Improve our loops per jiffy estimate */
-       loops_per_jiffy = ((1000 + HZ - 1)/HZ)*cpu_khz;
-       boot_cpu_data.loops_per_jiffy = loops_per_jiffy;
-       cpu_data[0].loops_per_jiffy = loops_per_jiffy;
-
-       /* setup_apic_nmi_watchdog doesn't work properly before cpu_khz is
-        * initialized.  So redo it here to ensure the boot cpu is setup
-        * properly.
-        */
-       if (nmi_watchdog == NMI_LOCAL_APIC)
-               setup_apic_nmi_watchdog();
+       setup_local_APIC();
 
 #ifdef CONFIG_X86_IO_APIC
-       if (smp_found_config && !skip_ioapic_setup && nr_ioapics)
-               IO_APIC_late_time_init();
+       if (smp_found_config)
+               if (!skip_ioapic_setup && nr_ioapics)
+                       setup_IO_APIC();
 #endif
        setup_boot_APIC_clock();
+
+       return 0;
 }