Pull more ACPI and power management updates from Rafael Wysocki: "These are fixups on top of the previous PM+ACPI pull request, regression fixes (ACPI hotplug, cpufreq ppc-corenet), other bug fixes (ACPI reset, cpufreq), new PM trace points for system suspend profiling and a copyright notice update. Specifics: - I didn't remember correctly that the Hans de Goede's ACPI video patches actually didn't flip the video.use_native_backlight default, although we had discussed that and decided to do that. Since I said we would do that in the previous PM+ACPI pull request, make that change for real now. - ACPI bus check notifications for PCI host bridges don't cause the bus below the host bridge to be checked for changes as they should because of a mistake in the ACPI-based PCI hotplug (ACPIPHP) subsystem that forgets to add hotplug contexts to PCI host bridge ACPI device objects. Create hotplug contexts for PCI host bridges too as appropriate. - Revert recent cpufreq commit related to the big.LITTLE cpufreq driver that breaks arm64 builds. - Fix for a regression in the ppc-corenet cpufreq driver introduced during the 3.15 cycle and causing the driver to use the remainder from do_div instead of the quotient. From Ed Swarthout. - Resets triggered by panic activate a BUG_ON() in vmalloc.c on systems where the ACPI reset register is located in memory address space. Fix from Randy Wright. - Fix for a problem with cpufreq governors that decisions made by them may be suboptimal due to the fact that deferrable timers are used by them for CPU load sampling. From Srivatsa S Bhat. - Fix for a problem with the Tegra cpufreq driver where the CPU frequency is temporarily switched to a "stable" level that is different from both the initial and target frequencies during transitions which causes udelay() to expire earlier than it should sometimes. From Viresh Kumar. - New trace points and rework of some existing trace points for system suspend/resume profiling from Todd Brandt. - Assorted cpufreq fixes and cleanups from Stratos Karafotis and Viresh Kumar. - Copyright notice update for suspend-and-cpuhotplug.txt from Srivatsa S Bhat" * tag 'pm+acpi-3.16-rc1-2' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: ACPI / hotplug / PCI: Add hotplug contexts to PCI host bridges PM / sleep: trace events for device PM callbacks cpufreq: cpufreq-cpu0: remove dependency on THERMAL and REGULATOR cpufreq: tegra: update comment for clarity cpufreq: intel_pstate: Remove duplicate CPU ID check cpufreq: Mark CPU0 driver with CPUFREQ_NEED_INITIAL_FREQ_CHECK flag PM / Documentation: Update copyright in suspend-and-cpuhotplug.txt cpufreq: governor: remove copy_prev_load from 'struct cpu_dbs_common_info' cpufreq: governor: Be friendly towards latency-sensitive bursty workloads PM / sleep: trace events for suspend/resume cpufreq: ppc-corenet-cpu-freq: do_div use quotient Revert "cpufreq: Enable big.LITTLE cpufreq driver on arm64" cpufreq: Tegra: implement intermediate frequency callbacks cpufreq: add support for intermediate (stable) frequencies ACPI / video: Change the default for video.use_native_backlight to 1 ACPI: Fix bug when ACPI reset register is implemented in system memory
Unified · Split
| @@ -26,6 +26,7 @@ Contents: · 25 unmodified lines | ||
| 26 | 26 | 1.4 target/target_index or setpolicy? |
| 27 | 27 | 1.5 target/target_index |
| 28 | 28 | 1.6 setpolicy |
| 29 | +1.7 get_intermediate and target_intermediate | |
| 29 | 30 | 2. Frequency Table Helpers |
| 30 | 31 | |
| 31 | 32 | |
| @@ -79,6 +80,10 @@ cpufreq_driver.attr - A pointer to a NULL-terminated list of · 47 unmodified lines | ||
| 79 | 80 | "struct freq_attr" which allow to |
| 80 | 81 | export values to sysfs. |
| 81 | 82 | |
| 83 | +cpufreq_driver.get_intermediate | |
| 84 | +and target_intermediate Used to switch to stable frequency while | |
| 85 | + changing CPU frequency. | |
| 86 | + | |
| 82 | 87 | |
| 83 | 88 | 1.2 Per-CPU Initialization |
| 84 | 89 | -------------------------- |
| @@ -151,7 +156,7 @@ Some cpufreq-capable processors switch the frequency between certain · 66 unmodified lines | ||
| 151 | 156 | limits on their own. These shall use the ->setpolicy call |
| 152 | 157 | |
| 153 | 158 | |
| 154 | −1.4. target/target_index | |
| 159 | +1.5. target/target_index | |
| 155 | 160 | ------------- |
| 156 | 161 | |
| 157 | 162 | The target_index call has two arguments: struct cpufreq_policy *policy, |
| @@ -160,6 +165,9 @@ and unsigned int index (into the exposed frequency table). · 2 unmodified lines | ||
| 160 | 165 | The CPUfreq driver must set the new frequency when called here. The |
| 161 | 166 | actual frequency must be determined by freq_table[index].frequency. |
| 162 | 167 | |
| 168 | +It should always restore to earlier frequency (i.e. policy->restore_freq) in | |
| 169 | +case of errors, even if we switched to intermediate frequency earlier. | |
| 170 | + | |
| 163 | 171 | Deprecated: |
| 164 | 172 | ---------- |
| 165 | 173 | The target call has three arguments: struct cpufreq_policy *policy, |
| @@ -179,7 +187,7 @@ Here again the frequency table helper might assist you - see section 2 · 13 unmodified lines | ||
| 179 | 187 | for details. |
| 180 | 188 | |
| 181 | 189 | |
| 182 | −1.5 setpolicy | |
| 190 | +1.6 setpolicy | |
| 183 | 191 | --------------- |
| 184 | 192 | |
| 185 | 193 | The setpolicy call only takes a struct cpufreq_policy *policy as |
| @@ -190,6 +198,23 @@ setting when policy->policy is CPUFREQ_POLICY_PERFORMANCE, and a · 4 unmodified lines | ||
| 190 | 198 | powersaving-oriented setting when CPUFREQ_POLICY_POWERSAVE. Also check |
| 191 | 199 | the reference implementation in drivers/cpufreq/longrun.c |
| 192 | 200 | |
| 201 | +1.7 get_intermediate and target_intermediate | |
| 202 | +-------------------------------------------- | |
| 203 | + | |
| 204 | +Only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION unset. | |
| 205 | + | |
| 206 | +get_intermediate should return a stable intermediate frequency platform wants to | |
| 207 | +switch to, and target_intermediate() should set CPU to to that frequency, before | |
| 208 | +jumping to the frequency corresponding to 'index'. Core will take care of | |
| 209 | +sending notifications and driver doesn't have to handle them in | |
| 210 | +target_intermediate() or target_index(). | |
| 211 | + | |
| 212 | +Drivers can return '0' from get_intermediate() in case they don't wish to switch | |
| 213 | +to intermediate frequency for some target frequency. In that case core will | |
| 214 | +directly call ->target_index(). | |
| 215 | + | |
| 216 | +NOTE: ->target_index() should restore to policy->restore_freq in case of | |
| 217 | +failures as core would send notifications for that. | |
| 193 | 218 | |
| 194 | 219 | |
| 195 | 220 | 2. Frequency Table Helpers |
| @@ -1,6 +1,6 @@ | ||
| 1 | 1 | Interaction of Suspend code (S3) with the CPU hotplug infrastructure |
| 2 | 2 | |
| 3 | − (C) 2011 Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com> | |
| 3 | + (C) 2011 - 2014 Srivatsa S. Bhat <srivatsa.bhat@linux.vnet.ibm.com> | |
| 4 | 4 | |
| 5 | 5 | |
| 6 | 6 | I. How does the regular CPU hotplug code differ from how the Suspend-to-RAM |
| @@ -1810,6 +1810,16 @@ acpi_status __init acpi_os_initialize(void) · 1809 unmodified lines | ||
| 1810 | 1810 | acpi_os_map_generic_address(&acpi_gbl_FADT.xpm1b_event_block); |
| 1811 | 1811 | acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe0_block); |
| 1812 | 1812 | acpi_os_map_generic_address(&acpi_gbl_FADT.xgpe1_block); |
| 1813 | + if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) { | |
| 1814 | + /* | |
| 1815 | + * Use acpi_os_map_generic_address to pre-map the reset | |
| 1816 | + * register if it's in system memory. | |
| 1817 | + */ | |
| 1818 | + int rv; | |
| 1819 | + | |
| 1820 | + rv = acpi_os_map_generic_address(&acpi_gbl_FADT.reset_register); | |
| 1821 | + pr_debug(PREFIX "%s: map reset_reg status %d\n", __func__, rv); | |
| 1822 | + } | |
| 1813 | 1823 | |
| 1814 | 1824 | return AE_OK; |
| 1815 | 1825 | } |
| @@ -1838,6 +1848,8 @@ acpi_status acpi_os_terminate(void) · 22 unmodified lines | ||
| 1838 | 1848 | acpi_os_unmap_generic_address(&acpi_gbl_FADT.xgpe0_block); |
| 1839 | 1849 | acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1b_event_block); |
| 1840 | 1850 | acpi_os_unmap_generic_address(&acpi_gbl_FADT.xpm1a_event_block); |
| 1851 | + if (acpi_gbl_FADT.flags & ACPI_FADT_RESET_REGISTER) | |
| 1852 | + acpi_os_unmap_generic_address(&acpi_gbl_FADT.reset_register); | |
| 1841 | 1853 | |
| 1842 | 1854 | destroy_workqueue(kacpid_wq); |
| 1843 | 1855 | destroy_workqueue(kacpi_notify_wq); |
| @@ -19,6 +19,7 @@ · 18 unmodified lines | ||
| 19 | 19 | #include <linux/acpi.h> |
| 20 | 20 | #include <linux/module.h> |
| 21 | 21 | #include <asm/io.h> |
| 22 | +#include <trace/events/power.h> | |
| 22 | 23 | |
| 23 | 24 | #include "internal.h" |
| 24 | 25 | #include "sleep.h" |
| @@ -501,6 +502,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) · 476 unmodified lines | ||
| 501 | 502 | |
| 502 | 503 | ACPI_FLUSH_CPU_CACHE(); |
| 503 | 504 | |
| 505 | + trace_suspend_resume(TPS("acpi_suspend"), acpi_state, true); | |
| 504 | 506 | switch (acpi_state) { |
| 505 | 507 | case ACPI_STATE_S1: |
| 506 | 508 | barrier(); |
| @@ -516,6 +518,7 @@ static int acpi_suspend_enter(suspend_state_t pm_state) · 9 unmodified lines | ||
| 516 | 518 | pr_info(PREFIX "Low-level resume complete\n"); |
| 517 | 519 | break; |
| 518 | 520 | } |
| 521 | + trace_suspend_resume(TPS("acpi_suspend"), acpi_state, false); | |
| 519 | 522 | |
| 520 | 523 | /* This violates the spec but is required for bug compatibility. */ |
| 521 | 524 | acpi_write_bit_register(ACPI_BITREG_SCI_ENABLE, 1); |
| @@ -82,7 +82,7 @@ module_param(allow_duplicates, bool, 0644); · 81 unmodified lines | ||
| 82 | 82 | * For Windows 8 systems: used to decide if video module |
| 83 | 83 | * should skip registering backlight interface of its own. |
| 84 | 84 | */ |
| 85 | −static int use_native_backlight_param = -1; | |
| 85 | +static int use_native_backlight_param = 1; | |
| 86 | 86 | module_param_named(use_native_backlight, use_native_backlight_param, int, 0444); |
| 87 | 87 | static bool use_native_backlight_dmi = false; |
| 88 | 88 | |
| @@ -214,9 +214,6 @@ static void initcall_debug_report(struct device *dev, ktime_t calltime, · 213 unmodified lines | ||
| 214 | 214 | pr_info("call %s+ returned %d after %Ld usecs\n", dev_name(dev), |
| 215 | 215 | error, (unsigned long long)nsecs >> 10); |
| 216 | 216 | } |
| 217 | − | |
| 218 | − trace_device_pm_report_time(dev, info, nsecs, pm_verb(state.event), | |
| 219 | − error); | |
| 220 | 217 | } |
| 221 | 218 | |
| 222 | 219 | /** |
| @@ -387,7 +384,9 @@ static int dpm_run_callback(pm_callback_t cb, struct device *dev, · 164 unmodified lines | ||
| 387 | 384 | calltime = initcall_debug_start(dev); |
| 388 | 385 | |
| 389 | 386 | pm_dev_dbg(dev, state, info); |
| 387 | + trace_device_pm_callback_start(dev, info, state.event); | |
| 390 | 388 | error = cb(dev); |
| 389 | + trace_device_pm_callback_end(dev, error); | |
| 391 | 390 | suspend_report_result(cb, error); |
| 392 | 391 | |
| 393 | 392 | initcall_debug_report(dev, calltime, error, state, info); |
| @@ -545,6 +544,7 @@ static void dpm_resume_noirq(pm_message_t state) · 151 unmodified lines | ||
| 545 | 544 | struct device *dev; |
| 546 | 545 | ktime_t starttime = ktime_get(); |
| 547 | 546 | |
| 547 | + trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, true); | |
| 548 | 548 | mutex_lock(&dpm_list_mtx); |
| 549 | 549 | pm_transition = state; |
| 550 | 550 | |
| @@ -587,6 +587,7 @@ static void dpm_resume_noirq(pm_message_t state) · 36 unmodified lines | ||
| 587 | 587 | dpm_show_time(starttime, state, "noirq"); |
| 588 | 588 | resume_device_irqs(); |
| 589 | 589 | cpuidle_resume(); |
| 590 | + trace_suspend_resume(TPS("dpm_resume_noirq"), state.event, false); | |
| 590 | 591 | } |
| 591 | 592 | |
| 592 | 593 | /** |
| @@ -664,6 +665,7 @@ static void dpm_resume_early(pm_message_t state) · 71 unmodified lines | ||
| 664 | 665 | struct device *dev; |
| 665 | 666 | ktime_t starttime = ktime_get(); |
| 666 | 667 | |
| 668 | + trace_suspend_resume(TPS("dpm_resume_early"), state.event, true); | |
| 667 | 669 | mutex_lock(&dpm_list_mtx); |
| 668 | 670 | pm_transition = state; |
| 669 | 671 | |
| @@ -703,6 +705,7 @@ static void dpm_resume_early(pm_message_t state) · 33 unmodified lines | ||
| 703 | 705 | mutex_unlock(&dpm_list_mtx); |
| 704 | 706 | async_synchronize_full(); |
| 705 | 707 | dpm_show_time(starttime, state, "early"); |
| 708 | + trace_suspend_resume(TPS("dpm_resume_early"), state.event, false); | |
| 706 | 709 | } |
| 707 | 710 | |
| 708 | 711 | /** |
| @@ -834,6 +837,7 @@ void dpm_resume(pm_message_t state) · 125 unmodified lines | ||
| 834 | 837 | struct device *dev; |
| 835 | 838 | ktime_t starttime = ktime_get(); |
| 836 | 839 | |
| 840 | + trace_suspend_resume(TPS("dpm_resume"), state.event, true); | |
| 837 | 841 | might_sleep(); |
| 838 | 842 | |
| 839 | 843 | mutex_lock(&dpm_list_mtx); |
| @@ -875,6 +879,7 @@ void dpm_resume(pm_message_t state) · 35 unmodified lines | ||
| 875 | 879 | dpm_show_time(starttime, state, NULL); |
| 876 | 880 | |
| 877 | 881 | cpufreq_resume(); |
| 882 | + trace_suspend_resume(TPS("dpm_resume"), state.event, false); | |
| 878 | 883 | } |
| 879 | 884 | |
| 880 | 885 | /** |
| @@ -913,7 +918,9 @@ static void device_complete(struct device *dev, pm_message_t state) · 32 unmodified lines | ||
| 913 | 918 | |
| 914 | 919 | if (callback) { |
| 915 | 920 | pm_dev_dbg(dev, state, info); |
| 921 | + trace_device_pm_callback_start(dev, info, state.event); | |
| 916 | 922 | callback(dev); |
| 923 | + trace_device_pm_callback_end(dev, 0); | |
| 917 | 924 | } |
| 918 | 925 | |
| 919 | 926 | device_unlock(dev); |
| @@ -932,6 +939,7 @@ void dpm_complete(pm_message_t state) · 12 unmodified lines | ||
| 932 | 939 | { |
| 933 | 940 | struct list_head list; |
| 934 | 941 | |
| 942 | + trace_suspend_resume(TPS("dpm_complete"), state.event, true); | |
| 935 | 943 | might_sleep(); |
| 936 | 944 | |
| 937 | 945 | INIT_LIST_HEAD(&list); |
| @@ -951,6 +959,7 @@ void dpm_complete(pm_message_t state) · 13 unmodified lines | ||
| 951 | 959 | } |
| 952 | 960 | list_splice(&list, &dpm_list); |
| 953 | 961 | mutex_unlock(&dpm_list_mtx); |
| 962 | + trace_suspend_resume(TPS("dpm_complete"), state.event, false); | |
| 954 | 963 | } |
| 955 | 964 | |
| 956 | 965 | /** |
| @@ -1086,6 +1095,7 @@ static int dpm_suspend_noirq(pm_message_t state) · 129 unmodified lines | ||
| 1086 | 1095 | ktime_t starttime = ktime_get(); |
| 1087 | 1096 | int error = 0; |
| 1088 | 1097 | |
| 1098 | + trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, true); | |
| 1089 | 1099 | cpuidle_pause(); |
| 1090 | 1100 | suspend_device_irqs(); |
| 1091 | 1101 | mutex_lock(&dpm_list_mtx); |
| @@ -1126,6 +1136,7 @@ static int dpm_suspend_noirq(pm_message_t state) · 34 unmodified lines | ||
| 1126 | 1136 | } else { |
| 1127 | 1137 | dpm_show_time(starttime, state, "noirq"); |
| 1128 | 1138 | } |
| 1139 | + trace_suspend_resume(TPS("dpm_suspend_noirq"), state.event, false); | |
| 1129 | 1140 | return error; |
| 1130 | 1141 | } |
| 1131 | 1142 | |
| @@ -1222,6 +1233,7 @@ static int dpm_suspend_late(pm_message_t state) · 90 unmodified lines | ||
| 1222 | 1233 | ktime_t starttime = ktime_get(); |
| 1223 | 1234 | int error = 0; |
| 1224 | 1235 | |
| 1236 | + trace_suspend_resume(TPS("dpm_suspend_late"), state.event, true); | |
| 1225 | 1237 | mutex_lock(&dpm_list_mtx); |
| 1226 | 1238 | pm_transition = state; |
| 1227 | 1239 | async_error = 0; |
| @@ -1257,6 +1269,7 @@ static int dpm_suspend_late(pm_message_t state) · 29 unmodified lines | ||
| 1257 | 1269 | } else { |
| 1258 | 1270 | dpm_show_time(starttime, state, "late"); |
| 1259 | 1271 | } |
| 1272 | + trace_suspend_resume(TPS("dpm_suspend_late"), state.event, false); | |
| 1260 | 1273 | return error; |
| 1261 | 1274 | } |
| 1262 | 1275 | |
| @@ -1295,7 +1308,9 @@ static int legacy_suspend(struct device *dev, pm_message_t state, · 32 unmodified lines | ||
| 1295 | 1308 | |
| 1296 | 1309 | calltime = initcall_debug_start(dev); |
| 1297 | 1310 | |
| 1311 | + trace_device_pm_callback_start(dev, info, state.event); | |
| 1298 | 1312 | error = cb(dev, state); |
| 1313 | + trace_device_pm_callback_end(dev, error); | |
| 1299 | 1314 | suspend_report_result(cb, error); |
| 1300 | 1315 | |
| 1301 | 1316 | initcall_debug_report(dev, calltime, error, state, info); |
| @@ -1461,6 +1476,7 @@ int dpm_suspend(pm_message_t state) · 159 unmodified lines | ||
| 1461 | 1476 | ktime_t starttime = ktime_get(); |
| 1462 | 1477 | int error = 0; |
| 1463 | 1478 | |
| 1479 | + trace_suspend_resume(TPS("dpm_suspend"), state.event, true); | |
| 1464 | 1480 | might_sleep(); |
| 1465 | 1481 | |
| 1466 | 1482 | cpufreq_suspend(); |
| @@ -1498,6 +1514,7 @@ int dpm_suspend(pm_message_t state) · 31 unmodified lines | ||
| 1498 | 1514 | dpm_save_failed_step(SUSPEND_SUSPEND); |
| 1499 | 1515 | } else |
| 1500 | 1516 | dpm_show_time(starttime, state, NULL); |
| 1517 | + trace_suspend_resume(TPS("dpm_suspend"), state.event, false); | |
| 1501 | 1518 | return error; |
| 1502 | 1519 | } |
| 1503 | 1520 | |
| @@ -1549,8 +1566,11 @@ static int device_prepare(struct device *dev, pm_message_t state) · 45 unmodified lines | ||
| 1549 | 1566 | callback = dev->driver->pm->prepare; |
| 1550 | 1567 | } |
| 1551 | 1568 | |
| 1552 | − if (callback) | |
| 1569 | + if (callback) { | |
| 1570 | + trace_device_pm_callback_start(dev, info, state.event); | |
| 1553 | 1571 | ret = callback(dev); |
| 1572 | + trace_device_pm_callback_end(dev, ret); | |
| 1573 | + } | |
| 1554 | 1574 | |
| 1555 | 1575 | device_unlock(dev); |
| 1556 | 1576 | |
| @@ -1582,6 +1602,7 @@ int dpm_prepare(pm_message_t state) · 25 unmodified lines | ||
| 1582 | 1602 | { |
| 1583 | 1603 | int error = 0; |
| 1584 | 1604 | |
| 1605 | + trace_suspend_resume(TPS("dpm_prepare"), state.event, true); | |
| 1585 | 1606 | might_sleep(); |
| 1586 | 1607 | |
| 1587 | 1608 | mutex_lock(&dpm_list_mtx); |
| @@ -1612,6 +1633,7 @@ int dpm_prepare(pm_message_t state) · 24 unmodified lines | ||
| 1612 | 1633 | put_device(dev); |
| 1613 | 1634 | } |
| 1614 | 1635 | mutex_unlock(&dpm_list_mtx); |
| 1636 | + trace_suspend_resume(TPS("dpm_prepare"), state.event, false); | |
| 1615 | 1637 | return error; |
| 1616 | 1638 | } |
| 1617 | 1639 | |
| @@ -10,6 +10,7 @@ · 9 unmodified lines | ||
| 10 | 10 | #include <linux/mutex.h> |
| 11 | 11 | #include <linux/module.h> |
| 12 | 12 | #include <linux/interrupt.h> |
| 13 | +#include <trace/events/power.h> | |
| 13 | 14 | |
| 14 | 15 | static LIST_HEAD(syscore_ops_list); |
| 15 | 16 | static DEFINE_MUTEX(syscore_ops_lock); |
| @@ -49,6 +50,7 @@ int syscore_suspend(void) · 33 unmodified lines | ||
| 49 | 50 | struct syscore_ops *ops; |
| 50 | 51 | int ret = 0; |
| 51 | 52 | |
| 53 | + trace_suspend_resume(TPS("syscore_suspend"), 0, true); | |
| 52 | 54 | pr_debug("Checking wakeup interrupts\n"); |
| 53 | 55 | |
| 54 | 56 | /* Return error code if there are any wakeup interrupts pending. */ |
| @@ -70,6 +72,7 @@ int syscore_suspend(void) · 15 unmodified lines | ||
| 70 | 72 | "Interrupts enabled after %pF\n", ops->suspend); |
| 71 | 73 | } |
| 72 | 74 | |
| 75 | + trace_suspend_resume(TPS("syscore_suspend"), 0, false); | |
| 73 | 76 | return 0; |
| 74 | 77 | |
| 75 | 78 | err_out: |
| @@ -92,6 +95,7 @@ void syscore_resume(void) · 16 unmodified lines | ||
| 92 | 95 | { |
| 93 | 96 | struct syscore_ops *ops; |
| 94 | 97 | |
| 98 | + trace_suspend_resume(TPS("syscore_resume"), 0, true); | |
| 95 | 99 | WARN_ONCE(!irqs_disabled(), |
| 96 | 100 | "Interrupts enabled before system core resume.\n"); |
| 97 | 101 | |
| @@ -103,6 +107,7 @@ void syscore_resume(void) · 5 unmodified lines | ||
| 103 | 107 | WARN_ONCE(!irqs_disabled(), |
| 104 | 108 | "Interrupts enabled after %pF\n", ops->resume); |
| 105 | 109 | } |
| 110 | + trace_suspend_resume(TPS("syscore_resume"), 0, false); | |
| 106 | 111 | } |
| 107 | 112 | EXPORT_SYMBOL_GPL(syscore_resume); |
| 108 | 113 | #endif /* CONFIG_PM_SLEEP */ |
| @@ -185,7 +185,7 @@ config CPU_FREQ_GOV_CONSERVATIVE · 184 unmodified lines | ||
| 185 | 185 | |
| 186 | 186 | config GENERIC_CPUFREQ_CPU0 |
| 187 | 187 | tristate "Generic CPU0 cpufreq driver" |
| 188 | − depends on HAVE_CLK && REGULATOR && OF && THERMAL && CPU_THERMAL | |
| 188 | + depends on HAVE_CLK && OF | |
| 189 | 189 | select PM_OPP |
| 190 | 190 | help |
| 191 | 191 | This adds a generic cpufreq driver for CPU0 frequency management. |
| @@ -5,8 +5,7 @@ · 4 unmodified lines | ||
| 5 | 5 | # big LITTLE core layer and glue drivers |
| 6 | 6 | config ARM_BIG_LITTLE_CPUFREQ |
| 7 | 7 | tristate "Generic ARM big LITTLE CPUfreq driver" |
| 8 | − depends on (BIG_LITTLE && ARM_CPU_TOPOLOGY) || (ARM64 && SMP) | |
| 9 | − depends on HAVE_CLK | |
| 8 | + depends on ARM && BIG_LITTLE && ARM_CPU_TOPOLOGY && HAVE_CLK | |
| 10 | 9 | select PM_OPP |
| 11 | 10 | help |
| 12 | 11 | This enables the Generic CPUfreq driver for ARM big.LITTLE platforms. |
| @@ -104,7 +104,7 @@ static int cpu0_cpufreq_init(struct cpufreq_policy *policy) · 103 unmodified lines | ||
| 104 | 104 | } |
| 105 | 105 | |
| 106 | 106 | static struct cpufreq_driver cpu0_cpufreq_driver = { |
| 107 | − .flags = CPUFREQ_STICKY, | |
| 107 | + .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK, | |
| 108 | 108 | .verify = cpufreq_generic_frequency_table_verify, |
| 109 | 109 | .target_index = cpu0_set_target, |
| 110 | 110 | .get = cpufreq_generic_get, |
| @@ -1816,20 +1816,55 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier); · 1815 unmodified lines | ||
| 1816 | 1816 | * GOVERNORS * |
| 1817 | 1817 | *********************************************************************/ |
| 1818 | 1818 | |
| 1819 | +/* Must set freqs->new to intermediate frequency */ | |
| 1820 | +static int __target_intermediate(struct cpufreq_policy *policy, | |
| 1821 | + struct cpufreq_freqs *freqs, int index) | |
| 1822 | +{ | |
| 1823 | + int ret; | |
| 1824 | + | |
| 1825 | + freqs->new = cpufreq_driver->get_intermediate(policy, index); | |
| 1826 | + | |
| 1827 | + /* We don't need to switch to intermediate freq */ | |
| 1828 | + if (!freqs->new) | |
| 1829 | + return 0; | |
| 1830 | + | |
| 1831 | + pr_debug("%s: cpu: %d, switching to intermediate freq: oldfreq: %u, intermediate freq: %u\n", | |
| 1832 | + __func__, policy->cpu, freqs->old, freqs->new); | |
| 1833 | + | |
| 1834 | + cpufreq_freq_transition_begin(policy, freqs); | |
| 1835 | + ret = cpufreq_driver->target_intermediate(policy, index); | |
| 1836 | + cpufreq_freq_transition_end(policy, freqs, ret); | |
| 1837 | + | |
| 1838 | + if (ret) | |
| 1839 | + pr_err("%s: Failed to change to intermediate frequency: %d\n", | |
| 1840 | + __func__, ret); | |
| 1841 | + | |
| 1842 | + return ret; | |
| 1843 | +} | |
| 1844 | + | |
| 1819 | 1845 | static int __target_index(struct cpufreq_policy *policy, |
| 1820 | 1846 | struct cpufreq_frequency_table *freq_table, int index) |
| 1821 | 1847 | { |
| 1822 | − struct cpufreq_freqs freqs; | |
| 1848 | + struct cpufreq_freqs freqs = {.old = policy->cur, .flags = 0}; | |
| 1849 | + unsigned int intermediate_freq = 0; | |
| 1823 | 1850 | int retval = -EINVAL; |
| 1824 | 1851 | bool notify; |
| 1825 | 1852 | |
| 1826 | 1853 | notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION); |
| 1827 | − | |
| 1828 | 1854 | if (notify) { |
| 1829 | − freqs.old = policy->cur; | |
| 1830 | − freqs.new = freq_table[index].frequency; | |
| 1831 | − freqs.flags = 0; | |
| 1855 | + /* Handle switching to intermediate frequency */ | |
| 1856 | + if (cpufreq_driver->get_intermediate) { | |
| 1857 | + retval = __target_intermediate(policy, &freqs, index); | |
| 1858 | + if (retval) | |
| 1859 | + return retval; | |
| 1860 | + | |
| 1861 | + intermediate_freq = freqs.new; | |
| 1862 | + /* Set old freq to intermediate */ | |
| 1863 | + if (intermediate_freq) | |
| 1864 | + freqs.old = freqs.new; | |
| 1865 | + } | |
| 1832 | 1866 | |
| 1867 | + freqs.new = freq_table[index].frequency; | |
| 1833 | 1868 | pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n", |
| 1834 | 1869 | __func__, policy->cpu, freqs.old, freqs.new); |
| 1835 | 1870 | |
| @@ -1841,9 +1876,23 @@ static int __target_index(struct cpufreq_policy *policy, · 5 unmodified lines | ||
| 1841 | 1876 | pr_err("%s: Failed to change cpu frequency: %d\n", __func__, |
| 1842 | 1877 | retval); |
| 1843 | 1878 | |
| 1844 | − if (notify) | |
| 1879 | + if (notify) { | |
| 1845 | 1880 | cpufreq_freq_transition_end(policy, &freqs, retval); |
| 1846 | 1881 | |
| 1882 | + /* | |
| 1883 | + * Failed after setting to intermediate freq? Driver should have | |
| 1884 | + * reverted back to initial frequency and so should we. Check | |
| 1885 | + * here for intermediate_freq instead of get_intermediate, in | |
| 1886 | + * case we have't switched to intermediate freq at all. | |
| 1887 | + */ | |
| 1888 | + if (unlikely(retval && intermediate_freq)) { | |
| 1889 | + freqs.old = intermediate_freq; | |
| 1890 | + freqs.new = policy->restore_freq; | |
| 1891 | + cpufreq_freq_transition_begin(policy, &freqs); | |
| 1892 | + cpufreq_freq_transition_end(policy, &freqs, 0); | |
| 1893 | + } | |
| 1894 | + } | |
| 1895 | + | |
| 1847 | 1896 | return retval; |
| 1848 | 1897 | } |
| 1849 | 1898 | |
| @@ -1875,6 +1924,9 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, · 25 unmodified lines | ||
| 1875 | 1924 | if (target_freq == policy->cur) |
| 1876 | 1925 | return 0; |
| 1877 | 1926 | |
| 1927 | + /* Save last value to restore later on errors */ | |
| 1928 | + policy->restore_freq = policy->cur; | |
| 1929 | + | |
| 1878 | 1930 | if (cpufreq_driver->target) |
| 1879 | 1931 | retval = cpufreq_driver->target(policy, target_freq, relation); |
| 1880 | 1932 | else if (cpufreq_driver->target_index) { |
| @@ -2361,7 +2413,8 @@ int cpufreq_register_driver(struct cpufreq_driver *driver_data) · 480 unmodified lines | ||
| 2361 | 2413 | !(driver_data->setpolicy || driver_data->target_index || |
| 2362 | 2414 | driver_data->target) || |
| 2363 | 2415 | (driver_data->setpolicy && (driver_data->target_index || |
| 2364 | − driver_data->target))) | |
| 2416 | + driver_data->target)) || | |
| 2417 | + (!!driver_data->get_intermediate != !!driver_data->target_intermediate)) | |
| 2365 | 2418 | return -EINVAL; |
| 2366 | 2419 | |
| 2367 | 2420 | pr_debug("trying to register driver %s\n", driver_data->name); |
| @@ -36,14 +36,29 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) · 35 unmodified lines | ||
| 36 | 36 | struct od_dbs_tuners *od_tuners = dbs_data->tuners; |
| 37 | 37 | struct cs_dbs_tuners *cs_tuners = dbs_data->tuners; |
| 38 | 38 | struct cpufreq_policy *policy; |
| 39 | + unsigned int sampling_rate; | |
| 39 | 40 | unsigned int max_load = 0; |
| 40 | 41 | unsigned int ignore_nice; |
| 41 | 42 | unsigned int j; |
| 42 | 43 | |
| 43 | − if (dbs_data->cdata->governor == GOV_ONDEMAND) | |
| 44 | + if (dbs_data->cdata->governor == GOV_ONDEMAND) { | |
| 45 | + struct od_cpu_dbs_info_s *od_dbs_info = | |
| 46 | + dbs_data->cdata->get_cpu_dbs_info_s(cpu); | |
| 47 | + | |
| 48 | + /* | |
| 49 | + * Sometimes, the ondemand governor uses an additional | |
| 50 | + * multiplier to give long delays. So apply this multiplier to | |
| 51 | + * the 'sampling_rate', so as to keep the wake-up-from-idle | |
| 52 | + * detection logic a bit conservative. | |
| 53 | + */ | |
| 54 | + sampling_rate = od_tuners->sampling_rate; | |
| 55 | + sampling_rate *= od_dbs_info->rate_mult; | |
| 56 | + | |
| 44 | 57 | ignore_nice = od_tuners->ignore_nice_load; |
| 45 | − else | |
| 58 | + } else { | |
| 59 | + sampling_rate = cs_tuners->sampling_rate; | |
| 46 | 60 | ignore_nice = cs_tuners->ignore_nice_load; |
| 61 | + } | |
| 47 | 62 | |
| 48 | 63 | policy = cdbs->cur_policy; |
| 49 | 64 | |
| @@ -96,7 +111,46 @@ void dbs_check_cpu(struct dbs_data *dbs_data, int cpu) · 46 unmodified lines | ||
| 96 | 111 | if (unlikely(!wall_time || wall_time < idle_time)) |
| 97 | 112 | continue; |
| 98 | 113 | |
| 99 | − load = 100 * (wall_time - idle_time) / wall_time; | |
| 114 | + /* | |
| 115 | + * If the CPU had gone completely idle, and a task just woke up | |
| 116 | + * on this CPU now, it would be unfair to calculate 'load' the | |
| 117 | + * usual way for this elapsed time-window, because it will show | |
| 118 | + * near-zero load, irrespective of how CPU intensive that task | |
| 119 | + * actually is. This is undesirable for latency-sensitive bursty | |
| 120 | + * workloads. | |
| 121 | + * | |
| 122 | + * To avoid this, we reuse the 'load' from the previous | |
| 123 | + * time-window and give this task a chance to start with a | |
| 124 | + * reasonably high CPU frequency. (However, we shouldn't over-do | |
| 125 | + * this copy, lest we get stuck at a high load (high frequency) | |
| 126 | + * for too long, even when the current system load has actually | |
| 127 | + * dropped down. So we perform the copy only once, upon the | |
| 128 | + * first wake-up from idle.) | |
| 129 | + * | |
| 130 | + * Detecting this situation is easy: the governor's deferrable | |
| 131 | + * timer would not have fired during CPU-idle periods. Hence | |
| 132 | + * an unusually large 'wall_time' (as compared to the sampling | |
| 133 | + * rate) indicates this scenario. | |
| 134 | + * | |
| 135 | + * prev_load can be zero in two cases and we must recalculate it | |
| 136 | + * for both cases: | |
| 137 | + * - during long idle intervals | |
| 138 | + * - explicitly set to zero | |
| 139 | + */ | |
| 140 | + if (unlikely(wall_time > (2 * sampling_rate) && | |
| 141 | + j_cdbs->prev_load)) { | |
| 142 | + load = j_cdbs->prev_load; | |
| 143 | + | |
| 144 | + /* | |
| 145 | + * Perform a destructive copy, to ensure that we copy | |
| 146 | + * the previous load only once, upon the first wake-up | |
| 147 | + * from idle. | |
| 148 | + */ | |
| 149 | + j_cdbs->prev_load = 0; | |
| 150 | + } else { | |
| 151 | + load = 100 * (wall_time - idle_time) / wall_time; | |
| 152 | + j_cdbs->prev_load = load; | |
| 153 | + } | |
| 100 | 154 | |
| 101 | 155 | if (load > max_load) |
| 102 | 156 | max_load = load; |
| @@ -318,11 +372,18 @@ int cpufreq_governor_dbs(struct cpufreq_policy *policy, · 215 unmodified lines | ||
| 318 | 372 | for_each_cpu(j, policy->cpus) { |
| 319 | 373 | struct cpu_dbs_common_info *j_cdbs = |
| 320 | 374 | dbs_data->cdata->get_cpu_cdbs(j); |
| 375 | + unsigned int prev_load; | |
| 321 | 376 | |
| 322 | 377 | j_cdbs->cpu = j; |
| 323 | 378 | j_cdbs->cur_policy = policy; |
| 324 | 379 | j_cdbs->prev_cpu_idle = get_cpu_idle_time(j, |
| 325 | 380 | &j_cdbs->prev_cpu_wall, io_busy); |
| 381 | + | |
| 382 | + prev_load = (unsigned int) | |
| 383 | + (j_cdbs->prev_cpu_wall - j_cdbs->prev_cpu_idle); | |
| 384 | + j_cdbs->prev_load = 100 * prev_load / | |
| 385 | + (unsigned int) j_cdbs->prev_cpu_wall; | |
| 386 | + | |
| 326 | 387 | if (ignore_nice) |
| 327 | 388 | j_cdbs->prev_cpu_nice = |
| 328 | 389 | kcpustat_cpu(j).cpustat[CPUTIME_NICE]; |
| @@ -134,6 +134,13 @@ struct cpu_dbs_common_info { · 133 unmodified lines | ||
| 134 | 134 | u64 prev_cpu_idle; |
| 135 | 135 | u64 prev_cpu_wall; |
| 136 | 136 | u64 prev_cpu_nice; |
| 137 | + /* | |
| 138 | + * Used to keep track of load in the previous interval. However, when | |
| 139 | + * explicitly set to zero, it is used as a flag to ensure that we copy | |
| 140 | + * the previous load to the current interval only once, upon the first | |
| 141 | + * wake-up from idle. | |
| 142 | + */ | |
| 143 | + unsigned int prev_load; | |
| 137 | 144 | struct cpufreq_policy *cur_policy; |
| 138 | 145 | struct delayed_work work; |
| 139 | 146 | /* |
| @@ -691,14 +691,8 @@ MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids); · 690 unmodified lines | ||
| 691 | 691 | |
| 692 | 692 | static int intel_pstate_init_cpu(unsigned int cpunum) |
| 693 | 693 | { |
| 694 | − | |
| 695 | − const struct x86_cpu_id *id; | |
| 696 | 694 | struct cpudata *cpu; |
| 697 | 695 | |
| 698 | − id = x86_match_cpu(intel_pstate_cpu_ids); | |
| 699 | − if (!id) | |
| 700 | − return -ENODEV; | |
| 701 | − | |
| 702 | 696 | all_cpu_data[cpunum] = kzalloc(sizeof(struct cpudata), GFP_KERNEL); |
| 703 | 697 | if (!all_cpu_data[cpunum]) |
| 704 | 698 | return -ENOMEM; |
| @@ -138,7 +138,7 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy) · 137 unmodified lines | ||
| 138 | 138 | struct cpufreq_frequency_table *table; |
| 139 | 139 | struct cpu_data *data; |
| 140 | 140 | unsigned int cpu = policy->cpu; |
| 141 | − u64 transition_latency_hz; | |
| 141 | + u64 u64temp; | |
| 142 | 142 | |
| 143 | 143 | np = of_get_cpu_node(cpu, NULL); |
| 144 | 144 | if (!np) |
| @@ -206,9 +206,10 @@ static int corenet_cpufreq_cpu_init(struct cpufreq_policy *policy) · 61 unmodified lines | ||
| 206 | 206 | for_each_cpu(i, per_cpu(cpu_mask, cpu)) |
| 207 | 207 | per_cpu(cpu_data, i) = data; |
| 208 | 208 | |
| 209 | − transition_latency_hz = 12ULL * NSEC_PER_SEC; | |
| 210 | − policy->cpuinfo.transition_latency = | |
| 211 | − do_div(transition_latency_hz, fsl_get_sys_freq()); | |
| 209 | + /* Minimum transition latency is 12 platform clocks */ | |
| 210 | + u64temp = 12ULL * NSEC_PER_SEC; | |
| 211 | + do_div(u64temp, fsl_get_sys_freq()); | |
| 212 | + policy->cpuinfo.transition_latency = u64temp + 1; | |
| 212 | 213 | |
| 213 | 214 | of_node_put(np); |
| 214 | 215 | |
| @@ -45,46 +45,54 @@ static struct clk *cpu_clk; · 44 unmodified lines | ||
| 45 | 45 | static struct clk *pll_x_clk; |
| 46 | 46 | static struct clk *pll_p_clk; |
| 47 | 47 | static struct clk *emc_clk; |
| 48 | +static bool pll_x_prepared; | |
| 48 | 49 | |
| 49 | −static int tegra_cpu_clk_set_rate(unsigned long rate) | |
| 50 | +static unsigned int tegra_get_intermediate(struct cpufreq_policy *policy, | |
| 51 | + unsigned int index) | |
| 52 | +{ | |
| 53 | + unsigned int ifreq = clk_get_rate(pll_p_clk) / 1000; | |
| 54 | + | |
| 55 | + /* | |
| 56 | + * Don't switch to intermediate freq if: | |
| 57 | + * - we are already at it, i.e. policy->cur == ifreq | |
| 58 | + * - index corresponds to ifreq | |
| 59 | + */ | |
| 60 | + if ((freq_table[index].frequency == ifreq) || (policy->cur == ifreq)) | |
| 61 | + return 0; | |
| 62 | + | |
| 63 | + return ifreq; | |
| 64 | +} | |
| 65 | + | |
| 66 | +static int tegra_target_intermediate(struct cpufreq_policy *policy, | |
| 67 | + unsigned int index) | |
| 50 | 68 | { |
| 51 | 69 | int ret; |
| 52 | 70 | |
| 53 | 71 | /* |
| 54 | 72 | * Take an extra reference to the main pll so it doesn't turn |
| 55 | − * off when we move the cpu off of it | |
| 73 | + * off when we move the cpu off of it as enabling it again while we | |
| 74 | + * switch to it from tegra_target() would take additional time. | |
| 75 | + * | |
| 76 | + * When target-freq is equal to intermediate freq we don't need to | |
| 77 | + * switch to an intermediate freq and so this routine isn't called. | |
| 78 | + * Also, we wouldn't be using pll_x anymore and must not take extra | |
| 79 | + * reference to it, as it can be disabled now to save some power. | |
| 56 | 80 | */ |
| 57 | 81 | clk_prepare_enable(pll_x_clk); |
| 58 | 82 | |
| 59 | 83 | ret = clk_set_parent(cpu_clk, pll_p_clk); |
| 60 | − if (ret) { | |
| 61 | − pr_err("Failed to switch cpu to clock pll_p\n"); | |
| 62 | − goto out; | |
| 63 | − } | |
| 64 | − | |
| 65 | − if (rate == clk_get_rate(pll_p_clk)) | |
| 66 | − goto out; | |
| 67 | − | |
| 68 | − ret = clk_set_rate(pll_x_clk, rate); | |
| 69 | − if (ret) { | |
| 70 | − pr_err("Failed to change pll_x to %lu\n", rate); | |
| 71 | − goto out; | |
| 72 | − } | |
| 73 | − | |
| 74 | − ret = clk_set_parent(cpu_clk, pll_x_clk); | |
| 75 | − if (ret) { | |
| 76 | − pr_err("Failed to switch cpu to clock pll_x\n"); | |
| 77 | − goto out; | |
| 78 | − } | |
| 84 | + if (ret) | |
| 85 | + clk_disable_unprepare(pll_x_clk); | |
| 86 | + else | |
| 87 | + pll_x_prepared = true; | |
| 79 | 88 | |
| 80 | −out: | |
| 81 | − clk_disable_unprepare(pll_x_clk); | |
| 82 | 89 | return ret; |
| 83 | 90 | } |
| 84 | 91 | |
| 85 | 92 | static int tegra_target(struct cpufreq_policy *policy, unsigned int index) |
| 86 | 93 | { |
| 87 | 94 | unsigned long rate = freq_table[index].frequency; |
| 95 | + unsigned int ifreq = clk_get_rate(pll_p_clk) / 1000; | |
| 88 | 96 | int ret = 0; |
| 89 | 97 | |
| 90 | 98 | /* |
| @@ -98,10 +106,30 @@ static int tegra_target(struct cpufreq_policy *policy, unsigned int index) · 7 unmodified lines | ||
| 98 | 106 | else |
| 99 | 107 | clk_set_rate(emc_clk, 100000000); /* emc 50Mhz */ |
| 100 | 108 | |
| 101 | − ret = tegra_cpu_clk_set_rate(rate * 1000); | |
| 109 | + /* | |
| 110 | + * target freq == pll_p, don't need to take extra reference to pll_x_clk | |
| 111 | + * as it isn't used anymore. | |
| 112 | + */ | |
| 113 | + if (rate == ifreq) | |
| 114 | + return clk_set_parent(cpu_clk, pll_p_clk); | |
| 115 | + | |
| 116 | + ret = clk_set_rate(pll_x_clk, rate * 1000); | |
| 117 | + /* Restore to earlier frequency on error, i.e. pll_x */ | |
| 102 | 118 | if (ret) |
| 103 | − pr_err("cpu-tegra: Failed to set cpu frequency to %lu kHz\n", | |
| 104 | − rate); | |
| 119 | + pr_err("Failed to change pll_x to %lu\n", rate); | |
| 120 | + | |
| 121 | + ret = clk_set_parent(cpu_clk, pll_x_clk); | |
| 122 | + /* This shouldn't fail while changing or restoring */ | |
| 123 | + WARN_ON(ret); | |
| 124 | + | |
| 125 | + /* | |
| 126 | + * Drop count to pll_x clock only if we switched to intermediate freq | |
| 127 | + * earlier while transitioning to a target frequency. | |
| 128 | + */ | |
| 129 | + if (pll_x_prepared) { | |
| 130 | + clk_disable_unprepare(pll_x_clk); | |
| 131 | + pll_x_prepared = false; | |
| 132 | + } | |
| 105 | 133 | |
| 106 | 134 | return ret; |
| 107 | 135 | } |
| @@ -137,16 +165,18 @@ static int tegra_cpu_exit(struct cpufreq_policy *policy) · 29 unmodified lines | ||
| 137 | 165 | } |
| 138 | 166 | |
| 139 | 167 | static struct cpufreq_driver tegra_cpufreq_driver = { |
| 140 | − .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, | |
| 141 | − .verify = cpufreq_generic_frequency_table_verify, | |
| 142 | − .target_index = tegra_target, | |
| 143 | − .get = cpufreq_generic_get, | |
| 144 | − .init = tegra_cpu_init, | |
| 145 | − .exit = tegra_cpu_exit, | |
| 146 | − .name = "tegra", | |
| 147 | − .attr = cpufreq_generic_attr, | |
| 168 | + .flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK, | |
| 169 | + .verify = cpufreq_generic_frequency_table_verify, | |
| 170 | + .get_intermediate = tegra_get_intermediate, | |
| 171 | + .target_intermediate = tegra_target_intermediate, | |
| 172 | + .target_index = tegra_target, | |
| 173 | + .get = cpufreq_generic_get, | |
| 174 | + .init = tegra_cpu_init, | |
| 175 | + .exit = tegra_cpu_exit, | |
| 176 | + .name = "tegra", | |
| 177 | + .attr = cpufreq_generic_attr, | |
| 148 | 178 | #ifdef CONFIG_PM |
| 149 | − .suspend = cpufreq_generic_suspend, | |
| 179 | + .suspend = cpufreq_generic_suspend, | |
| 150 | 180 | #endif |
| 151 | 181 | }; |
| 152 | 182 | |
| @@ -142,6 +142,16 @@ static inline acpi_handle func_to_handle(struct acpiphp_func *func) · 141 unmodified lines | ||
| 142 | 142 | return func_to_acpi_device(func)->handle; |
| 143 | 143 | } |
| 144 | 144 | |
| 145 | +struct acpiphp_root_context { | |
| 146 | + struct acpi_hotplug_context hp; | |
| 147 | + struct acpiphp_bridge *root_bridge; | |
| 148 | +}; | |
| 149 | + | |
| 150 | +static inline struct acpiphp_root_context *to_acpiphp_root_context(struct acpi_hotplug_context *hp) | |
| 151 | +{ | |
| 152 | + return container_of(hp, struct acpiphp_root_context, hp); | |
| 153 | +} | |
| 154 | + | |
| 145 | 155 | /* |
| 146 | 156 | * struct acpiphp_attention_info - device specific attention registration |
| 147 | 157 | * |
| @@ -373,17 +373,13 @@ static acpi_status acpiphp_add_context(acpi_handle handle, u32 lvl, void *data, · 372 unmodified lines | ||
| 373 | 373 | |
| 374 | 374 | static struct acpiphp_bridge *acpiphp_dev_to_bridge(struct acpi_device *adev) |
| 375 | 375 | { |
| 376 | − struct acpiphp_context *context; | |
| 377 | 376 | struct acpiphp_bridge *bridge = NULL; |
| 378 | 377 | |
| 379 | 378 | acpi_lock_hp_context(); |
| 380 | − context = acpiphp_get_context(adev); | |
| 381 | − if (context) { | |
| 382 | − bridge = context->bridge; | |
| 379 | + if (adev->hp) { | |
| 380 | + bridge = to_acpiphp_root_context(adev->hp)->root_bridge; | |
| 383 | 381 | if (bridge) |
| 384 | 382 | get_bridge(bridge); |
| 385 | − | |
| 386 | − acpiphp_put_context(context); | |
| 387 | 383 | } |
| 388 | 384 | acpi_unlock_hp_context(); |
| 389 | 385 | return bridge; |
| @@ -881,7 +877,17 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) · 491 unmodified lines | ||
| 881 | 877 | */ |
| 882 | 878 | get_device(&bus->dev); |
| 883 | 879 | |
| 884 | − if (!pci_is_root_bus(bridge->pci_bus)) { | |
| 880 | + acpi_lock_hp_context(); | |
| 881 | + if (pci_is_root_bus(bridge->pci_bus)) { | |
| 882 | + struct acpiphp_root_context *root_context; | |
| 883 | + | |
| 884 | + root_context = kzalloc(sizeof(*root_context), GFP_KERNEL); | |
| 885 | + if (!root_context) | |
| 886 | + goto err; | |
| 887 | + | |
| 888 | + root_context->root_bridge = bridge; | |
| 889 | + acpi_set_hp_context(adev, &root_context->hp, NULL, NULL, NULL); | |
| 890 | + } else { | |
| 885 | 891 | struct acpiphp_context *context; |
| 886 | 892 | |
| 887 | 893 | /* |
| @@ -890,21 +896,16 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) · 2 unmodified lines | ||
| 890 | 896 | * parent is going to be handled by pciehp, in which case this |
| 891 | 897 | * bridge is not interesting to us either. |
| 892 | 898 | */ |
| 893 | − acpi_lock_hp_context(); | |
| 894 | 899 | context = acpiphp_get_context(adev); |
| 895 | − if (!context) { | |
| 896 | − acpi_unlock_hp_context(); | |
| 897 | − put_device(&bus->dev); | |
| 898 | − pci_dev_put(bridge->pci_dev); | |
| 899 | − kfree(bridge); | |
| 900 | − return; | |
| 901 | − } | |
| 900 | + if (!context) | |
| 901 | + goto err; | |
| 902 | + | |
| 902 | 903 | bridge->context = context; |
| 903 | 904 | context->bridge = bridge; |
| 904 | 905 | /* Get a reference to the parent bridge. */ |
| 905 | 906 | get_bridge(context->func.parent); |
| 906 | − acpi_unlock_hp_context(); | |
| 907 | 907 | } |
| 908 | + acpi_unlock_hp_context(); | |
| 908 | 909 | |
| 909 | 910 | /* Must be added to the list prior to calling acpiphp_add_context(). */ |
| 910 | 911 | mutex_lock(&bridge_mutex); |
| @@ -919,6 +920,30 @@ void acpiphp_enumerate_slots(struct pci_bus *bus) · 8 unmodified lines | ||
| 919 | 920 | cleanup_bridge(bridge); |
| 920 | 921 | put_bridge(bridge); |
| 921 | 922 | } |
| 923 | + return; | |
| 924 | + | |
| 925 | + err: | |
| 926 | + acpi_unlock_hp_context(); | |
| 927 | + put_device(&bus->dev); | |
| 928 | + pci_dev_put(bridge->pci_dev); | |
| 929 | + kfree(bridge); | |
| 930 | +} | |
| 931 | + | |
| 932 | +void acpiphp_drop_bridge(struct acpiphp_bridge *bridge) | |
| 933 | +{ | |
| 934 | + if (pci_is_root_bus(bridge->pci_bus)) { | |
| 935 | + struct acpiphp_root_context *root_context; | |
| 936 | + struct acpi_device *adev; | |
| 937 | + | |
| 938 | + acpi_lock_hp_context(); | |
| 939 | + adev = ACPI_COMPANION(bridge->pci_bus->bridge); | |
| 940 | + root_context = to_acpiphp_root_context(adev->hp); | |
| 941 | + adev->hp = NULL; | |
| 942 | + acpi_unlock_hp_context(); | |
| 943 | + kfree(root_context); | |
| 944 | + } | |
| 945 | + cleanup_bridge(bridge); | |
| 946 | + put_bridge(bridge); | |
| 922 | 947 | } |
| 923 | 948 | |
| 924 | 949 | /** |
| @@ -936,8 +961,7 @@ void acpiphp_remove_slots(struct pci_bus *bus) · 11 unmodified lines | ||
| 936 | 961 | list_for_each_entry(bridge, &bridge_list, list) |
| 937 | 962 | if (bridge->pci_bus == bus) { |
| 938 | 963 | mutex_unlock(&bridge_mutex); |
| 939 | − cleanup_bridge(bridge); | |
| 940 | − put_bridge(bridge); | |
| 964 | + acpiphp_drop_bridge(bridge); | |
| 941 | 965 | return; |
| 942 | 966 | } |
| 943 | 967 | |
| @@ -75,6 +75,7 @@ struct cpufreq_policy { · 74 unmodified lines | ||
| 75 | 75 | unsigned int max; /* in kHz */ |
| 76 | 76 | unsigned int cur; /* in kHz, only needed if cpufreq |
| 77 | 77 | * governors are used */ |
| 78 | + unsigned int restore_freq; /* = policy->cur before transition */ | |
| 78 | 79 | unsigned int suspend_freq; /* freq to set during suspend */ |
| 79 | 80 | |
| 80 | 81 | unsigned int policy; /* see above */ |
| @@ -221,11 +222,35 @@ struct cpufreq_driver { · 140 unmodified lines | ||
| 221 | 222 | |
| 222 | 223 | /* define one out of two */ |
| 223 | 224 | int (*setpolicy) (struct cpufreq_policy *policy); |
| 225 | + | |
| 226 | + /* | |
| 227 | + * On failure, should always restore frequency to policy->restore_freq | |
| 228 | + * (i.e. old freq). | |
| 229 | + */ | |
| 224 | 230 | int (*target) (struct cpufreq_policy *policy, /* Deprecated */ |
| 225 | 231 | unsigned int target_freq, |
| 226 | 232 | unsigned int relation); |
| 227 | 233 | int (*target_index) (struct cpufreq_policy *policy, |
| 228 | 234 | unsigned int index); |
| 235 | + /* | |
| 236 | + * Only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION | |
| 237 | + * unset. | |
| 238 | + * | |
| 239 | + * get_intermediate should return a stable intermediate frequency | |
| 240 | + * platform wants to switch to and target_intermediate() should set CPU | |
| 241 | + * to to that frequency, before jumping to the frequency corresponding | |
| 242 | + * to 'index'. Core will take care of sending notifications and driver | |
| 243 | + * doesn't have to handle them in target_intermediate() or | |
| 244 | + * target_index(). | |
| 245 | + * | |
| 246 | + * Drivers can return '0' from get_intermediate() in case they don't | |
| 247 | + * wish to switch to intermediate frequency for some target frequency. | |
| 248 | + * In that case core will directly call ->target_index(). | |
| 249 | + */ | |
| 250 | + unsigned int (*get_intermediate)(struct cpufreq_policy *policy, | |
| 251 | + unsigned int index); | |
| 252 | + int (*target_intermediate)(struct cpufreq_policy *policy, | |
| 253 | + unsigned int index); | |
| 229 | 254 | |
| 230 | 255 | /* should be defined, if possible */ |
| 231 | 256 | unsigned int (*get) (unsigned int cpu); |
| @@ -7,6 +7,9 @@ · 6 unmodified lines | ||
| 7 | 7 | #include <linux/ktime.h> |
| 8 | 8 | #include <linux/pm_qos.h> |
| 9 | 9 | #include <linux/tracepoint.h> |
| 10 | +#include <linux/ftrace_event.h> | |
| 11 | + | |
| 12 | +#define TPS(x) tracepoint_string(x) | |
| 10 | 13 | |
| 11 | 14 | DECLARE_EVENT_CLASS(cpu, |
| 12 | 15 | |
| @@ -90,6 +93,17 @@ TRACE_EVENT(pstate_sample, · 77 unmodified lines | ||
| 90 | 93 | #define PWR_EVENT_EXIT -1 |
| 91 | 94 | #endif |
| 92 | 95 | |
| 96 | +#define pm_verb_symbolic(event) \ | |
| 97 | + __print_symbolic(event, \ | |
| 98 | + { PM_EVENT_SUSPEND, "suspend" }, \ | |
| 99 | + { PM_EVENT_RESUME, "resume" }, \ | |
| 100 | + { PM_EVENT_FREEZE, "freeze" }, \ | |
| 101 | + { PM_EVENT_QUIESCE, "quiesce" }, \ | |
| 102 | + { PM_EVENT_HIBERNATE, "hibernate" }, \ | |
| 103 | + { PM_EVENT_THAW, "thaw" }, \ | |
| 104 | + { PM_EVENT_RESTORE, "restore" }, \ | |
| 105 | + { PM_EVENT_RECOVER, "recover" }) | |
| 106 | + | |
| 93 | 107 | DEFINE_EVENT(cpu, cpu_frequency, |
| 94 | 108 | |
| 95 | 109 | TP_PROTO(unsigned int frequency, unsigned int cpu_id), |
| @@ -97,58 +111,76 @@ DEFINE_EVENT(cpu, cpu_frequency, · 1 unmodified line | ||
| 97 | 111 | TP_ARGS(frequency, cpu_id) |
| 98 | 112 | ); |
| 99 | 113 | |
| 100 | −TRACE_EVENT(machine_suspend, | |
| 114 | +TRACE_EVENT(device_pm_callback_start, | |
| 101 | 115 | |
| 102 | − TP_PROTO(unsigned int state), | |
| 116 | + TP_PROTO(struct device *dev, const char *pm_ops, int event), | |
| 103 | 117 | |
| 104 | − TP_ARGS(state), | |
| 118 | + TP_ARGS(dev, pm_ops, event), | |
| 105 | 119 | |
| 106 | 120 | TP_STRUCT__entry( |
| 107 | − __field( u32, state ) | |
| 121 | + __string(device, dev_name(dev)) | |
| 122 | + __string(driver, dev_driver_string(dev)) | |
| 123 | + __string(parent, dev->parent ? dev_name(dev->parent) : "none") | |
| 124 | + __string(pm_ops, pm_ops ? pm_ops : "none ") | |
| 125 | + __field(int, event) | |
| 108 | 126 | ), |
| 109 | 127 | |
| 110 | 128 | TP_fast_assign( |
| 111 | − __entry->state = state; | |
| 129 | + __assign_str(device, dev_name(dev)); | |
| 130 | + __assign_str(driver, dev_driver_string(dev)); | |
| 131 | + __assign_str(parent, | |
| 132 | + dev->parent ? dev_name(dev->parent) : "none"); | |
| 133 | + __assign_str(pm_ops, pm_ops ? pm_ops : "none "); | |
| 134 | + __entry->event = event; | |
| 112 | 135 | ), |
| 113 | 136 | |
| 114 | − TP_printk("state=%lu", (unsigned long)__entry->state) | |
| 137 | + TP_printk("%s %s, parent: %s, %s[%s]", __get_str(driver), | |
| 138 | + __get_str(device), __get_str(parent), __get_str(pm_ops), | |
| 139 | + pm_verb_symbolic(__entry->event)) | |
| 115 | 140 | ); |
| 116 | 141 | |
| 117 | −TRACE_EVENT(device_pm_report_time, | |
| 142 | +TRACE_EVENT(device_pm_callback_end, | |
| 118 | 143 | |
| 119 | − TP_PROTO(struct device *dev, const char *pm_ops, s64 ops_time, | |
| 120 | − char *pm_event_str, int error), | |
| 144 | + TP_PROTO(struct device *dev, int error), | |
| 121 | 145 | |
| 122 | − TP_ARGS(dev, pm_ops, ops_time, pm_event_str, error), | |
| 146 | + TP_ARGS(dev, error), | |
| 123 | 147 | |
| 124 | 148 | TP_STRUCT__entry( |
| 125 | 149 | __string(device, dev_name(dev)) |
| 126 | 150 | __string(driver, dev_driver_string(dev)) |
| 127 | − __string(parent, dev->parent ? dev_name(dev->parent) : "none") | |
| 128 | − __string(pm_ops, pm_ops ? pm_ops : "none ") | |
| 129 | − __string(pm_event_str, pm_event_str) | |
| 130 | − __field(s64, ops_time) | |
| 131 | 151 | __field(int, error) |
| 132 | 152 | ), |
| 133 | 153 | |
| 134 | 154 | TP_fast_assign( |
| 135 | − const char *tmp = dev->parent ? dev_name(dev->parent) : "none"; | |
| 136 | − const char *tmp_i = pm_ops ? pm_ops : "none "; | |
| 137 | − | |
| 138 | 155 | __assign_str(device, dev_name(dev)); |
| 139 | 156 | __assign_str(driver, dev_driver_string(dev)); |
| 140 | − __assign_str(parent, tmp); | |
| 141 | − __assign_str(pm_ops, tmp_i); | |
| 142 | − __assign_str(pm_event_str, pm_event_str); | |
| 143 | − __entry->ops_time = ops_time; | |
| 144 | 157 | __entry->error = error; |
| 145 | 158 | ), |
| 146 | 159 | |
| 147 | − /* ops_str has an extra space at the end */ | |
| 148 | − TP_printk("%s %s parent=%s state=%s ops=%snsecs=%lld err=%d", | |
| 149 | − __get_str(driver), __get_str(device), __get_str(parent), | |
| 150 | − __get_str(pm_event_str), __get_str(pm_ops), | |
| 151 | − __entry->ops_time, __entry->error) | |
| 160 | + TP_printk("%s %s, err=%d", | |
| 161 | + __get_str(driver), __get_str(device), __entry->error) | |
| 162 | +); | |
| 163 | + | |
| 164 | +TRACE_EVENT(suspend_resume, | |
| 165 | + | |
| 166 | + TP_PROTO(const char *action, int val, bool start), | |
| 167 | + | |
| 168 | + TP_ARGS(action, val, start), | |
| 169 | + | |
| 170 | + TP_STRUCT__entry( | |
| 171 | + __field(const char *, action) | |
| 172 | + __field(int, val) | |
| 173 | + __field(bool, start) | |
| 174 | + ), | |
| 175 | + | |
| 176 | + TP_fast_assign( | |
| 177 | + __entry->action = action; | |
| 178 | + __entry->val = val; | |
| 179 | + __entry->start = start; | |
| 180 | + ), | |
| 181 | + | |
| 182 | + TP_printk("%s[%u] %s", __entry->action, (unsigned int)__entry->val, | |
| 183 | + (__entry->start)?"begin":"end") | |
| 152 | 184 | ); |
| 153 | 185 | |
| 154 | 186 | DECLARE_EVENT_CLASS(wakeup_source, |
| @@ -20,6 +20,7 @@ · 19 unmodified lines | ||
| 20 | 20 | #include <linux/gfp.h> |
| 21 | 21 | #include <linux/suspend.h> |
| 22 | 22 | #include <linux/lockdep.h> |
| 23 | +#include <trace/events/power.h> | |
| 23 | 24 | |
| 24 | 25 | #include "smpboot.h" |
| 25 | 26 | |
| @@ -520,7 +521,9 @@ int disable_nonboot_cpus(void) · 494 unmodified lines | ||
| 520 | 521 | for_each_online_cpu(cpu) { |
| 521 | 522 | if (cpu == first_cpu) |
| 522 | 523 | continue; |
| 524 | + trace_suspend_resume(TPS("CPU_OFF"), cpu, true); | |
| 523 | 525 | error = _cpu_down(cpu, 1); |
| 526 | + trace_suspend_resume(TPS("CPU_OFF"), cpu, false); | |
| 524 | 527 | if (!error) |
| 525 | 528 | cpumask_set_cpu(cpu, frozen_cpus); |
| 526 | 529 | else { |
| @@ -563,7 +566,9 @@ void __ref enable_nonboot_cpus(void) · 36 unmodified lines | ||
| 563 | 566 | arch_enable_nonboot_cpus_begin(); |
| 564 | 567 | |
| 565 | 568 | for_each_cpu(cpu, frozen_cpus) { |
| 569 | + trace_suspend_resume(TPS("CPU_ON"), cpu, true); | |
| 566 | 570 | error = _cpu_up(cpu, 1); |
| 571 | + trace_suspend_resume(TPS("CPU_ON"), cpu, false); | |
| 567 | 572 | if (!error) { |
| 568 | 573 | pr_info("CPU%d is up\n", cpu); |
| 569 | 574 | continue; |
| @@ -28,6 +28,7 @@ · 27 unmodified lines | ||
| 28 | 28 | #include <linux/syscore_ops.h> |
| 29 | 29 | #include <linux/ctype.h> |
| 30 | 30 | #include <linux/genhd.h> |
| 31 | +#include <trace/events/power.h> | |
| 31 | 32 | |
| 32 | 33 | #include "power.h" |
| 33 | 34 | |
| @@ -292,7 +293,9 @@ static int create_image(int platform_mode) · 258 unmodified lines | ||
| 292 | 293 | |
| 293 | 294 | in_suspend = 1; |
| 294 | 295 | save_processor_state(); |
| 296 | + trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, true); | |
| 295 | 297 | error = swsusp_arch_suspend(); |
| 298 | + trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, false); | |
| 296 | 299 | if (error) |
| 297 | 300 | printk(KERN_ERR "PM: Error %d creating hibernation image\n", |
| 298 | 301 | error); |
| @@ -17,6 +17,7 @@ · 16 unmodified lines | ||
| 17 | 17 | #include <linux/delay.h> |
| 18 | 18 | #include <linux/workqueue.h> |
| 19 | 19 | #include <linux/kmod.h> |
| 20 | +#include <trace/events/power.h> | |
| 20 | 21 | |
| 21 | 22 | /* |
| 22 | 23 | * Timeout for stopping processes |
| @@ -175,6 +176,7 @@ void thaw_processes(void) · 152 unmodified lines | ||
| 175 | 176 | struct task_struct *g, *p; |
| 176 | 177 | struct task_struct *curr = current; |
| 177 | 178 | |
| 179 | + trace_suspend_resume(TPS("thaw_processes"), 0, true); | |
| 178 | 180 | if (pm_freezing) |
| 179 | 181 | atomic_dec(&system_freezing_cnt); |
| 180 | 182 | pm_freezing = false; |
| @@ -201,6 +203,7 @@ void thaw_processes(void) · 20 unmodified lines | ||
| 201 | 203 | |
| 202 | 204 | schedule(); |
| 203 | 205 | printk("done.\n"); |
| 206 | + trace_suspend_resume(TPS("thaw_processes"), 0, false); | |
| 204 | 207 | } |
| 205 | 208 | |
| 206 | 209 | void thaw_kernel_threads(void) |
| @@ -177,7 +177,9 @@ static int suspend_prepare(suspend_state_t state) · 176 unmodified lines | ||
| 177 | 177 | if (error) |
| 178 | 178 | goto Finish; |
| 179 | 179 | |
| 180 | + trace_suspend_resume(TPS("freeze_processes"), 0, true); | |
| 180 | 181 | error = suspend_freeze_processes(); |
| 182 | + trace_suspend_resume(TPS("freeze_processes"), 0, false); | |
| 181 | 183 | if (!error) |
| 182 | 184 | return 0; |
| 183 | 185 | |
| @@ -240,7 +242,9 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) · 56 unmodified lines | ||
| 240 | 242 | * all the devices are suspended. |
| 241 | 243 | */ |
| 242 | 244 | if (state == PM_SUSPEND_FREEZE) { |
| 245 | + trace_suspend_resume(TPS("machine_suspend"), state, true); | |
| 243 | 246 | freeze_enter(); |
| 247 | + trace_suspend_resume(TPS("machine_suspend"), state, false); | |
| 244 | 248 | goto Platform_wake; |
| 245 | 249 | } |
| 246 | 250 | |
| @@ -256,7 +260,11 @@ static int suspend_enter(suspend_state_t state, bool *wakeup) · 9 unmodified lines | ||
| 256 | 260 | if (!error) { |
| 257 | 261 | *wakeup = pm_wakeup_pending(); |
| 258 | 262 | if (!(suspend_test(TEST_CORE) || *wakeup)) { |
| 263 | + trace_suspend_resume(TPS("machine_suspend"), | |
| 264 | + state, true); | |
| 259 | 265 | error = suspend_ops->enter(state); |
| 266 | + trace_suspend_resume(TPS("machine_suspend"), | |
| 267 | + state, false); | |
| 260 | 268 | events_check_enabled = false; |
| 261 | 269 | } |
| 262 | 270 | syscore_resume(); |
| @@ -294,7 +302,6 @@ int suspend_devices_and_enter(suspend_state_t state) · 31 unmodified lines | ||
| 294 | 302 | if (need_suspend_ops(state) && !suspend_ops) |
| 295 | 303 | return -ENOSYS; |
| 296 | 304 | |
| 297 | − trace_machine_suspend(state); | |
| 298 | 305 | if (need_suspend_ops(state) && suspend_ops->begin) { |
| 299 | 306 | error = suspend_ops->begin(state); |
| 300 | 307 | if (error) |
| @@ -331,7 +338,6 @@ int suspend_devices_and_enter(suspend_state_t state) · 30 unmodified lines | ||
| 331 | 338 | else if (state == PM_SUSPEND_FREEZE && freeze_ops->end) |
| 332 | 339 | freeze_ops->end(); |
| 333 | 340 | |
| 334 | − trace_machine_suspend(PWR_EVENT_EXIT); | |
| 335 | 341 | return error; |
| 336 | 342 | |
| 337 | 343 | Recover_platform: |
| @@ -365,6 +371,7 @@ static int enter_state(suspend_state_t state) · 27 unmodified lines | ||
| 365 | 371 | { |
| 366 | 372 | int error; |
| 367 | 373 | |
| 374 | + trace_suspend_resume(TPS("suspend_enter"), state, true); | |
| 368 | 375 | if (state == PM_SUSPEND_FREEZE) { |
| 369 | 376 | #ifdef CONFIG_PM_DEBUG |
| 370 | 377 | if (pm_test_level != TEST_NONE && pm_test_level <= TEST_CPUS) { |
| @@ -382,9 +389,11 @@ static int enter_state(suspend_state_t state) · 11 unmodified lines | ||
| 382 | 389 | if (state == PM_SUSPEND_FREEZE) |
| 383 | 390 | freeze_begin(); |
| 384 | 391 | |
| 392 | + trace_suspend_resume(TPS("sync_filesystems"), 0, true); | |
| 385 | 393 | printk(KERN_INFO "PM: Syncing filesystems ... "); |
| 386 | 394 | sys_sync(); |
| 387 | 395 | printk("done.\n"); |
| 396 | + trace_suspend_resume(TPS("sync_filesystems"), 0, false); | |
| 388 | 397 | |
| 389 | 398 | pr_debug("PM: Preparing system for %s sleep\n", pm_states[state].label); |
| 390 | 399 | error = suspend_prepare(state); |
| @@ -394,6 +403,7 @@ static int enter_state(suspend_state_t state) · 3 unmodified lines | ||
| 394 | 403 | if (suspend_test(TEST_FREEZER)) |
| 395 | 404 | goto Finish; |
| 396 | 405 | |
| 406 | + trace_suspend_resume(TPS("suspend_enter"), state, false); | |
| 397 | 407 | pr_debug("PM: Entering %s sleep\n", pm_states[state].label); |
| 398 | 408 | pm_restrict_gfp_mask(); |
| 399 | 409 | error = suspend_devices_and_enter(state); |