aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi/processor_idle.c
diff options
context:
space:
mode:
authoralex.shi <alex.shi@intel.com>2009-03-04 14:55:26 -0500
committerLen Brown <len.brown@intel.com>2009-03-17 01:13:46 -0400
commitff69f2bba67bd45514923aaedbf40fe351787c59 (patch)
tree822f92e20e6c55b454bf1d860ace5089c05bfa51 /drivers/acpi/processor_idle.c
parentc15d8a6499d04e5d2cac07f8120f207bb275f60f (diff)
acpi: fix of pmtimer overflow that make Cx states time incorrect
We found Cx states time abnormal in our some of machines which have 16 LCPUs, the C0 take too many time while system is really idle when kernel enabled tickless and highres. powertop output is below: PowerTOP version 1.9 (C) 2007 Intel Corporation Cn Avg residency P-states (frequencies) C0 (cpu running) (40.5%) 2.53 Ghz 0.0% C1 0.0ms ( 0.0%) 2.53 Ghz 0.0% C2 128.8ms (59.5%) 2.40 Ghz 0.0% 1.60 Ghz 100.0% Wakeups-from-idle per second : 4.7 interval: 20.0s no ACPI power usage estimate available Top causes for wakeups: 41.4% ( 24.9) <interrupt> : extra timer interrupt 20.2% ( 12.2) <kernel core> : usb_hcd_poll_rh_status (rh_timer_func) After tacking detailed for this issue, Yakui and I find it is due to 24 bit PM timer overflows when some of cpu sleep more than 4 seconds. With tickless kernel, the CPU want to sleep as much as possible when system idle. But the Cx sleep time are recorded by pmtimer which length is determined by BIOS. The current Cx time was gotten in the following function from driver/acpi/processor_idle.c: static inline u32 ticks_elapsed(u32 t1, u32 t2) { if (t2 >= t1) return (t2 - t1); else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER)) return (((0x00FFFFFF - t1) + t2) & 0x00FFFFFF); else return ((0xFFFFFFFF - t1) + t2); } If pmtimer is 24 bits and it take 5 seconds from t1 to t2, in above function, just about 1 seconds ticks was recorded. So the Cx time will be reduced about 4 seconds. and this is why we see above powertop output. To resolve this problem, Yakui and I use ktime_get() to record the Cx states time instead of PM timer as the following patch. the patch was tested with i386/x86_64 modes on several platforms. Acked-by: Venkatesh Pallipadi <venkatesh.pallipadi@intel.com> Tested-by: Alex Shi <alex.shi@intel.com> Signed-off-by: Alex Shi <alex.shi@intel.com> Signed-off-by: Yakui.zhao <yakui.zhao@intel.com> Signed-off-by: Andrew Morton <akpm@linux-foundation.org> Signed-off-by: Len Brown <len.brown@intel.com>
Diffstat (limited to 'drivers/acpi/processor_idle.c')
-rw-r--r--drivers/acpi/processor_idle.c63
1 files changed, 27 insertions, 36 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 7bc22a471fe3..879af875c213 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -64,7 +64,6 @@
64#define _COMPONENT ACPI_PROCESSOR_COMPONENT 64#define _COMPONENT ACPI_PROCESSOR_COMPONENT
65ACPI_MODULE_NAME("processor_idle"); 65ACPI_MODULE_NAME("processor_idle");
66#define ACPI_PROCESSOR_FILE_POWER "power" 66#define ACPI_PROCESSOR_FILE_POWER "power"
67#define US_TO_PM_TIMER_TICKS(t) ((t * (PM_TIMER_FREQUENCY/1000)) / 1000)
68#define PM_TIMER_TICK_NS (1000000000ULL/PM_TIMER_FREQUENCY) 67#define PM_TIMER_TICK_NS (1000000000ULL/PM_TIMER_FREQUENCY)
69#define C2_OVERHEAD 1 /* 1us */ 68#define C2_OVERHEAD 1 /* 1us */
70#define C3_OVERHEAD 1 /* 1us */ 69#define C3_OVERHEAD 1 /* 1us */
@@ -78,6 +77,10 @@ module_param(nocst, uint, 0000);
78static unsigned int latency_factor __read_mostly = 2; 77static unsigned int latency_factor __read_mostly = 2;
79module_param(latency_factor, uint, 0644); 78module_param(latency_factor, uint, 0644);
80 79
80static s64 us_to_pm_timer_ticks(s64 t)
81{
82 return div64_u64(t * PM_TIMER_FREQUENCY, 1000000);
83}
81/* 84/*
82 * IBM ThinkPad R40e crashes mysteriously when going into C2 or C3. 85 * IBM ThinkPad R40e crashes mysteriously when going into C2 or C3.
83 * For now disable this. Probably a bug somewhere else. 86 * For now disable this. Probably a bug somewhere else.
@@ -159,25 +162,6 @@ static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = {
159 {}, 162 {},
160}; 163};
161 164
162static inline u32 ticks_elapsed(u32 t1, u32 t2)
163{
164 if (t2 >= t1)
165 return (t2 - t1);
166 else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER))
167 return (((0x00FFFFFF - t1) + t2) & 0x00FFFFFF);
168 else
169 return ((0xFFFFFFFF - t1) + t2);
170}
171
172static inline u32 ticks_elapsed_in_us(u32 t1, u32 t2)
173{
174 if (t2 >= t1)
175 return PM_TIMER_TICKS_TO_US(t2 - t1);
176 else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER))
177 return PM_TIMER_TICKS_TO_US(((0x00FFFFFF - t1) + t2) & 0x00FFFFFF);
178 else
179 return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2);
180}
181 165
182/* 166/*
183 * Callers should disable interrupts before the call and enable 167 * Callers should disable interrupts before the call and enable
@@ -853,7 +837,8 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
853static int acpi_idle_enter_c1(struct cpuidle_device *dev, 837static int acpi_idle_enter_c1(struct cpuidle_device *dev,
854 struct cpuidle_state *state) 838 struct cpuidle_state *state)
855{ 839{
856 u32 t1, t2; 840 ktime_t kt1, kt2;
841 s64 idle_time;
857 struct acpi_processor *pr; 842 struct acpi_processor *pr;
858 struct acpi_processor_cx *cx = cpuidle_get_statedata(state); 843 struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
859 844
@@ -871,14 +856,15 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
871 return 0; 856 return 0;
872 } 857 }
873 858
874 t1 = inl(acpi_gbl_FADT.xpm_timer_block.address); 859 kt1 = ktime_get_real();
875 acpi_idle_do_entry(cx); 860 acpi_idle_do_entry(cx);
876 t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); 861 kt2 = ktime_get_real();
862 idle_time = ktime_to_us(ktime_sub(kt2, kt1));
877 863
878 local_irq_enable(); 864 local_irq_enable();
879 cx->usage++; 865 cx->usage++;
880 866
881 return ticks_elapsed_in_us(t1, t2); 867 return idle_time;
882} 868}
883 869
884/** 870/**
@@ -891,8 +877,9 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
891{ 877{
892 struct acpi_processor *pr; 878 struct acpi_processor *pr;
893 struct acpi_processor_cx *cx = cpuidle_get_statedata(state); 879 struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
894 u32 t1, t2; 880 ktime_t kt1, kt2;
895 int sleep_ticks = 0; 881 s64 idle_time;
882 s64 sleep_ticks = 0;
896 883
897 pr = __get_cpu_var(processors); 884 pr = __get_cpu_var(processors);
898 885
@@ -925,18 +912,19 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
925 if (cx->type == ACPI_STATE_C3) 912 if (cx->type == ACPI_STATE_C3)
926 ACPI_FLUSH_CPU_CACHE(); 913 ACPI_FLUSH_CPU_CACHE();
927 914
928 t1 = inl(acpi_gbl_FADT.xpm_timer_block.address); 915 kt1 = ktime_get_real();
929 /* Tell the scheduler that we are going deep-idle: */ 916 /* Tell the scheduler that we are going deep-idle: */
930 sched_clock_idle_sleep_event(); 917 sched_clock_idle_sleep_event();
931 acpi_idle_do_entry(cx); 918 acpi_idle_do_entry(cx);
932 t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); 919 kt2 = ktime_get_real();
920 idle_time = ktime_to_us(ktime_sub(kt2, kt1));
933 921
934#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86) 922#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
935 /* TSC could halt in idle, so notify users */ 923 /* TSC could halt in idle, so notify users */
936 if (tsc_halts_in_c(cx->type)) 924 if (tsc_halts_in_c(cx->type))
937 mark_tsc_unstable("TSC halts in idle");; 925 mark_tsc_unstable("TSC halts in idle");;
938#endif 926#endif
939 sleep_ticks = ticks_elapsed(t1, t2); 927 sleep_ticks = us_to_pm_timer_ticks(idle_time);
940 928
941 /* Tell the scheduler how much we idled: */ 929 /* Tell the scheduler how much we idled: */
942 sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS); 930 sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
@@ -948,7 +936,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
948 936
949 acpi_state_timer_broadcast(pr, cx, 0); 937 acpi_state_timer_broadcast(pr, cx, 0);
950 cx->time += sleep_ticks; 938 cx->time += sleep_ticks;
951 return ticks_elapsed_in_us(t1, t2); 939 return idle_time;
952} 940}
953 941
954static int c3_cpu_count; 942static int c3_cpu_count;
@@ -966,8 +954,10 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
966{ 954{
967 struct acpi_processor *pr; 955 struct acpi_processor *pr;
968 struct acpi_processor_cx *cx = cpuidle_get_statedata(state); 956 struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
969 u32 t1, t2; 957 ktime_t kt1, kt2;
970 int sleep_ticks = 0; 958 s64 idle_time;
959 s64 sleep_ticks = 0;
960
971 961
972 pr = __get_cpu_var(processors); 962 pr = __get_cpu_var(processors);
973 963
@@ -1034,9 +1024,10 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
1034 ACPI_FLUSH_CPU_CACHE(); 1024 ACPI_FLUSH_CPU_CACHE();
1035 } 1025 }
1036 1026
1037 t1 = inl(acpi_gbl_FADT.xpm_timer_block.address); 1027 kt1 = ktime_get_real();
1038 acpi_idle_do_entry(cx); 1028 acpi_idle_do_entry(cx);
1039 t2 = inl(acpi_gbl_FADT.xpm_timer_block.address); 1029 kt2 = ktime_get_real();
1030 idle_time = ktime_to_us(ktime_sub(kt2, kt1));
1040 1031
1041 /* Re-enable bus master arbitration */ 1032 /* Re-enable bus master arbitration */
1042 if (pr->flags.bm_check && pr->flags.bm_control) { 1033 if (pr->flags.bm_check && pr->flags.bm_control) {
@@ -1051,7 +1042,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
1051 if (tsc_halts_in_c(ACPI_STATE_C3)) 1042 if (tsc_halts_in_c(ACPI_STATE_C3))
1052 mark_tsc_unstable("TSC halts in idle"); 1043 mark_tsc_unstable("TSC halts in idle");
1053#endif 1044#endif
1054 sleep_ticks = ticks_elapsed(t1, t2); 1045 sleep_ticks = us_to_pm_timer_ticks(idle_time);
1055 /* Tell the scheduler how much we idled: */ 1046 /* Tell the scheduler how much we idled: */
1056 sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS); 1047 sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
1057 1048
@@ -1062,7 +1053,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
1062 1053
1063 acpi_state_timer_broadcast(pr, cx, 0); 1054 acpi_state_timer_broadcast(pr, cx, 0);
1064 cx->time += sleep_ticks; 1055 cx->time += sleep_ticks;
1065 return ticks_elapsed_in_us(t1, t2); 1056 return idle_time;
1066} 1057}
1067 1058
1068struct cpuidle_driver acpi_idle_driver = { 1059struct cpuidle_driver acpi_idle_driver = {