Merge branch 'devel' of master.kernel.org:/home/rmk/linux-2.6-arm
[pandora-kernel.git] / arch / x86_64 / kernel / apic.c
index 723417d..900ff38 100644 (file)
@@ -19,7 +19,6 @@
 #include <linux/mm.h>
 #include <linux/delay.h>
 #include <linux/bootmem.h>
-#include <linux/smp_lock.h>
 #include <linux/interrupt.h>
 #include <linux/mc146818rtc.h>
 #include <linux/kernel_stat.h>
@@ -47,6 +46,10 @@ int apic_calibrate_pmtmr __initdata;
 
 int disable_apic_timer __initdata;
 
+/* Local APIC timer works in C2? */
+int local_apic_timer_c2_ok;
+EXPORT_SYMBOL_GPL(local_apic_timer_c2_ok);
+
 static struct resource *ioapic_resources;
 static struct resource lapic_resource = {
        .name = "Local APIC",
@@ -64,11 +67,34 @@ int using_apic_timer __read_mostly = 0;
 
 static void apic_pm_activate(void);
 
+void apic_wait_icr_idle(void)
+{
+       while (apic_read(APIC_ICR) & APIC_ICR_BUSY)
+               cpu_relax();
+}
+
+unsigned int safe_apic_wait_icr_idle(void)
+{
+       unsigned int send_status;
+       int timeout;
+
+       timeout = 0;
+       do {
+               send_status = apic_read(APIC_ICR) & APIC_ICR_BUSY;
+               if (!send_status)
+                       break;
+               udelay(100);
+       } while (timeout++ < 1000);
+
+       return send_status;
+}
+
 void enable_NMI_through_LVT0 (void * dummy)
 {
        unsigned int v;
-       
-       v = APIC_DM_NMI;                        /* unmask and set to NMI */
+
+       /* unmask and set to NMI */
+       v = APIC_DM_NMI;
        apic_write(APIC_LVT0, v);
 }
 
@@ -95,7 +121,7 @@ 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 don't ack when the APIC is disabled. -AK
+        * But don't ack when the APIC is disabled. -AK
         */
        if (!disable_apic)
                ack_APIC_irq();
@@ -591,7 +617,7 @@ early_param("apic", apic_set_verbosity);
  * Detect and enable local APICs on non-SMP boards.
  * Original code written by Keir Fraser.
  * On AMD64 we trust the BIOS - if it says no APIC it is likely
- * not correctly set up (usually the APIC timer won't work etc.) 
+ * not correctly set up (usually the APIC timer won't work etc.)
  */
 
 static int __init detect_init_APIC (void)
@@ -764,13 +790,13 @@ static void setup_APIC_timer(unsigned int clocks)
        local_irq_save(flags);
 
        /* wait for irq slice */
-       if (hpet_address && hpet_use_timer) {
-               int trigger = hpet_readl(HPET_T0_CMP);
-               while (hpet_readl(HPET_COUNTER) >= trigger)
-                       /* do nothing */ ;
-               while (hpet_readl(HPET_COUNTER) <  trigger)
-                       /* do nothing */ ;
-       } else {
+       if (hpet_address && hpet_use_timer) {
+               int trigger = hpet_readl(HPET_T0_CMP);
+               while (hpet_readl(HPET_COUNTER) >= trigger)
+                       /* do nothing */ ;
+               while (hpet_readl(HPET_COUNTER) <  trigger)
+                       /* do nothing */ ;
+       } else {
                int c1, c2;
                outb_p(0x00, 0x43);
                c2 = inb_p(0x40);
@@ -813,14 +839,15 @@ static void setup_APIC_timer(unsigned int clocks)
 
 static int __init calibrate_APIC_clock(void)
 {
-       int apic, apic_start, tsc, tsc_start;
+       unsigned apic, apic_start;
+       unsigned long tsc, tsc_start;
        int result;
        /*
         * Put whatever arbitrary (but long enough) timeout
         * value into the APIC clock, we just want to get the
         * counter running for calibration.
         */
-       __setup_APIC_LVTT(1000000000);
+       __setup_APIC_LVTT(4000000000);
 
        apic_start = apic_read(APIC_TMCCT);
 #ifdef CONFIG_X86_PM_TIMER
@@ -831,15 +858,15 @@ static int __init calibrate_APIC_clock(void)
        } else
 #endif
        {
-               rdtscl(tsc_start);
+               rdtscll(tsc_start);
 
                do {
                        apic = apic_read(APIC_TMCCT);
-                       rdtscl(tsc);
+                       rdtscll(tsc);
                } while ((tsc - tsc_start) < TICK_COUNT &&
-                               (apic - apic_start) < TICK_COUNT);
+                               (apic_start - apic) < TICK_COUNT);
 
-               result = (apic_start - apic) * 1000L * cpu_khz /
+               result = (apic_start - apic) * 1000L * tsc_khz /
                                        (tsc - tsc_start);
        }
        printk("result %d\n", result);
@@ -855,10 +882,10 @@ static unsigned int calibration_result;
 
 void __init setup_boot_APIC_clock (void)
 {
-       if (disable_apic_timer) { 
-               printk(KERN_INFO "Disabling APIC timer\n"); 
-               return; 
-       } 
+       if (disable_apic_timer) {
+               printk(KERN_INFO "Disabling APIC timer\n");
+               return;
+       }
 
        printk(KERN_INFO "Using local APIC timer interrupts.\n");
        using_apic_timer = 1;
@@ -930,9 +957,17 @@ EXPORT_SYMBOL(switch_APIC_timer_to_ipi);
 
 void smp_send_timer_broadcast_ipi(void)
 {
+       int cpu = smp_processor_id();
        cpumask_t mask;
 
        cpus_and(mask, cpu_online_map, timer_interrupt_broadcast_ipi_mask);
+
+       if (cpu_isset(cpu, mask)) {
+               cpu_clear(cpu, mask);
+               add_pda(apic_timer_irqs, 1);
+               smp_local_timer_interrupt();
+       }
+
        if (!cpus_empty(mask)) {
                send_IPI_mask(mask, LOCAL_TIMER_VECTOR);
        }
@@ -956,8 +991,8 @@ int setup_profiling_timer(unsigned int multiplier)
        return -EINVAL;
 }
 
-void setup_APIC_extened_lvt(unsigned char lvt_off, unsigned char vector,
-                           unsigned char msg_type, unsigned char mask)
+void setup_APIC_extended_lvt(unsigned char lvt_off, unsigned char vector,
+                            unsigned char msg_type, unsigned char mask)
 {
        unsigned long reg = (lvt_off << 4) + K8_APIC_EXT_LVT_BASE;
        unsigned int  v   = (mask << 16) | (msg_type << 8) | vector;
@@ -1094,20 +1129,6 @@ asmlinkage void smp_spurious_interrupt(void)
        if (v & (1 << (SPURIOUS_APIC_VECTOR & 0x1f)))
                ack_APIC_irq();
 
-#if 0
-       static unsigned long last_warning; 
-       static unsigned long skipped; 
-
-       /* see sw-dev-man vol 3, chapter 7.4.13.5 */
-       if (time_before(last_warning+30*HZ,jiffies)) { 
-               printk(KERN_INFO "spurious APIC interrupt on CPU#%d, %ld skipped.\n",
-                      smp_processor_id(), skipped);
-               last_warning = jiffies; 
-               skipped = 0;
-       } else { 
-               skipped++; 
-       } 
-#endif 
        irq_exit();
 }
 
@@ -1139,11 +1160,11 @@ asmlinkage void smp_error_interrupt(void)
           7: Illegal register address
        */
        printk (KERN_DEBUG "APIC error on CPU%d: %02x(%02x)\n",
-               smp_processor_id(), v , v1);
+               smp_processor_id(), v , v1);
        irq_exit();
 }
 
-int disable_apic; 
+int disable_apic;
 
 /*
  * This initializes the IO-APIC and APIC hardware if this is
@@ -1151,11 +1172,11 @@ int disable_apic;
  */
 int __init APIC_init_uniprocessor (void)
 {
-       if (disable_apic) { 
+       if (disable_apic) {
                printk(KERN_INFO "Apic disabled\n");
-               return -1; 
+               return -1;
        }
-       if (!cpu_has_apic) { 
+       if (!cpu_has_apic) {
                disable_apic = 1;
                printk(KERN_INFO "Apic disabled by BIOS\n");
                return -1;
@@ -1177,8 +1198,8 @@ int __init APIC_init_uniprocessor (void)
        return 0;
 }
 
-static __init int setup_disableapic(char *str) 
-{ 
+static __init int setup_disableapic(char *str)
+{
        disable_apic = 1;
        clear_bit(X86_FEATURE_APIC, boot_cpu_data.x86_capability);
        return 0;
@@ -1186,19 +1207,26 @@ static __init int setup_disableapic(char *str)
 early_param("disableapic", setup_disableapic);
 
 /* same as disableapic, for compatibility */
-static __init int setup_nolapic(char *str) 
-{ 
+static __init int setup_nolapic(char *str)
+{
        return setup_disableapic(str);
-} 
+}
 early_param("nolapic", setup_nolapic);
 
-static __init int setup_noapictimer(char *str) 
-{ 
+static int __init parse_lapic_timer_c2_ok(char *arg)
+{
+       local_apic_timer_c2_ok = 1;
+       return 0;
+}
+early_param("lapic_timer_c2_ok", parse_lapic_timer_c2_ok);
+
+static __init int setup_noapictimer(char *str)
+{
        if (str[0] != ' ' && str[0] != 0)
                return 0;
        disable_apic_timer = 1;
        return 1;
-} 
+}
 
 static __init int setup_apicmaintimer(char *str)
 {
@@ -1223,5 +1251,5 @@ static __init int setup_apicpmtimer(char *s)
 }
 __setup("apicpmtimer", setup_apicpmtimer);
 
-__setup("noapictimer", setup_noapictimer); 
+__setup("noapictimer", setup_noapictimer);