aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorJulius Werner <jwerner@chromium.org>2012-11-27 08:17:58 -0500
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2012-11-27 08:17:58 -0500
commita474a515497ef3566cfc17a2cab3d54d6d50ff1c (patch)
tree377b53565f728dfee5604ae0c8c6879d38a2a3ec /drivers/acpi
parenta093b93ee0e08cd73a07848752bc09ecea68cb13 (diff)
cpuidle: Measure idle state durations with monotonic clock
Many cpuidle drivers measure their time spent in an idle state by reading the wallclock time before and after idling and calculating the difference. This leads to erroneous results when the wallclock time gets updated by another processor in the meantime, adding that clock adjustment to the idle state's time counter. If the clock adjustment was negative, the result is even worse due to an erroneous cast from int to unsigned long long of the last_residency variable. The negative 32 bit integer will zero-extend and result in a forward time jump of roughly four billion milliseconds or 1.3 hours on the idle state residency counter. This patch changes all affected cpuidle drivers to either use the monotonic clock for their measurements or make use of the generic time measurement wrapper in cpuidle.c, which was already working correctly. Some superfluous CLIs/STIs in the ACPI code are removed (interrupts should always already be disabled before entering the idle function, and not get reenabled until the generic wrapper has performed its second measurement). It also removes the erroneous cast, making sure that negative residency values are applied correctly even though they should not appear anymore. Signed-off-by: Julius Werner <jwerner@chromium.org> Reviewed-by: Preeti U Murthy <preeti@linux.vnet.ibm.com> Tested-by: Daniel Lezcano <daniel.lezcano@linaro.org> Acked-by: Daniel Lezcano <daniel.lezcano@linaro.org> Acked-by: Len Brown <len.brown@intel.com> Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/processor_idle.c57
1 files changed, 3 insertions, 54 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index e8086c725305..f1a5da44591d 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -735,31 +735,18 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
735static int acpi_idle_enter_c1(struct cpuidle_device *dev, 735static int acpi_idle_enter_c1(struct cpuidle_device *dev,
736 struct cpuidle_driver *drv, int index) 736 struct cpuidle_driver *drv, int index)
737{ 737{
738 ktime_t kt1, kt2;
739 s64 idle_time;
740 struct acpi_processor *pr; 738 struct acpi_processor *pr;
741 struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; 739 struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
742 struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); 740 struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
743 741
744 pr = __this_cpu_read(processors); 742 pr = __this_cpu_read(processors);
745 dev->last_residency = 0;
746 743
747 if (unlikely(!pr)) 744 if (unlikely(!pr))
748 return -EINVAL; 745 return -EINVAL;
749 746
750 local_irq_disable();
751
752
753 lapic_timer_state_broadcast(pr, cx, 1); 747 lapic_timer_state_broadcast(pr, cx, 1);
754 kt1 = ktime_get_real();
755 acpi_idle_do_entry(cx); 748 acpi_idle_do_entry(cx);
756 kt2 = ktime_get_real();
757 idle_time = ktime_to_us(ktime_sub(kt2, kt1));
758
759 /* Update device last_residency*/
760 dev->last_residency = (int)idle_time;
761 749
762 local_irq_enable();
763 lapic_timer_state_broadcast(pr, cx, 0); 750 lapic_timer_state_broadcast(pr, cx, 0);
764 751
765 return index; 752 return index;
@@ -806,19 +793,12 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
806 struct acpi_processor *pr; 793 struct acpi_processor *pr;
807 struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; 794 struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
808 struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); 795 struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
809 ktime_t kt1, kt2;
810 s64 idle_time_ns;
811 s64 idle_time;
812 796
813 pr = __this_cpu_read(processors); 797 pr = __this_cpu_read(processors);
814 dev->last_residency = 0;
815 798
816 if (unlikely(!pr)) 799 if (unlikely(!pr))
817 return -EINVAL; 800 return -EINVAL;
818 801
819 local_irq_disable();
820
821
822 if (cx->entry_method != ACPI_CSTATE_FFH) { 802 if (cx->entry_method != ACPI_CSTATE_FFH) {
823 current_thread_info()->status &= ~TS_POLLING; 803 current_thread_info()->status &= ~TS_POLLING;
824 /* 804 /*
@@ -829,7 +809,6 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
829 809
830 if (unlikely(need_resched())) { 810 if (unlikely(need_resched())) {
831 current_thread_info()->status |= TS_POLLING; 811 current_thread_info()->status |= TS_POLLING;
832 local_irq_enable();
833 return -EINVAL; 812 return -EINVAL;
834 } 813 }
835 } 814 }
@@ -843,22 +822,12 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
843 if (cx->type == ACPI_STATE_C3) 822 if (cx->type == ACPI_STATE_C3)
844 ACPI_FLUSH_CPU_CACHE(); 823 ACPI_FLUSH_CPU_CACHE();
845 824
846 kt1 = ktime_get_real();
847 /* Tell the scheduler that we are going deep-idle: */ 825 /* Tell the scheduler that we are going deep-idle: */
848 sched_clock_idle_sleep_event(); 826 sched_clock_idle_sleep_event();
849 acpi_idle_do_entry(cx); 827 acpi_idle_do_entry(cx);
850 kt2 = ktime_get_real();
851 idle_time_ns = ktime_to_ns(ktime_sub(kt2, kt1));
852 idle_time = idle_time_ns;
853 do_div(idle_time, NSEC_PER_USEC);
854 828
855 /* Update device last_residency*/ 829 sched_clock_idle_wakeup_event(0);
856 dev->last_residency = (int)idle_time;
857 830
858 /* Tell the scheduler how much we idled: */
859 sched_clock_idle_wakeup_event(idle_time_ns);
860
861 local_irq_enable();
862 if (cx->entry_method != ACPI_CSTATE_FFH) 831 if (cx->entry_method != ACPI_CSTATE_FFH)
863 current_thread_info()->status |= TS_POLLING; 832 current_thread_info()->status |= TS_POLLING;
864 833
@@ -883,13 +852,8 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
883 struct acpi_processor *pr; 852 struct acpi_processor *pr;
884 struct cpuidle_state_usage *state_usage = &dev->states_usage[index]; 853 struct cpuidle_state_usage *state_usage = &dev->states_usage[index];
885 struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage); 854 struct acpi_processor_cx *cx = cpuidle_get_statedata(state_usage);
886 ktime_t kt1, kt2;
887 s64 idle_time_ns;
888 s64 idle_time;
889
890 855
891 pr = __this_cpu_read(processors); 856 pr = __this_cpu_read(processors);
892 dev->last_residency = 0;
893 857
894 if (unlikely(!pr)) 858 if (unlikely(!pr))
895 return -EINVAL; 859 return -EINVAL;
@@ -899,16 +863,11 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
899 return drv->states[drv->safe_state_index].enter(dev, 863 return drv->states[drv->safe_state_index].enter(dev,
900 drv, drv->safe_state_index); 864 drv, drv->safe_state_index);
901 } else { 865 } else {
902 local_irq_disable();
903 acpi_safe_halt(); 866 acpi_safe_halt();
904 local_irq_enable();
905 return -EBUSY; 867 return -EBUSY;
906 } 868 }
907 } 869 }
908 870
909 local_irq_disable();
910
911
912 if (cx->entry_method != ACPI_CSTATE_FFH) { 871 if (cx->entry_method != ACPI_CSTATE_FFH) {
913 current_thread_info()->status &= ~TS_POLLING; 872 current_thread_info()->status &= ~TS_POLLING;
914 /* 873 /*
@@ -919,7 +878,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
919 878
920 if (unlikely(need_resched())) { 879 if (unlikely(need_resched())) {
921 current_thread_info()->status |= TS_POLLING; 880 current_thread_info()->status |= TS_POLLING;
922 local_irq_enable();
923 return -EINVAL; 881 return -EINVAL;
924 } 882 }
925 } 883 }
@@ -934,7 +892,6 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
934 */ 892 */
935 lapic_timer_state_broadcast(pr, cx, 1); 893 lapic_timer_state_broadcast(pr, cx, 1);
936 894
937 kt1 = ktime_get_real();
938 /* 895 /*
939 * disable bus master 896 * disable bus master
940 * bm_check implies we need ARB_DIS 897 * bm_check implies we need ARB_DIS
@@ -965,18 +922,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
965 c3_cpu_count--; 922 c3_cpu_count--;
966 raw_spin_unlock(&c3_lock); 923 raw_spin_unlock(&c3_lock);
967 } 924 }
968 kt2 = ktime_get_real();
969 idle_time_ns = ktime_to_ns(ktime_sub(kt2, kt1));
970 idle_time = idle_time_ns;
971 do_div(idle_time, NSEC_PER_USEC);
972
973 /* Update device last_residency*/
974 dev->last_residency = (int)idle_time;
975 925
976 /* Tell the scheduler how much we idled: */ 926 sched_clock_idle_wakeup_event(0);
977 sched_clock_idle_wakeup_event(idle_time_ns);
978 927
979 local_irq_enable();
980 if (cx->entry_method != ACPI_CSTATE_FFH) 928 if (cx->entry_method != ACPI_CSTATE_FFH)
981 current_thread_info()->status |= TS_POLLING; 929 current_thread_info()->status |= TS_POLLING;
982 930
@@ -987,6 +935,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
987struct cpuidle_driver acpi_idle_driver = { 935struct cpuidle_driver acpi_idle_driver = {
988 .name = "acpi_idle", 936 .name = "acpi_idle",
989 .owner = THIS_MODULE, 937 .owner = THIS_MODULE,
938 .en_core_tk_irqen = 1,
990}; 939};
991 940
992/** 941/**