Merge branch 'x86-apic-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-block.git] / arch / x86 / kernel / apic / apic.c
index 85be316665b4a38e2d650bda07db3843485a91e1..1bd91cb7b320a2363097374cd9264005e39b04a7 100644 (file)
@@ -195,7 +195,7 @@ static struct resource lapic_resource = {
        .flags = IORESOURCE_MEM | IORESOURCE_BUSY,
 };
 
-unsigned int lapic_timer_frequency = 0;
+unsigned int lapic_timer_period = 0;
 
 static void apic_pm_activate(void);
 
@@ -501,7 +501,7 @@ lapic_timer_set_periodic_oneshot(struct clock_event_device *evt, bool oneshot)
        if (evt->features & CLOCK_EVT_FEAT_DUMMY)
                return 0;
 
-       __setup_APIC_LVTT(lapic_timer_frequency, oneshot, 1);
+       __setup_APIC_LVTT(lapic_timer_period, oneshot, 1);
        return 0;
 }
 
@@ -805,11 +805,11 @@ calibrate_by_pmtimer(long deltapm, long *delta, long *deltatsc)
 
 static int __init lapic_init_clockevent(void)
 {
-       if (!lapic_timer_frequency)
+       if (!lapic_timer_period)
                return -1;
 
        /* Calculate the scaled math multiplication factor */
-       lapic_clockevent.mult = div_sc(lapic_timer_frequency/APIC_DIVISOR,
+       lapic_clockevent.mult = div_sc(lapic_timer_period/APIC_DIVISOR,
                                        TICK_NSEC, lapic_clockevent.shift);
        lapic_clockevent.max_delta_ns =
                clockevent_delta2ns(0x7FFFFFFF, &lapic_clockevent);
@@ -821,6 +821,33 @@ static int __init lapic_init_clockevent(void)
        return 0;
 }
 
+bool __init apic_needs_pit(void)
+{
+       /*
+        * If the frequencies are not known, PIT is required for both TSC
+        * and apic timer calibration.
+        */
+       if (!tsc_khz || !cpu_khz)
+               return true;
+
+       /* Is there an APIC at all? */
+       if (!boot_cpu_has(X86_FEATURE_APIC))
+               return true;
+
+       /* Deadline timer is based on TSC so no further PIT action required */
+       if (boot_cpu_has(X86_FEATURE_TSC_DEADLINE_TIMER))
+               return false;
+
+       /* APIC timer disabled? */
+       if (disable_apic_timer)
+               return true;
+       /*
+        * The APIC timer frequency is known already, no PIT calibration
+        * required. If unknown, let the PIT be initialized.
+        */
+       return lapic_timer_period == 0;
+}
+
 static int __init calibrate_APIC_clock(void)
 {
        struct clock_event_device *levt = this_cpu_ptr(&lapic_events);
@@ -839,7 +866,7 @@ static int __init calibrate_APIC_clock(void)
         */
        if (!lapic_init_clockevent()) {
                apic_printk(APIC_VERBOSE, "lapic timer already calibrated %d\n",
-                           lapic_timer_frequency);
+                           lapic_timer_period);
                /*
                 * Direct calibration methods must have an always running
                 * local APIC timer, no need for broadcast timer.
@@ -884,13 +911,13 @@ static int __init calibrate_APIC_clock(void)
        pm_referenced = !calibrate_by_pmtimer(lapic_cal_pm2 - lapic_cal_pm1,
                                        &delta, &deltatsc);
 
-       lapic_timer_frequency = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
+       lapic_timer_period = (delta * APIC_DIVISOR) / LAPIC_CAL_LOOPS;
        lapic_init_clockevent();
 
        apic_printk(APIC_VERBOSE, "..... delta %ld\n", delta);
        apic_printk(APIC_VERBOSE, "..... mult: %u\n", lapic_clockevent.mult);
        apic_printk(APIC_VERBOSE, "..... calibration result: %u\n",
-                   lapic_timer_frequency);
+                   lapic_timer_period);
 
        if (boot_cpu_has(X86_FEATURE_TSC)) {
                apic_printk(APIC_VERBOSE, "..... CPU clock speed is "
@@ -901,13 +928,13 @@ static int __init calibrate_APIC_clock(void)
 
        apic_printk(APIC_VERBOSE, "..... host bus clock speed is "
                    "%u.%04u MHz.\n",
-                   lapic_timer_frequency / (1000000 / HZ),
-                   lapic_timer_frequency % (1000000 / HZ));
+                   lapic_timer_period / (1000000 / HZ),
+                   lapic_timer_period % (1000000 / HZ));
 
        /*
         * Do a sanity check on the APIC calibration result
         */
-       if (lapic_timer_frequency < (1000000 / HZ)) {
+       if (lapic_timer_period < (1000000 / HZ)) {
                local_irq_enable();
                pr_warning("APIC frequency too slow, disabling apic timer\n");
                return -1;
@@ -1351,6 +1378,8 @@ void __init init_bsp_APIC(void)
        apic_write(APIC_LVT1, value);
 }
 
+static void __init apic_bsp_setup(bool upmode);
+
 /* Init the interrupt delivery mode for the BSP */
 void __init apic_intr_mode_init(void)
 {
@@ -2041,21 +2070,32 @@ __visible void __irq_entry smp_spurious_interrupt(struct pt_regs *regs)
        entering_irq();
        trace_spurious_apic_entry(vector);
 
+       inc_irq_stat(irq_spurious_count);
+
+       /*
+        * If this is a spurious interrupt then do not acknowledge
+        */
+       if (vector == SPURIOUS_APIC_VECTOR) {
+               /* See SDM vol 3 */
+               pr_info("Spurious APIC interrupt (vector 0xFF) on CPU#%d, should never happen.\n",
+                       smp_processor_id());
+               goto out;
+       }
+
        /*
-        * Check if this really is a spurious interrupt and ACK it
-        * if it is a vectored one.  Just in case...
-        * Spurious interrupts should not be ACKed.
+        * If it is a vectored one, verify it's set in the ISR. If set,
+        * acknowledge it.
         */
        v = apic_read(APIC_ISR + ((vector & ~0x1f) >> 1));
-       if (v & (1 << (vector & 0x1f)))
+       if (v & (1 << (vector & 0x1f))) {
+               pr_info("Spurious interrupt (vector 0x%02x) on CPU#%d. Acked\n",
+                       vector, smp_processor_id());
                ack_APIC_irq();
-
-       inc_irq_stat(irq_spurious_count);
-
-       /* see sw-dev-man vol 3, chapter 7.4.13.5 */
-       pr_info("spurious APIC interrupt through vector %02x on CPU#%d, "
-               "should never happen.\n", vector, smp_processor_id());
-
+       } else {
+               pr_info("Spurious interrupt (vector 0x%02x) on CPU#%d. Not pending!\n",
+                       vector, smp_processor_id());
+       }
+out:
        trace_spurious_apic_exit(vector);
        exiting_irq();
 }
@@ -2416,11 +2456,8 @@ static void __init apic_bsp_up_setup(void)
 /**
  * apic_bsp_setup - Setup function for local apic and io-apic
  * @upmode:            Force UP mode (for APIC_init_uniprocessor)
- *
- * Returns:
- * apic_id of BSP APIC
  */
-void __init apic_bsp_setup(bool upmode)
+static void __init apic_bsp_setup(bool upmode)
 {
        connect_bsp_APIC();
        if (upmode)