aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel/apic/apic.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86/kernel/apic/apic.c')
-rw-r--r--arch/x86/kernel/apic/apic.c72
1 files changed, 57 insertions, 15 deletions
diff --git a/arch/x86/kernel/apic/apic.c b/arch/x86/kernel/apic/apic.c
index f5291362da1a..dba2828b779a 100644
--- a/arch/x86/kernel/apic/apic.c
+++ b/arch/x86/kernel/apic/apic.c
@@ -722,7 +722,7 @@ static __initdata unsigned long lapic_cal_pm1, lapic_cal_pm2;
722static __initdata unsigned long lapic_cal_j1, lapic_cal_j2; 722static __initdata unsigned long lapic_cal_j1, lapic_cal_j2;
723 723
724/* 724/*
725 * Temporary interrupt handler. 725 * Temporary interrupt handler and polled calibration function.
726 */ 726 */
727static void __init lapic_cal_handler(struct clock_event_device *dev) 727static void __init lapic_cal_handler(struct clock_event_device *dev)
728{ 728{
@@ -851,7 +851,8 @@ bool __init apic_needs_pit(void)
851static int __init calibrate_APIC_clock(void) 851static int __init calibrate_APIC_clock(void)
852{ 852{
853 struct clock_event_device *levt = this_cpu_ptr(&lapic_events); 853 struct clock_event_device *levt = this_cpu_ptr(&lapic_events);
854 void (*real_handler)(struct clock_event_device *dev); 854 u64 tsc_perj = 0, tsc_start = 0;
855 unsigned long jif_start;
855 unsigned long deltaj; 856 unsigned long deltaj;
856 long delta, deltatsc; 857 long delta, deltatsc;
857 int pm_referenced = 0; 858 int pm_referenced = 0;
@@ -878,28 +879,64 @@ static int __init calibrate_APIC_clock(void)
878 apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n" 879 apic_printk(APIC_VERBOSE, "Using local APIC timer interrupts.\n"
879 "calibrating APIC timer ...\n"); 880 "calibrating APIC timer ...\n");
880 881
882 /*
883 * There are platforms w/o global clockevent devices. Instead of
884 * making the calibration conditional on that, use a polling based
885 * approach everywhere.
886 */
881 local_irq_disable(); 887 local_irq_disable();
882 888
883 /* Replace the global interrupt handler */
884 real_handler = global_clock_event->event_handler;
885 global_clock_event->event_handler = lapic_cal_handler;
886
887 /* 889 /*
888 * Setup the APIC counter to maximum. There is no way the lapic 890 * Setup the APIC counter to maximum. There is no way the lapic
889 * can underflow in the 100ms detection time frame 891 * can underflow in the 100ms detection time frame
890 */ 892 */
891 __setup_APIC_LVTT(0xffffffff, 0, 0); 893 __setup_APIC_LVTT(0xffffffff, 0, 0);
892 894
893 /* Let the interrupts run */ 895 /*
896 * Methods to terminate the calibration loop:
897 * 1) Global clockevent if available (jiffies)
898 * 2) TSC if available and frequency is known
899 */
900 jif_start = READ_ONCE(jiffies);
901
902 if (tsc_khz) {
903 tsc_start = rdtsc();
904 tsc_perj = div_u64((u64)tsc_khz * 1000, HZ);
905 }
906
907 /*
908 * Enable interrupts so the tick can fire, if a global
909 * clockevent device is available
910 */
894 local_irq_enable(); 911 local_irq_enable();
895 912
896 while (lapic_cal_loops <= LAPIC_CAL_LOOPS) 913 while (lapic_cal_loops <= LAPIC_CAL_LOOPS) {
897 cpu_relax(); 914 /* Wait for a tick to elapse */
915 while (1) {
916 if (tsc_khz) {
917 u64 tsc_now = rdtsc();
918 if ((tsc_now - tsc_start) >= tsc_perj) {
919 tsc_start += tsc_perj;
920 break;
921 }
922 } else {
923 unsigned long jif_now = READ_ONCE(jiffies);
898 924
899 local_irq_disable(); 925 if (time_after(jif_now, jif_start)) {
926 jif_start = jif_now;
927 break;
928 }
929 }
930 cpu_relax();
931 }
900 932
901 /* Restore the real event handler */ 933 /* Invoke the calibration routine */
902 global_clock_event->event_handler = real_handler; 934 local_irq_disable();
935 lapic_cal_handler(NULL);
936 local_irq_enable();
937 }
938
939 local_irq_disable();
903 940
904 /* Build delta t1-t2 as apic timer counts down */ 941 /* Build delta t1-t2 as apic timer counts down */
905 delta = lapic_cal_t1 - lapic_cal_t2; 942 delta = lapic_cal_t1 - lapic_cal_t2;
@@ -943,10 +980,11 @@ static int __init calibrate_APIC_clock(void)
943 levt->features &= ~CLOCK_EVT_FEAT_DUMMY; 980 levt->features &= ~CLOCK_EVT_FEAT_DUMMY;
944 981
945 /* 982 /*
946 * PM timer calibration failed or not turned on 983 * PM timer calibration failed or not turned on so lets try APIC
947 * so lets try APIC timer based calibration 984 * timer based calibration, if a global clockevent device is
985 * available.
948 */ 986 */
949 if (!pm_referenced) { 987 if (!pm_referenced && global_clock_event) {
950 apic_printk(APIC_VERBOSE, "... verify APIC timer\n"); 988 apic_printk(APIC_VERBOSE, "... verify APIC timer\n");
951 989
952 /* 990 /*
@@ -1141,6 +1179,10 @@ void clear_local_APIC(void)
1141 apic_write(APIC_LVT0, v | APIC_LVT_MASKED); 1179 apic_write(APIC_LVT0, v | APIC_LVT_MASKED);
1142 v = apic_read(APIC_LVT1); 1180 v = apic_read(APIC_LVT1);
1143 apic_write(APIC_LVT1, v | APIC_LVT_MASKED); 1181 apic_write(APIC_LVT1, v | APIC_LVT_MASKED);
1182 if (!x2apic_enabled()) {
1183 v = apic_read(APIC_LDR) & ~APIC_LDR_MASK;
1184 apic_write(APIC_LDR, v);
1185 }
1144 if (maxlvt >= 4) { 1186 if (maxlvt >= 4) {
1145 v = apic_read(APIC_LVTPC); 1187 v = apic_read(APIC_LVTPC);
1146 apic_write(APIC_LVTPC, v | APIC_LVT_MASKED); 1188 apic_write(APIC_LVTPC, v | APIC_LVT_MASKED);