History

Merge tag 'pm-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm

Pull power management updates from Rafael Wysocki: "Again, the majority of changes go into the cpufreq subsystem, but there are no big features this time. The cpufreq changes that stand out somewhat are the governor interface rework and improvements related to the handling of frequency tables. Apart from those, there are fixes and new device/CPU IDs in drivers, cleanups and an improvement of the new schedutil governor. Next, there are some changes in the hibernation core, including a fix for a nasty problem related to the MONITOR/MWAIT usage by CPU offline during resume from hibernation, a few core improvements related to memory management during resume, a couple of additional debug features and cleanups. Finally, we have some fixes and cleanups in the devfreq subsystem, generic power domains framework improvements related to system suspend/resume, support for some new chips in intel_idle and in the power capping RAPL driver, a new version of the AnalyzeSuspend utility and some assorted fixes and cleanups. Specifics: - Rework the cpufreq governor interface to make it more straightforward and modify the conservative governor to avoid using transition notifications (Rafael Wysocki). - Rework the handling of frequency tables by the cpufreq core to make it more efficient (Viresh Kumar). - Modify the schedutil governor to reduce the number of wakeups it causes to occur in cases when the CPU frequency doesn't need to be changed (Steve Muckle, Viresh Kumar). - Fix some minor issues and clean up code in the cpufreq core and governors (Rafael Wysocki, Viresh Kumar). - Add Intel Broxton support to the intel_pstate driver (Srinivas Pandruvada). - Fix problems related to the config TDP feature and to the validity of the MSR_HWP_INTERRUPT register in intel_pstate (Jan Kiszka, Srinivas Pandruvada). - Make intel_pstate update the cpu_frequency tracepoint even if the frequency doesn't change to avoid confusing powertop (Rafael Wysocki). - Clean up the usage of __init/__initdata in intel_pstate, mark some of its internal variables as __read_mostly and drop an unused structure element from it (Jisheng Zhang, Carsten Emde). - Clean up the usage of some duplicate MSR symbols in intel_pstate and turbostat (Srinivas Pandruvada). - Update/fix the powernv, s3c24xx and mvebu cpufreq drivers (Akshay Adiga, Viresh Kumar, Ben Dooks). - Fix a regression (introduced during the 4.5 cycle) in the pcc-cpufreq driver by reverting the problematic commit (Andreas Herrmann). - Add support for Intel Denverton to intel_idle, clean up Broxton support in it and make it explicitly non-modular (Jacob Pan, Jan Beulich, Paul Gortmaker). - Add support for Denverton and Ivy Bridge server to the Intel RAPL power capping driver and make it more careful about the handing of MSRs that may not be present (Jacob Pan, Xiaolong Wang). - Fix resume from hibernation on x86-64 by making the CPU offline during resume avoid using MONITOR/MWAIT in the "play dead" loop which may lead to an inadvertent "revival" of a "dead" CPU and a page fault leading to a kernel crash from it (Rafael Wysocki). - Make memory management during resume from hibernation more straightforward (Rafael Wysocki). - Add debug features that should help to detect problems related to hibernation and resume from it (Rafael Wysocki, Chen Yu). - Clean up hibernation core somewhat (Rafael Wysocki). - Prevent KASAN from instrumenting the hibernation core which leads to large numbers of false-positives from it (James Morse). - Prevent PM (hibernate and suspend) notifiers from being called during the cleanup phase if they have not been called during the corresponding preparation phase which is possible if one of the other notifiers returns an error at that time (Lianwei Wang). - Improve suspend-related debug printout in the tasks freezer and clean up suspend-related console handling (Roger Lu, Borislav Petkov). - Update the AnalyzeSuspend script in the kernel sources to version 4.2 (Todd Brandt). - Modify the generic power domains framework to make it handle system suspend/resume better (Ulf Hansson). - Make the runtime PM framework avoid resuming devices synchronously when user space changes the runtime PM settings for them and improve its error reporting (Rafael Wysocki, Linus Walleij). - Fix error paths in devfreq drivers (exynos, exynos-ppmu, exynos-bus) and in the core, make some devfreq code explicitly non-modular and change some of it into tristate (Bartlomiej Zolnierkiewicz, Peter Chen, Paul Gortmaker). - Add DT support to the generic PM clocks management code and make it export some more symbols (Jon Hunter, Paul Gortmaker). - Make the PCI PM core code slightly more robust against possible driver errors (Andy Shevchenko). - Make it possible to change DESTDIR and PREFIX in turbostat (Andy Shevchenko)" * tag 'pm-4.8-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (89 commits) Revert "cpufreq: pcc-cpufreq: update default value of cpuinfo_transition_latency" PM / hibernate: Introduce test_resume mode for hibernation cpufreq: export cpufreq_driver_resolve_freq() cpufreq: Disallow ->resolve_freq() for drivers providing ->target_index() PCI / PM: check all fields in pci_set_platform_pm() cpufreq: acpi-cpufreq: use cached frequency mapping when possible cpufreq: schedutil: map raw required frequency to driver frequency cpufreq: add cpufreq_driver_resolve_freq() cpufreq: intel_pstate: Check cpuid for MSR_HWP_INTERRUPT intel_pstate: Update cpu_frequency tracepoint every time cpufreq: intel_pstate: clean remnant struct element PM / tools: scripts: AnalyzeSuspend v4.2 x86 / hibernate: Use hlt_play_dead() when resuming from hibernation cpufreq: powernv: Replacing pstate_id with frequency table index intel_pstate: Fix MSR_CONFIG_TDP_x addressing in core_get_max_pstate() PM / hibernate: Image data protection during restoration PM / hibernate: Add missing braces in __register_nosave_region() PM / hibernate: Clean up comments in snapshot.c PM / hibernate: Clean up function headers in snapshot.c PM / hibernate: Add missing braces in hibernate_setup() ...

Linus Torvalds committed 10 years ago

Commit 6453dbd2 parents 27b7902 bc841e265 files · +4332 −2821Browse files

Unified · Split

65 files
  1. Documentation/cpu-freq/core.txt +2 −2
  2. Documentation/cpu-freq/cpu-drivers.txt +4 −6
  3. Documentation/cpu-freq/pcc-cpufreq.txt +2 −2
  4. Documentation/kernel-parameters.txt +3 −0
  5. arch/powerpc/platforms/cell/cpufreq_spudemand.c +34 −38
  6. arch/x86/include/asm/msr-index.h +0 −2
  7. arch/x86/include/asm/smp.h +1 −0
  8. arch/x86/kernel/smpboot.c +1 −1
  9. arch/x86/power/cpu.c +30 −0
  10. drivers/base/power/clock_ops.c +45 −0
  11. drivers/base/power/domain.c +54 −247
  12. drivers/base/power/runtime.c +10 −3
  13. drivers/cpufreq/Kconfig +4 −9
  14. drivers/cpufreq/acpi-cpufreq.c +7 −10
  15. drivers/cpufreq/amd_freq_sensitivity.c +4 −6
  16. drivers/cpufreq/cpufreq.c +136 −87
  17. drivers/cpufreq/cpufreq_conservative.c +17 −71
  18. drivers/cpufreq/cpufreq_governor.c +22 −51
  19. drivers/cpufreq/cpufreq_governor.h +21 −3
  20. drivers/cpufreq/cpufreq_ondemand.c +13 −25
  21. drivers/cpufreq/cpufreq_ondemand.h +0 −1
  22. drivers/cpufreq/cpufreq_performance.c +4 −15
  23. drivers/cpufreq/cpufreq_powersave.c +4 −15
  24. drivers/cpufreq/cpufreq_stats.c +22 −135
  25. drivers/cpufreq/cpufreq_userspace.c +52 −52
  26. drivers/cpufreq/davinci-cpufreq.c +1 −21
  27. drivers/cpufreq/freq_table.c +80 −26
  28. drivers/cpufreq/intel_pstate.c +45 −29
  29. drivers/cpufreq/mvebu-cpufreq.c +1 −1
  30. drivers/cpufreq/pcc-cpufreq.c +0 −2
  31. drivers/cpufreq/powernv-cpufreq.c +103 −78
  32. drivers/cpufreq/ppc_cbe_cpufreq_pmi.c +1 −2
  33. drivers/cpufreq/s3c24xx-cpufreq.c +7 −26
  34. drivers/cpufreq/s5pv210-cpufreq.c +1 −6
  35. drivers/devfreq/Kconfig +1 −1
  36. drivers/devfreq/devfreq-event.c +1 −11
  37. drivers/devfreq/devfreq.c +3 −12
  38. drivers/devfreq/event/Kconfig +2 −2
  39. drivers/devfreq/event/exynos-ppmu.c +2 −1
  40. drivers/devfreq/exynos-bus.c +7 −4
  41. drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c +0 −23
  42. drivers/idle/intel_idle.c +58 −49
  43. drivers/pci/pci.c +2 −2
  44. drivers/powercap/intel_rapl.c +82 −25
  45. drivers/thermal/cpu_cooling.c +19 −5
  46. include/linux/cpufreq.h +272 −17
  47. include/linux/pm_clock.h +1 −0
  48. include/linux/pm_domain.h +5 −5
  49. include/linux/suspend.h +2 −3
  50. kernel/power/Makefile +2 −0
  51. kernel/power/console.c +4 −4
  52. kernel/power/hibernate.c +68 −33
  53. kernel/power/main.c +9 −2
  54. kernel/power/power.h +11 −0
  55. kernel/power/process.c +3 −0
  56. kernel/power/snapshot.c +515 −425
  57. kernel/power/suspend.c +6 −4
  58. kernel/power/swap.c +6 −0
  59. kernel/power/user.c +8 −6
  60. kernel/sched/cpufreq_schedutil.c +32 −42
  61. kernel/workqueue.c +2 −2
  62. scripts/analyze_suspend.py +2474 −1167
  63. tools/power/x86/turbostat/Makefile +2 −2
  64. tools/power/x86/turbostat/turbostat.8 +1 −1
  65. tools/power/x86/turbostat/turbostat.c +1 −1
Documentation/cpu-freq/core.txt+2−2
@@ -96,7 +96,7 @@ new - new frequency · 95 unmodified lines
9696 For details about OPP, see Documentation/power/opp.txt
9797
9898 dev_pm_opp_init_cpufreq_table - cpufreq framework typically is initialized with
99− cpufreq_frequency_table_cpuinfo which is provided with the list of
99+ cpufreq_table_validate_and_show() which is provided with the list of
100100 frequencies that are available for operation. This function provides
101101 a ready to use conversion routine to translate the OPP layer's internal
102102 information about the available frequencies into a format readily
@@ -110,7 +110,7 @@ dev_pm_opp_init_cpufreq_table - cpufreq framework typically is initialized with · 7 unmodified lines
110110 /* Do things */
111111 r = dev_pm_opp_init_cpufreq_table(dev, &freq_table);
112112 if (!r)
113− cpufreq_frequency_table_cpuinfo(policy, freq_table);
113+ cpufreq_table_validate_and_show(policy, freq_table);
114114 /* Do other things */
115115 }
116116
Documentation/cpu-freq/cpu-drivers.txt+4−6
@@ -231,7 +231,7 @@ if you want to skip one entry in the table, set the frequency to · 230 unmodified lines
231231 CPUFREQ_ENTRY_INVALID. The entries don't need to be in ascending
232232 order.
233233
234−By calling cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy,
234+By calling cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
235235 struct cpufreq_frequency_table *table);
236236 the cpuinfo.min_freq and cpuinfo.max_freq values are detected, and
237237 policy->min and policy->max are set to the same values. This is
@@ -244,14 +244,12 @@ policy->max, and all other criteria are met. This is helpful for the · 6 unmodified lines
244244 ->verify call.
245245
246246 int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
247− struct cpufreq_frequency_table *table,
248247 unsigned int target_freq,
249− unsigned int relation,
250− unsigned int *index);
248+ unsigned int relation);
251249
252250 is the corresponding frequency table helper for the ->target
253−stage. Just pass the values to this function, and the unsigned int
254−index returns the number of the frequency table entry which contains
251+stage. Just pass the values to this function, and this function
252+returns the number of the frequency table entry which contains
255253 the frequency the CPU shall be set to.
256254
257255 The following macros can be used as iterators over cpufreq_frequency_table:
Documentation/cpu-freq/pcc-cpufreq.txt+2−2
@@ -159,8 +159,8 @@ to be strictly associated with a P-state. · 158 unmodified lines
159159
160160 2.2 cpuinfo_transition_latency:
161161 -------------------------------
162−The cpuinfo_transition_latency field is CPUFREQ_ETERNAL. The PCC specification
163−does not include a field to expose this value currently.
162+The cpuinfo_transition_latency field is 0. The PCC specification does
163+not include a field to expose this value currently.
164164
165165 2.3 cpuinfo_cur_freq:
166166 ---------------------
Documentation/kernel-parameters.txt+3−0
@@ -3598,6 +3598,9 @@ bytes respectively. Such letter suffixes can also be entirely omitted. · 3597 unmodified lines
35983598 present during boot.
35993599 nocompress Don't compress/decompress hibernation images.
36003600 no Disable hibernation and resume.
3601+ protect_image Turn on image protection during restoration
3602+ (that will set all pages holding image data
3603+ during restoration read-only).
36013604
36023605 retain_initrd [RAM] Keep initrd memory after extraction
36033606
arch/powerpc/platforms/cell/cpufreq_spudemand.c+34−38
@@ -85,61 +85,57 @@ static void spu_gov_cancel_work(struct spu_gov_info_struct *info) · 84 unmodified lines
8585 cancel_delayed_work_sync(&info->work);
8686 }
8787
88−static int spu_gov_govern(struct cpufreq_policy *policy, unsigned int event)
88+static int spu_gov_start(struct cpufreq_policy *policy)
8989 {
9090 unsigned int cpu = policy->cpu;
91− struct spu_gov_info_struct *info, *affected_info;
91+ struct spu_gov_info_struct *info = &per_cpu(spu_gov_info, cpu);
92+ struct spu_gov_info_struct *affected_info;
9293 int i;
93− int ret = 0;
9494
95− info = &per_cpu(spu_gov_info, cpu);
96−
97− switch (event) {
98− case CPUFREQ_GOV_START:
99− if (!cpu_online(cpu)) {
100− printk(KERN_ERR "cpu %d is not online\n", cpu);
101− ret = -EINVAL;
102− break;
103− }
95+ if (!cpu_online(cpu)) {
96+ printk(KERN_ERR "cpu %d is not online\n", cpu);
97+ return -EINVAL;
98+ }
10499
105− if (!policy->cur) {
106− printk(KERN_ERR "no cpu specified in policy\n");
107− ret = -EINVAL;
108− break;
109− }
100+ if (!policy->cur) {
101+ printk(KERN_ERR "no cpu specified in policy\n");
102+ return -EINVAL;
103+ }
110104
111− /* initialize spu_gov_info for all affected cpus */
112− for_each_cpu(i, policy->cpus) {
113− affected_info = &per_cpu(spu_gov_info, i);
114− affected_info->policy = policy;
115− }
105+ /* initialize spu_gov_info for all affected cpus */
106+ for_each_cpu(i, policy->cpus) {
107+ affected_info = &per_cpu(spu_gov_info, i);
108+ affected_info->policy = policy;
109+ }
116110
117− info->poll_int = POLL_TIME;
111+ info->poll_int = POLL_TIME;
118112
119− /* setup timer */
120− spu_gov_init_work(info);
113+ /* setup timer */
114+ spu_gov_init_work(info);
121115
122− break;
116+ return 0;
117+}
123118
124− case CPUFREQ_GOV_STOP:
125− /* cancel timer */
126− spu_gov_cancel_work(info);
119+static void spu_gov_stop(struct cpufreq_policy *policy)
120+{
121+ unsigned int cpu = policy->cpu;
122+ struct spu_gov_info_struct *info = &per_cpu(spu_gov_info, cpu);
123+ int i;
127124
128− /* clean spu_gov_info for all affected cpus */
129− for_each_cpu (i, policy->cpus) {
130− info = &per_cpu(spu_gov_info, i);
131− info->policy = NULL;
132− }
125+ /* cancel timer */
126+ spu_gov_cancel_work(info);
133127
134− break;
128+ /* clean spu_gov_info for all affected cpus */
129+ for_each_cpu (i, policy->cpus) {
130+ info = &per_cpu(spu_gov_info, i);
131+ info->policy = NULL;
135132 }
136−
137− return ret;
138133 }
139134
140135 static struct cpufreq_governor spu_governor = {
141136 .name = "spudemand",
142− .governor = spu_gov_govern,
137+ .start = spu_gov_start,
138+ .stop = spu_gov_stop,
143139 .owner = THIS_MODULE,
144140 };
145141
arch/x86/include/asm/msr-index.h+0−2
@@ -64,8 +64,6 @@ · 63 unmodified lines
6464
6565 #define MSR_OFFCORE_RSP_0 0x000001a6
6666 #define MSR_OFFCORE_RSP_1 0x000001a7
67−#define MSR_NHM_TURBO_RATIO_LIMIT 0x000001ad
68−#define MSR_IVT_TURBO_RATIO_LIMIT 0x000001ae
6967 #define MSR_TURBO_RATIO_LIMIT 0x000001ad
7068 #define MSR_TURBO_RATIO_LIMIT1 0x000001ae
7169 #define MSR_TURBO_RATIO_LIMIT2 0x000001af
arch/x86/include/asm/smp.h+1−0
@@ -135,6 +135,7 @@ int native_cpu_up(unsigned int cpunum, struct task_struct *tidle); · 134 unmodified lines
135135 int native_cpu_disable(void);
136136 int common_cpu_die(unsigned int cpu);
137137 void native_cpu_die(unsigned int cpu);
138+void hlt_play_dead(void);
138139 void native_play_dead(void);
139140 void play_dead_common(void);
140141 void wbinvd_on_cpu(int cpu);
arch/x86/kernel/smpboot.c+1−1
@@ -1644,7 +1644,7 @@ static inline void mwait_play_dead(void) · 1643 unmodified lines
16441644 }
16451645 }
16461646
1647−static inline void hlt_play_dead(void)
1647+void hlt_play_dead(void)
16481648 {
16491649 if (__this_cpu_read(cpu_info.x86) >= 4)
16501650 wbinvd();
arch/x86/power/cpu.c+30−0
@@ -12,6 +12,7 @@ · 11 unmodified lines
1212 #include <linux/export.h>
1313 #include <linux/smp.h>
1414 #include <linux/perf_event.h>
15+#include <linux/tboot.h>
1516
1617 #include <asm/pgtable.h>
1718 #include <asm/proto.h>
@@ -266,6 +267,35 @@ void notrace restore_processor_state(void) · 248 unmodified lines
266267 EXPORT_SYMBOL(restore_processor_state);
267268 #endif
268269
270+#if defined(CONFIG_HIBERNATION) && defined(CONFIG_HOTPLUG_CPU)
271+static void resume_play_dead(void)
272+{
273+ play_dead_common();
274+ tboot_shutdown(TB_SHUTDOWN_WFS);
275+ hlt_play_dead();
276+}
277+
278+int hibernate_resume_nonboot_cpu_disable(void)
279+{
280+ void (*play_dead)(void) = smp_ops.play_dead;
281+ int ret;
282+
283+ /*
284+ * Ensure that MONITOR/MWAIT will not be used in the "play dead" loop
285+ * during hibernate image restoration, because it is likely that the
286+ * monitored address will be actually written to at that time and then
287+ * the "dead" CPU will attempt to execute instructions again, but the
288+ * address in its instruction pointer may not be possible to resolve
289+ * any more at that point (the page tables used by it previously may
290+ * have been overwritten by hibernate image data).
291+ */
292+ smp_ops.play_dead = resume_play_dead;
293+ ret = disable_nonboot_cpus();
294+ smp_ops.play_dead = play_dead;
295+ return ret;
296+}
297+#endif
298+
269299 /*
270300 * When bsp_check() is called in hibernate and suspend, cpu hotplug
271301 * is disabled already. So it's unnessary to handle race condition between
drivers/base/power/clock_ops.c+45−0
@@ -121,6 +121,7 @@ int pm_clk_add(struct device *dev, const char *con_id) · 120 unmodified lines
121121 {
122122 return __pm_clk_add(dev, con_id, NULL);
123123 }
124+EXPORT_SYMBOL_GPL(pm_clk_add);
124125
125126 /**
126127 * pm_clk_add_clk - Start using a device clock for power management.
@@ -136,8 +137,41 @@ int pm_clk_add_clk(struct device *dev, struct clk *clk) · 9 unmodified lines
136137 {
137138 return __pm_clk_add(dev, NULL, clk);
138139 }
140+EXPORT_SYMBOL_GPL(pm_clk_add_clk);
139141
140142
143+/**
144+ * of_pm_clk_add_clk - Start using a device clock for power management.
145+ * @dev: Device whose clock is going to be used for power management.
146+ * @name: Name of clock that is going to be used for power management.
147+ *
148+ * Add the clock described in the 'clocks' device-tree node that matches
149+ * with the 'name' provided, to the list of clocks used for the power
150+ * management of @dev. On success, returns 0. Returns a negative error
151+ * code if the clock is not found or cannot be added.
152+ */
153+int of_pm_clk_add_clk(struct device *dev, const char *name)
154+{
155+ struct clk *clk;
156+ int ret;
157+
158+ if (!dev || !dev->of_node || !name)
159+ return -EINVAL;
160+
161+ clk = of_clk_get_by_name(dev->of_node, name);
162+ if (IS_ERR(clk))
163+ return PTR_ERR(clk);
164+
165+ ret = pm_clk_add_clk(dev, clk);
166+ if (ret) {
167+ clk_put(clk);
168+ return ret;
169+ }
170+
171+ return 0;
172+}
173+EXPORT_SYMBOL_GPL(of_pm_clk_add_clk);
174+
141175 /**
142176 * of_pm_clk_add_clks - Start using device clock(s) for power management.
143177 * @dev: Device whose clock(s) is going to be used for power management.
@@ -192,6 +226,7 @@ error: · 48 unmodified lines
192226
193227 return ret;
194228 }
229+EXPORT_SYMBOL_GPL(of_pm_clk_add_clks);
195230
196231 /**
197232 * __pm_clk_remove - Destroy PM clock entry.
@@ -252,6 +287,7 @@ void pm_clk_remove(struct device *dev, const char *con_id) · 54 unmodified lines
252287
253288 __pm_clk_remove(ce);
254289 }
290+EXPORT_SYMBOL_GPL(pm_clk_remove);
255291
256292 /**
257293 * pm_clk_remove_clk - Stop using a device clock for power management.
@@ -285,6 +321,7 @@ void pm_clk_remove_clk(struct device *dev, struct clk *clk) · 27 unmodified lines
285321
286322 __pm_clk_remove(ce);
287323 }
324+EXPORT_SYMBOL_GPL(pm_clk_remove_clk);
288325
289326 /**
290327 * pm_clk_init - Initialize a device's list of power management clocks.
@@ -299,6 +336,7 @@ void pm_clk_init(struct device *dev) · 8 unmodified lines
299336 if (psd)
300337 INIT_LIST_HEAD(&psd->clock_list);
301338 }
339+EXPORT_SYMBOL_GPL(pm_clk_init);
302340
303341 /**
304342 * pm_clk_create - Create and initialize a device's list of PM clocks.
@@ -311,6 +349,7 @@ int pm_clk_create(struct device *dev) · 6 unmodified lines
311349 {
312350 return dev_pm_get_subsys_data(dev);
313351 }
352+EXPORT_SYMBOL_GPL(pm_clk_create);
314353
315354 /**
316355 * pm_clk_destroy - Destroy a device's list of power management clocks.
@@ -345,6 +384,7 @@ void pm_clk_destroy(struct device *dev) · 28 unmodified lines
345384 __pm_clk_remove(ce);
346385 }
347386 }
387+EXPORT_SYMBOL_GPL(pm_clk_destroy);
348388
349389 /**
350390 * pm_clk_suspend - Disable clocks in a device's PM clock list.
@@ -375,6 +415,7 @@ int pm_clk_suspend(struct device *dev) · 24 unmodified lines
375415
376416 return 0;
377417 }
418+EXPORT_SYMBOL_GPL(pm_clk_suspend);
378419
379420 /**
380421 * pm_clk_resume - Enable clocks in a device's PM clock list.
@@ -400,6 +441,7 @@ int pm_clk_resume(struct device *dev) · 19 unmodified lines
400441
401442 return 0;
402443 }
444+EXPORT_SYMBOL_GPL(pm_clk_resume);
403445
404446 /**
405447 * pm_clk_notify - Notify routine for device addition and removal.
@@ -480,6 +522,7 @@ int pm_clk_runtime_suspend(struct device *dev) · 74 unmodified lines
480522
481523 return 0;
482524 }
525+EXPORT_SYMBOL_GPL(pm_clk_runtime_suspend);
483526
484527 int pm_clk_runtime_resume(struct device *dev)
485528 {
@@ -495,6 +538,7 @@ int pm_clk_runtime_resume(struct device *dev) · 9 unmodified lines
495538
496539 return pm_generic_runtime_resume(dev);
497540 }
541+EXPORT_SYMBOL_GPL(pm_clk_runtime_resume);
498542
499543 #else /* !CONFIG_PM_CLK */
500544
@@ -598,3 +642,4 @@ void pm_clk_add_notifier(struct bus_type *bus, · 97 unmodified lines
598642 clknb->nb.notifier_call = pm_clk_notify;
599643 bus_register_notifier(bus, &clknb->nb);
600644 }
645+EXPORT_SYMBOL_GPL(pm_clk_add_notifier);
drivers/base/power/domain.c+54−247
@@ -187,8 +187,7 @@ static int genpd_poweron(struct generic_pm_domain *genpd, unsigned int depth) · 186 unmodified lines
187187 struct gpd_link *link;
188188 int ret = 0;
189189
190− if (genpd->status == GPD_STATE_ACTIVE
191− || (genpd->prepared_count > 0 && genpd->suspend_power_off))
190+ if (genpd->status == GPD_STATE_ACTIVE)
192191 return 0;
193192
194193 /*
@@ -735,81 +734,23 @@ static int pm_genpd_prepare(struct device *dev) · 540 unmodified lines
735734
736735 mutex_lock(&genpd->lock);
737736
738− if (genpd->prepared_count++ == 0) {
737+ if (genpd->prepared_count++ == 0)
739738 genpd->suspended_count = 0;
740− genpd->suspend_power_off = genpd->status == GPD_STATE_POWER_OFF;
741− }
742739
743740 mutex_unlock(&genpd->lock);
744741
745− if (genpd->suspend_power_off)
746− return 0;
747−
748− /*
749− * The PM domain must be in the GPD_STATE_ACTIVE state at this point,
750− * so genpd_poweron() will return immediately, but if the device
751− * is suspended (e.g. it's been stopped by genpd_stop_dev()), we need
752− * to make it operational.
753− */
754− pm_runtime_resume(dev);
755− __pm_runtime_disable(dev, false);
756−
757742 ret = pm_generic_prepare(dev);
758743 if (ret) {
759744 mutex_lock(&genpd->lock);
760745
761− if (--genpd->prepared_count == 0)
762− genpd->suspend_power_off = false;
746+ genpd->prepared_count--;
763747
764748 mutex_unlock(&genpd->lock);
765− pm_runtime_enable(dev);
766749 }
767750
768751 return ret;
769752 }
770753
771−/**
772− * pm_genpd_suspend - Suspend a device belonging to an I/O PM domain.
773− * @dev: Device to suspend.
774− *
775− * Suspend a device under the assumption that its pm_domain field points to the
776− * domain member of an object of type struct generic_pm_domain representing
777− * a PM domain consisting of I/O devices.
778− */
779−static int pm_genpd_suspend(struct device *dev)
780−{
781− struct generic_pm_domain *genpd;
782−
783− dev_dbg(dev, "%s()\n", __func__);
784−
785− genpd = dev_to_genpd(dev);
786− if (IS_ERR(genpd))
787− return -EINVAL;
788−
789− return genpd->suspend_power_off ? 0 : pm_generic_suspend(dev);
790−}
791−
792−/**
793− * pm_genpd_suspend_late - Late suspend of a device from an I/O PM domain.
794− * @dev: Device to suspend.
795− *
796− * Carry out a late suspend of a device under the assumption that its
797− * pm_domain field points to the domain member of an object of type
798− * struct generic_pm_domain representing a PM domain consisting of I/O devices.
799− */
800−static int pm_genpd_suspend_late(struct device *dev)
801−{
802− struct generic_pm_domain *genpd;
803−
804− dev_dbg(dev, "%s()\n", __func__);
805−
806− genpd = dev_to_genpd(dev);
807− if (IS_ERR(genpd))
808− return -EINVAL;
809−
810− return genpd->suspend_power_off ? 0 : pm_generic_suspend_late(dev);
811−}
812−
813754 /**
814755 * pm_genpd_suspend_noirq - Completion of suspend of device in an I/O PM domain.
815756 * @dev: Device to suspend.
@@ -820,6 +761,7 @@ static int pm_genpd_suspend_late(struct device *dev) · 4 unmodified lines
820761 static int pm_genpd_suspend_noirq(struct device *dev)
821762 {
822763 struct generic_pm_domain *genpd;
764+ int ret;
823765
824766 dev_dbg(dev, "%s()\n", __func__);
825767
@@ -827,11 +769,14 @@ static int pm_genpd_suspend_noirq(struct device *dev) · 1 unmodified line
827769 if (IS_ERR(genpd))
828770 return -EINVAL;
829771
830− if (genpd->suspend_power_off
831− || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)))
772+ if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
832773 return 0;
833774
834− genpd_stop_dev(genpd, dev);
775+ if (genpd->dev_ops.stop && genpd->dev_ops.start) {
776+ ret = pm_runtime_force_suspend(dev);
777+ if (ret)
778+ return ret;
779+ }
835780
836781 /*
837782 * Since all of the "noirq" callbacks are executed sequentially, it is
@@ -853,6 +798,7 @@ static int pm_genpd_suspend_noirq(struct device *dev) · 15 unmodified lines
853798 static int pm_genpd_resume_noirq(struct device *dev)
854799 {
855800 struct generic_pm_domain *genpd;
801+ int ret = 0;
856802
857803 dev_dbg(dev, "%s()\n", __func__);
858804
@@ -860,8 +806,7 @@ static int pm_genpd_resume_noirq(struct device *dev) · 1 unmodified line
860806 if (IS_ERR(genpd))
861807 return -EINVAL;
862808
863− if (genpd->suspend_power_off
864− || (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev)))
809+ if (dev->power.wakeup_path && genpd_dev_active_wakeup(genpd, dev))
865810 return 0;
866811
867812 /*
@@ -872,93 +817,10 @@ static int pm_genpd_resume_noirq(struct device *dev) · 4 unmodified lines
872817 pm_genpd_sync_poweron(genpd, true);
873818 genpd->suspended_count--;
874819
875− return genpd_start_dev(genpd, dev);
876−}
877−
878−/**
879− * pm_genpd_resume_early - Early resume of a device in an I/O PM domain.
880− * @dev: Device to resume.
881− *
882− * Carry out an early resume of a device under the assumption that its
883− * pm_domain field points to the domain member of an object of type
884− * struct generic_pm_domain representing a power domain consisting of I/O
885− * devices.
886− */
887−static int pm_genpd_resume_early(struct device *dev)
888−{
889− struct generic_pm_domain *genpd;
890−
891− dev_dbg(dev, "%s()\n", __func__);
892−
893− genpd = dev_to_genpd(dev);
894− if (IS_ERR(genpd))
895− return -EINVAL;
896−
897− return genpd->suspend_power_off ? 0 : pm_generic_resume_early(dev);
898−}
899−
900−/**
901− * pm_genpd_resume - Resume of device in an I/O PM domain.
902− * @dev: Device to resume.
903− *
904− * Resume a device under the assumption that its pm_domain field points to the
905− * domain member of an object of type struct generic_pm_domain representing
906− * a power domain consisting of I/O devices.
907− */
908−static int pm_genpd_resume(struct device *dev)
909−{
910− struct generic_pm_domain *genpd;
911−
912− dev_dbg(dev, "%s()\n", __func__);
913−
914− genpd = dev_to_genpd(dev);
915− if (IS_ERR(genpd))
916− return -EINVAL;
917−
918− return genpd->suspend_power_off ? 0 : pm_generic_resume(dev);
919−}
920−
921−/**
922− * pm_genpd_freeze - Freezing a device in an I/O PM domain.
923− * @dev: Device to freeze.
924− *
925− * Freeze a device under the assumption that its pm_domain field points to the
926− * domain member of an object of type struct generic_pm_domain representing
927− * a power domain consisting of I/O devices.
928− */
929−static int pm_genpd_freeze(struct device *dev)
930−{
931− struct generic_pm_domain *genpd;
932−
933− dev_dbg(dev, "%s()\n", __func__);
934−
935− genpd = dev_to_genpd(dev);
936− if (IS_ERR(genpd))
937− return -EINVAL;
938−
939− return genpd->suspend_power_off ? 0 : pm_generic_freeze(dev);
940−}
820+ if (genpd->dev_ops.stop && genpd->dev_ops.start)
821+ ret = pm_runtime_force_resume(dev);
941822
942−/**
943− * pm_genpd_freeze_late - Late freeze of a device in an I/O PM domain.
944− * @dev: Device to freeze.
945− *
946− * Carry out a late freeze of a device under the assumption that its
947− * pm_domain field points to the domain member of an object of type
948− * struct generic_pm_domain representing a power domain consisting of I/O
949− * devices.
950− */
951−static int pm_genpd_freeze_late(struct device *dev)
952−{
953− struct generic_pm_domain *genpd;
954−
955− dev_dbg(dev, "%s()\n", __func__);
956−
957− genpd = dev_to_genpd(dev);
958− if (IS_ERR(genpd))
959− return -EINVAL;
960−
961− return genpd->suspend_power_off ? 0 : pm_generic_freeze_late(dev);
823+ return ret;
962824 }
963825
964826 /**
@@ -973,6 +835,7 @@ static int pm_genpd_freeze_late(struct device *dev) · 8 unmodified lines
973835 static int pm_genpd_freeze_noirq(struct device *dev)
974836 {
975837 struct generic_pm_domain *genpd;
838+ int ret = 0;
976839
977840 dev_dbg(dev, "%s()\n", __func__);
978841
@@ -980,7 +843,10 @@ static int pm_genpd_freeze_noirq(struct device *dev) · 1 unmodified line
980843 if (IS_ERR(genpd))
981844 return -EINVAL;
982845
983− return genpd->suspend_power_off ? 0 : genpd_stop_dev(genpd, dev);
846+ if (genpd->dev_ops.stop && genpd->dev_ops.start)
847+ ret = pm_runtime_force_suspend(dev);
848+
849+ return ret;
984850 }
985851
986852 /**
@@ -993,6 +859,7 @@ static int pm_genpd_freeze_noirq(struct device *dev) · 6 unmodified lines
993859 static int pm_genpd_thaw_noirq(struct device *dev)
994860 {
995861 struct generic_pm_domain *genpd;
862+ int ret = 0;
996863
997864 dev_dbg(dev, "%s()\n", __func__);
998865
@@ -1000,51 +867,10 @@ static int pm_genpd_thaw_noirq(struct device *dev) · 1 unmodified line
1000867 if (IS_ERR(genpd))
1001868 return -EINVAL;
1002869
1003− return genpd->suspend_power_off ?
1004− 0 : genpd_start_dev(genpd, dev);
1005−}
1006−
1007−/**
1008− * pm_genpd_thaw_early - Early thaw of device in an I/O PM domain.
1009− * @dev: Device to thaw.
1010− *
1011− * Carry out an early thaw of a device under the assumption that its
1012− * pm_domain field points to the domain member of an object of type
1013− * struct generic_pm_domain representing a power domain consisting of I/O
1014− * devices.
1015− */
1016−static int pm_genpd_thaw_early(struct device *dev)
1017−{
1018− struct generic_pm_domain *genpd;
1019−
1020− dev_dbg(dev, "%s()\n", __func__);
1021−
1022− genpd = dev_to_genpd(dev);
1023− if (IS_ERR(genpd))
1024− return -EINVAL;
1025−
1026− return genpd->suspend_power_off ? 0 : pm_generic_thaw_early(dev);
1027−}
1028−
1029−/**
1030− * pm_genpd_thaw - Thaw a device belonging to an I/O power domain.
1031− * @dev: Device to thaw.
1032− *
1033− * Thaw a device under the assumption that its pm_domain field points to the
1034− * domain member of an object of type struct generic_pm_domain representing
1035− * a power domain consisting of I/O devices.
1036− */
1037−static int pm_genpd_thaw(struct device *dev)
1038−{
1039− struct generic_pm_domain *genpd;
1040−
1041− dev_dbg(dev, "%s()\n", __func__);
870+ if (genpd->dev_ops.stop && genpd->dev_ops.start)
871+ ret = pm_runtime_force_resume(dev);
1042872
1043− genpd = dev_to_genpd(dev);
1044− if (IS_ERR(genpd))
1045− return -EINVAL;
1046−
1047− return genpd->suspend_power_off ? 0 : pm_generic_thaw(dev);
873+ return ret;
1048874 }
1049875
1050876 /**
@@ -1057,6 +883,7 @@ static int pm_genpd_thaw(struct device *dev) · 6 unmodified lines
1057883 static int pm_genpd_restore_noirq(struct device *dev)
1058884 {
1059885 struct generic_pm_domain *genpd;
886+ int ret = 0;
1060887
1061888 dev_dbg(dev, "%s()\n", __func__);
1062889
@@ -1072,30 +899,20 @@ static int pm_genpd_restore_noirq(struct device *dev) · 9 unmodified lines
1072899 * At this point suspended_count == 0 means we are being run for the
1073900 * first time for the given domain in the present cycle.
1074901 */
1075− if (genpd->suspended_count++ == 0) {
902+ if (genpd->suspended_count++ == 0)
1076903 /*
1077904 * The boot kernel might put the domain into arbitrary state,
1078905 * so make it appear as powered off to pm_genpd_sync_poweron(),
1079906 * so that it tries to power it on in case it was really off.
1080907 */
1081908 genpd->status = GPD_STATE_POWER_OFF;
1082− if (genpd->suspend_power_off) {
1083− /*
1084− * If the domain was off before the hibernation, make
1085− * sure it will be off going forward.
1086− */
1087− genpd_power_off(genpd, true);
1088−
1089− return 0;
1090− }
1091− }
1092−
1093− if (genpd->suspend_power_off)
1094− return 0;
1095909
1096910 pm_genpd_sync_poweron(genpd, true);
1097911
1098− return genpd_start_dev(genpd, dev);
912+ if (genpd->dev_ops.stop && genpd->dev_ops.start)
913+ ret = pm_runtime_force_resume(dev);
914+
915+ return ret;
1099916 }
1100917
1101918 /**
@@ -1110,7 +927,6 @@ static int pm_genpd_restore_noirq(struct device *dev) · 8 unmodified lines
1110927 static void pm_genpd_complete(struct device *dev)
1111928 {
1112929 struct generic_pm_domain *genpd;
1113− bool run_complete;
1114930
1115931 dev_dbg(dev, "%s()\n", __func__);
1116932
@@ -1118,20 +934,15 @@ static void pm_genpd_complete(struct device *dev) · 1 unmodified line
1118934 if (IS_ERR(genpd))
1119935 return;
1120936
937+ pm_generic_complete(dev);
938+
1121939 mutex_lock(&genpd->lock);
1122940
1123− run_complete = !genpd->suspend_power_off;
1124− if (--genpd->prepared_count == 0)
1125− genpd->suspend_power_off = false;
941+ genpd->prepared_count--;
942+ if (!genpd->prepared_count)
943+ genpd_queue_power_off_work(genpd);
1126944
1127945 mutex_unlock(&genpd->lock);
1128−
1129− if (run_complete) {
1130− pm_generic_complete(dev);
1131− pm_runtime_set_active(dev);
1132− pm_runtime_enable(dev);
1133− pm_request_idle(dev);
1134− }
1135946 }
1136947
1137948 /**
@@ -1173,18 +984,10 @@ EXPORT_SYMBOL_GPL(pm_genpd_syscore_poweron); · 35 unmodified lines
1173984 #else /* !CONFIG_PM_SLEEP */
1174985
1175986 #define pm_genpd_prepare NULL
1176−#define pm_genpd_suspend NULL
1177−#define pm_genpd_suspend_late NULL
1178987 #define pm_genpd_suspend_noirq NULL
1179−#define pm_genpd_resume_early NULL
1180988 #define pm_genpd_resume_noirq NULL
1181−#define pm_genpd_resume NULL
1182−#define pm_genpd_freeze NULL
1183−#define pm_genpd_freeze_late NULL
1184989 #define pm_genpd_freeze_noirq NULL
1185−#define pm_genpd_thaw_early NULL
1186990 #define pm_genpd_thaw_noirq NULL
1187−#define pm_genpd_thaw NULL
1188991 #define pm_genpd_restore_noirq NULL
1189992 #define pm_genpd_complete NULL
1190993
@@ -1455,12 +1258,14 @@ EXPORT_SYMBOL_GPL(pm_genpd_remove_subdomain); · 264 unmodified lines
14551258 * @genpd: PM domain object to initialize.
14561259 * @gov: PM domain governor to associate with the domain (may be NULL).
14571260 * @is_off: Initial value of the domain's power_is_off field.
1261+ *
1262+ * Returns 0 on successful initialization, else a negative error code.
14581263 */
1459−void pm_genpd_init(struct generic_pm_domain *genpd,
1460− struct dev_power_governor *gov, bool is_off)
1264+int pm_genpd_init(struct generic_pm_domain *genpd,
1265+ struct dev_power_governor *gov, bool is_off)
14611266 {
14621267 if (IS_ERR_OR_NULL(genpd))
1463− return;
1268+ return -EINVAL;
14641269
14651270 INIT_LIST_HEAD(&genpd->master_links);
14661271 INIT_LIST_HEAD(&genpd->slave_links);
@@ -1476,24 +1281,24 @@ void pm_genpd_init(struct generic_pm_domain *genpd, · 9 unmodified lines
14761281 genpd->domain.ops.runtime_suspend = genpd_runtime_suspend;
14771282 genpd->domain.ops.runtime_resume = genpd_runtime_resume;
14781283 genpd->domain.ops.prepare = pm_genpd_prepare;
1479− genpd->domain.ops.suspend = pm_genpd_suspend;
1480− genpd->domain.ops.suspend_late = pm_genpd_suspend_late;
1284+ genpd->domain.ops.suspend = pm_generic_suspend;
1285+ genpd->domain.ops.suspend_late = pm_generic_suspend_late;
14811286 genpd->domain.ops.suspend_noirq = pm_genpd_suspend_noirq;
14821287 genpd->domain.ops.resume_noirq = pm_genpd_resume_noirq;
1483− genpd->domain.ops.resume_early = pm_genpd_resume_early;
1484− genpd->domain.ops.resume = pm_genpd_resume;
1485− genpd->domain.ops.freeze = pm_genpd_freeze;
1486− genpd->domain.ops.freeze_late = pm_genpd_freeze_late;
1288+ genpd->domain.ops.resume_early = pm_generic_resume_early;
1289+ genpd->domain.ops.resume = pm_generic_resume;
1290+ genpd->domain.ops.freeze = pm_generic_freeze;
1291+ genpd->domain.ops.freeze_late = pm_generic_freeze_late;
14871292 genpd->domain.ops.freeze_noirq = pm_genpd_freeze_noirq;
14881293 genpd->domain.ops.thaw_noirq = pm_genpd_thaw_noirq;
1489− genpd->domain.ops.thaw_early = pm_genpd_thaw_early;
1490− genpd->domain.ops.thaw = pm_genpd_thaw;
1491− genpd->domain.ops.poweroff = pm_genpd_suspend;
1492− genpd->domain.ops.poweroff_late = pm_genpd_suspend_late;
1294+ genpd->domain.ops.thaw_early = pm_generic_thaw_early;
1295+ genpd->domain.ops.thaw = pm_generic_thaw;
1296+ genpd->domain.ops.poweroff = pm_generic_poweroff;
1297+ genpd->domain.ops.poweroff_late = pm_generic_poweroff_late;
14931298 genpd->domain.ops.poweroff_noirq = pm_genpd_suspend_noirq;
14941299 genpd->domain.ops.restore_noirq = pm_genpd_restore_noirq;
1495− genpd->domain.ops.restore_early = pm_genpd_resume_early;
1496− genpd->domain.ops.restore = pm_genpd_resume;
1300+ genpd->domain.ops.restore_early = pm_generic_restore_early;
1301+ genpd->domain.ops.restore = pm_generic_restore;
14971302 genpd->domain.ops.complete = pm_genpd_complete;
14981303
14991304 if (genpd->flags & GENPD_FLAG_PM_CLK) {
@@ -1518,6 +1323,8 @@ void pm_genpd_init(struct generic_pm_domain *genpd, · 18 unmodified lines
15181323 mutex_lock(&gpd_list_lock);
15191324 list_add(&genpd->gpd_list_node, &gpd_list);
15201325 mutex_unlock(&gpd_list_lock);
1326+
1327+ return 0;
15211328 }
15221329 EXPORT_SYMBOL_GPL(pm_genpd_init);
15231330
drivers/base/power/runtime.c+10−3
@@ -1045,10 +1045,14 @@ int __pm_runtime_set_status(struct device *dev, unsigned int status) · 1044 unmodified lines
10451045 */
10461046 if (!parent->power.disable_depth
10471047 && !parent->power.ignore_children
1048− && parent->power.runtime_status != RPM_ACTIVE)
1048+ && parent->power.runtime_status != RPM_ACTIVE) {
1049+ dev_err(dev, "runtime PM trying to activate child device %s but parent (%s) is not active\n",
1050+ dev_name(dev),
1051+ dev_name(parent));
10491052 error = -EBUSY;
1050− else if (dev->power.runtime_status == RPM_SUSPENDED)
1053+ } else if (dev->power.runtime_status == RPM_SUSPENDED) {
10511054 atomic_inc(&parent->power.child_count);
1055+ }
10521056
10531057 spin_unlock(&parent->power.lock);
10541058
@@ -1256,7 +1260,7 @@ void pm_runtime_allow(struct device *dev) · 201 unmodified lines
12561260
12571261 dev->power.runtime_auto = true;
12581262 if (atomic_dec_and_test(&dev->power.usage_count))
1259− rpm_idle(dev, RPM_AUTO);
1263+ rpm_idle(dev, RPM_AUTO | RPM_ASYNC);
12601264
12611265 out:
12621266 spin_unlock_irq(&dev->power.lock);
@@ -1506,6 +1510,9 @@ int pm_runtime_force_resume(struct device *dev) · 243 unmodified lines
15061510 goto out;
15071511 }
15081512
1513+ if (!pm_runtime_status_suspended(dev))
1514+ goto out;
1515+
15091516 ret = pm_runtime_set_active(dev);
15101517 if (ret)
15111518 goto out;
drivers/cpufreq/Kconfig+4−9
@@ -31,23 +31,18 @@ config CPU_FREQ_BOOST_SW · 30 unmodified lines
3131 depends on THERMAL
3232
3333 config CPU_FREQ_STAT
34− tristate "CPU frequency translation statistics"
34+ bool "CPU frequency transition statistics"
3535 default y
3636 help
37− This driver exports CPU frequency statistics information through sysfs
38− file system.
39−
40− To compile this driver as a module, choose M here: the
41− module will be called cpufreq_stats.
37+ Export CPU frequency statistics information through sysfs.
4238
4339 If in doubt, say N.
4440
4541 config CPU_FREQ_STAT_DETAILS
46− bool "CPU frequency translation statistics details"
42+ bool "CPU frequency transition statistics details"
4743 depends on CPU_FREQ_STAT
4844 help
49− This will show detail CPU frequency translation table in sysfs file
50− system.
45+ Show detailed CPU frequency transition table in sysfs.
5146
5247 If in doubt, say N.
5348
drivers/cpufreq/acpi-cpufreq.c+7−10
@@ -468,20 +468,17 @@ unsigned int acpi_cpufreq_fast_switch(struct cpufreq_policy *policy, · 467 unmodified lines
468468 struct acpi_cpufreq_data *data = policy->driver_data;
469469 struct acpi_processor_performance *perf;
470470 struct cpufreq_frequency_table *entry;
471− unsigned int next_perf_state, next_freq, freq;
471+ unsigned int next_perf_state, next_freq, index;
472472
473473 /*
474474 * Find the closest frequency above target_freq.
475− *
476− * The table is sorted in the reverse order with respect to the
477− * frequency and all of the entries are valid (see the initialization).
478475 */
479− entry = policy->freq_table;
480− do {
481− entry++;
482− freq = entry->frequency;
483− } while (freq >= target_freq && freq != CPUFREQ_TABLE_END);
484− entry--;
476+ if (policy->cached_target_freq == target_freq)
477+ index = policy->cached_resolved_idx;
478+ else
479+ index = cpufreq_table_find_index_dl(policy, target_freq);
480+
481+ entry = &policy->freq_table[index];
485482 next_freq = entry->frequency;
486483 next_perf_state = entry->driver_data;
487484
drivers/cpufreq/amd_freq_sensitivity.c+4−6
@@ -48,9 +48,8 @@ static unsigned int amd_powersave_bias_target(struct cpufreq_policy *policy, · 47 unmodified lines
4848 struct policy_dbs_info *policy_dbs = policy->governor_data;
4949 struct dbs_data *od_data = policy_dbs->dbs_data;
5050 struct od_dbs_tuners *od_tuners = od_data->tuners;
51− struct od_policy_dbs_info *od_info = to_dbs_info(policy_dbs);
5251
53− if (!od_info->freq_table)
52+ if (!policy->freq_table)
5453 return freq_next;
5554
5655 rdmsr_on_cpu(policy->cpu, MSR_AMD64_FREQ_SENSITIVITY_ACTUAL,
@@ -92,10 +91,9 @@ static unsigned int amd_powersave_bias_target(struct cpufreq_policy *policy, · 35 unmodified lines
9291 else {
9392 unsigned int index;
9493
95− cpufreq_frequency_table_target(policy,
96− od_info->freq_table, policy->cur - 1,
97− CPUFREQ_RELATION_H, &index);
98− freq_next = od_info->freq_table[index].frequency;
94+ index = cpufreq_table_find_index_h(policy,
95+ policy->cur - 1);
96+ freq_next = policy->freq_table[index].frequency;
9997 }
10098
10199 data->freq_prev = freq_next;
drivers/cpufreq/cpufreq.c+136−87
@@ -74,19 +74,12 @@ static inline bool has_target(void) · 73 unmodified lines
7474 }
7575
7676 /* internal prototypes */
77−static int cpufreq_governor(struct cpufreq_policy *policy, unsigned int event);
7877 static unsigned int __cpufreq_get(struct cpufreq_policy *policy);
78+static int cpufreq_init_governor(struct cpufreq_policy *policy);
79+static void cpufreq_exit_governor(struct cpufreq_policy *policy);
7980 static int cpufreq_start_governor(struct cpufreq_policy *policy);
80−
81−static inline void cpufreq_exit_governor(struct cpufreq_policy *policy)
82−{
83− (void)cpufreq_governor(policy, CPUFREQ_GOV_POLICY_EXIT);
84−}
85−
86−static inline void cpufreq_stop_governor(struct cpufreq_policy *policy)
87−{
88− (void)cpufreq_governor(policy, CPUFREQ_GOV_STOP);
89−}
81+static void cpufreq_stop_governor(struct cpufreq_policy *policy);
82+static void cpufreq_governor_limits(struct cpufreq_policy *policy);
9083
9184 /**
9285 * Two notifier lists: the "policy" list is involved in the
@@ -133,15 +126,6 @@ struct kobject *get_governor_parent_kobj(struct cpufreq_policy *policy) · 40 unmodified lines
133126 }
134127 EXPORT_SYMBOL_GPL(get_governor_parent_kobj);
135128
136−struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu)
137−{
138− struct cpufreq_policy *policy = per_cpu(cpufreq_cpu_data, cpu);
139−
140− return policy && !policy_is_inactive(policy) ?
141− policy->freq_table : NULL;
142−}
143−EXPORT_SYMBOL_GPL(cpufreq_frequency_get_table);
144−
145129 static inline u64 get_cpu_idle_time_jiffy(unsigned int cpu, u64 *wall)
146130 {
147131 u64 idle_time;
@@ -354,6 +338,7 @@ static void __cpufreq_notify_transition(struct cpufreq_policy *policy, · 206 unmodified lines
354338 pr_debug("FREQ: %lu - CPU: %lu\n",
355339 (unsigned long)freqs->new, (unsigned long)freqs->cpu);
356340 trace_cpu_frequency(freqs->new, freqs->cpu);
341+ cpufreq_stats_record_transition(policy, freqs->new);
357342 srcu_notifier_call_chain(&cpufreq_transition_notifier_list,
358343 CPUFREQ_POSTCHANGE, freqs);
359344 if (likely(policy) && likely(policy->cpu == freqs->cpu))
@@ -507,6 +492,38 @@ void cpufreq_disable_fast_switch(struct cpufreq_policy *policy) · 147 unmodified lines
507492 }
508493 EXPORT_SYMBOL_GPL(cpufreq_disable_fast_switch);
509494
495+/**
496+ * cpufreq_driver_resolve_freq - Map a target frequency to a driver-supported
497+ * one.
498+ * @target_freq: target frequency to resolve.
499+ *
500+ * The target to driver frequency mapping is cached in the policy.
501+ *
502+ * Return: Lowest driver-supported frequency greater than or equal to the
503+ * given target_freq, subject to policy (min/max) and driver limitations.
504+ */
505+unsigned int cpufreq_driver_resolve_freq(struct cpufreq_policy *policy,
506+ unsigned int target_freq)
507+{
508+ target_freq = clamp_val(target_freq, policy->min, policy->max);
509+ policy->cached_target_freq = target_freq;
510+
511+ if (cpufreq_driver->target_index) {
512+ int idx;
513+
514+ idx = cpufreq_frequency_table_target(policy, target_freq,
515+ CPUFREQ_RELATION_L);
516+ policy->cached_resolved_idx = idx;
517+ return policy->freq_table[idx].frequency;
518+ }
519+
520+ if (cpufreq_driver->resolve_freq)
521+ return cpufreq_driver->resolve_freq(policy, target_freq);
522+
523+ return target_freq;
524+}
525+EXPORT_SYMBOL_GPL(cpufreq_driver_resolve_freq);
526+
510527 /*********************************************************************
511528 * SYSFS INTERFACE *
512529 *********************************************************************/
@@ -1115,6 +1132,7 @@ static void cpufreq_policy_put_kobj(struct cpufreq_policy *policy, bool notify) · 602 unmodified lines
11151132 CPUFREQ_REMOVE_POLICY, policy);
11161133
11171134 down_write(&policy->rwsem);
1135+ cpufreq_stats_free_table(policy);
11181136 cpufreq_remove_dev_symlink(policy);
11191137 kobj = &policy->kobj;
11201138 cmp = &policy->kobj_unregister;
@@ -1265,13 +1283,12 @@ static int cpufreq_online(unsigned int cpu) · 144 unmodified lines
12651283 }
12661284 }
12671285
1268− blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
1269− CPUFREQ_START, policy);
1270−
12711286 if (new_policy) {
12721287 ret = cpufreq_add_dev_interface(policy);
12731288 if (ret)
12741289 goto out_exit_policy;
1290+
1291+ cpufreq_stats_create_table(policy);
12751292 blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
12761293 CPUFREQ_CREATE_POLICY, policy);
12771294
@@ -1280,6 +1297,9 @@ static int cpufreq_online(unsigned int cpu) · 2 unmodified lines
12801297 write_unlock_irqrestore(&cpufreq_driver_lock, flags);
12811298 }
12821299
1300+ blocking_notifier_call_chain(&cpufreq_policy_notifier_list,
1301+ CPUFREQ_START, policy);
1302+
12831303 ret = cpufreq_init_policy(policy);
12841304 if (ret) {
12851305 pr_err("%s: Failed to initialize policy for cpu: %d (%d)\n",
@@ -1556,9 +1576,6 @@ static unsigned int cpufreq_update_current_freq(struct cpufreq_policy *policy) · 270 unmodified lines
15561576 {
15571577 unsigned int new_freq;
15581578
1559− if (cpufreq_suspended)
1560− return 0;
1561−
15621579 new_freq = cpufreq_driver->get(policy->cpu);
15631580 if (!new_freq)
15641581 return 0;
@@ -1864,14 +1881,17 @@ static int __target_intermediate(struct cpufreq_policy *policy, · 299 unmodified lines
18641881 return ret;
18651882 }
18661883
1867−static int __target_index(struct cpufreq_policy *policy,
1868− struct cpufreq_frequency_table *freq_table, int index)
1884+static int __target_index(struct cpufreq_policy *policy, int index)
18691885 {
18701886 struct cpufreq_freqs freqs = {.old = policy->cur, .flags = 0};
18711887 unsigned int intermediate_freq = 0;
1888+ unsigned int newfreq = policy->freq_table[index].frequency;
18721889 int retval = -EINVAL;
18731890 bool notify;
18741891
1892+ if (newfreq == policy->cur)
1893+ return 0;
1894+
18751895 notify = !(cpufreq_driver->flags & CPUFREQ_ASYNC_NOTIFICATION);
18761896 if (notify) {
18771897 /* Handle switching to intermediate frequency */
@@ -1886,7 +1906,7 @@ static int __target_index(struct cpufreq_policy *policy, · 8 unmodified lines
18861906 freqs.old = freqs.new;
18871907 }
18881908
1889− freqs.new = freq_table[index].frequency;
1909+ freqs.new = newfreq;
18901910 pr_debug("%s: cpu: %d, oldfreq: %u, new freq: %u\n",
18911911 __func__, policy->cpu, freqs.old, freqs.new);
18921912
@@ -1923,17 +1943,13 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, · 30 unmodified lines
19231943 unsigned int relation)
19241944 {
19251945 unsigned int old_target_freq = target_freq;
1926− struct cpufreq_frequency_table *freq_table;
1927− int index, retval;
1946+ int index;
19281947
19291948 if (cpufreq_disabled())
19301949 return -ENODEV;
19311950
19321951 /* Make sure that target_freq is within supported range */
1933− if (target_freq > policy->max)
1934− target_freq = policy->max;
1935− if (target_freq < policy->min)
1936− target_freq = policy->min;
1952+ target_freq = clamp_val(target_freq, policy->min, policy->max);
19371953
19381954 pr_debug("target for CPU %u: %u kHz, relation %u, requested %u kHz\n",
19391955 policy->cpu, target_freq, relation, old_target_freq);
@@ -1956,23 +1972,9 @@ int __cpufreq_driver_target(struct cpufreq_policy *policy, · 16 unmodified lines
19561972 if (!cpufreq_driver->target_index)
19571973 return -EINVAL;
19581974
1959− freq_table = cpufreq_frequency_get_table(policy->cpu);
1960− if (unlikely(!freq_table)) {
1961− pr_err("%s: Unable to find freq_table\n", __func__);
1962− return -EINVAL;
1963− }
1964−
1965− retval = cpufreq_frequency_table_target(policy, freq_table, target_freq,
1966− relation, &index);
1967− if (unlikely(retval)) {
1968− pr_err("%s: Unable to find matching freq\n", __func__);
1969− return retval;
1970− }
1971−
1972− if (freq_table[index].frequency == policy->cur)
1973− return 0;
1975+ index = cpufreq_frequency_table_target(policy, target_freq, relation);
19741976
1975− return __target_index(policy, freq_table, index);
1977+ return __target_index(policy, index);
19761978 }
19771979 EXPORT_SYMBOL_GPL(__cpufreq_driver_target);
19781980
@@ -1997,7 +1999,7 @@ __weak struct cpufreq_governor *cpufreq_fallback_governor(void) · 18 unmodified lines
19971999 return NULL;
19982000 }
19992001
2000−static int cpufreq_governor(struct cpufreq_policy *policy, unsigned int event)
2002+static int cpufreq_init_governor(struct cpufreq_policy *policy)
20012003 {
20022004 int ret;
20032005
@@ -2025,36 +2027,82 @@ static int cpufreq_governor(struct cpufreq_policy *policy, unsigned int event) · 21 unmodified lines
20252027 }
20262028 }
20272029
2028− if (event == CPUFREQ_GOV_POLICY_INIT)
2029− if (!try_module_get(policy->governor->owner))
2030− return -EINVAL;
2031−
2032− pr_debug("%s: for CPU %u, event %u\n", __func__, policy->cpu, event);
2030+ if (!try_module_get(policy->governor->owner))
2031+ return -EINVAL;
20332032
2034− ret = policy->governor->governor(policy, event);
2033+ pr_debug("%s: for CPU %u\n", __func__, policy->cpu);
20352034
2036− if (event == CPUFREQ_GOV_POLICY_INIT) {
2037− if (ret)
2035+ if (policy->governor->init) {
2036+ ret = policy->governor->init(policy);
2037+ if (ret) {
20382038 module_put(policy->governor->owner);
2039− else
2040− policy->governor->initialized++;
2041− } else if (event == CPUFREQ_GOV_POLICY_EXIT) {
2042− policy->governor->initialized--;
2043− module_put(policy->governor->owner);
2039+ return ret;
2040+ }
20442041 }
20452042
2046− return ret;
2043+ return 0;
2044+}
2045+
2046+static void cpufreq_exit_governor(struct cpufreq_policy *policy)
2047+{
2048+ if (cpufreq_suspended || !policy->governor)
2049+ return;
2050+
2051+ pr_debug("%s: for CPU %u\n", __func__, policy->cpu);
2052+
2053+ if (policy->governor->exit)
2054+ policy->governor->exit(policy);
2055+
2056+ module_put(policy->governor->owner);
20472057 }
20482058
20492059 static int cpufreq_start_governor(struct cpufreq_policy *policy)
20502060 {
20512061 int ret;
20522062
2063+ if (cpufreq_suspended)
2064+ return 0;
2065+
2066+ if (!policy->governor)
2067+ return -EINVAL;
2068+
2069+ pr_debug("%s: for CPU %u\n", __func__, policy->cpu);
2070+
20532071 if (cpufreq_driver->get && !cpufreq_driver->setpolicy)
20542072 cpufreq_update_current_freq(policy);
20552073
2056− ret = cpufreq_governor(policy, CPUFREQ_GOV_START);
2057− return ret ? ret : cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
2074+ if (policy->governor->start) {
2075+ ret = policy->governor->start(policy);
2076+ if (ret)
2077+ return ret;
2078+ }
2079+
2080+ if (policy->governor->limits)
2081+ policy->governor->limits(policy);
2082+
2083+ return 0;
2084+}
2085+
2086+static void cpufreq_stop_governor(struct cpufreq_policy *policy)
2087+{
2088+ if (cpufreq_suspended || !policy->governor)
2089+ return;
2090+
2091+ pr_debug("%s: for CPU %u\n", __func__, policy->cpu);
2092+
2093+ if (policy->governor->stop)
2094+ policy->governor->stop(policy);
2095+}
2096+
2097+static void cpufreq_governor_limits(struct cpufreq_policy *policy)
2098+{
2099+ if (cpufreq_suspended || !policy->governor)
2100+ return;
2101+
2102+ pr_debug("%s: for CPU %u\n", __func__, policy->cpu);
2103+
2104+ if (policy->governor->limits)
2105+ policy->governor->limits(policy);
20582106 }
20592107
20602108 int cpufreq_register_governor(struct cpufreq_governor *governor)
@@ -2069,7 +2117,6 @@ int cpufreq_register_governor(struct cpufreq_governor *governor) · 8 unmodified lines
20692117
20702118 mutex_lock(&cpufreq_governor_mutex);
20712119
2072− governor->initialized = 0;
20732120 err = -EBUSY;
20742121 if (!find_governor(governor->name)) {
20752122 err = 0;
@@ -2184,6 +2231,8 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, · 108 unmodified lines
21842231 policy->min = new_policy->min;
21852232 policy->max = new_policy->max;
21862233
2234+ policy->cached_target_freq = UINT_MAX;
2235+
21872236 pr_debug("new min and max freqs are %u - %u kHz\n",
21882237 policy->min, policy->max);
21892238
@@ -2195,7 +2244,8 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, · 5 unmodified lines
21952244
21962245 if (new_policy->governor == policy->governor) {
21972246 pr_debug("cpufreq: governor limits update\n");
2198− return cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
2247+ cpufreq_governor_limits(policy);
2248+ return 0;
21992249 }
22002250
22012251 pr_debug("governor switch\n");
@@ -2210,7 +2260,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, · 8 unmodified lines
22102260
22112261 /* start new governor */
22122262 policy->governor = new_policy->governor;
2213− ret = cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT);
2263+ ret = cpufreq_init_governor(policy);
22142264 if (!ret) {
22152265 ret = cpufreq_start_governor(policy);
22162266 if (!ret) {
@@ -2224,7 +2274,7 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy, · 7 unmodified lines
22242274 pr_debug("starting governor %s failed\n", policy->governor->name);
22252275 if (old_gov) {
22262276 policy->governor = old_gov;
2227− if (cpufreq_governor(policy, CPUFREQ_GOV_POLICY_INIT))
2277+ if (cpufreq_init_governor(policy))
22282278 policy->governor = NULL;
22292279 else
22302280 cpufreq_start_governor(policy);
@@ -2309,26 +2359,25 @@ static struct notifier_block __refdata cpufreq_cpu_notifier = { · 78 unmodified lines
23092359 *********************************************************************/
23102360 static int cpufreq_boost_set_sw(int state)
23112361 {
2312− struct cpufreq_frequency_table *freq_table;
23132362 struct cpufreq_policy *policy;
23142363 int ret = -EINVAL;
23152364
23162365 for_each_active_policy(policy) {
2317− freq_table = cpufreq_frequency_get_table(policy->cpu);
2318− if (freq_table) {
2319− ret = cpufreq_frequency_table_cpuinfo(policy,
2320− freq_table);
2321− if (ret) {
2322− pr_err("%s: Policy frequency update failed\n",
2323− __func__);
2324− break;
2325− }
2326−
2327− down_write(&policy->rwsem);
2328− policy->user_policy.max = policy->max;
2329− cpufreq_governor(policy, CPUFREQ_GOV_LIMITS);
2330− up_write(&policy->rwsem);
2366+ if (!policy->freq_table)
2367+ continue;
2368+
2369+ ret = cpufreq_frequency_table_cpuinfo(policy,
2370+ policy->freq_table);
2371+ if (ret) {
2372+ pr_err("%s: Policy frequency update failed\n",
2373+ __func__);
2374+ break;
23312375 }
2376+
2377+ down_write(&policy->rwsem);
2378+ policy->user_policy.max = policy->max;
2379+ cpufreq_governor_limits(policy);
2380+ up_write(&policy->rwsem);
23322381 }
23332382
23342383 return ret;
drivers/cpufreq/cpufreq_conservative.c+17−71
@@ -17,7 +17,6 @@ · 16 unmodified lines
1717 struct cs_policy_dbs_info {
1818 struct policy_dbs_info policy_dbs;
1919 unsigned int down_skip;
20− unsigned int requested_freq;
2120 };
2221
2322 static inline struct cs_policy_dbs_info *to_dbs_info(struct policy_dbs_info *policy_dbs)
@@ -75,19 +74,17 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy) · 51 unmodified lines
7574
7675 /* Check for frequency increase */
7776 if (load > dbs_data->up_threshold) {
77+ unsigned int requested_freq = policy->cur;
78+
7879 dbs_info->down_skip = 0;
7980
8081 /* if we are already at full speed then break out early */
81− if (dbs_info->requested_freq == policy->max)
82+ if (requested_freq == policy->max)
8283 goto out;
8384
84− dbs_info->requested_freq += get_freq_target(cs_tuners, policy);
85−
86− if (dbs_info->requested_freq > policy->max)
87− dbs_info->requested_freq = policy->max;
85+ requested_freq += get_freq_target(cs_tuners, policy);
8886
89− __cpufreq_driver_target(policy, dbs_info->requested_freq,
90− CPUFREQ_RELATION_H);
87+ __cpufreq_driver_target(policy, requested_freq, CPUFREQ_RELATION_H);
9188 goto out;
9289 }
9390
@@ -98,36 +95,27 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy) · 4 unmodified lines
9895
9996 /* Check for frequency decrease */
10097 if (load < cs_tuners->down_threshold) {
101− unsigned int freq_target;
98+ unsigned int freq_target, requested_freq = policy->cur;
10299 /*
103100 * if we cannot reduce the frequency anymore, break out early
104101 */
105− if (policy->cur == policy->min)
102+ if (requested_freq == policy->min)
106103 goto out;
107104
108105 freq_target = get_freq_target(cs_tuners, policy);
109− if (dbs_info->requested_freq > freq_target)
110− dbs_info->requested_freq -= freq_target;
106+ if (requested_freq > freq_target)
107+ requested_freq -= freq_target;
111108 else
112− dbs_info->requested_freq = policy->min;
109+ requested_freq = policy->min;
113110
114− __cpufreq_driver_target(policy, dbs_info->requested_freq,
115− CPUFREQ_RELATION_L);
111+ __cpufreq_driver_target(policy, requested_freq, CPUFREQ_RELATION_L);
116112 }
117113
118114 out:
119115 return dbs_data->sampling_rate;
120116 }
121117
122−static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
123− void *data);
124−
125−static struct notifier_block cs_cpufreq_notifier_block = {
126− .notifier_call = dbs_cpufreq_notifier,
127−};
128−
129118 /************************** sysfs interface ************************/
130−static struct dbs_governor cs_dbs_gov;
131119
132120 static ssize_t store_sampling_down_factor(struct gov_attr_set *attr_set,
133121 const char *buf, size_t count)
@@ -268,15 +256,13 @@ static void cs_free(struct policy_dbs_info *policy_dbs) · 134 unmodified lines
268256 kfree(to_dbs_info(policy_dbs));
269257 }
270258
271−static int cs_init(struct dbs_data *dbs_data, bool notify)
259+static int cs_init(struct dbs_data *dbs_data)
272260 {
273261 struct cs_dbs_tuners *tuners;
274262
275263 tuners = kzalloc(sizeof(*tuners), GFP_KERNEL);
276− if (!tuners) {
277− pr_err("%s: kzalloc failed\n", __func__);
264+ if (!tuners)
278265 return -ENOMEM;
279− }
280266
281267 tuners->down_threshold = DEF_FREQUENCY_DOWN_THRESHOLD;
282268 tuners->freq_step = DEF_FREQUENCY_STEP;
@@ -288,19 +274,11 @@ static int cs_init(struct dbs_data *dbs_data, bool notify) · 5 unmodified lines
288274 dbs_data->min_sampling_rate = MIN_SAMPLING_RATE_RATIO *
289275 jiffies_to_usecs(10);
290276
291− if (notify)
292− cpufreq_register_notifier(&cs_cpufreq_notifier_block,
293− CPUFREQ_TRANSITION_NOTIFIER);
294−
295277 return 0;
296278 }
297279
298−static void cs_exit(struct dbs_data *dbs_data, bool notify)
280+static void cs_exit(struct dbs_data *dbs_data)
299281 {
300− if (notify)
301− cpufreq_unregister_notifier(&cs_cpufreq_notifier_block,
302− CPUFREQ_TRANSITION_NOTIFIER);
303−
304282 kfree(dbs_data->tuners);
305283 }
306284
@@ -309,16 +287,10 @@ static void cs_start(struct cpufreq_policy *policy) · 2 unmodified lines
309287 struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data);
310288
311289 dbs_info->down_skip = 0;
312− dbs_info->requested_freq = policy->cur;
313290 }
314291
315−static struct dbs_governor cs_dbs_gov = {
316− .gov = {
317− .name = "conservative",
318− .governor = cpufreq_governor_dbs,
319− .max_transition_latency = TRANSITION_LATENCY_LIMIT,
320− .owner = THIS_MODULE,
321− },
292+static struct dbs_governor cs_governor = {
293+ .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"),
322294 .kobj_type = { .default_attrs = cs_attributes },
323295 .gov_dbs_timer = cs_dbs_timer,
324296 .alloc = cs_alloc,
@@ -328,33 +300,7 @@ static struct dbs_governor cs_dbs_gov = { · 3 unmodified lines
328300 .start = cs_start,
329301 };
330302
331−#define CPU_FREQ_GOV_CONSERVATIVE (&cs_dbs_gov.gov)
332−
333−static int dbs_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
334− void *data)
335−{
336− struct cpufreq_freqs *freq = data;
337− struct cpufreq_policy *policy = cpufreq_cpu_get_raw(freq->cpu);
338− struct cs_policy_dbs_info *dbs_info;
339−
340− if (!policy)
341− return 0;
342−
343− /* policy isn't governed by conservative governor */
344− if (policy->governor != CPU_FREQ_GOV_CONSERVATIVE)
345− return 0;
346−
347− dbs_info = to_dbs_info(policy->governor_data);
348− /*
349− * we only care if our internally tracked freq moves outside the 'valid'
350− * ranges of frequency available to us otherwise we do not change it
351− */
352− if (dbs_info->requested_freq > policy->max
353− || dbs_info->requested_freq < policy->min)
354− dbs_info->requested_freq = freq->new;
355−
356− return 0;
357−}
303+#define CPU_FREQ_GOV_CONSERVATIVE (&cs_governor.gov)
358304
359305 static int __init cpufreq_gov_dbs_init(void)
360306 {
drivers/cpufreq/cpufreq_governor.c+22−51
@@ -336,17 +336,6 @@ static inline void gov_clear_update_util(struct cpufreq_policy *policy) · 335 unmodified lines
336336 synchronize_sched();
337337 }
338338
339−static void gov_cancel_work(struct cpufreq_policy *policy)
340−{
341− struct policy_dbs_info *policy_dbs = policy->governor_data;
342−
343− gov_clear_update_util(policy_dbs->policy);
344− irq_work_sync(&policy_dbs->irq_work);
345− cancel_work_sync(&policy_dbs->work);
346− atomic_set(&policy_dbs->work_count, 0);
347− policy_dbs->work_in_progress = false;
348−}
349−
350339 static struct policy_dbs_info *alloc_policy_dbs_info(struct cpufreq_policy *policy,
351340 struct dbs_governor *gov)
352341 {
@@ -389,7 +378,7 @@ static void free_policy_dbs_info(struct policy_dbs_info *policy_dbs, · 36 unmodified lines
389378 gov->free(policy_dbs);
390379 }
391380
392−static int cpufreq_governor_init(struct cpufreq_policy *policy)
381+int cpufreq_dbs_governor_init(struct cpufreq_policy *policy)
393382 {
394383 struct dbs_governor *gov = dbs_governor_of(policy);
395384 struct dbs_data *dbs_data;
@@ -429,7 +418,7 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy) · 33 unmodified lines
429418
430419 gov_attr_set_init(&dbs_data->attr_set, &policy_dbs->list);
431420
432− ret = gov->init(dbs_data, !policy->governor->initialized);
421+ ret = gov->init(dbs_data);
433422 if (ret)
434423 goto free_policy_dbs_info;
435424
@@ -458,13 +447,13 @@ static int cpufreq_governor_init(struct cpufreq_policy *policy) · 22 unmodified lines
458447 goto out;
459448
460449 /* Failure, so roll back. */
461− pr_err("cpufreq: Governor initialization failed (dbs_data kobject init error %d)\n", ret);
450+ pr_err("initialization failed (dbs_data kobject init error %d)\n", ret);
462451
463452 policy->governor_data = NULL;
464453
465454 if (!have_governor_per_policy())
466455 gov->gdbs_data = NULL;
467− gov->exit(dbs_data, !policy->governor->initialized);
456+ gov->exit(dbs_data);
468457 kfree(dbs_data);
469458
470459 free_policy_dbs_info:
@@ -474,8 +463,9 @@ out: · 3 unmodified lines
474463 mutex_unlock(&gov_dbs_data_mutex);
475464 return ret;
476465 }
466+EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_init);
477467
478−static int cpufreq_governor_exit(struct cpufreq_policy *policy)
468+void cpufreq_dbs_governor_exit(struct cpufreq_policy *policy)
479469 {
480470 struct dbs_governor *gov = dbs_governor_of(policy);
481471 struct policy_dbs_info *policy_dbs = policy->governor_data;
@@ -493,17 +483,17 @@ static int cpufreq_governor_exit(struct cpufreq_policy *policy) · 11 unmodified lines
493483 if (!have_governor_per_policy())
494484 gov->gdbs_data = NULL;
495485
496− gov->exit(dbs_data, policy->governor->initialized == 1);
486+ gov->exit(dbs_data);
497487 kfree(dbs_data);
498488 }
499489
500490 free_policy_dbs_info(policy_dbs, gov);
501491
502492 mutex_unlock(&gov_dbs_data_mutex);
503− return 0;
504493 }
494+EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_exit);
505495
506−static int cpufreq_governor_start(struct cpufreq_policy *policy)
496+int cpufreq_dbs_governor_start(struct cpufreq_policy *policy)
507497 {
508498 struct dbs_governor *gov = dbs_governor_of(policy);
509499 struct policy_dbs_info *policy_dbs = policy->governor_data;
@@ -539,47 +529,28 @@ static int cpufreq_governor_start(struct cpufreq_policy *policy) · 29 unmodified lines
539529 gov_set_update_util(policy_dbs, sampling_rate);
540530 return 0;
541531 }
532+EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_start);
542533
543−static int cpufreq_governor_stop(struct cpufreq_policy *policy)
534+void cpufreq_dbs_governor_stop(struct cpufreq_policy *policy)
544535 {
545− gov_cancel_work(policy);
546− return 0;
536+ struct policy_dbs_info *policy_dbs = policy->governor_data;
537+
538+ gov_clear_update_util(policy_dbs->policy);
539+ irq_work_sync(&policy_dbs->irq_work);
540+ cancel_work_sync(&policy_dbs->work);
541+ atomic_set(&policy_dbs->work_count, 0);
542+ policy_dbs->work_in_progress = false;
547543 }
544+EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_stop);
548545
549−static int cpufreq_governor_limits(struct cpufreq_policy *policy)
546+void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
550547 {
551548 struct policy_dbs_info *policy_dbs = policy->governor_data;
552549
553550 mutex_lock(&policy_dbs->timer_mutex);
554−
555− if (policy->max < policy->cur)
556− __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H);
557− else if (policy->min > policy->cur)
558− __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L);
559−
551+ cpufreq_policy_apply_limits(policy);
560552 gov_update_sample_delay(policy_dbs, 0);
561553
562554 mutex_unlock(&policy_dbs->timer_mutex);
563−
564− return 0;
565−}
566−
567−int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event)
568−{
569− if (event == CPUFREQ_GOV_POLICY_INIT) {
570− return cpufreq_governor_init(policy);
571− } else if (policy->governor_data) {
572− switch (event) {
573− case CPUFREQ_GOV_POLICY_EXIT:
574− return cpufreq_governor_exit(policy);
575− case CPUFREQ_GOV_START:
576− return cpufreq_governor_start(policy);
577− case CPUFREQ_GOV_STOP:
578− return cpufreq_governor_stop(policy);
579− case CPUFREQ_GOV_LIMITS:
580− return cpufreq_governor_limits(policy);
581− }
582− }
583− return -EINVAL;
584555 }
585−EXPORT_SYMBOL_GPL(cpufreq_governor_dbs);
556+EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_limits);
drivers/cpufreq/cpufreq_governor.h+21−3
@@ -138,8 +138,8 @@ struct dbs_governor { · 137 unmodified lines
138138 unsigned int (*gov_dbs_timer)(struct cpufreq_policy *policy);
139139 struct policy_dbs_info *(*alloc)(void);
140140 void (*free)(struct policy_dbs_info *policy_dbs);
141− int (*init)(struct dbs_data *dbs_data, bool notify);
142− void (*exit)(struct dbs_data *dbs_data, bool notify);
141+ int (*init)(struct dbs_data *dbs_data);
142+ void (*exit)(struct dbs_data *dbs_data);
143143 void (*start)(struct cpufreq_policy *policy);
144144 };
145145
@@ -148,6 +148,25 @@ static inline struct dbs_governor *dbs_governor_of(struct cpufreq_policy *policy · 2 unmodified lines
148148 return container_of(policy->governor, struct dbs_governor, gov);
149149 }
150150
151+/* Governor callback routines */
152+int cpufreq_dbs_governor_init(struct cpufreq_policy *policy);
153+void cpufreq_dbs_governor_exit(struct cpufreq_policy *policy);
154+int cpufreq_dbs_governor_start(struct cpufreq_policy *policy);
155+void cpufreq_dbs_governor_stop(struct cpufreq_policy *policy);
156+void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy);
157+
158+#define CPUFREQ_DBS_GOVERNOR_INITIALIZER(_name_) \
159+ { \
160+ .name = _name_, \
161+ .max_transition_latency = TRANSITION_LATENCY_LIMIT, \
162+ .owner = THIS_MODULE, \
163+ .init = cpufreq_dbs_governor_init, \
164+ .exit = cpufreq_dbs_governor_exit, \
165+ .start = cpufreq_dbs_governor_start, \
166+ .stop = cpufreq_dbs_governor_stop, \
167+ .limits = cpufreq_dbs_governor_limits, \
168+ }
169+
151170 /* Governor specific operations */
152171 struct od_ops {
153172 unsigned int (*powersave_bias_target)(struct cpufreq_policy *policy,
@@ -155,7 +174,6 @@ struct od_ops { · 1 unmodified line
155174 };
156175
157176 unsigned int dbs_update(struct cpufreq_policy *policy);
158−int cpufreq_governor_dbs(struct cpufreq_policy *policy, unsigned int event);
159177 void od_register_powersave_bias_handler(unsigned int (*f)
160178 (struct cpufreq_policy *, unsigned int, unsigned int),
161179 unsigned int powersave_bias);
drivers/cpufreq/cpufreq_ondemand.c+13−25
@@ -65,34 +65,30 @@ static unsigned int generic_powersave_bias_target(struct cpufreq_policy *policy, · 64 unmodified lines
6565 {
6666 unsigned int freq_req, freq_reduc, freq_avg;
6767 unsigned int freq_hi, freq_lo;
68− unsigned int index = 0;
68+ unsigned int index;
6969 unsigned int delay_hi_us;
7070 struct policy_dbs_info *policy_dbs = policy->governor_data;
7171 struct od_policy_dbs_info *dbs_info = to_dbs_info(policy_dbs);
7272 struct dbs_data *dbs_data = policy_dbs->dbs_data;
7373 struct od_dbs_tuners *od_tuners = dbs_data->tuners;
74+ struct cpufreq_frequency_table *freq_table = policy->freq_table;
7475
75− if (!dbs_info->freq_table) {
76+ if (!freq_table) {
7677 dbs_info->freq_lo = 0;
7778 dbs_info->freq_lo_delay_us = 0;
7879 return freq_next;
7980 }
8081
81− cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_next,
82− relation, &index);
83− freq_req = dbs_info->freq_table[index].frequency;
82+ index = cpufreq_frequency_table_target(policy, freq_next, relation);
83+ freq_req = freq_table[index].frequency;
8484 freq_reduc = freq_req * od_tuners->powersave_bias / 1000;
8585 freq_avg = freq_req - freq_reduc;
8686
8787 /* Find freq bounds for freq_avg in freq_table */
88− index = 0;
89− cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg,
90− CPUFREQ_RELATION_H, &index);
91− freq_lo = dbs_info->freq_table[index].frequency;
92− index = 0;
93− cpufreq_frequency_table_target(policy, dbs_info->freq_table, freq_avg,
94− CPUFREQ_RELATION_L, &index);
95− freq_hi = dbs_info->freq_table[index].frequency;
88+ index = cpufreq_table_find_index_h(policy, freq_avg);
89+ freq_lo = freq_table[index].frequency;
90+ index = cpufreq_table_find_index_l(policy, freq_avg);
91+ freq_hi = freq_table[index].frequency;
9692
9793 /* Find out how long we have to be in hi and lo freqs */
9894 if (freq_hi == freq_lo) {
@@ -113,7 +109,6 @@ static void ondemand_powersave_bias_init(struct cpufreq_policy *policy) · 14 unmodified lines
113109 {
114110 struct od_policy_dbs_info *dbs_info = to_dbs_info(policy->governor_data);
115111
116− dbs_info->freq_table = cpufreq_frequency_get_table(policy->cpu);
117112 dbs_info->freq_lo = 0;
118113 }
119114
@@ -361,17 +356,15 @@ static void od_free(struct policy_dbs_info *policy_dbs) · 241 unmodified lines
361356 kfree(to_dbs_info(policy_dbs));
362357 }
363358
364−static int od_init(struct dbs_data *dbs_data, bool notify)
359+static int od_init(struct dbs_data *dbs_data)
365360 {
366361 struct od_dbs_tuners *tuners;
367362 u64 idle_time;
368363 int cpu;
369364
370365 tuners = kzalloc(sizeof(*tuners), GFP_KERNEL);
371− if (!tuners) {
372− pr_err("%s: kzalloc failed\n", __func__);
366+ if (!tuners)
373367 return -ENOMEM;
374− }
375368
376369 cpu = get_cpu();
377370 idle_time = get_cpu_idle_time_us(cpu, NULL);
@@ -402,7 +395,7 @@ static int od_init(struct dbs_data *dbs_data, bool notify) · 24 unmodified lines
402395 return 0;
403396 }
404397
405−static void od_exit(struct dbs_data *dbs_data, bool notify)
398+static void od_exit(struct dbs_data *dbs_data)
406399 {
407400 kfree(dbs_data->tuners);
408401 }
@@ -420,12 +413,7 @@ static struct od_ops od_ops = { · 11 unmodified lines
420413 };
421414
422415 static struct dbs_governor od_dbs_gov = {
423− .gov = {
424− .name = "ondemand",
425− .governor = cpufreq_governor_dbs,
426− .max_transition_latency = TRANSITION_LATENCY_LIMIT,
427− .owner = THIS_MODULE,
428− },
416+ .gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("ondemand"),
429417 .kobj_type = { .default_attrs = od_attributes },
430418 .gov_dbs_timer = od_dbs_timer,
431419 .alloc = od_alloc,
drivers/cpufreq/cpufreq_ondemand.h+0−1
@@ -13,7 +13,6 @@ · 12 unmodified lines
1313
1414 struct od_policy_dbs_info {
1515 struct policy_dbs_info policy_dbs;
16− struct cpufreq_frequency_table *freq_table;
1716 unsigned int freq_lo;
1817 unsigned int freq_lo_delay_us;
1918 unsigned int freq_hi_delay_us;
drivers/cpufreq/cpufreq_performance.c+4−15
@@ -16,27 +16,16 @@ · 15 unmodified lines
1616 #include <linux/init.h>
1717 #include <linux/module.h>
1818
19−static int cpufreq_governor_performance(struct cpufreq_policy *policy,
20− unsigned int event)
19+static void cpufreq_gov_performance_limits(struct cpufreq_policy *policy)
2120 {
22− switch (event) {
23− case CPUFREQ_GOV_START:
24− case CPUFREQ_GOV_LIMITS:
25− pr_debug("setting to %u kHz because of event %u\n",
26− policy->max, event);
27− __cpufreq_driver_target(policy, policy->max,
28− CPUFREQ_RELATION_H);
29− break;
30− default:
31− break;
32− }
33− return 0;
21+ pr_debug("setting to %u kHz\n", policy->max);
22+ __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H);
3423 }
3524
3625 static struct cpufreq_governor cpufreq_gov_performance = {
3726 .name = "performance",
38− .governor = cpufreq_governor_performance,
3927 .owner = THIS_MODULE,
28+ .limits = cpufreq_gov_performance_limits,
4029 };
4130
4231 static int __init cpufreq_gov_performance_init(void)
drivers/cpufreq/cpufreq_powersave.c+4−15
@@ -16,26 +16,15 @@ · 15 unmodified lines
1616 #include <linux/init.h>
1717 #include <linux/module.h>
1818
19−static int cpufreq_governor_powersave(struct cpufreq_policy *policy,
20− unsigned int event)
19+static void cpufreq_gov_powersave_limits(struct cpufreq_policy *policy)
2120 {
22− switch (event) {
23− case CPUFREQ_GOV_START:
24− case CPUFREQ_GOV_LIMITS:
25− pr_debug("setting to %u kHz because of event %u\n",
26− policy->min, event);
27− __cpufreq_driver_target(policy, policy->min,
28− CPUFREQ_RELATION_L);
29− break;
30− default:
31− break;
32− }
33− return 0;
21+ pr_debug("setting to %u kHz\n", policy->min);
22+ __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L);
3423 }
3524
3625 static struct cpufreq_governor cpufreq_gov_powersave = {
3726 .name = "powersave",
38− .governor = cpufreq_governor_powersave,
27+ .limits = cpufreq_gov_powersave_limits,
3928 .owner = THIS_MODULE,
4029 };
4130
drivers/cpufreq/cpufreq_stats.c+22−135
@@ -15,7 +15,7 @@ · 14 unmodified lines
1515 #include <linux/slab.h>
1616 #include <linux/cputime.h>
1717
18−static spinlock_t cpufreq_stats_lock;
18+static DEFINE_SPINLOCK(cpufreq_stats_lock);
1919
2020 struct cpufreq_stats {
2121 unsigned int total_trans;
@@ -52,6 +52,9 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf) · 30 unmodified lines
5252 ssize_t len = 0;
5353 int i;
5454
55+ if (policy->fast_switch_enabled)
56+ return 0;
57+
5558 cpufreq_stats_update(stats);
5659 for (i = 0; i < stats->state_num; i++) {
5760 len += sprintf(buf + len, "%u %llu\n", stats->freq_table[i],
@@ -68,6 +71,9 @@ static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf) · 10 unmodified lines
6871 ssize_t len = 0;
6972 int i, j;
7073
74+ if (policy->fast_switch_enabled)
75+ return 0;
76+
7177 len += snprintf(buf + len, PAGE_SIZE - len, " From : To\n");
7278 len += snprintf(buf + len, PAGE_SIZE - len, " : ");
7379 for (i = 0; i < stats->state_num; i++) {
@@ -130,7 +136,7 @@ static int freq_table_get_index(struct cpufreq_stats *stats, unsigned int freq) · 56 unmodified lines
130136 return -1;
131137 }
132138
133−static void __cpufreq_stats_free_table(struct cpufreq_policy *policy)
139+void cpufreq_stats_free_table(struct cpufreq_policy *policy)
134140 {
135141 struct cpufreq_stats *stats = policy->stats;
136142
@@ -146,39 +152,25 @@ static void __cpufreq_stats_free_table(struct cpufreq_policy *policy) · 9 unmodified lines
146152 policy->stats = NULL;
147153 }
148154
149−static void cpufreq_stats_free_table(unsigned int cpu)
150−{
151− struct cpufreq_policy *policy;
152−
153− policy = cpufreq_cpu_get(cpu);
154− if (!policy)
155− return;
156−
157− __cpufreq_stats_free_table(policy);
158−
159− cpufreq_cpu_put(policy);
160−}
161−
162−static int __cpufreq_stats_create_table(struct cpufreq_policy *policy)
155+void cpufreq_stats_create_table(struct cpufreq_policy *policy)
163156 {
164157 unsigned int i = 0, count = 0, ret = -ENOMEM;
165158 struct cpufreq_stats *stats;
166159 unsigned int alloc_size;
167− unsigned int cpu = policy->cpu;
168160 struct cpufreq_frequency_table *pos, *table;
169161
170162 /* We need cpufreq table for creating stats table */
171− table = cpufreq_frequency_get_table(cpu);
163+ table = policy->freq_table;
172164 if (unlikely(!table))
173− return 0;
165+ return;
174166
175167 /* stats already initialized */
176168 if (policy->stats)
177− return -EEXIST;
169+ return;
178170
179171 stats = kzalloc(sizeof(*stats), GFP_KERNEL);
180172 if (!stats)
181− return -ENOMEM;
173+ return;
182174
183175 /* Find total allocation size */
184176 cpufreq_for_each_valid_entry(pos, table)
@@ -215,80 +207,32 @@ static int __cpufreq_stats_create_table(struct cpufreq_policy *policy) · 30 unmodified lines
215207 policy->stats = stats;
216208 ret = sysfs_create_group(&policy->kobj, &stats_attr_group);
217209 if (!ret)
218− return 0;
210+ return;
219211
220212 /* We failed, release resources */
221213 policy->stats = NULL;
222214 kfree(stats->time_in_state);
223215 free_stat:
224216 kfree(stats);
225−
226− return ret;
227−}
228−
229−static void cpufreq_stats_create_table(unsigned int cpu)
230−{
231− struct cpufreq_policy *policy;
232−
233− /*
234− * "likely(!policy)" because normally cpufreq_stats will be registered
235− * before cpufreq driver
236− */
237− policy = cpufreq_cpu_get(cpu);
238− if (likely(!policy))
239− return;
240−
241− __cpufreq_stats_create_table(policy);
242−
243− cpufreq_cpu_put(policy);
244217 }
245218
246−static int cpufreq_stat_notifier_policy(struct notifier_block *nb,
247− unsigned long val, void *data)
219+void cpufreq_stats_record_transition(struct cpufreq_policy *policy,
220+ unsigned int new_freq)
248221 {
249− int ret = 0;
250− struct cpufreq_policy *policy = data;
251−
252− if (val == CPUFREQ_CREATE_POLICY)
253− ret = __cpufreq_stats_create_table(policy);
254− else if (val == CPUFREQ_REMOVE_POLICY)
255− __cpufreq_stats_free_table(policy);
256−
257− return ret;
258−}
259−
260−static int cpufreq_stat_notifier_trans(struct notifier_block *nb,
261− unsigned long val, void *data)
262−{
263− struct cpufreq_freqs *freq = data;
264− struct cpufreq_policy *policy = cpufreq_cpu_get(freq->cpu);
265− struct cpufreq_stats *stats;
222+ struct cpufreq_stats *stats = policy->stats;
266223 int old_index, new_index;
267224
268− if (!policy) {
269− pr_err("%s: No policy found\n", __func__);
270− return 0;
271− }
272−
273− if (val != CPUFREQ_POSTCHANGE)
274− goto put_policy;
275−
276− if (!policy->stats) {
225+ if (!stats) {
277226 pr_debug("%s: No stats found\n", __func__);
278− goto put_policy;
227+ return;
279228 }
280229
281− stats = policy->stats;
282−
283230 old_index = stats->last_index;
284− new_index = freq_table_get_index(stats, freq->new);
231+ new_index = freq_table_get_index(stats, new_freq);
285232
286233 /* We can't do stats->time_in_state[-1]= .. */
287− if (old_index == -1 || new_index == -1)
288− goto put_policy;
289−
290− if (old_index == new_index)
291− goto put_policy;
234+ if (old_index == -1 || new_index == -1 || old_index == new_index)
235+ return;
292236
293237 cpufreq_stats_update(stats);
294238
@@ -297,61 +241,4 @@ static int cpufreq_stat_notifier_trans(struct notifier_block *nb, · 2 unmodified lines
297241 stats->trans_table[old_index * stats->max_state + new_index]++;
298242 #endif
299243 stats->total_trans++;
300−
301−put_policy:
302− cpufreq_cpu_put(policy);
303− return 0;
304244 }
305−
306−static struct notifier_block notifier_policy_block = {
307− .notifier_call = cpufreq_stat_notifier_policy
308−};
309−
310−static struct notifier_block notifier_trans_block = {
311− .notifier_call = cpufreq_stat_notifier_trans
312−};
313−
314−static int __init cpufreq_stats_init(void)
315−{
316− int ret;
317− unsigned int cpu;
318−
319− spin_lock_init(&cpufreq_stats_lock);
320− ret = cpufreq_register_notifier(&notifier_policy_block,
321− CPUFREQ_POLICY_NOTIFIER);
322− if (ret)
323− return ret;
324−
325− for_each_online_cpu(cpu)
326− cpufreq_stats_create_table(cpu);
327−
328− ret = cpufreq_register_notifier(&notifier_trans_block,
329− CPUFREQ_TRANSITION_NOTIFIER);
330− if (ret) {
331− cpufreq_unregister_notifier(&notifier_policy_block,
332− CPUFREQ_POLICY_NOTIFIER);
333− for_each_online_cpu(cpu)
334− cpufreq_stats_free_table(cpu);
335− return ret;
336− }
337−
338− return 0;
339−}
340−static void __exit cpufreq_stats_exit(void)
341−{
342− unsigned int cpu;
343−
344− cpufreq_unregister_notifier(&notifier_policy_block,
345− CPUFREQ_POLICY_NOTIFIER);
346− cpufreq_unregister_notifier(&notifier_trans_block,
347− CPUFREQ_TRANSITION_NOTIFIER);
348− for_each_online_cpu(cpu)
349− cpufreq_stats_free_table(cpu);
350−}
351−
352−MODULE_AUTHOR("Zou Nan hai <nanhai.zou@intel.com>");
353−MODULE_DESCRIPTION("Export cpufreq stats via sysfs");
354−MODULE_LICENSE("GPL");
355−
356−module_init(cpufreq_stats_init);
357−module_exit(cpufreq_stats_exit);
drivers/cpufreq/cpufreq_userspace.c+52−52
@@ -65,66 +65,66 @@ static int cpufreq_userspace_policy_init(struct cpufreq_policy *policy) · 64 unmodified lines
6565 return 0;
6666 }
6767
68−static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
69− unsigned int event)
68+static void cpufreq_userspace_policy_exit(struct cpufreq_policy *policy)
69+{
70+ mutex_lock(&userspace_mutex);
71+ kfree(policy->governor_data);
72+ policy->governor_data = NULL;
73+ mutex_unlock(&userspace_mutex);
74+}
75+
76+static int cpufreq_userspace_policy_start(struct cpufreq_policy *policy)
7077 {
7178 unsigned int *setspeed = policy->governor_data;
72− unsigned int cpu = policy->cpu;
73− int rc = 0;
7479
75− if (event == CPUFREQ_GOV_POLICY_INIT)
76− return cpufreq_userspace_policy_init(policy);
80+ BUG_ON(!policy->cur);
81+ pr_debug("started managing cpu %u\n", policy->cpu);
7782
78− if (!setspeed)
79− return -EINVAL;
80−
81− switch (event) {
82− case CPUFREQ_GOV_POLICY_EXIT:
83− mutex_lock(&userspace_mutex);
84− policy->governor_data = NULL;
85− kfree(setspeed);
86− mutex_unlock(&userspace_mutex);
87− break;
88− case CPUFREQ_GOV_START:
89− BUG_ON(!policy->cur);
90− pr_debug("started managing cpu %u\n", cpu);
91−
92− mutex_lock(&userspace_mutex);
93− per_cpu(cpu_is_managed, cpu) = 1;
94− *setspeed = policy->cur;
95− mutex_unlock(&userspace_mutex);
96− break;
97− case CPUFREQ_GOV_STOP:
98− pr_debug("managing cpu %u stopped\n", cpu);
99−
100− mutex_lock(&userspace_mutex);
101− per_cpu(cpu_is_managed, cpu) = 0;
102− *setspeed = 0;
103− mutex_unlock(&userspace_mutex);
104− break;
105− case CPUFREQ_GOV_LIMITS:
106− mutex_lock(&userspace_mutex);
107− pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n",
108− cpu, policy->min, policy->max, policy->cur, *setspeed);
109−
110− if (policy->max < *setspeed)
111− __cpufreq_driver_target(policy, policy->max,
112− CPUFREQ_RELATION_H);
113− else if (policy->min > *setspeed)
114− __cpufreq_driver_target(policy, policy->min,
115− CPUFREQ_RELATION_L);
116− else
117− __cpufreq_driver_target(policy, *setspeed,
118− CPUFREQ_RELATION_L);
119− mutex_unlock(&userspace_mutex);
120− break;
121− }
122− return rc;
83+ mutex_lock(&userspace_mutex);
84+ per_cpu(cpu_is_managed, policy->cpu) = 1;
85+ *setspeed = policy->cur;
86+ mutex_unlock(&userspace_mutex);
87+ return 0;
88+}
89+
90+static void cpufreq_userspace_policy_stop(struct cpufreq_policy *policy)
91+{
92+ unsigned int *setspeed = policy->governor_data;
93+
94+ pr_debug("managing cpu %u stopped\n", policy->cpu);
95+
96+ mutex_lock(&userspace_mutex);
97+ per_cpu(cpu_is_managed, policy->cpu) = 0;
98+ *setspeed = 0;
99+ mutex_unlock(&userspace_mutex);
100+}
101+
102+static void cpufreq_userspace_policy_limits(struct cpufreq_policy *policy)
103+{
104+ unsigned int *setspeed = policy->governor_data;
105+
106+ mutex_lock(&userspace_mutex);
107+
108+ pr_debug("limit event for cpu %u: %u - %u kHz, currently %u kHz, last set to %u kHz\n",
109+ policy->cpu, policy->min, policy->max, policy->cur, *setspeed);
110+
111+ if (policy->max < *setspeed)
112+ __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H);
113+ else if (policy->min > *setspeed)
114+ __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L);
115+ else
116+ __cpufreq_driver_target(policy, *setspeed, CPUFREQ_RELATION_L);
117+
118+ mutex_unlock(&userspace_mutex);
123119 }
124120
125121 static struct cpufreq_governor cpufreq_gov_userspace = {
126122 .name = "userspace",
127− .governor = cpufreq_governor_userspace,
123+ .init = cpufreq_userspace_policy_init,
124+ .exit = cpufreq_userspace_policy_exit,
125+ .start = cpufreq_userspace_policy_start,
126+ .stop = cpufreq_userspace_policy_stop,
127+ .limits = cpufreq_userspace_policy_limits,
128128 .store_setspeed = cpufreq_set,
129129 .show_setspeed = show_speed,
130130 .owner = THIS_MODULE,
drivers/cpufreq/davinci-cpufreq.c+1−21
@@ -38,26 +38,6 @@ struct davinci_cpufreq { · 37 unmodified lines
3838 };
3939 static struct davinci_cpufreq cpufreq;
4040
41−static int davinci_verify_speed(struct cpufreq_policy *policy)
42−{
43− struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
44− struct cpufreq_frequency_table *freq_table = pdata->freq_table;
45− struct clk *armclk = cpufreq.armclk;
46−
47− if (freq_table)
48− return cpufreq_frequency_table_verify(policy, freq_table);
49−
50− if (policy->cpu)
51− return -EINVAL;
52−
53− cpufreq_verify_within_cpu_limits(policy);
54− policy->min = clk_round_rate(armclk, policy->min * 1000) / 1000;
55− policy->max = clk_round_rate(armclk, policy->max * 1000) / 1000;
56− cpufreq_verify_within_limits(policy, policy->cpuinfo.min_freq,
57− policy->cpuinfo.max_freq);
58− return 0;
59−}
60−
6141 static int davinci_target(struct cpufreq_policy *policy, unsigned int idx)
6242 {
6343 struct davinci_cpufreq_config *pdata = cpufreq.dev->platform_data;
@@ -121,7 +101,7 @@ static int davinci_cpu_init(struct cpufreq_policy *policy) · 57 unmodified lines
121101
122102 static struct cpufreq_driver davinci_driver = {
123103 .flags = CPUFREQ_STICKY | CPUFREQ_NEED_INITIAL_FREQ_CHECK,
124− .verify = davinci_verify_speed,
104+ .verify = cpufreq_generic_frequency_table_verify,
125105 .target_index = davinci_target,
126106 .get = cpufreq_generic_get,
127107 .init = davinci_cpu_init,
drivers/cpufreq/freq_table.c+80−26
@@ -63,8 +63,6 @@ int cpufreq_frequency_table_cpuinfo(struct cpufreq_policy *policy, · 62 unmodified lines
6363 else
6464 return 0;
6565 }
66−EXPORT_SYMBOL_GPL(cpufreq_frequency_table_cpuinfo);
67−
6866
6967 int cpufreq_frequency_table_verify(struct cpufreq_policy *policy,
7068 struct cpufreq_frequency_table *table)
@@ -108,20 +106,16 @@ EXPORT_SYMBOL_GPL(cpufreq_frequency_table_verify); · 37 unmodified lines
108106 */
109107 int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy)
110108 {
111− struct cpufreq_frequency_table *table =
112− cpufreq_frequency_get_table(policy->cpu);
113− if (!table)
109+ if (!policy->freq_table)
114110 return -ENODEV;
115111
116− return cpufreq_frequency_table_verify(policy, table);
112+ return cpufreq_frequency_table_verify(policy, policy->freq_table);
117113 }
118114 EXPORT_SYMBOL_GPL(cpufreq_generic_frequency_table_verify);
119115
120−int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
121− struct cpufreq_frequency_table *table,
122− unsigned int target_freq,
123− unsigned int relation,
124− unsigned int *index)
116+int cpufreq_table_index_unsorted(struct cpufreq_policy *policy,
117+ unsigned int target_freq,
118+ unsigned int relation)
125119 {
126120 struct cpufreq_frequency_table optimal = {
127121 .driver_data = ~0,
@@ -132,7 +126,9 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, · 4 unmodified lines
132126 .frequency = 0,
133127 };
134128 struct cpufreq_frequency_table *pos;
129+ struct cpufreq_frequency_table *table = policy->freq_table;
135130 unsigned int freq, diff, i = 0;
131+ int index;
136132
137133 pr_debug("request for target %u kHz (relation: %u) for cpu %u\n",
138134 target_freq, relation, policy->cpu);
@@ -196,25 +192,26 @@ int cpufreq_frequency_table_target(struct cpufreq_policy *policy, · 57 unmodified lines
196192 }
197193 }
198194 if (optimal.driver_data > i) {
199− if (suboptimal.driver_data > i)
200− return -EINVAL;
201− *index = suboptimal.driver_data;
202− } else
203− *index = optimal.driver_data;
195+ if (suboptimal.driver_data > i) {
196+ WARN(1, "Invalid frequency table: %d\n", policy->cpu);
197+ return 0;
198+ }
204199
205− pr_debug("target index is %u, freq is:%u kHz\n", *index,
206− table[*index].frequency);
200+ index = suboptimal.driver_data;
201+ } else
202+ index = optimal.driver_data;
207203
208− return 0;
204+ pr_debug("target index is %u, freq is:%u kHz\n", index,
205+ table[index].frequency);
206+ return index;
209207 }
210−EXPORT_SYMBOL_GPL(cpufreq_frequency_table_target);
208+EXPORT_SYMBOL_GPL(cpufreq_table_index_unsorted);
211209
212210 int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
213211 unsigned int freq)
214212 {
215− struct cpufreq_frequency_table *pos, *table;
213+ struct cpufreq_frequency_table *pos, *table = policy->freq_table;
216214
217− table = cpufreq_frequency_get_table(policy->cpu);
218215 if (unlikely(!table)) {
219216 pr_debug("%s: Unable to find frequency table\n", __func__);
220217 return -ENOENT;
@@ -300,15 +297,72 @@ struct freq_attr *cpufreq_generic_attr[] = { · 79 unmodified lines
300297 };
301298 EXPORT_SYMBOL_GPL(cpufreq_generic_attr);
302299
300+static int set_freq_table_sorted(struct cpufreq_policy *policy)
301+{
302+ struct cpufreq_frequency_table *pos, *table = policy->freq_table;
303+ struct cpufreq_frequency_table *prev = NULL;
304+ int ascending = 0;
305+
306+ policy->freq_table_sorted = CPUFREQ_TABLE_UNSORTED;
307+
308+ cpufreq_for_each_valid_entry(pos, table) {
309+ if (!prev) {
310+ prev = pos;
311+ continue;
312+ }
313+
314+ if (pos->frequency == prev->frequency) {
315+ pr_warn("Duplicate freq-table entries: %u\n",
316+ pos->frequency);
317+ return -EINVAL;
318+ }
319+
320+ /* Frequency increased from prev to pos */
321+ if (pos->frequency > prev->frequency) {
322+ /* But frequency was decreasing earlier */
323+ if (ascending < 0) {
324+ pr_debug("Freq table is unsorted\n");
325+ return 0;
326+ }
327+
328+ ascending++;
329+ } else {
330+ /* Frequency decreased from prev to pos */
331+
332+ /* But frequency was increasing earlier */
333+ if (ascending > 0) {
334+ pr_debug("Freq table is unsorted\n");
335+ return 0;
336+ }
337+
338+ ascending--;
339+ }
340+
341+ prev = pos;
342+ }
343+
344+ if (ascending > 0)
345+ policy->freq_table_sorted = CPUFREQ_TABLE_SORTED_ASCENDING;
346+ else
347+ policy->freq_table_sorted = CPUFREQ_TABLE_SORTED_DESCENDING;
348+
349+ pr_debug("Freq table is sorted in %s order\n",
350+ ascending > 0 ? "ascending" : "descending");
351+
352+ return 0;
353+}
354+
303355 int cpufreq_table_validate_and_show(struct cpufreq_policy *policy,
304356 struct cpufreq_frequency_table *table)
305357 {
306− int ret = cpufreq_frequency_table_cpuinfo(policy, table);
358+ int ret;
307359
308− if (!ret)
309− policy->freq_table = table;
360+ ret = cpufreq_frequency_table_cpuinfo(policy, table);
361+ if (ret)
362+ return ret;
310363
311− return ret;
364+ policy->freq_table = table;
365+ return set_freq_table_sorted(policy);
312366 }
313367 EXPORT_SYMBOL_GPL(cpufreq_table_validate_and_show);
314368
drivers/cpufreq/intel_pstate.c+45−29
@@ -97,7 +97,6 @@ static inline u64 div_ext_fp(u64 x, u64 y) · 96 unmodified lines
9797 * read from MPERF MSR between last and current sample
9898 * @tsc: Difference of time stamp counter between last and
9999 * current sample
100− * @freq: Effective frequency calculated from APERF/MPERF
101100 * @time: Current time from scheduler
102101 *
103102 * This structure is used in the cpudata structure to store performance sample
@@ -109,7 +108,6 @@ struct sample { · 5 unmodified lines
109108 u64 aperf;
110109 u64 mperf;
111110 u64 tsc;
112− int freq;
113111 u64 time;
114112 };
115113
@@ -282,9 +280,9 @@ struct cpu_defaults { · 166 unmodified lines
282280 static inline int32_t get_target_pstate_use_performance(struct cpudata *cpu);
283281 static inline int32_t get_target_pstate_use_cpu_load(struct cpudata *cpu);
284282
285−static struct pstate_adjust_policy pid_params;
286−static struct pstate_funcs pstate_funcs;
287−static int hwp_active;
283+static struct pstate_adjust_policy pid_params __read_mostly;
284+static struct pstate_funcs pstate_funcs __read_mostly;
285+static int hwp_active __read_mostly;
288286
289287 #ifdef CONFIG_ACPI
290288 static bool acpi_ppc;
@@ -808,7 +806,8 @@ static void __init intel_pstate_sysfs_expose_params(void) · 517 unmodified lines
808806 static void intel_pstate_hwp_enable(struct cpudata *cpudata)
809807 {
810808 /* First disable HWP notification interrupt as we don't process them */
811− wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_INTERRUPT, 0x00);
809+ if (static_cpu_has(X86_FEATURE_HWP_NOTIFY))
810+ wrmsrl_on_cpu(cpudata->cpu, MSR_HWP_INTERRUPT, 0x00);
812811
813812 wrmsrl_on_cpu(cpudata->cpu, MSR_PM_ENABLE, 0x1);
814813 }
@@ -945,7 +944,7 @@ static int core_get_max_pstate(void) · 130 unmodified lines
945944 if (err)
946945 goto skip_tar;
947946
948− tdp_msr = MSR_CONFIG_TDP_NOMINAL + tdp_ctrl;
947+ tdp_msr = MSR_CONFIG_TDP_NOMINAL + (tdp_ctrl & 0x3);
949948 err = rdmsrl_safe(tdp_msr, &tdp_ratio);
950949 if (err)
951950 goto skip_tar;
@@ -973,7 +972,7 @@ static int core_get_turbo_pstate(void) · 21 unmodified lines
973972 u64 value;
974973 int nont, ret;
975974
976− rdmsrl(MSR_NHM_TURBO_RATIO_LIMIT, value);
975+ rdmsrl(MSR_TURBO_RATIO_LIMIT, value);
977976 nont = core_get_max_pstate();
978977 ret = (value) & 255;
979978 if (ret <= nont)
@@ -1002,7 +1001,7 @@ static int knl_get_turbo_pstate(void) · 22 unmodified lines
10021001 u64 value;
10031002 int nont, ret;
10041003
1005− rdmsrl(MSR_NHM_TURBO_RATIO_LIMIT, value);
1004+ rdmsrl(MSR_TURBO_RATIO_LIMIT, value);
10061005 nont = core_get_max_pstate();
10071006 ret = (((value) >> 8) & 0xFF);
10081007 if (ret <= nont)
@@ -1092,6 +1091,26 @@ static struct cpu_defaults knl_params = { · 83 unmodified lines
10921091 },
10931092 };
10941093
1094+static struct cpu_defaults bxt_params = {
1095+ .pid_policy = {
1096+ .sample_rate_ms = 10,
1097+ .deadband = 0,
1098+ .setpoint = 60,
1099+ .p_gain_pct = 14,
1100+ .d_gain_pct = 0,
1101+ .i_gain_pct = 4,
1102+ },
1103+ .funcs = {
1104+ .get_max = core_get_max_pstate,
1105+ .get_max_physical = core_get_max_pstate_physical,
1106+ .get_min = core_get_min_pstate,
1107+ .get_turbo = core_get_turbo_pstate,
1108+ .get_scaling = core_get_scaling,
1109+ .get_val = core_get_val,
1110+ .get_target_pstate = get_target_pstate_use_cpu_load,
1111+ },
1112+};
1113+
10951114 static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max)
10961115 {
10971116 int max_perf = cpu->pstate.turbo_pstate;
@@ -1114,17 +1133,12 @@ static void intel_pstate_get_min_max(struct cpudata *cpu, int *min, int *max) · 16 unmodified lines
11141133 *min = clamp_t(int, min_perf, cpu->pstate.min_pstate, max_perf);
11151134 }
11161135
1117−static inline void intel_pstate_record_pstate(struct cpudata *cpu, int pstate)
1118−{
1119− trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu);
1120− cpu->pstate.current_pstate = pstate;
1121−}
1122−
11231136 static void intel_pstate_set_min_pstate(struct cpudata *cpu)
11241137 {
11251138 int pstate = cpu->pstate.min_pstate;
11261139
1127− intel_pstate_record_pstate(cpu, pstate);
1140+ trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu);
1141+ cpu->pstate.current_pstate = pstate;
11281142 /*
11291143 * Generally, there is no guarantee that this code will always run on
11301144 * the CPU being updated, so force the register update to run on the
@@ -1284,10 +1298,11 @@ static inline void intel_pstate_update_pstate(struct cpudata *cpu, int pstate) · 153 unmodified lines
12841298
12851299 intel_pstate_get_min_max(cpu, &min_perf, &max_perf);
12861300 pstate = clamp_t(int, pstate, min_perf, max_perf);
1301+ trace_cpu_frequency(pstate * cpu->pstate.scaling, cpu->cpu);
12871302 if (pstate == cpu->pstate.current_pstate)
12881303 return;
12891304
1290− intel_pstate_record_pstate(cpu, pstate);
1305+ cpu->pstate.current_pstate = pstate;
12911306 wrmsrl(MSR_IA32_PERF_CTL, pstate_funcs.get_val(cpu, pstate));
12921307 }
12931308
@@ -1352,11 +1367,12 @@ static const struct x86_cpu_id intel_pstate_cpu_ids[] = { · 58 unmodified lines
13521367 ICPU(INTEL_FAM6_SKYLAKE_DESKTOP, core_params),
13531368 ICPU(INTEL_FAM6_BROADWELL_XEON_D, core_params),
13541369 ICPU(INTEL_FAM6_XEON_PHI_KNL, knl_params),
1370+ ICPU(INTEL_FAM6_ATOM_GOLDMONT, bxt_params),
13551371 {}
13561372 };
13571373 MODULE_DEVICE_TABLE(x86cpu, intel_pstate_cpu_ids);
13581374
1359−static const struct x86_cpu_id intel_pstate_cpu_oob_ids[] = {
1375+static const struct x86_cpu_id intel_pstate_cpu_oob_ids[] __initconst = {
13601376 ICPU(INTEL_FAM6_BROADWELL_XEON_D, core_params),
13611377 {}
13621378 };
@@ -1576,12 +1592,12 @@ static struct cpufreq_driver intel_pstate_driver = { · 213 unmodified lines
15761592 .name = "intel_pstate",
15771593 };
15781594
1579−static int __initdata no_load;
1580−static int __initdata no_hwp;
1581−static int __initdata hwp_only;
1582−static unsigned int force_load;
1595+static int no_load __initdata;
1596+static int no_hwp __initdata;
1597+static int hwp_only __initdata;
1598+static unsigned int force_load __initdata;
15831599
1584−static int intel_pstate_msrs_not_valid(void)
1600+static int __init intel_pstate_msrs_not_valid(void)
15851601 {
15861602 if (!pstate_funcs.get_max() ||
15871603 !pstate_funcs.get_min() ||
@@ -1591,7 +1607,7 @@ static int intel_pstate_msrs_not_valid(void) · 3 unmodified lines
15911607 return 0;
15921608 }
15931609
1594−static void copy_pid_params(struct pstate_adjust_policy *policy)
1610+static void __init copy_pid_params(struct pstate_adjust_policy *policy)
15951611 {
15961612 pid_params.sample_rate_ms = policy->sample_rate_ms;
15971613 pid_params.sample_rate_ns = pid_params.sample_rate_ms * NSEC_PER_MSEC;
@@ -1602,7 +1618,7 @@ static void copy_pid_params(struct pstate_adjust_policy *policy) · 4 unmodified lines
16021618 pid_params.setpoint = policy->setpoint;
16031619 }
16041620
1605−static void copy_cpu_funcs(struct pstate_funcs *funcs)
1621+static void __init copy_cpu_funcs(struct pstate_funcs *funcs)
16061622 {
16071623 pstate_funcs.get_max = funcs->get_max;
16081624 pstate_funcs.get_max_physical = funcs->get_max_physical;
@@ -1617,7 +1633,7 @@ static void copy_cpu_funcs(struct pstate_funcs *funcs) · 8 unmodified lines
16171633
16181634 #ifdef CONFIG_ACPI
16191635
1620−static bool intel_pstate_no_acpi_pss(void)
1636+static bool __init intel_pstate_no_acpi_pss(void)
16211637 {
16221638 int i;
16231639
@@ -1646,7 +1662,7 @@ static bool intel_pstate_no_acpi_pss(void) · 22 unmodified lines
16461662 return true;
16471663 }
16481664
1649−static bool intel_pstate_has_acpi_ppc(void)
1665+static bool __init intel_pstate_has_acpi_ppc(void)
16501666 {
16511667 int i;
16521668
@@ -1674,7 +1690,7 @@ struct hw_vendor_info { · 21 unmodified lines
16741690 };
16751691
16761692 /* Hardware vendor-specific info that has its own power management modes */
1677−static struct hw_vendor_info vendor_info[] = {
1693+static struct hw_vendor_info vendor_info[] __initdata = {
16781694 {1, "HP ", "ProLiant", PSS},
16791695 {1, "ORACLE", "X4-2 ", PPC},
16801696 {1, "ORACLE", "X4-2L ", PPC},
@@ -1693,7 +1709,7 @@ static struct hw_vendor_info vendor_info[] = { · 12 unmodified lines
16931709 {0, "", ""},
16941710 };
16951711
1696−static bool intel_pstate_platform_pwr_mgmt_exists(void)
1712+static bool __init intel_pstate_platform_pwr_mgmt_exists(void)
16971713 {
16981714 struct acpi_table_header hdr;
16991715 struct hw_vendor_info *v_info;
drivers/cpufreq/mvebu-cpufreq.c+1−1
@@ -70,7 +70,7 @@ static int __init armada_xp_pmsu_cpufreq_init(void) · 69 unmodified lines
7070 continue;
7171 }
7272
73− clk = clk_get(cpu_dev, 0);
73+ clk = clk_get(cpu_dev, NULL);
7474 if (IS_ERR(clk)) {
7575 pr_err("Cannot get clock for CPU %d\n", cpu);
7676 return PTR_ERR(clk);
drivers/cpufreq/pcc-cpufreq.c+0−2
@@ -555,8 +555,6 @@ static int pcc_cpufreq_cpu_init(struct cpufreq_policy *policy) · 554 unmodified lines
555555 policy->min = policy->cpuinfo.min_freq =
556556 ioread32(&pcch_hdr->minimum_frequency) * 1000;
557557
558− policy->cpuinfo.transition_latency = CPUFREQ_ETERNAL;
559−
560558 pr_debug("init: policy->max is %d, policy->min is %d\n",
561559 policy->max, policy->min);
562560 out:
drivers/cpufreq/powernv-cpufreq.c+103−78
@@ -64,12 +64,14 @@ · 63 unmodified lines
6464 /**
6565 * struct global_pstate_info - Per policy data structure to maintain history of
6666 * global pstates
67− * @highest_lpstate: The local pstate from which we are ramping down
67+ * @highest_lpstate_idx: The local pstate index from which we are
68+ * ramping down
6869 * @elapsed_time: Time in ms spent in ramping down from
69− * highest_lpstate
70+ * highest_lpstate_idx
7071 * @last_sampled_time: Time from boot in ms when global pstates were
7172 * last set
72− * @last_lpstate,last_gpstate: Last set values for local and global pstates
73+ * @last_lpstate_idx, Last set value of local pstate and global
74+ * last_gpstate_idx pstate in terms of cpufreq table index
7375 * @timer: Is used for ramping down if cpu goes idle for
7476 * a long time with global pstate held high
7577 * @gpstate_lock: A spinlock to maintain synchronization between
@@ -77,11 +79,11 @@ · 1 unmodified line
7779 * governer's target_index calls
7880 */
7981 struct global_pstate_info {
80− int highest_lpstate;
82+ int highest_lpstate_idx;
8183 unsigned int elapsed_time;
8284 unsigned int last_sampled_time;
83− int last_lpstate;
84− int last_gpstate;
85+ int last_lpstate_idx;
86+ int last_gpstate_idx;
8587 spinlock_t gpstate_lock;
8688 struct timer_list timer;
8789 };
@@ -124,29 +126,47 @@ static int nr_chips; · 36 unmodified lines
124126 static DEFINE_PER_CPU(struct chip *, chip_info);
125127
126128 /*
127− * Note: The set of pstates consists of contiguous integers, the
128− * smallest of which is indicated by powernv_pstate_info.min, the
129− * largest of which is indicated by powernv_pstate_info.max.
129+ * Note:
130+ * The set of pstates consists of contiguous integers.
131+ * powernv_pstate_info stores the index of the frequency table for
132+ * max, min and nominal frequencies. It also stores number of
133+ * available frequencies.
130134 *
131− * The nominal pstate is the highest non-turbo pstate in this
132− * platform. This is indicated by powernv_pstate_info.nominal.
135+ * powernv_pstate_info.nominal indicates the index to the highest
136+ * non-turbo frequency.
133137 */
134138 static struct powernv_pstate_info {
135− int min;
136− int max;
137− int nominal;
138− int nr_pstates;
139+ unsigned int min;
140+ unsigned int max;
141+ unsigned int nominal;
142+ unsigned int nr_pstates;
139143 } powernv_pstate_info;
140144
145+/* Use following macros for conversions between pstate_id and index */
146+static inline int idx_to_pstate(unsigned int i)
147+{
148+ return powernv_freqs[i].driver_data;
149+}
150+
151+static inline unsigned int pstate_to_idx(int pstate)
152+{
153+ /*
154+ * abs() is deliberately used so that is works with
155+ * both monotonically increasing and decreasing
156+ * pstate values
157+ */
158+ return abs(pstate - idx_to_pstate(powernv_pstate_info.max));
159+}
160+
141161 static inline void reset_gpstates(struct cpufreq_policy *policy)
142162 {
143163 struct global_pstate_info *gpstates = policy->driver_data;
144164
145− gpstates->highest_lpstate = 0;
165+ gpstates->highest_lpstate_idx = 0;
146166 gpstates->elapsed_time = 0;
147167 gpstates->last_sampled_time = 0;
148− gpstates->last_lpstate = 0;
149− gpstates->last_gpstate = 0;
168+ gpstates->last_lpstate_idx = 0;
169+ gpstates->last_gpstate_idx = 0;
150170 }
151171
152172 /*
@@ -156,9 +176,10 @@ static inline void reset_gpstates(struct cpufreq_policy *policy) · 3 unmodified lines
156176 static int init_powernv_pstates(void)
157177 {
158178 struct device_node *power_mgt;
159− int i, pstate_min, pstate_max, pstate_nominal, nr_pstates = 0;
179+ int i, nr_pstates = 0;
160180 const __be32 *pstate_ids, *pstate_freqs;
161181 u32 len_ids, len_freqs;
182+ u32 pstate_min, pstate_max, pstate_nominal;
162183
163184 power_mgt = of_find_node_by_path("/ibm,opal/power-mgt");
164185 if (!power_mgt) {
@@ -208,6 +229,7 @@ static int init_powernv_pstates(void) · 43 unmodified lines
208229 return -ENODEV;
209230 }
210231
232+ powernv_pstate_info.nr_pstates = nr_pstates;
211233 pr_debug("NR PStates %d\n", nr_pstates);
212234 for (i = 0; i < nr_pstates; i++) {
213235 u32 id = be32_to_cpu(pstate_ids[i]);
@@ -216,15 +238,17 @@ static int init_powernv_pstates(void) · 2 unmodified lines
216238 pr_debug("PState id %d freq %d MHz\n", id, freq);
217239 powernv_freqs[i].frequency = freq * 1000; /* kHz */
218240 powernv_freqs[i].driver_data = id;
241+
242+ if (id == pstate_max)
243+ powernv_pstate_info.max = i;
244+ else if (id == pstate_nominal)
245+ powernv_pstate_info.nominal = i;
246+ else if (id == pstate_min)
247+ powernv_pstate_info.min = i;
219248 }
249+
220250 /* End of list marker entry */
221251 powernv_freqs[i].frequency = CPUFREQ_TABLE_END;
222−
223− powernv_pstate_info.min = pstate_min;
224− powernv_pstate_info.max = pstate_max;
225− powernv_pstate_info.nominal = pstate_nominal;
226− powernv_pstate_info.nr_pstates = nr_pstates;
227−
228252 return 0;
229253 }
230254
@@ -233,12 +257,12 @@ static unsigned int pstate_id_to_freq(int pstate_id) · 2 unmodified lines
233257 {
234258 int i;
235259
236− i = powernv_pstate_info.max - pstate_id;
260+ i = pstate_to_idx(pstate_id);
237261 if (i >= powernv_pstate_info.nr_pstates || i < 0) {
238262 pr_warn("PState id %d outside of PState table, "
239263 "reporting nominal id %d instead\n",
240− pstate_id, powernv_pstate_info.nominal);
241− i = powernv_pstate_info.max - powernv_pstate_info.nominal;
264+ pstate_id, idx_to_pstate(powernv_pstate_info.nominal));
265+ i = powernv_pstate_info.nominal;
242266 }
243267
244268 return powernv_freqs[i].frequency;
@@ -252,7 +276,7 @@ static ssize_t cpuinfo_nominal_freq_show(struct cpufreq_policy *policy, · 7 unmodified lines
252276 char *buf)
253277 {
254278 return sprintf(buf, "%u\n",
255− pstate_id_to_freq(powernv_pstate_info.nominal));
279+ powernv_freqs[powernv_pstate_info.nominal].frequency);
256280 }
257281
258282 struct freq_attr cpufreq_freq_attr_cpuinfo_nominal_freq =
@@ -426,7 +450,7 @@ static void set_pstate(void *data) · 167 unmodified lines
426450 */
427451 static inline unsigned int get_nominal_index(void)
428452 {
429− return powernv_pstate_info.max - powernv_pstate_info.nominal;
453+ return powernv_pstate_info.nominal;
430454 }
431455
432456 static void powernv_cpufreq_throttle_check(void *data)
@@ -435,20 +459,22 @@ static void powernv_cpufreq_throttle_check(void *data) · 2 unmodified lines
435459 unsigned int cpu = smp_processor_id();
436460 unsigned long pmsr;
437461 int pmsr_pmax;
462+ unsigned int pmsr_pmax_idx;
438463
439464 pmsr = get_pmspr(SPRN_PMSR);
440465 chip = this_cpu_read(chip_info);
441466
442467 /* Check for Pmax Capping */
443468 pmsr_pmax = (s8)PMSR_MAX(pmsr);
444− if (pmsr_pmax != powernv_pstate_info.max) {
469+ pmsr_pmax_idx = pstate_to_idx(pmsr_pmax);
470+ if (pmsr_pmax_idx != powernv_pstate_info.max) {
445471 if (chip->throttled)
446472 goto next;
447473 chip->throttled = true;
448− if (pmsr_pmax < powernv_pstate_info.nominal) {
449− pr_warn_once("CPU %d on Chip %u has Pmax reduced below nominal frequency (%d < %d)\n",
474+ if (pmsr_pmax_idx > powernv_pstate_info.nominal) {
475+ pr_warn_once("CPU %d on Chip %u has Pmax(%d) reduced below nominal frequency(%d)\n",
450476 cpu, chip->id, pmsr_pmax,
451− powernv_pstate_info.nominal);
477+ idx_to_pstate(powernv_pstate_info.nominal));
452478 chip->throttle_sub_turbo++;
453479 } else {
454480 chip->throttle_turbo++;
@@ -484,34 +510,35 @@ next: · 29 unmodified lines
484510
485511 /**
486512 * calc_global_pstate - Calculate global pstate
487− * @elapsed_time: Elapsed time in milliseconds
488− * @local_pstate: New local pstate
489− * @highest_lpstate: pstate from which its ramping down
513+ * @elapsed_time: Elapsed time in milliseconds
514+ * @local_pstate_idx: New local pstate
515+ * @highest_lpstate_idx: pstate from which its ramping down
490516 *
491517 * Finds the appropriate global pstate based on the pstate from which its
492518 * ramping down and the time elapsed in ramping down. It follows a quadratic
493519 * equation which ensures that it reaches ramping down to pmin in 5sec.
494520 */
495521 static inline int calc_global_pstate(unsigned int elapsed_time,
496− int highest_lpstate, int local_pstate)
522+ int highest_lpstate_idx,
523+ int local_pstate_idx)
497524 {
498− int pstate_diff;
525+ int index_diff;
499526
500527 /*
501528 * Using ramp_down_percent we get the percentage of rampdown
502529 * that we are expecting to be dropping. Difference between
503− * highest_lpstate and powernv_pstate_info.min will give a absolute
530+ * highest_lpstate_idx and powernv_pstate_info.min will give a absolute
504531 * number of how many pstates we will drop eventually by the end of
505532 * 5 seconds, then just scale it get the number pstates to be dropped.
506533 */
507− pstate_diff = ((int)ramp_down_percent(elapsed_time) *
508− (highest_lpstate - powernv_pstate_info.min)) / 100;
534+ index_diff = ((int)ramp_down_percent(elapsed_time) *
535+ (powernv_pstate_info.min - highest_lpstate_idx)) / 100;
509536
510537 /* Ensure that global pstate is >= to local pstate */
511− if (highest_lpstate - pstate_diff < local_pstate)
512− return local_pstate;
538+ if (highest_lpstate_idx + index_diff >= local_pstate_idx)
539+ return local_pstate_idx;
513540 else
514− return highest_lpstate - pstate_diff;
541+ return highest_lpstate_idx + index_diff;
515542 }
516543
517544 static inline void queue_gpstate_timer(struct global_pstate_info *gpstates)
@@ -546,7 +573,7 @@ void gpstate_timer_handler(unsigned long data) · 28 unmodified lines
546573 {
547574 struct cpufreq_policy *policy = (struct cpufreq_policy *)data;
548575 struct global_pstate_info *gpstates = policy->driver_data;
549− int gpstate_id;
576+ int gpstate_idx;
550577 unsigned int time_diff = jiffies_to_msecs(jiffies)
551578 - gpstates->last_sampled_time;
552579 struct powernv_smp_call_data freq_data;
@@ -556,29 +583,29 @@ void gpstate_timer_handler(unsigned long data) · 3 unmodified lines
556583
557584 gpstates->last_sampled_time += time_diff;
558585 gpstates->elapsed_time += time_diff;
559− freq_data.pstate_id = gpstates->last_lpstate;
586+ freq_data.pstate_id = idx_to_pstate(gpstates->last_lpstate_idx);
560587
561− if ((gpstates->last_gpstate == freq_data.pstate_id) ||
588+ if ((gpstates->last_gpstate_idx == gpstates->last_lpstate_idx) ||
562589 (gpstates->elapsed_time > MAX_RAMP_DOWN_TIME)) {
563− gpstate_id = freq_data.pstate_id;
590+ gpstate_idx = pstate_to_idx(freq_data.pstate_id);
564591 reset_gpstates(policy);
565− gpstates->highest_lpstate = freq_data.pstate_id;
592+ gpstates->highest_lpstate_idx = gpstate_idx;
566593 } else {
567− gpstate_id = calc_global_pstate(gpstates->elapsed_time,
568− gpstates->highest_lpstate,
569− freq_data.pstate_id);
594+ gpstate_idx = calc_global_pstate(gpstates->elapsed_time,
595+ gpstates->highest_lpstate_idx,
596+ freq_data.pstate_id);
570597 }
571598
572599 /*
573600 * If local pstate is equal to global pstate, rampdown is over
574601 * So timer is not required to be queued.
575602 */
576− if (gpstate_id != freq_data.pstate_id)
603+ if (gpstate_idx != gpstates->last_lpstate_idx)
577604 queue_gpstate_timer(gpstates);
578605
579− freq_data.gpstate_id = gpstate_id;
580− gpstates->last_gpstate = freq_data.gpstate_id;
581− gpstates->last_lpstate = freq_data.pstate_id;
606+ freq_data.gpstate_id = idx_to_pstate(gpstate_idx);
607+ gpstates->last_gpstate_idx = pstate_to_idx(freq_data.gpstate_id);
608+ gpstates->last_lpstate_idx = pstate_to_idx(freq_data.pstate_id);
582609
583610 spin_unlock(&gpstates->gpstate_lock);
584611
@@ -595,7 +622,7 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy, · 10 unmodified lines
595622 unsigned int new_index)
596623 {
597624 struct powernv_smp_call_data freq_data;
598− unsigned int cur_msec, gpstate_id;
625+ unsigned int cur_msec, gpstate_idx;
599626 struct global_pstate_info *gpstates = policy->driver_data;
600627
601628 if (unlikely(rebooting) && new_index != get_nominal_index())
@@ -607,15 +634,15 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy, · 5 unmodified lines
607634 cur_msec = jiffies_to_msecs(get_jiffies_64());
608635
609636 spin_lock(&gpstates->gpstate_lock);
610− freq_data.pstate_id = powernv_freqs[new_index].driver_data;
637+ freq_data.pstate_id = idx_to_pstate(new_index);
611638
612639 if (!gpstates->last_sampled_time) {
613− gpstate_id = freq_data.pstate_id;
614− gpstates->highest_lpstate = freq_data.pstate_id;
640+ gpstate_idx = new_index;
641+ gpstates->highest_lpstate_idx = new_index;
615642 goto gpstates_done;
616643 }
617644
618− if (gpstates->last_gpstate > freq_data.pstate_id) {
645+ if (gpstates->last_gpstate_idx < new_index) {
619646 gpstates->elapsed_time += cur_msec -
620647 gpstates->last_sampled_time;
621648
@@ -626,34 +653,34 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy, · 4 unmodified lines
626653 */
627654 if (gpstates->elapsed_time > MAX_RAMP_DOWN_TIME) {
628655 reset_gpstates(policy);
629− gpstates->highest_lpstate = freq_data.pstate_id;
630− gpstate_id = freq_data.pstate_id;
656+ gpstates->highest_lpstate_idx = new_index;
657+ gpstate_idx = new_index;
631658 } else {
632659 /* Elaspsed_time is less than 5 seconds, continue to rampdown */
633− gpstate_id = calc_global_pstate(gpstates->elapsed_time,
634− gpstates->highest_lpstate,
635− freq_data.pstate_id);
660+ gpstate_idx = calc_global_pstate(gpstates->elapsed_time,
661+ gpstates->highest_lpstate_idx,
662+ new_index);
636663 }
637664 } else {
638665 reset_gpstates(policy);
639− gpstates->highest_lpstate = freq_data.pstate_id;
640− gpstate_id = freq_data.pstate_id;
666+ gpstates->highest_lpstate_idx = new_index;
667+ gpstate_idx = new_index;
641668 }
642669
643670 /*
644671 * If local pstate is equal to global pstate, rampdown is over
645672 * So timer is not required to be queued.
646673 */
647− if (gpstate_id != freq_data.pstate_id)
674+ if (gpstate_idx != new_index)
648675 queue_gpstate_timer(gpstates);
649676 else
650677 del_timer_sync(&gpstates->timer);
651678
652679 gpstates_done:
653− freq_data.gpstate_id = gpstate_id;
680+ freq_data.gpstate_id = idx_to_pstate(gpstate_idx);
654681 gpstates->last_sampled_time = cur_msec;
655− gpstates->last_gpstate = freq_data.gpstate_id;
656− gpstates->last_lpstate = freq_data.pstate_id;
682+ gpstates->last_gpstate_idx = gpstate_idx;
683+ gpstates->last_lpstate_idx = new_index;
657684
658685 spin_unlock(&gpstates->gpstate_lock);
659686
@@ -759,9 +786,7 @@ void powernv_cpufreq_work_fn(struct work_struct *work) · 99 unmodified lines
759786 struct cpufreq_policy policy;
760787
761788 cpufreq_get_policy(&policy, cpu);
762− cpufreq_frequency_table_target(&policy, policy.freq_table,
763− policy.cur,
764− CPUFREQ_RELATION_C, &index);
789+ index = cpufreq_table_find_index_c(&policy, policy.cur);
765790 powernv_cpufreq_target_index(&policy, index);
766791 cpumask_andnot(&mask, &mask, policy.cpus);
767792 }
@@ -847,8 +872,8 @@ static void powernv_cpufreq_stop_cpu(struct cpufreq_policy *policy) · 79 unmodified lines
847872 struct powernv_smp_call_data freq_data;
848873 struct global_pstate_info *gpstates = policy->driver_data;
849874
850− freq_data.pstate_id = powernv_pstate_info.min;
851− freq_data.gpstate_id = powernv_pstate_info.min;
875+ freq_data.pstate_id = idx_to_pstate(powernv_pstate_info.min);
876+ freq_data.gpstate_id = idx_to_pstate(powernv_pstate_info.min);
852877 smp_call_function_single(policy->cpu, set_pstate, &freq_data, 1);
853878 del_timer_sync(&gpstates->timer);
854879 }
drivers/cpufreq/ppc_cbe_cpufreq_pmi.c+1−2
@@ -94,7 +94,7 @@ static int pmi_notifier(struct notifier_block *nb, · 93 unmodified lines
9494 unsigned long event, void *data)
9595 {
9696 struct cpufreq_policy *policy = data;
97− struct cpufreq_frequency_table *cbe_freqs;
97+ struct cpufreq_frequency_table *cbe_freqs = policy->freq_table;
9898 u8 node;
9999
100100 /* Should this really be called for CPUFREQ_ADJUST and CPUFREQ_NOTIFY
@@ -103,7 +103,6 @@ static int pmi_notifier(struct notifier_block *nb, · 2 unmodified lines
103103 if (event == CPUFREQ_START)
104104 return 0;
105105
106− cbe_freqs = cpufreq_frequency_get_table(policy->cpu);
107106 node = cbe_cpu_to_node(policy->cpu);
108107
109108 pr_debug("got notified, event=%lu, node=%u\n", event, node);
drivers/cpufreq/s3c24xx-cpufreq.c+7−26
@@ -293,12 +293,8 @@ static int s3c_cpufreq_target(struct cpufreq_policy *policy, · 292 unmodified lines
293293 __func__, policy, target_freq, relation);
294294
295295 if (ftab) {
296− if (cpufreq_frequency_table_target(policy, ftab,
297− target_freq, relation,
298− &index)) {
299− s3c_freq_dbg("%s: table failed\n", __func__);
300− return -EINVAL;
301− }
296+ index = cpufreq_frequency_table_target(policy, target_freq,
297+ relation);
302298
303299 s3c_freq_dbg("%s: adjust %d to entry %d (%u)\n", __func__,
304300 target_freq, index, ftab[index].frequency);
@@ -315,7 +311,6 @@ static int s3c_cpufreq_target(struct cpufreq_policy *policy, · 10 unmodified lines
315311 pll = NULL;
316312 } else {
317313 struct cpufreq_policy tmp_policy;
318− int ret;
319314
320315 /* we keep the cpu pll table in Hz, to ensure we get an
321316 * accurate value for the PLL output. */
@@ -323,20 +318,14 @@ static int s3c_cpufreq_target(struct cpufreq_policy *policy, · 1 unmodified line
323318 tmp_policy.min = policy->min * 1000;
324319 tmp_policy.max = policy->max * 1000;
325320 tmp_policy.cpu = policy->cpu;
321+ tmp_policy.freq_table = pll_reg;
326322
327− /* cpufreq_frequency_table_target uses a pointer to 'index'
328− * which is the number of the table entry, not the value of
323+ /* cpufreq_frequency_table_target returns the index
324+ * of the table entry, not the value of
329325 * the table entry's index field. */
330326
331− ret = cpufreq_frequency_table_target(&tmp_policy, pll_reg,
332− target_freq, relation,
333− &index);
334−
335− if (ret < 0) {
336− pr_err("%s: no PLL available\n", __func__);
337− goto err_notpossible;
338− }
339−
327+ index = cpufreq_frequency_table_target(&tmp_policy, target_freq,
328+ relation);
340329 pll = pll_reg + index;
341330
342331 s3c_freq_dbg("%s: target %u => %u\n",
@@ -346,10 +335,6 @@ static int s3c_cpufreq_target(struct cpufreq_policy *policy, · 3 unmodified lines
346335 }
347336
348337 return s3c_cpufreq_settarget(policy, target_freq, pll);
349−
350− err_notpossible:
351− pr_err("no compatible settings for %d\n", target_freq);
352− return -EINVAL;
353338 }
354339
355340 struct clk *s3c_cpufreq_clk_get(struct device *dev, const char *name)
@@ -571,11 +556,7 @@ static int s3c_cpufreq_build_freq(void) · 215 unmodified lines
571556 {
572557 int size, ret;
573558
574− if (!cpu_cur.info->calc_freqtable)
575− return -EINVAL;
576−
577559 kfree(ftab);
578− ftab = NULL;
579560
580561 size = cpu_cur.info->calc_freqtable(&cpu_cur, NULL, 0);
581562 size++;
drivers/cpufreq/s5pv210-cpufreq.c+1−6
@@ -246,12 +246,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index) · 245 unmodified lines
246246 new_freq = s5pv210_freq_table[index].frequency;
247247
248248 /* Finding current running level index */
249− if (cpufreq_frequency_table_target(policy, s5pv210_freq_table,
250− old_freq, CPUFREQ_RELATION_H,
251− &priv_index)) {
252− ret = -EINVAL;
253− goto exit;
254− }
249+ priv_index = cpufreq_table_find_index_h(policy, old_freq);
255250
256251 arm_volt = dvs_conf[index].arm_volt;
257252 int_volt = dvs_conf[index].int_volt;
drivers/devfreq/Kconfig+1−1
@@ -75,7 +75,7 @@ config DEVFREQ_GOV_PASSIVE · 74 unmodified lines
7575 comment "DEVFREQ Drivers"
7676
7777 config ARM_EXYNOS_BUS_DEVFREQ
78− bool "ARM EXYNOS Generic Memory Bus DEVFREQ Driver"
78+ tristate "ARM EXYNOS Generic Memory Bus DEVFREQ Driver"
7979 depends on ARCH_EXYNOS
8080 select DEVFREQ_GOV_SIMPLE_ONDEMAND
8181 select DEVFREQ_GOV_PASSIVE
drivers/devfreq/devfreq-event.c+1−11
@@ -15,7 +15,7 @@ · 14 unmodified lines
1515 #include <linux/kernel.h>
1616 #include <linux/err.h>
1717 #include <linux/init.h>
18−#include <linux/module.h>
18+#include <linux/export.h>
1919 #include <linux/slab.h>
2020 #include <linux/list.h>
2121 #include <linux/of.h>
@@ -481,13 +481,3 @@ static int __init devfreq_event_init(void) · 459 unmodified lines
481481 return 0;
482482 }
483483 subsys_initcall(devfreq_event_init);
484−
485−static void __exit devfreq_event_exit(void)
486−{
487− class_destroy(devfreq_event_class);
488−}
489−module_exit(devfreq_event_exit);
490−
491−MODULE_AUTHOR("Chanwoo Choi <cw00.choi@samsung.com>");
492−MODULE_DESCRIPTION("DEVFREQ-Event class support");
493−MODULE_LICENSE("GPL");
drivers/devfreq/devfreq.c+3−12
@@ -15,7 +15,7 @@ · 14 unmodified lines
1515 #include <linux/errno.h>
1616 #include <linux/err.h>
1717 #include <linux/init.h>
18−#include <linux/module.h>
18+#include <linux/export.h>
1919 #include <linux/slab.h>
2020 #include <linux/stat.h>
2121 #include <linux/pm_opp.h>
@@ -707,10 +707,12 @@ struct devfreq *devfreq_get_devfreq_by_phandle(struct device *dev, int index) · 685 unmodified lines
707707 if (devfreq->dev.parent
708708 && devfreq->dev.parent->of_node == node) {
709709 mutex_unlock(&devfreq_list_lock);
710+ of_node_put(node);
710711 return devfreq;
711712 }
712713 }
713714 mutex_unlock(&devfreq_list_lock);
715+ of_node_put(node);
714716
715717 return ERR_PTR(-EPROBE_DEFER);
716718 }
@@ -1199,13 +1201,6 @@ static int __init devfreq_init(void) · 482 unmodified lines
11991201 }
12001202 subsys_initcall(devfreq_init);
12011203
1202−static void __exit devfreq_exit(void)
1203−{
1204− class_destroy(devfreq_class);
1205− destroy_workqueue(devfreq_wq);
1206−}
1207−module_exit(devfreq_exit);
1208−
12091204 /*
12101205 * The followings are helper functions for devfreq user device drivers with
12111206 * OPP framework.
@@ -1471,7 +1466,3 @@ void devm_devfreq_unregister_notifier(struct device *dev, · 259 unmodified lines
14711466 devm_devfreq_dev_match, devfreq));
14721467 }
14731468 EXPORT_SYMBOL(devm_devfreq_unregister_notifier);
1474−
1475−MODULE_AUTHOR("MyungJoo Ham <myungjoo.ham@samsung.com>");
1476−MODULE_DESCRIPTION("devfreq class support");
1477−MODULE_LICENSE("GPL");
drivers/devfreq/event/Kconfig+2−2
@@ -14,7 +14,7 @@ menuconfig PM_DEVFREQ_EVENT · 13 unmodified lines
1414 if PM_DEVFREQ_EVENT
1515
1616 config DEVFREQ_EVENT_EXYNOS_NOCP
17− bool "EXYNOS NoC (Network On Chip) Probe DEVFREQ event Driver"
17+ tristate "EXYNOS NoC (Network On Chip) Probe DEVFREQ event Driver"
1818 depends on ARCH_EXYNOS
1919 select PM_OPP
2020 help
@@ -22,7 +22,7 @@ config DEVFREQ_EVENT_EXYNOS_NOCP · 1 unmodified line
2222 (Network on Chip) Probe counters to measure the bandwidth of AXI bus.
2323
2424 config DEVFREQ_EVENT_EXYNOS_PPMU
25− bool "EXYNOS PPMU (Platform Performance Monitoring Unit) DEVFREQ event Driver"
25+ tristate "EXYNOS PPMU (Platform Performance Monitoring Unit) DEVFREQ event Driver"
2626 depends on ARCH_EXYNOS
2727 select PM_OPP
2828 help
drivers/devfreq/event/exynos-ppmu.c+2−1
@@ -482,7 +482,8 @@ static int exynos_ppmu_probe(struct platform_device *pdev) · 481 unmodified lines
482482 if (!info->edev) {
483483 dev_err(&pdev->dev,
484484 "failed to allocate memory devfreq-event devices\n");
485− return -ENOMEM;
485+ ret = -ENOMEM;
486+ goto err;
486487 }
487488 edev = info->edev;
488489 platform_set_drvdata(pdev, info);
drivers/devfreq/exynos-bus.c+7−4
@@ -383,7 +383,7 @@ err_clk: · 382 unmodified lines
383383 static int exynos_bus_probe(struct platform_device *pdev)
384384 {
385385 struct device *dev = &pdev->dev;
386− struct device_node *np = dev->of_node;
386+ struct device_node *np = dev->of_node, *node;
387387 struct devfreq_dev_profile *profile;
388388 struct devfreq_simple_ondemand_data *ondemand_data;
389389 struct devfreq_passive_data *passive_data;
@@ -407,7 +407,7 @@ static int exynos_bus_probe(struct platform_device *pdev) · 17 unmodified lines
407407 /* Parse the device-tree to get the resource information */
408408 ret = exynos_bus_parse_of(np, bus);
409409 if (ret < 0)
410− goto err;
410+ return ret;
411411
412412 profile = devm_kzalloc(dev, sizeof(*profile), GFP_KERNEL);
413413 if (!profile) {
@@ -415,10 +415,13 @@ static int exynos_bus_probe(struct platform_device *pdev) · 1 unmodified line
415415 goto err;
416416 }
417417
418− if (of_parse_phandle(dev->of_node, "devfreq", 0))
418+ node = of_parse_phandle(dev->of_node, "devfreq", 0);
419+ if (node) {
420+ of_node_put(node);
419421 goto passive;
420− else
422+ } else {
421423 ret = exynos_bus_parent_parse_of(np, bus);
424+ }
422425
423426 if (ret < 0)
424427 goto err;
drivers/gpu/drm/amd/amdgpu/amdgpu_acp.c+0−23
@@ -421,29 +421,6 @@ static int acp_suspend(void *handle) · 420 unmodified lines
421421
422422 static int acp_resume(void *handle)
423423 {
424− int i, ret;
425− struct acp_pm_domain *apd;
426− struct amdgpu_device *adev = (struct amdgpu_device *)handle;
427−
428− /* return early if no ACP */
429− if (!adev->acp.acp_genpd)
430− return 0;
431−
432− /* SMU block will power on ACP irrespective of ACP runtime status.
433− * Power off explicitly based on genpd ACP runtime status so that ACP
434− * hw and ACP-genpd status are in sync.
435− * 'suspend_power_off' represents "Power status before system suspend"
436− */
437− if (adev->acp.acp_genpd->gpd.suspend_power_off == true) {
438− apd = container_of(&adev->acp.acp_genpd->gpd,
439− struct acp_pm_domain, gpd);
440−
441− for (i = 4; i >= 0 ; i--) {
442− ret = acp_suspend_tile(apd->cgs_dev, ACP_TILE_P1 + i);
443− if (ret)
444− pr_err("ACP tile %d tile suspend failed\n", i);
445− }
446− }
447424 return 0;
448425 }
449426
drivers/idle/intel_idle.c+58−49
@@ -46,8 +46,6 @@ · 45 unmodified lines
4646 * to avoid complications with the lapic timer workaround.
4747 * Have not seen issues with suspend, but may need same workaround here.
4848 *
49− * There is currently no kernel-based automatic probing/loading mechanism
50− * if the driver is built as a module.
5149 */
5250
5351 /* un-comment DEBUG to enable pr_debug() statements */
@@ -60,7 +58,7 @@ · 6 unmodified lines
6058 #include <linux/sched.h>
6159 #include <linux/notifier.h>
6260 #include <linux/cpu.h>
63−#include <linux/module.h>
61+#include <linux/moduleparam.h>
6462 #include <asm/cpu_device_id.h>
6563 #include <asm/intel-family.h>
6664 #include <asm/mwait.h>
@@ -828,6 +826,35 @@ static struct cpuidle_state bxt_cstates[] = { · 761 unmodified lines
828826 .enter = NULL }
829827 };
830828
829+static struct cpuidle_state dnv_cstates[] = {
830+ {
831+ .name = "C1-DNV",
832+ .desc = "MWAIT 0x00",
833+ .flags = MWAIT2flg(0x00),
834+ .exit_latency = 2,
835+ .target_residency = 2,
836+ .enter = &intel_idle,
837+ .enter_freeze = intel_idle_freeze, },
838+ {
839+ .name = "C1E-DNV",
840+ .desc = "MWAIT 0x01",
841+ .flags = MWAIT2flg(0x01),
842+ .exit_latency = 10,
843+ .target_residency = 20,
844+ .enter = &intel_idle,
845+ .enter_freeze = intel_idle_freeze, },
846+ {
847+ .name = "C6-DNV",
848+ .desc = "MWAIT 0x20",
849+ .flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
850+ .exit_latency = 50,
851+ .target_residency = 500,
852+ .enter = &intel_idle,
853+ .enter_freeze = intel_idle_freeze, },
854+ {
855+ .enter = NULL }
856+};
857+
831858 /**
832859 * intel_idle
833860 * @dev: cpuidle_device
@@ -1017,6 +1044,11 @@ static const struct idle_cpu idle_cpu_bxt = { · 183 unmodified lines
10171044 .disable_promotion_to_c1e = true,
10181045 };
10191046
1047+static const struct idle_cpu idle_cpu_dnv = {
1048+ .state_table = dnv_cstates,
1049+ .disable_promotion_to_c1e = true,
1050+};
1051+
10201052 #define ICPU(model, cpu) \
10211053 { X86_VENDOR_INTEL, 6, model, X86_FEATURE_MWAIT, (unsigned long)&cpu }
10221054
@@ -1053,9 +1085,9 @@ static const struct x86_cpu_id intel_idle_ids[] __initconst = { · 30 unmodified lines
10531085 ICPU(INTEL_FAM6_SKYLAKE_X, idle_cpu_skx),
10541086 ICPU(INTEL_FAM6_XEON_PHI_KNL, idle_cpu_knl),
10551087 ICPU(INTEL_FAM6_ATOM_GOLDMONT, idle_cpu_bxt),
1088+ ICPU(INTEL_FAM6_ATOM_DENVERTON, idle_cpu_dnv),
10561089 {}
10571090 };
1058−MODULE_DEVICE_TABLE(x86cpu, intel_idle_ids);
10591091
10601092 /*
10611093 * intel_idle_probe()
@@ -1155,7 +1187,10 @@ static unsigned long long irtl_2_usec(unsigned long long irtl) · 93 unmodified lines
11551187 {
11561188 unsigned long long ns;
11571189
1158− ns = irtl_ns_units[(irtl >> 10) & 0x3];
1190+ if (!irtl)
1191+ return 0;
1192+
1193+ ns = irtl_ns_units[(irtl >> 10) & 0x7];
11591194
11601195 return div64_u64((irtl & 0x3FF) * ns, 1000);
11611196 }
@@ -1168,43 +1203,39 @@ static unsigned long long irtl_2_usec(unsigned long long irtl) · 6 unmodified lines
11681203 static void bxt_idle_state_table_update(void)
11691204 {
11701205 unsigned long long msr;
1206+ unsigned int usec;
11711207
11721208 rdmsrl(MSR_PKGC6_IRTL, msr);
1173− if (msr) {
1174− unsigned int usec = irtl_2_usec(msr);
1175−
1209+ usec = irtl_2_usec(msr);
1210+ if (usec) {
11761211 bxt_cstates[2].exit_latency = usec;
11771212 bxt_cstates[2].target_residency = usec;
11781213 }
11791214
11801215 rdmsrl(MSR_PKGC7_IRTL, msr);
1181− if (msr) {
1182− unsigned int usec = irtl_2_usec(msr);
1183−
1216+ usec = irtl_2_usec(msr);
1217+ if (usec) {
11841218 bxt_cstates[3].exit_latency = usec;
11851219 bxt_cstates[3].target_residency = usec;
11861220 }
11871221
11881222 rdmsrl(MSR_PKGC8_IRTL, msr);
1189− if (msr) {
1190− unsigned int usec = irtl_2_usec(msr);
1191−
1223+ usec = irtl_2_usec(msr);
1224+ if (usec) {
11921225 bxt_cstates[4].exit_latency = usec;
11931226 bxt_cstates[4].target_residency = usec;
11941227 }
11951228
11961229 rdmsrl(MSR_PKGC9_IRTL, msr);
1197− if (msr) {
1198− unsigned int usec = irtl_2_usec(msr);
1199−
1230+ usec = irtl_2_usec(msr);
1231+ if (usec) {
12001232 bxt_cstates[5].exit_latency = usec;
12011233 bxt_cstates[5].target_residency = usec;
12021234 }
12031235
12041236 rdmsrl(MSR_PKGC10_IRTL, msr);
1205− if (msr) {
1206− unsigned int usec = irtl_2_usec(msr);
1207−
1237+ usec = irtl_2_usec(msr);
1238+ if (usec) {
12081239 bxt_cstates[6].exit_latency = usec;
12091240 bxt_cstates[6].target_residency = usec;
12101241 }
@@ -1416,34 +1447,12 @@ static int __init intel_idle_init(void) · 205 unmodified lines
14161447
14171448 return 0;
14181449 }
1450+device_initcall(intel_idle_init);
14191451
1420−static void __exit intel_idle_exit(void)
1421−{
1422− struct cpuidle_device *dev;
1423− int i;
1424−
1425− cpu_notifier_register_begin();
1426−
1427− if (lapic_timer_reliable_states != LAPIC_TIMER_ALWAYS_RELIABLE)
1428− on_each_cpu(__setup_broadcast_timer, (void *)false, 1);
1429− __unregister_cpu_notifier(&cpu_hotplug_notifier);
1430−
1431− for_each_possible_cpu(i) {
1432− dev = per_cpu_ptr(intel_idle_cpuidle_devices, i);
1433− cpuidle_unregister_device(dev);
1434− }
1435−
1436− cpu_notifier_register_done();
1437−
1438− cpuidle_unregister_driver(&intel_idle_driver);
1439− free_percpu(intel_idle_cpuidle_devices);
1440−}
1441−
1442−module_init(intel_idle_init);
1443−module_exit(intel_idle_exit);
1444−
1452+/*
1453+ * We are not really modular, but we used to support that. Meaning we also
1454+ * support "intel_idle.max_cstate=..." at boot and also a read-only export of
1455+ * it at /sys/module/intel_idle/parameters/max_cstate -- so using module_param
1456+ * is the easiest way (currently) to continue doing that.
1457+ */
14451458 module_param(max_cstate, int, 0444);
1446−
1447−MODULE_AUTHOR("Len Brown <len.brown@intel.com>");
1448−MODULE_DESCRIPTION("Cpuidle driver for Intel Hardware v" INTEL_IDLE_VERSION);
1449−MODULE_LICENSE("GPL");
drivers/pci/pci.c+2−2
@@ -530,8 +530,8 @@ static const struct pci_platform_pm_ops *pci_platform_pm; · 529 unmodified lines
530530
531531 int pci_set_platform_pm(const struct pci_platform_pm_ops *ops)
532532 {
533− if (!ops->is_manageable || !ops->set_state || !ops->choose_state
534− || !ops->sleep_wake)
533+ if (!ops->is_manageable || !ops->set_state || !ops->choose_state ||
534+ !ops->sleep_wake || !ops->run_wake || !ops->need_resume)
535535 return -EINVAL;
536536 pci_platform_pm = ops;
537537 return 0;
drivers/powercap/intel_rapl.c+82−25
@@ -336,14 +336,14 @@ static int release_zone(struct powercap_zone *power_zone) · 335 unmodified lines
336336
337337 static int find_nr_power_limit(struct rapl_domain *rd)
338338 {
339− int i;
339+ int i, nr_pl = 0;
340340
341341 for (i = 0; i < NR_POWER_LIMITS; i++) {
342− if (rd->rpl[i].name == NULL)
343− break;
342+ if (rd->rpl[i].name)
343+ nr_pl++;
344344 }
345345
346− return i;
346+ return nr_pl;
347347 }
348348
349349 static int set_domain_enable(struct powercap_zone *power_zone, bool mode)
@@ -426,15 +426,38 @@ static const struct powercap_zone_ops zone_ops[] = { · 76 unmodified lines
426426 },
427427 };
428428
429−static int set_power_limit(struct powercap_zone *power_zone, int id,
429+
430+/*
431+ * Constraint index used by powercap can be different than power limit (PL)
432+ * index in that some PLs maybe missing due to non-existant MSRs. So we
433+ * need to convert here by finding the valid PLs only (name populated).
434+ */
435+static int contraint_to_pl(struct rapl_domain *rd, int cid)
436+{
437+ int i, j;
438+
439+ for (i = 0, j = 0; i < NR_POWER_LIMITS; i++) {
440+ if ((rd->rpl[i].name) && j++ == cid) {
441+ pr_debug("%s: index %d\n", __func__, i);
442+ return i;
443+ }
444+ }
445+
446+ return -EINVAL;
447+}
448+
449+static int set_power_limit(struct powercap_zone *power_zone, int cid,
430450 u64 power_limit)
431451 {
432452 struct rapl_domain *rd;
433453 struct rapl_package *rp;
434454 int ret = 0;
455+ int id;
435456
436457 get_online_cpus();
437458 rd = power_zone_to_rapl_domain(power_zone);
459+ id = contraint_to_pl(rd, cid);
460+
438461 rp = rd->rp;
439462
440463 if (rd->state & DOMAIN_STATE_BIOS_LOCKED) {
@@ -461,16 +484,18 @@ set_exit: · 20 unmodified lines
461484 return ret;
462485 }
463486
464−static int get_current_power_limit(struct powercap_zone *power_zone, int id,
487+static int get_current_power_limit(struct powercap_zone *power_zone, int cid,
465488 u64 *data)
466489 {
467490 struct rapl_domain *rd;
468491 u64 val;
469492 int prim;
470493 int ret = 0;
494+ int id;
471495
472496 get_online_cpus();
473497 rd = power_zone_to_rapl_domain(power_zone);
498+ id = contraint_to_pl(rd, cid);
474499 switch (rd->rpl[id].prim_id) {
475500 case PL1_ENABLE:
476501 prim = POWER_LIMIT1;
@@ -492,14 +517,17 @@ static int get_current_power_limit(struct powercap_zone *power_zone, int id, · 15 unmodified lines
492517 return ret;
493518 }
494519
495−static int set_time_window(struct powercap_zone *power_zone, int id,
520+static int set_time_window(struct powercap_zone *power_zone, int cid,
496521 u64 window)
497522 {
498523 struct rapl_domain *rd;
499524 int ret = 0;
525+ int id;
500526
501527 get_online_cpus();
502528 rd = power_zone_to_rapl_domain(power_zone);
529+ id = contraint_to_pl(rd, cid);
530+
503531 switch (rd->rpl[id].prim_id) {
504532 case PL1_ENABLE:
505533 rapl_write_data_raw(rd, TIME_WINDOW1, window);
@@ -514,14 +542,17 @@ static int set_time_window(struct powercap_zone *power_zone, int id, · 8 unmodified lines
514542 return ret;
515543 }
516544
517−static int get_time_window(struct powercap_zone *power_zone, int id, u64 *data)
545+static int get_time_window(struct powercap_zone *power_zone, int cid, u64 *data)
518546 {
519547 struct rapl_domain *rd;
520548 u64 val;
521549 int ret = 0;
550+ int id;
522551
523552 get_online_cpus();
524553 rd = power_zone_to_rapl_domain(power_zone);
554+ id = contraint_to_pl(rd, cid);
555+
525556 switch (rd->rpl[id].prim_id) {
526557 case PL1_ENABLE:
527558 ret = rapl_read_data_raw(rd, TIME_WINDOW1, true, &val);
@@ -540,15 +571,17 @@ static int get_time_window(struct powercap_zone *power_zone, int id, u64 *data) · 12 unmodified lines
540571 return ret;
541572 }
542573
543−static const char *get_constraint_name(struct powercap_zone *power_zone, int id)
574+static const char *get_constraint_name(struct powercap_zone *power_zone, int cid)
544575 {
545− struct rapl_power_limit *rpl;
546576 struct rapl_domain *rd;
577+ int id;
547578
548579 rd = power_zone_to_rapl_domain(power_zone);
549− rpl = (struct rapl_power_limit *) &rd->rpl[id];
580+ id = contraint_to_pl(rd, cid);
581+ if (id >= 0)
582+ return rd->rpl[id].name;
550583
551− return rpl->name;
584+ return NULL;
552585 }
553586
554587
@@ -1101,6 +1134,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = { · 546 unmodified lines
11011134 RAPL_CPU(INTEL_FAM6_SANDYBRIDGE_X, rapl_defaults_core),
11021135
11031136 RAPL_CPU(INTEL_FAM6_IVYBRIDGE, rapl_defaults_core),
1137+ RAPL_CPU(INTEL_FAM6_IVYBRIDGE_X, rapl_defaults_core),
11041138
11051139 RAPL_CPU(INTEL_FAM6_HASWELL_CORE, rapl_defaults_core),
11061140 RAPL_CPU(INTEL_FAM6_HASWELL_ULT, rapl_defaults_core),
@@ -1123,6 +1157,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = { · 16 unmodified lines
11231157 RAPL_CPU(INTEL_FAM6_ATOM_MERRIFIELD1, rapl_defaults_tng),
11241158 RAPL_CPU(INTEL_FAM6_ATOM_MERRIFIELD2, rapl_defaults_ann),
11251159 RAPL_CPU(INTEL_FAM6_ATOM_GOLDMONT, rapl_defaults_core),
1160+ RAPL_CPU(INTEL_FAM6_ATOM_DENVERTON, rapl_defaults_core),
11261161
11271162 RAPL_CPU(INTEL_FAM6_XEON_PHI_KNL, rapl_defaults_hsw_server),
11281163 {}
@@ -1381,6 +1416,37 @@ static int rapl_check_domain(int cpu, int domain) · 252 unmodified lines
13811416 return 0;
13821417 }
13831418
1419+
1420+/*
1421+ * Check if power limits are available. Two cases when they are not available:
1422+ * 1. Locked by BIOS, in this case we still provide read-only access so that
1423+ * users can see what limit is set by the BIOS.
1424+ * 2. Some CPUs make some domains monitoring only which means PLx MSRs may not
1425+ * exist at all. In this case, we do not show the contraints in powercap.
1426+ *
1427+ * Called after domains are detected and initialized.
1428+ */
1429+static void rapl_detect_powerlimit(struct rapl_domain *rd)
1430+{
1431+ u64 val64;
1432+ int i;
1433+
1434+ /* check if the domain is locked by BIOS, ignore if MSR doesn't exist */
1435+ if (!rapl_read_data_raw(rd, FW_LOCK, false, &val64)) {
1436+ if (val64) {
1437+ pr_info("RAPL package %d domain %s locked by BIOS\n",
1438+ rd->rp->id, rd->name);
1439+ rd->state |= DOMAIN_STATE_BIOS_LOCKED;
1440+ }
1441+ }
1442+ /* check if power limit MSRs exists, otherwise domain is monitoring only */
1443+ for (i = 0; i < NR_POWER_LIMITS; i++) {
1444+ int prim = rd->rpl[i].prim_id;
1445+ if (rapl_read_data_raw(rd, prim, false, &val64))
1446+ rd->rpl[i].name = NULL;
1447+ }
1448+}
1449+
13841450 /* Detect active and valid domains for the given CPU, caller must
13851451 * ensure the CPU belongs to the targeted package and CPU hotlug is disabled.
13861452 */
@@ -1389,7 +1455,6 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu) · 2 unmodified lines
13891455 int i;
13901456 int ret = 0;
13911457 struct rapl_domain *rd;
1392− u64 locked;
13931458
13941459 for (i = 0; i < RAPL_DOMAIN_MAX; i++) {
13951460 /* use physical package id to read counters */
@@ -1400,7 +1465,7 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu) · 4 unmodified lines
14001465 }
14011466 rp->nr_domains = bitmap_weight(&rp->domain_map, RAPL_DOMAIN_MAX);
14021467 if (!rp->nr_domains) {
1403− pr_err("no valid rapl domains found in package %d\n", rp->id);
1468+ pr_debug("no valid rapl domains found in package %d\n", rp->id);
14041469 ret = -ENODEV;
14051470 goto done;
14061471 }
@@ -1414,17 +1479,9 @@ static int rapl_detect_domains(struct rapl_package *rp, int cpu) · 7 unmodified lines
14141479 }
14151480 rapl_init_domains(rp);
14161481
1417− for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++) {
1418− /* check if the domain is locked by BIOS */
1419− ret = rapl_read_data_raw(rd, FW_LOCK, false, &locked);
1420− if (ret)
1421− return ret;
1422− if (locked) {
1423− pr_info("RAPL package %d domain %s locked by BIOS\n",
1424− rp->id, rd->name);
1425− rd->state |= DOMAIN_STATE_BIOS_LOCKED;
1426− }
1427− }
1482+ for (rd = rp->domains; rd < rp->domains + rp->nr_domains; rd++)
1483+ rapl_detect_powerlimit(rd);
1484+
14281485
14291486
14301487 done:
drivers/thermal/cpu_cooling.c+19−5
@@ -787,22 +787,34 @@ __cpufreq_cooling_register(struct device_node *np, · 786 unmodified lines
787787 const struct cpumask *clip_cpus, u32 capacitance,
788788 get_static_t plat_static_func)
789789 {
790+ struct cpufreq_policy *policy;
790791 struct thermal_cooling_device *cool_dev;
791792 struct cpufreq_cooling_device *cpufreq_dev;
792793 char dev_name[THERMAL_NAME_LENGTH];
793794 struct cpufreq_frequency_table *pos, *table;
795+ struct cpumask temp_mask;
794796 unsigned int freq, i, num_cpus;
795797 int ret;
796798
797− table = cpufreq_frequency_get_table(cpumask_first(clip_cpus));
799+ cpumask_and(&temp_mask, clip_cpus, cpu_online_mask);
800+ policy = cpufreq_cpu_get(cpumask_first(&temp_mask));
801+ if (!policy) {
802+ pr_debug("%s: CPUFreq policy not found\n", __func__);
803+ return ERR_PTR(-EPROBE_DEFER);
804+ }
805+
806+ table = policy->freq_table;
798807 if (!table) {
799808 pr_debug("%s: CPUFreq table not found\n", __func__);
800− return ERR_PTR(-EPROBE_DEFER);
809+ cool_dev = ERR_PTR(-ENODEV);
810+ goto put_policy;
801811 }
802812
803813 cpufreq_dev = kzalloc(sizeof(*cpufreq_dev), GFP_KERNEL);
804− if (!cpufreq_dev)
805− return ERR_PTR(-ENOMEM);
814+ if (!cpufreq_dev) {
815+ cool_dev = ERR_PTR(-ENOMEM);
816+ goto put_policy;
817+ }
806818
807819 num_cpus = cpumask_weight(clip_cpus);
808820 cpufreq_dev->time_in_idle = kcalloc(num_cpus,
@@ -892,7 +904,7 @@ __cpufreq_cooling_register(struct device_node *np, · 83 unmodified lines
892904 CPUFREQ_POLICY_NOTIFIER);
893905 mutex_unlock(&cooling_cpufreq_lock);
894906
895− return cool_dev;
907+ goto put_policy;
896908
897909 remove_idr:
898910 release_idr(&cpufreq_idr, cpufreq_dev->id);
@@ -906,6 +918,8 @@ free_time_in_idle: · 7 unmodified lines
906918 kfree(cpufreq_dev->time_in_idle);
907919 free_cdev:
908920 kfree(cpufreq_dev);
921+put_policy:
922+ cpufreq_cpu_put(policy);
909923
910924 return cool_dev;
911925 }
include/linux/cpufreq.h+272−17
@@ -36,6 +36,12 @@ · 35 unmodified lines
3636
3737 struct cpufreq_governor;
3838
39+enum cpufreq_table_sorting {
40+ CPUFREQ_TABLE_UNSORTED,
41+ CPUFREQ_TABLE_SORTED_ASCENDING,
42+ CPUFREQ_TABLE_SORTED_DESCENDING
43+};
44+
3945 struct cpufreq_freqs {
4046 unsigned int cpu; /* cpu nr */
4147 unsigned int old;
@@ -87,6 +93,7 @@ struct cpufreq_policy { · 45 unmodified lines
8793
8894 struct cpufreq_user_policy user_policy;
8995 struct cpufreq_frequency_table *freq_table;
96+ enum cpufreq_table_sorting freq_table_sorted;
9097
9198 struct list_head policy_list;
9299 struct kobject kobj;
@@ -113,6 +120,10 @@ struct cpufreq_policy { · 20 unmodified lines
113120 bool fast_switch_possible;
114121 bool fast_switch_enabled;
115122
123+ /* Cached frequency lookup from cpufreq_driver_resolve_freq. */
124+ unsigned int cached_target_freq;
125+ int cached_resolved_idx;
126+
116127 /* Synchronization for frequency transitions */
117128 bool transition_ongoing; /* Tracks transition status */
118129 spinlock_t transition_lock;
@@ -185,6 +196,18 @@ static inline unsigned int cpufreq_quick_get_max(unsigned int cpu) · 66 unmodified lines
185196 static inline void disable_cpufreq(void) { }
186197 #endif
187198
199+#ifdef CONFIG_CPU_FREQ_STAT
200+void cpufreq_stats_create_table(struct cpufreq_policy *policy);
201+void cpufreq_stats_free_table(struct cpufreq_policy *policy);
202+void cpufreq_stats_record_transition(struct cpufreq_policy *policy,
203+ unsigned int new_freq);
204+#else
205+static inline void cpufreq_stats_create_table(struct cpufreq_policy *policy) { }
206+static inline void cpufreq_stats_free_table(struct cpufreq_policy *policy) { }
207+static inline void cpufreq_stats_record_transition(struct cpufreq_policy *policy,
208+ unsigned int new_freq) { }
209+#endif /* CONFIG_CPU_FREQ_STAT */
210+
188211 /*********************************************************************
189212 * CPUFREQ DRIVER INTERFACE *
190213 *********************************************************************/
@@ -251,6 +274,16 @@ struct cpufreq_driver { · 60 unmodified lines
251274 unsigned int index);
252275 unsigned int (*fast_switch)(struct cpufreq_policy *policy,
253276 unsigned int target_freq);
277+
278+ /*
279+ * Caches and returns the lowest driver-supported frequency greater than
280+ * or equal to the target frequency, subject to any driver limitations.
281+ * Does not set the frequency. Only to be implemented for drivers with
282+ * target().
283+ */
284+ unsigned int (*resolve_freq)(struct cpufreq_policy *policy,
285+ unsigned int target_freq);
286+
254287 /*
255288 * Only for drivers with target_index() and CPUFREQ_ASYNC_NOTIFICATION
256289 * unset.
@@ -455,18 +488,13 @@ static inline unsigned long cpufreq_scale(unsigned long old, u_int div, · 198 unmodified lines
455488 #define MIN_LATENCY_MULTIPLIER (20)
456489 #define TRANSITION_LATENCY_LIMIT (10 * 1000 * 1000)
457490
458−/* Governor Events */
459−#define CPUFREQ_GOV_START 1
460−#define CPUFREQ_GOV_STOP 2
461−#define CPUFREQ_GOV_LIMITS 3
462−#define CPUFREQ_GOV_POLICY_INIT 4
463−#define CPUFREQ_GOV_POLICY_EXIT 5
464−
465491 struct cpufreq_governor {
466492 char name[CPUFREQ_NAME_LEN];
467− int initialized;
468− int (*governor) (struct cpufreq_policy *policy,
469− unsigned int event);
493+ int (*init)(struct cpufreq_policy *policy);
494+ void (*exit)(struct cpufreq_policy *policy);
495+ int (*start)(struct cpufreq_policy *policy);
496+ void (*stop)(struct cpufreq_policy *policy);
497+ void (*limits)(struct cpufreq_policy *policy);
470498 ssize_t (*show_setspeed) (struct cpufreq_policy *policy,
471499 char *buf);
472500 int (*store_setspeed) (struct cpufreq_policy *policy,
@@ -487,12 +515,22 @@ int cpufreq_driver_target(struct cpufreq_policy *policy, · 14 unmodified lines
487515 int __cpufreq_driver_target(struct cpufreq_policy *policy,
488516 unsigned int target_freq,
489517 unsigned int relation);
518+unsigned int cpufreq_driver_resolve_freq(struct cpufreq_policy *policy,
519+ unsigned int target_freq);
490520 int cpufreq_register_governor(struct cpufreq_governor *governor);
491521 void cpufreq_unregister_governor(struct cpufreq_governor *governor);
492522
493523 struct cpufreq_governor *cpufreq_default_governor(void);
494524 struct cpufreq_governor *cpufreq_fallback_governor(void);
495525
526+static inline void cpufreq_policy_apply_limits(struct cpufreq_policy *policy)
527+{
528+ if (policy->max < policy->cur)
529+ __cpufreq_driver_target(policy, policy->max, CPUFREQ_RELATION_H);
530+ else if (policy->min > policy->cur)
531+ __cpufreq_driver_target(policy, policy->min, CPUFREQ_RELATION_L);
532+}
533+
496534 /* Governor attribute set */
497535 struct gov_attr_set {
498536 struct kobject kobj;
@@ -582,11 +620,9 @@ int cpufreq_frequency_table_verify(struct cpufreq_policy *policy, · 83 unmodified lines
582620 struct cpufreq_frequency_table *table);
583621 int cpufreq_generic_frequency_table_verify(struct cpufreq_policy *policy);
584622
585−int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
586− struct cpufreq_frequency_table *table,
587− unsigned int target_freq,
588− unsigned int relation,
589− unsigned int *index);
623+int cpufreq_table_index_unsorted(struct cpufreq_policy *policy,
624+ unsigned int target_freq,
625+ unsigned int relation);
590626 int cpufreq_frequency_table_get_index(struct cpufreq_policy *policy,
591627 unsigned int freq);
592628
@@ -597,6 +633,227 @@ int cpufreq_boost_trigger_state(int state); · 4 unmodified lines
597633 int cpufreq_boost_enabled(void);
598634 int cpufreq_enable_boost_support(void);
599635 bool policy_has_boost_freq(struct cpufreq_policy *policy);
636+
637+/* Find lowest freq at or above target in a table in ascending order */
638+static inline int cpufreq_table_find_index_al(struct cpufreq_policy *policy,
639+ unsigned int target_freq)
640+{
641+ struct cpufreq_frequency_table *table = policy->freq_table;
642+ unsigned int freq;
643+ int i, best = -1;
644+
645+ for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
646+ freq = table[i].frequency;
647+
648+ if (freq >= target_freq)
649+ return i;
650+
651+ best = i;
652+ }
653+
654+ return best;
655+}
656+
657+/* Find lowest freq at or above target in a table in descending order */
658+static inline int cpufreq_table_find_index_dl(struct cpufreq_policy *policy,
659+ unsigned int target_freq)
660+{
661+ struct cpufreq_frequency_table *table = policy->freq_table;
662+ unsigned int freq;
663+ int i, best = -1;
664+
665+ for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
666+ freq = table[i].frequency;
667+
668+ if (freq == target_freq)
669+ return i;
670+
671+ if (freq > target_freq) {
672+ best = i;
673+ continue;
674+ }
675+
676+ /* No freq found above target_freq */
677+ if (best == -1)
678+ return i;
679+
680+ return best;
681+ }
682+
683+ return best;
684+}
685+
686+/* Works only on sorted freq-tables */
687+static inline int cpufreq_table_find_index_l(struct cpufreq_policy *policy,
688+ unsigned int target_freq)
689+{
690+ target_freq = clamp_val(target_freq, policy->min, policy->max);
691+
692+ if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING)
693+ return cpufreq_table_find_index_al(policy, target_freq);
694+ else
695+ return cpufreq_table_find_index_dl(policy, target_freq);
696+}
697+
698+/* Find highest freq at or below target in a table in ascending order */
699+static inline int cpufreq_table_find_index_ah(struct cpufreq_policy *policy,
700+ unsigned int target_freq)
701+{
702+ struct cpufreq_frequency_table *table = policy->freq_table;
703+ unsigned int freq;
704+ int i, best = -1;
705+
706+ for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
707+ freq = table[i].frequency;
708+
709+ if (freq == target_freq)
710+ return i;
711+
712+ if (freq < target_freq) {
713+ best = i;
714+ continue;
715+ }
716+
717+ /* No freq found below target_freq */
718+ if (best == -1)
719+ return i;
720+
721+ return best;
722+ }
723+
724+ return best;
725+}
726+
727+/* Find highest freq at or below target in a table in descending order */
728+static inline int cpufreq_table_find_index_dh(struct cpufreq_policy *policy,
729+ unsigned int target_freq)
730+{
731+ struct cpufreq_frequency_table *table = policy->freq_table;
732+ unsigned int freq;
733+ int i, best = -1;
734+
735+ for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
736+ freq = table[i].frequency;
737+
738+ if (freq <= target_freq)
739+ return i;
740+
741+ best = i;
742+ }
743+
744+ return best;
745+}
746+
747+/* Works only on sorted freq-tables */
748+static inline int cpufreq_table_find_index_h(struct cpufreq_policy *policy,
749+ unsigned int target_freq)
750+{
751+ target_freq = clamp_val(target_freq, policy->min, policy->max);
752+
753+ if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING)
754+ return cpufreq_table_find_index_ah(policy, target_freq);
755+ else
756+ return cpufreq_table_find_index_dh(policy, target_freq);
757+}
758+
759+/* Find closest freq to target in a table in ascending order */
760+static inline int cpufreq_table_find_index_ac(struct cpufreq_policy *policy,
761+ unsigned int target_freq)
762+{
763+ struct cpufreq_frequency_table *table = policy->freq_table;
764+ unsigned int freq;
765+ int i, best = -1;
766+
767+ for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
768+ freq = table[i].frequency;
769+
770+ if (freq == target_freq)
771+ return i;
772+
773+ if (freq < target_freq) {
774+ best = i;
775+ continue;
776+ }
777+
778+ /* No freq found below target_freq */
779+ if (best == -1)
780+ return i;
781+
782+ /* Choose the closest freq */
783+ if (target_freq - table[best].frequency > freq - target_freq)
784+ return i;
785+
786+ return best;
787+ }
788+
789+ return best;
790+}
791+
792+/* Find closest freq to target in a table in descending order */
793+static inline int cpufreq_table_find_index_dc(struct cpufreq_policy *policy,
794+ unsigned int target_freq)
795+{
796+ struct cpufreq_frequency_table *table = policy->freq_table;
797+ unsigned int freq;
798+ int i, best = -1;
799+
800+ for (i = 0; table[i].frequency != CPUFREQ_TABLE_END; i++) {
801+ freq = table[i].frequency;
802+
803+ if (freq == target_freq)
804+ return i;
805+
806+ if (freq > target_freq) {
807+ best = i;
808+ continue;
809+ }
810+
811+ /* No freq found above target_freq */
812+ if (best == -1)
813+ return i;
814+
815+ /* Choose the closest freq */
816+ if (table[best].frequency - target_freq > target_freq - freq)
817+ return i;
818+
819+ return best;
820+ }
821+
822+ return best;
823+}
824+
825+/* Works only on sorted freq-tables */
826+static inline int cpufreq_table_find_index_c(struct cpufreq_policy *policy,
827+ unsigned int target_freq)
828+{
829+ target_freq = clamp_val(target_freq, policy->min, policy->max);
830+
831+ if (policy->freq_table_sorted == CPUFREQ_TABLE_SORTED_ASCENDING)
832+ return cpufreq_table_find_index_ac(policy, target_freq);
833+ else
834+ return cpufreq_table_find_index_dc(policy, target_freq);
835+}
836+
837+static inline int cpufreq_frequency_table_target(struct cpufreq_policy *policy,
838+ unsigned int target_freq,
839+ unsigned int relation)
840+{
841+ if (unlikely(policy->freq_table_sorted == CPUFREQ_TABLE_UNSORTED))
842+ return cpufreq_table_index_unsorted(policy, target_freq,
843+ relation);
844+
845+ switch (relation) {
846+ case CPUFREQ_RELATION_L:
847+ return cpufreq_table_find_index_l(policy, target_freq);
848+ case CPUFREQ_RELATION_H:
849+ return cpufreq_table_find_index_h(policy, target_freq);
850+ case CPUFREQ_RELATION_C:
851+ return cpufreq_table_find_index_c(policy, target_freq);
852+ default:
853+ pr_err("%s: Invalid relation: %d\n", __func__, relation);
854+ return -EINVAL;
855+ }
856+}
600857 #else
601858 static inline int cpufreq_boost_trigger_state(int state)
602859 {
@@ -617,8 +874,6 @@ static inline bool policy_has_boost_freq(struct cpufreq_policy *policy) · 14 unmodified lines
617874 return false;
618875 }
619876 #endif
620−/* the following funtion is for cpufreq core use only */
621−struct cpufreq_frequency_table *cpufreq_frequency_get_table(unsigned int cpu);
622877
623878 /* the following are really really optional */
624879 extern struct freq_attr cpufreq_freq_attr_scaling_available_freqs;
include/linux/pm_clock.h+1−0
@@ -42,6 +42,7 @@ extern int pm_clk_create(struct device *dev); · 41 unmodified lines
4242 extern void pm_clk_destroy(struct device *dev);
4343 extern int pm_clk_add(struct device *dev, const char *con_id);
4444 extern int pm_clk_add_clk(struct device *dev, struct clk *clk);
45+extern int of_pm_clk_add_clk(struct device *dev, const char *name);
4546 extern int of_pm_clk_add_clks(struct device *dev);
4647 extern void pm_clk_remove(struct device *dev, const char *con_id);
4748 extern void pm_clk_remove_clk(struct device *dev, struct clk *clk);
include/linux/pm_domain.h+5−5
@@ -57,7 +57,6 @@ struct generic_pm_domain { · 56 unmodified lines
5757 unsigned int device_count; /* Number of devices */
5858 unsigned int suspended_count; /* System suspend device counter */
5959 unsigned int prepared_count; /* Suspend counter of prepared devices */
60− bool suspend_power_off; /* Power status before system suspend */
6160 int (*power_off)(struct generic_pm_domain *domain);
6261 int (*power_on)(struct generic_pm_domain *domain);
6362 struct gpd_dev_ops dev_ops;
@@ -128,8 +127,8 @@ extern int pm_genpd_add_subdomain(struct generic_pm_domain *genpd, · 64 unmodified lines
128127 struct generic_pm_domain *new_subdomain);
129128 extern int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd,
130129 struct generic_pm_domain *target);
131−extern void pm_genpd_init(struct generic_pm_domain *genpd,
132− struct dev_power_governor *gov, bool is_off);
130+extern int pm_genpd_init(struct generic_pm_domain *genpd,
131+ struct dev_power_governor *gov, bool is_off);
133132
134133 extern struct dev_power_governor simple_qos_governor;
135134 extern struct dev_power_governor pm_domain_always_on_gov;
@@ -164,9 +163,10 @@ static inline int pm_genpd_remove_subdomain(struct generic_pm_domain *genpd, · 28 unmodified lines
164163 {
165164 return -ENOSYS;
166165 }
167−static inline void pm_genpd_init(struct generic_pm_domain *genpd,
168− struct dev_power_governor *gov, bool is_off)
166+static inline int pm_genpd_init(struct generic_pm_domain *genpd,
167+ struct dev_power_governor *gov, bool is_off)
169168 {
169+ return -ENOSYS;
170170 }
171171 #endif
172172
include/linux/suspend.h+2−3
@@ -18,12 +18,11 @@ static inline void pm_set_vt_switch(int do_switch) · 17 unmodified lines
1818 #endif
1919
2020 #ifdef CONFIG_VT_CONSOLE_SLEEP
21−extern int pm_prepare_console(void);
21+extern void pm_prepare_console(void);
2222 extern void pm_restore_console(void);
2323 #else
24−static inline int pm_prepare_console(void)
24+static inline void pm_prepare_console(void)
2525 {
26− return 0;
2726 }
2827
2928 static inline void pm_restore_console(void)
kernel/power/Makefile+2−0
@@ -1,6 +1,8 @@
11
22 ccflags-$(CONFIG_PM_DEBUG) := -DDEBUG
33
4+KASAN_SANITIZE_snapshot.o := n
5+
46 obj-y += qos.o
57 obj-$(CONFIG_PM) += main.o
68 obj-$(CONFIG_VT_CONSOLE_SLEEP) += console.o
kernel/power/console.c+4−4
@@ -126,17 +126,17 @@ out: · 125 unmodified lines
126126 return ret;
127127 }
128128
129−int pm_prepare_console(void)
129+void pm_prepare_console(void)
130130 {
131131 if (!pm_vt_switch())
132− return 0;
132+ return;
133133
134134 orig_fgconsole = vt_move_to_console(SUSPEND_CONSOLE, 1);
135135 if (orig_fgconsole < 0)
136− return 1;
136+ return;
137137
138138 orig_kmsg = vt_kmsg_redirect(SUSPEND_CONSOLE);
139− return 0;
139+ return;
140140 }
141141
142142 void pm_restore_console(void)
kernel/power/hibernate.c+68−33
@@ -52,6 +52,7 @@ enum { · 51 unmodified lines
5252 #ifdef CONFIG_SUSPEND
5353 HIBERNATION_SUSPEND,
5454 #endif
55+ HIBERNATION_TEST_RESUME,
5556 /* keep last */
5657 __HIBERNATION_AFTER_LAST
5758 };
@@ -409,6 +410,11 @@ int hibernation_snapshot(int platform_mode) · 351 unmodified lines
409410 goto Close;
410411 }
411412
413+int __weak hibernate_resume_nonboot_cpu_disable(void)
414+{
415+ return disable_nonboot_cpus();
416+}
417+
412418 /**
413419 * resume_target_kernel - Restore system state from a hibernation image.
414420 * @platform_mode: Whether or not to use the platform driver.
@@ -433,7 +439,7 @@ static int resume_target_kernel(bool platform_mode) · 18 unmodified lines
433439 if (error)
434440 goto Cleanup;
435441
436− error = disable_nonboot_cpus();
442+ error = hibernate_resume_nonboot_cpu_disable();
437443 if (error)
438444 goto Enable_cpus;
439445
@@ -642,12 +648,39 @@ static void power_down(void) · 202 unmodified lines
642648 cpu_relax();
643649 }
644650
651+static int load_image_and_restore(void)
652+{
653+ int error;
654+ unsigned int flags;
655+
656+ pr_debug("PM: Loading hibernation image.\n");
657+
658+ lock_device_hotplug();
659+ error = create_basic_memory_bitmaps();
660+ if (error)
661+ goto Unlock;
662+
663+ error = swsusp_read(&flags);
664+ swsusp_close(FMODE_READ);
665+ if (!error)
666+ hibernation_restore(flags & SF_PLATFORM_MODE);
667+
668+ printk(KERN_ERR "PM: Failed to load hibernation image, recovering.\n");
669+ swsusp_free();
670+ free_basic_memory_bitmaps();
671+ Unlock:
672+ unlock_device_hotplug();
673+
674+ return error;
675+}
676+
645677 /**
646678 * hibernate - Carry out system hibernation, including saving the image.
647679 */
648680 int hibernate(void)
649681 {
650− int error;
682+ int error, nr_calls = 0;
683+ bool snapshot_test = false;
651684
652685 if (!hibernation_available()) {
653686 pr_debug("PM: Hibernation not available.\n");
@@ -662,9 +695,11 @@ int hibernate(void) · 8 unmodified lines
662695 }
663696
664697 pm_prepare_console();
665− error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
666− if (error)
698+ error = __pm_notifier_call_chain(PM_HIBERNATION_PREPARE, -1, &nr_calls);
699+ if (error) {
700+ nr_calls--;
667701 goto Exit;
702+ }
668703
669704 printk(KERN_INFO "PM: Syncing filesystems ... ");
670705 sys_sync();
@@ -697,8 +732,12 @@ int hibernate(void) · 26 unmodified lines
697732 pr_debug("PM: writing image.\n");
698733 error = swsusp_write(flags);
699734 swsusp_free();
700− if (!error)
701− power_down();
735+ if (!error) {
736+ if (hibernation_mode == HIBERNATION_TEST_RESUME)
737+ snapshot_test = true;
738+ else
739+ power_down();
740+ }
702741 in_suspend = 0;
703742 pm_restore_gfp_mask();
704743 } else {
@@ -709,12 +748,18 @@ int hibernate(void) · 4 unmodified lines
709748 free_basic_memory_bitmaps();
710749 Thaw:
711750 unlock_device_hotplug();
751+ if (snapshot_test) {
752+ pr_debug("PM: Checking hibernation image\n");
753+ error = swsusp_check();
754+ if (!error)
755+ error = load_image_and_restore();
756+ }
712757 thaw_processes();
713758
714759 /* Don't bother checking whether freezer_test_done is true */
715760 freezer_test_done = false;
716761 Exit:
717− pm_notifier_call_chain(PM_POST_HIBERNATION);
762+ __pm_notifier_call_chain(PM_POST_HIBERNATION, nr_calls, NULL);
718763 pm_restore_console();
719764 atomic_inc(&snapshot_device_available);
720765 Unlock:
@@ -740,8 +785,7 @@ int hibernate(void) · 19 unmodified lines
740785 */
741786 static int software_resume(void)
742787 {
743− int error;
744− unsigned int flags;
788+ int error, nr_calls = 0;
745789
746790 /*
747791 * If the user said "noresume".. bail out early.
@@ -827,35 +871,20 @@ static int software_resume(void) · 79 unmodified lines
827871 }
828872
829873 pm_prepare_console();
830− error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
831− if (error)
874+ error = __pm_notifier_call_chain(PM_RESTORE_PREPARE, -1, &nr_calls);
875+ if (error) {
876+ nr_calls--;
832877 goto Close_Finish;
878+ }
833879
834880 pr_debug("PM: Preparing processes for restore.\n");
835881 error = freeze_processes();
836882 if (error)
837883 goto Close_Finish;
838−
839− pr_debug("PM: Loading hibernation image.\n");
840−
841− lock_device_hotplug();
842− error = create_basic_memory_bitmaps();
843− if (error)
844− goto Thaw;
845−
846− error = swsusp_read(&flags);
847− swsusp_close(FMODE_READ);
848− if (!error)
849− hibernation_restore(flags & SF_PLATFORM_MODE);
850−
851− printk(KERN_ERR "PM: Failed to load hibernation image, recovering.\n");
852− swsusp_free();
853− free_basic_memory_bitmaps();
854− Thaw:
855− unlock_device_hotplug();
884+ error = load_image_and_restore();
856885 thaw_processes();
857886 Finish:
858− pm_notifier_call_chain(PM_POST_RESTORE);
887+ __pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL);
859888 pm_restore_console();
860889 atomic_inc(&snapshot_device_available);
861890 /* For success case, the suspend path will release the lock */
@@ -878,6 +907,7 @@ static const char * const hibernation_modes[] = { · 16 unmodified lines
878907 #ifdef CONFIG_SUSPEND
879908 [HIBERNATION_SUSPEND] = "suspend",
880909 #endif
910+ [HIBERNATION_TEST_RESUME] = "test_resume",
881911 };
882912
883913 /*
@@ -924,6 +954,7 @@ static ssize_t disk_show(struct kobject *kobj, struct kobj_attribute *attr, · 40 unmodified lines
924954 #ifdef CONFIG_SUSPEND
925955 case HIBERNATION_SUSPEND:
926956 #endif
957+ case HIBERNATION_TEST_RESUME:
927958 break;
928959 case HIBERNATION_PLATFORM:
929960 if (hibernation_ops)
@@ -970,6 +1001,7 @@ static ssize_t disk_store(struct kobject *kobj, struct kobj_attribute *attr, · 40 unmodified lines
9701001 #ifdef CONFIG_SUSPEND
9711002 case HIBERNATION_SUSPEND:
9721003 #endif
1004+ case HIBERNATION_TEST_RESUME:
9731005 hibernation_mode = mode;
9741006 break;
9751007 case HIBERNATION_PLATFORM:
@@ -1115,13 +1147,16 @@ static int __init resume_offset_setup(char *str) · 139 unmodified lines
11151147
11161148 static int __init hibernate_setup(char *str)
11171149 {
1118− if (!strncmp(str, "noresume", 8))
1150+ if (!strncmp(str, "noresume", 8)) {
11191151 noresume = 1;
1120− else if (!strncmp(str, "nocompress", 10))
1152+ } else if (!strncmp(str, "nocompress", 10)) {
11211153 nocompress = 1;
1122− else if (!strncmp(str, "no", 2)) {
1154+ } else if (!strncmp(str, "no", 2)) {
11231155 noresume = 1;
11241156 nohibernate = 1;
1157+ } else if (IS_ENABLED(CONFIG_DEBUG_RODATA)
1158+ && !strncmp(str, "protect_image", 13)) {
1159+ enable_restore_image_protection();
11251160 }
11261161 return 1;
11271162 }
kernel/power/main.c+9−2
@@ -38,12 +38,19 @@ int unregister_pm_notifier(struct notifier_block *nb) · 37 unmodified lines
3838 }
3939 EXPORT_SYMBOL_GPL(unregister_pm_notifier);
4040
41−int pm_notifier_call_chain(unsigned long val)
41+int __pm_notifier_call_chain(unsigned long val, int nr_to_call, int *nr_calls)
4242 {
43− int ret = blocking_notifier_call_chain(&pm_chain_head, val, NULL);
43+ int ret;
44+
45+ ret = __blocking_notifier_call_chain(&pm_chain_head, val, NULL,
46+ nr_to_call, nr_calls);
4447
4548 return notifier_to_errno(ret);
4649 }
50+int pm_notifier_call_chain(unsigned long val)
51+{
52+ return __pm_notifier_call_chain(val, -1, NULL);
53+}
4754
4855 /* If set, devices may be suspended and resumed asynchronously. */
4956 int pm_async_enabled = 1;
kernel/power/power.h+11−0
@@ -38,6 +38,8 @@ static inline char *check_image_kernel(struct swsusp_info *info) · 37 unmodified lines
3838 }
3939 #endif /* CONFIG_ARCH_HIBERNATION_HEADER */
4040
41+extern int hibernate_resume_nonboot_cpu_disable(void);
42+
4143 /*
4244 * Keep some memory free so that I/O operations can succeed without paging
4345 * [Might this be more than 4 MB?]
@@ -59,6 +61,13 @@ extern int hibernation_snapshot(int platform_mode); · 15 unmodified lines
5961 extern int hibernation_restore(int platform_mode);
6062 extern int hibernation_platform_enter(void);
6163
64+#ifdef CONFIG_DEBUG_RODATA
65+/* kernel/power/snapshot.c */
66+extern void enable_restore_image_protection(void);
67+#else
68+static inline void enable_restore_image_protection(void) {}
69+#endif /* CONFIG_DEBUG_RODATA */
70+
6271 #else /* !CONFIG_HIBERNATION */
6372
6473 static inline void hibernate_reserved_size_init(void) {}
@@ -200,6 +209,8 @@ static inline void suspend_test_finish(const char *label) {} · 135 unmodified lines
200209
201210 #ifdef CONFIG_PM_SLEEP
202211 /* kernel/power/main.c */
212+extern int __pm_notifier_call_chain(unsigned long val, int nr_to_call,
213+ int *nr_calls);
203214 extern int pm_notifier_call_chain(unsigned long val);
204215 #endif
205216
kernel/power/process.c+3−0
@@ -89,6 +89,9 @@ static int try_to_freeze_tasks(bool user_only) · 88 unmodified lines
8989 elapsed_msecs / 1000, elapsed_msecs % 1000,
9090 todo - wq_busy, wq_busy);
9191
92+ if (wq_busy)
93+ show_workqueue_state();
94+
9295 if (!wakeup) {
9396 read_lock(&tasklist_lock);
9497 for_each_process_thread(g, p) {
kernel/power/snapshot.c+515−425
@@ -38,6 +38,43 @@ · 37 unmodified lines
3838
3939 #include "power.h"
4040
41+#ifdef CONFIG_DEBUG_RODATA
42+static bool hibernate_restore_protection;
43+static bool hibernate_restore_protection_active;
44+
45+void enable_restore_image_protection(void)
46+{
47+ hibernate_restore_protection = true;
48+}
49+
50+static inline void hibernate_restore_protection_begin(void)
51+{
52+ hibernate_restore_protection_active = hibernate_restore_protection;
53+}
54+
55+static inline void hibernate_restore_protection_end(void)
56+{
57+ hibernate_restore_protection_active = false;
58+}
59+
60+static inline void hibernate_restore_protect_page(void *page_address)
61+{
62+ if (hibernate_restore_protection_active)
63+ set_memory_ro((unsigned long)page_address, 1);
64+}
65+
66+static inline void hibernate_restore_unprotect_page(void *page_address)
67+{
68+ if (hibernate_restore_protection_active)
69+ set_memory_rw((unsigned long)page_address, 1);
70+}
71+#else
72+static inline void hibernate_restore_protection_begin(void) {}
73+static inline void hibernate_restore_protection_end(void) {}
74+static inline void hibernate_restore_protect_page(void *page_address) {}
75+static inline void hibernate_restore_unprotect_page(void *page_address) {}
76+#endif /* CONFIG_DEBUG_RODATA */
77+
4178 static int swsusp_page_is_free(struct page *);
4279 static void swsusp_set_page_forbidden(struct page *);
4380 static void swsusp_unset_page_forbidden(struct page *);
@@ -67,25 +104,32 @@ void __init hibernate_image_size_init(void) · 23 unmodified lines
67104 image_size = ((totalram_pages * 2) / 5) * PAGE_SIZE;
68105 }
69106
70−/* List of PBEs needed for restoring the pages that were allocated before
107+/*
108+ * List of PBEs needed for restoring the pages that were allocated before
71109 * the suspend and included in the suspend image, but have also been
72110 * allocated by the "resume" kernel, so their contents cannot be written
73111 * directly to their "original" page frames.
74112 */
75113 struct pbe *restore_pblist;
76114
77−/* Pointer to an auxiliary buffer (1 page) */
78−static void *buffer;
115+/* struct linked_page is used to build chains of pages */
79116
80−/**
81− * @safe_needed - on resume, for storing the PBE list and the image,
82− * we can only use memory pages that do not conflict with the pages
83− * used before suspend. The unsafe pages have PageNosaveFree set
84− * and we count them using unsafe_pages.
85− *
86− * Each allocated image page is marked as PageNosave and PageNosaveFree
87− * so that swsusp_free() can release it.
117+#define LINKED_PAGE_DATA_SIZE (PAGE_SIZE - sizeof(void *))
118+
119+struct linked_page {
120+ struct linked_page *next;
121+ char data[LINKED_PAGE_DATA_SIZE];
122+} __packed;
123+
124+/*
125+ * List of "safe" pages (ie. pages that were not used by the image kernel
126+ * before hibernation) that may be used as temporary storage for image kernel
127+ * memory contents.
88128 */
129+static struct linked_page *safe_pages_list;
130+
131+/* Pointer to an auxiliary buffer (1 page) */
132+static void *buffer;
89133
90134 #define PG_ANY 0
91135 #define PG_SAFE 1
@@ -94,6 +138,19 @@ static void *buffer; · 2 unmodified lines
94138
95139 static unsigned int allocated_unsafe_pages;
96140
141+/**
142+ * get_image_page - Allocate a page for a hibernation image.
143+ * @gfp_mask: GFP mask for the allocation.
144+ * @safe_needed: Get pages that were not used before hibernation (restore only)
145+ *
146+ * During image restoration, for storing the PBE list and the image data, we can
147+ * only use memory pages that do not conflict with the pages used before
148+ * hibernation. The "unsafe" pages have PageNosaveFree set and we count them
149+ * using allocated_unsafe_pages.
150+ *
151+ * Each allocated image page is marked as PageNosave and PageNosaveFree so that
152+ * swsusp_free() can release it.
153+ */
97154 static void *get_image_page(gfp_t gfp_mask, int safe_needed)
98155 {
99156 void *res;
@@ -113,9 +170,21 @@ static void *get_image_page(gfp_t gfp_mask, int safe_needed) · 13 unmodified lines
113170 return res;
114171 }
115172
173+static void *__get_safe_page(gfp_t gfp_mask)
174+{
175+ if (safe_pages_list) {
176+ void *ret = safe_pages_list;
177+
178+ safe_pages_list = safe_pages_list->next;
179+ memset(ret, 0, PAGE_SIZE);
180+ return ret;
181+ }
182+ return get_image_page(gfp_mask, PG_SAFE);
183+}
184+
116185 unsigned long get_safe_page(gfp_t gfp_mask)
117186 {
118− return (unsigned long)get_image_page(gfp_mask, PG_SAFE);
187+ return (unsigned long)__get_safe_page(gfp_mask);
119188 }
120189
121190 static struct page *alloc_image_page(gfp_t gfp_mask)
@@ -130,11 +199,22 @@ static struct page *alloc_image_page(gfp_t gfp_mask) · 8 unmodified lines
130199 return page;
131200 }
132201
202+static void recycle_safe_page(void *page_address)
203+{
204+ struct linked_page *lp = page_address;
205+
206+ lp->next = safe_pages_list;
207+ safe_pages_list = lp;
208+}
209+
133210 /**
134− * free_image_page - free page represented by @addr, allocated with
135− * get_image_page (page flags set by it must be cleared)
211+ * free_image_page - Free a page allocated for hibernation image.
212+ * @addr: Address of the page to free.
213+ * @clear_nosave_free: If set, clear the PageNosaveFree bit for the page.
214+ *
215+ * The page to free should have been allocated by get_image_page() (page flags
216+ * set by it are affected).
136217 */
137−
138218 static inline void free_image_page(void *addr, int clear_nosave_free)
139219 {
140220 struct page *page;
@@ -150,17 +230,8 @@ static inline void free_image_page(void *addr, int clear_nosave_free) · 9 unmodified lines
150230 __free_page(page);
151231 }
152232
153−/* struct linked_page is used to build chains of pages */
154−
155−#define LINKED_PAGE_DATA_SIZE (PAGE_SIZE - sizeof(void *))
156−
157−struct linked_page {
158− struct linked_page *next;
159− char data[LINKED_PAGE_DATA_SIZE];
160−} __packed;
161−
162−static inline void
163−free_list_of_pages(struct linked_page *list, int clear_page_nosave)
233+static inline void free_list_of_pages(struct linked_page *list,
234+ int clear_page_nosave)
164235 {
165236 while (list) {
166237 struct linked_page *lp = list->next;
@@ -170,30 +241,28 @@ free_list_of_pages(struct linked_page *list, int clear_page_nosave) · 3 unmodified lines
170241 }
171242 }
172243
173−/**
174− * struct chain_allocator is used for allocating small objects out of
175− * a linked list of pages called 'the chain'.
176− *
177− * The chain grows each time when there is no room for a new object in
178− * the current page. The allocated objects cannot be freed individually.
179− * It is only possible to free them all at once, by freeing the entire
180− * chain.
181− *
182− * NOTE: The chain allocator may be inefficient if the allocated objects
183− * are not much smaller than PAGE_SIZE.
184− */
185−
244+/*
245+ * struct chain_allocator is used for allocating small objects out of
246+ * a linked list of pages called 'the chain'.
247+ *
248+ * The chain grows each time when there is no room for a new object in
249+ * the current page. The allocated objects cannot be freed individually.
250+ * It is only possible to free them all at once, by freeing the entire
251+ * chain.
252+ *
253+ * NOTE: The chain allocator may be inefficient if the allocated objects
254+ * are not much smaller than PAGE_SIZE.
255+ */
186256 struct chain_allocator {
187257 struct linked_page *chain; /* the chain */
188258 unsigned int used_space; /* total size of objects allocated out
189− * of the current page
190− */
259+ of the current page */
191260 gfp_t gfp_mask; /* mask for allocating pages */
192261 int safe_needed; /* if set, only "safe" pages are allocated */
193262 };
194263
195−static void
196−chain_init(struct chain_allocator *ca, gfp_t gfp_mask, int safe_needed)
264+static void chain_init(struct chain_allocator *ca, gfp_t gfp_mask,
265+ int safe_needed)
197266 {
198267 ca->chain = NULL;
199268 ca->used_space = LINKED_PAGE_DATA_SIZE;
@@ -208,7 +277,8 @@ static void *chain_alloc(struct chain_allocator *ca, unsigned int size) · 8 unmodified lines
208277 if (LINKED_PAGE_DATA_SIZE - ca->used_space < size) {
209278 struct linked_page *lp;
210279
211− lp = get_image_page(ca->gfp_mask, ca->safe_needed);
280+ lp = ca->safe_needed ? __get_safe_page(ca->gfp_mask) :
281+ get_image_page(ca->gfp_mask, PG_ANY);
212282 if (!lp)
213283 return NULL;
214284
@@ -222,44 +292,44 @@ static void *chain_alloc(struct chain_allocator *ca, unsigned int size) · 7 unmodified lines
222292 }
223293
224294 /**
225− * Data types related to memory bitmaps.
295+ * Data types related to memory bitmaps.
226296 *
227− * Memory bitmap is a structure consiting of many linked lists of
228− * objects. The main list's elements are of type struct zone_bitmap
229− * and each of them corresonds to one zone. For each zone bitmap
230− * object there is a list of objects of type struct bm_block that
231− * represent each blocks of bitmap in which information is stored.
297+ * Memory bitmap is a structure consiting of many linked lists of
298+ * objects. The main list's elements are of type struct zone_bitmap
299+ * and each of them corresonds to one zone. For each zone bitmap
300+ * object there is a list of objects of type struct bm_block that
301+ * represent each blocks of bitmap in which information is stored.
232302 *
233− * struct memory_bitmap contains a pointer to the main list of zone
234− * bitmap objects, a struct bm_position used for browsing the bitmap,
235− * and a pointer to the list of pages used for allocating all of the
236− * zone bitmap objects and bitmap block objects.
303+ * struct memory_bitmap contains a pointer to the main list of zone
304+ * bitmap objects, a struct bm_position used for browsing the bitmap,
305+ * and a pointer to the list of pages used for allocating all of the
306+ * zone bitmap objects and bitmap block objects.
237307 *
238− * NOTE: It has to be possible to lay out the bitmap in memory
239− * using only allocations of order 0. Additionally, the bitmap is
240− * designed to work with arbitrary number of zones (this is over the
241− * top for now, but let's avoid making unnecessary assumptions ;-).
308+ * NOTE: It has to be possible to lay out the bitmap in memory
309+ * using only allocations of order 0. Additionally, the bitmap is
310+ * designed to work with arbitrary number of zones (this is over the
311+ * top for now, but let's avoid making unnecessary assumptions ;-).
242312 *
243− * struct zone_bitmap contains a pointer to a list of bitmap block
244− * objects and a pointer to the bitmap block object that has been
245− * most recently used for setting bits. Additionally, it contains the
246− * pfns that correspond to the start and end of the represented zone.
313+ * struct zone_bitmap contains a pointer to a list of bitmap block
314+ * objects and a pointer to the bitmap block object that has been
315+ * most recently used for setting bits. Additionally, it contains the
316+ * PFNs that correspond to the start and end of the represented zone.
247317 *
248− * struct bm_block contains a pointer to the memory page in which
249− * information is stored (in the form of a block of bitmap)
250− * It also contains the pfns that correspond to the start and end of
251− * the represented memory area.
318+ * struct bm_block contains a pointer to the memory page in which
319+ * information is stored (in the form of a block of bitmap)
320+ * It also contains the pfns that correspond to the start and end of
321+ * the represented memory area.
252322 *
253− * The memory bitmap is organized as a radix tree to guarantee fast random
254− * access to the bits. There is one radix tree for each zone (as returned
255− * from create_mem_extents).
323+ * The memory bitmap is organized as a radix tree to guarantee fast random
324+ * access to the bits. There is one radix tree for each zone (as returned
325+ * from create_mem_extents).
256326 *
257− * One radix tree is represented by one struct mem_zone_bm_rtree. There are
258− * two linked lists for the nodes of the tree, one for the inner nodes and
259− * one for the leave nodes. The linked leave nodes are used for fast linear
260− * access of the memory bitmap.
327+ * One radix tree is represented by one struct mem_zone_bm_rtree. There are
328+ * two linked lists for the nodes of the tree, one for the inner nodes and
329+ * one for the leave nodes. The linked leave nodes are used for fast linear
330+ * access of the memory bitmap.
261331 *
262− * The struct rtree_node represents one node of the radix tree.
332+ * The struct rtree_node represents one node of the radix tree.
263333 */
264334
265335 #define BM_END_OF_MAP (~0UL)
@@ -305,9 +375,8 @@ struct bm_position { · 39 unmodified lines
305375 struct memory_bitmap {
306376 struct list_head zones;
307377 struct linked_page *p_list; /* list of pages used to store zone
308− * bitmap objects and bitmap block
309− * objects
310− */
378+ bitmap objects and bitmap block
379+ objects */
311380 struct bm_position cur; /* most recently used bit position */
312381 };
313382
@@ -321,12 +390,12 @@ struct memory_bitmap { · 7 unmodified lines
321390 #endif
322391 #define BM_RTREE_LEVEL_MASK ((1UL << BM_RTREE_LEVEL_SHIFT) - 1)
323392
324−/*
325− * alloc_rtree_node - Allocate a new node and add it to the radix tree.
393+/**
394+ * alloc_rtree_node - Allocate a new node and add it to the radix tree.
326395 *
327− * This function is used to allocate inner nodes as well as the
328− * leave nodes of the radix tree. It also adds the node to the
329− * corresponding linked list passed in by the *list parameter.
396+ * This function is used to allocate inner nodes as well as the
397+ * leave nodes of the radix tree. It also adds the node to the
398+ * corresponding linked list passed in by the *list parameter.
330399 */
331400 static struct rtree_node *alloc_rtree_node(gfp_t gfp_mask, int safe_needed,
332401 struct chain_allocator *ca,
@@ -347,12 +416,12 @@ static struct rtree_node *alloc_rtree_node(gfp_t gfp_mask, int safe_needed, · 14 unmodified lines
347416 return node;
348417 }
349418
350−/*
351− * add_rtree_block - Add a new leave node to the radix tree
419+/**
420+ * add_rtree_block - Add a new leave node to the radix tree.
352421 *
353− * The leave nodes need to be allocated in order to keep the leaves
354− * linked list in order. This is guaranteed by the zone->blocks
355− * counter.
422+ * The leave nodes need to be allocated in order to keep the leaves
423+ * linked list in order. This is guaranteed by the zone->blocks
424+ * counter.
356425 */
357426 static int add_rtree_block(struct mem_zone_bm_rtree *zone, gfp_t gfp_mask,
358427 int safe_needed, struct chain_allocator *ca)
@@ -417,17 +486,18 @@ static int add_rtree_block(struct mem_zone_bm_rtree *zone, gfp_t gfp_mask, · 58 unmodified lines
417486 static void free_zone_bm_rtree(struct mem_zone_bm_rtree *zone,
418487 int clear_nosave_free);
419488
420−/*
421− * create_zone_bm_rtree - create a radix tree for one zone
489+/**
490+ * create_zone_bm_rtree - Create a radix tree for one zone.
422491 *
423− * Allocated the mem_zone_bm_rtree structure and initializes it.
424− * This function also allocated and builds the radix tree for the
425− * zone.
492+ * Allocated the mem_zone_bm_rtree structure and initializes it.
493+ * This function also allocated and builds the radix tree for the
494+ * zone.
426495 */
427−static struct mem_zone_bm_rtree *
428−create_zone_bm_rtree(gfp_t gfp_mask, int safe_needed,
429− struct chain_allocator *ca,
430− unsigned long start, unsigned long end)
496+static struct mem_zone_bm_rtree *create_zone_bm_rtree(gfp_t gfp_mask,
497+ int safe_needed,
498+ struct chain_allocator *ca,
499+ unsigned long start,
500+ unsigned long end)
431501 {
432502 struct mem_zone_bm_rtree *zone;
433503 unsigned int i, nr_blocks;
@@ -454,12 +524,12 @@ create_zone_bm_rtree(gfp_t gfp_mask, int safe_needed, · 20 unmodified lines
454524 return zone;
455525 }
456526
457−/*
458− * free_zone_bm_rtree - Free the memory of the radix tree
527+/**
528+ * free_zone_bm_rtree - Free the memory of the radix tree.
459529 *
460− * Free all node pages of the radix tree. The mem_zone_bm_rtree
461− * structure itself is not freed here nor are the rtree_node
462− * structs.
530+ * Free all node pages of the radix tree. The mem_zone_bm_rtree
531+ * structure itself is not freed here nor are the rtree_node
532+ * structs.
463533 */
464534 static void free_zone_bm_rtree(struct mem_zone_bm_rtree *zone,
465535 int clear_nosave_free)
@@ -492,8 +562,8 @@ struct mem_extent { · 26 unmodified lines
492562 };
493563
494564 /**
495− * free_mem_extents - free a list of memory extents
496− * @list - list of extents to empty
565+ * free_mem_extents - Free a list of memory extents.
566+ * @list: List of extents to free.
497567 */
498568 static void free_mem_extents(struct list_head *list)
499569 {
@@ -506,10 +576,11 @@ static void free_mem_extents(struct list_head *list) · 6 unmodified lines
506576 }
507577
508578 /**
509− * create_mem_extents - create a list of memory extents representing
510− * contiguous ranges of PFNs
511− * @list - list to put the extents into
512− * @gfp_mask - mask to use for memory allocations
579+ * create_mem_extents - Create a list of memory extents.
580+ * @list: List to put the extents into.
581+ * @gfp_mask: Mask to use for memory allocations.
582+ *
583+ * The extents represent contiguous ranges of PFNs.
513584 */
514585 static int create_mem_extents(struct list_head *list, gfp_t gfp_mask)
515586 {
@@ -565,10 +636,10 @@ static int create_mem_extents(struct list_head *list, gfp_t gfp_mask) · 49 unmodified lines
565636 }
566637
567638 /**
568− * memory_bm_create - allocate memory for a memory bitmap
569− */
570−static int
571−memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask, int safe_needed)
639+ * memory_bm_create - Allocate memory for a memory bitmap.
640+ */
641+static int memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask,
642+ int safe_needed)
572643 {
573644 struct chain_allocator ca;
574645 struct list_head mem_extents;
@@ -607,8 +678,9 @@ memory_bm_create(struct memory_bitmap *bm, gfp_t gfp_mask, int safe_needed) · 32 unmodified lines
607678 }
608679
609680 /**
610− * memory_bm_free - free memory occupied by the memory bitmap @bm
611− */
681+ * memory_bm_free - Free memory occupied by the memory bitmap.
682+ * @bm: Memory bitmap.
683+ */
612684 static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free)
613685 {
614686 struct mem_zone_bm_rtree *zone;
@@ -622,14 +694,13 @@ static void memory_bm_free(struct memory_bitmap *bm, int clear_nosave_free) · 7 unmodified lines
622694 }
623695
624696 /**
625− * memory_bm_find_bit - Find the bit for pfn in the memory
626− * bitmap
697+ * memory_bm_find_bit - Find the bit for a given PFN in a memory bitmap.
627698 *
628− * Find the bit in the bitmap @bm that corresponds to given pfn.
629− * The cur.zone, cur.block and cur.node_pfn member of @bm are
630− * updated.
631− * It walks the radix tree to find the page which contains the bit for
632− * pfn and returns the bit position in **addr and *bit_nr.
699+ * Find the bit in memory bitmap @bm that corresponds to the given PFN.
700+ * The cur.zone, cur.block and cur.node_pfn members of @bm are updated.
701+ *
702+ * Walk the radix tree to find the page containing the bit that represents @pfn
703+ * and return the position of the bit in @addr and @bit_nr.
633704 */
634705 static int memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn,
635706 void **addr, unsigned int *bit_nr)
@@ -658,10 +729,9 @@ static int memory_bm_find_bit(struct memory_bitmap *bm, unsigned long pfn, · 22 unmodified lines
658729
659730 zone_found:
660731 /*
661− * We have a zone. Now walk the radix tree to find the leave
662− * node for our pfn.
732+ * We have found the zone. Now walk the radix tree to find the leaf node
733+ * for our PFN.
663734 */
664−
665735 node = bm->cur.node;
666736 if (((pfn - zone->start_pfn) & ~BM_BLOCK_MASK) == bm->cur.node_pfn)
667737 goto node_found;
@@ -754,14 +824,14 @@ static bool memory_bm_pfn_present(struct memory_bitmap *bm, unsigned long pfn) · 86 unmodified lines
754824 }
755825
756826 /*
757− * rtree_next_node - Jumps to the next leave node
827+ * rtree_next_node - Jump to the next leaf node.
758828 *
759− * Sets the position to the beginning of the next node in the
760− * memory bitmap. This is either the next node in the current
761− * zone's radix tree or the first node in the radix tree of the
762− * next zone.
829+ * Set the position to the beginning of the next node in the
830+ * memory bitmap. This is either the next node in the current
831+ * zone's radix tree or the first node in the radix tree of the
832+ * next zone.
763833 *
764− * Returns true if there is a next node, false otherwise.
834+ * Return true if there is a next node, false otherwise.
765835 */
766836 static bool rtree_next_node(struct memory_bitmap *bm)
767837 {
@@ -790,14 +860,15 @@ static bool rtree_next_node(struct memory_bitmap *bm) · 22 unmodified lines
790860 }
791861
792862 /**
793− * memory_bm_rtree_next_pfn - Find the next set bit in the bitmap @bm
863+ * memory_bm_rtree_next_pfn - Find the next set bit in a memory bitmap.
864+ * @bm: Memory bitmap.
794865 *
795− * Starting from the last returned position this function searches
796− * for the next set bit in the memory bitmap and returns its
797− * number. If no more bit is set BM_END_OF_MAP is returned.
866+ * Starting from the last returned position this function searches for the next
867+ * set bit in @bm and returns the PFN represented by it. If no more bits are
868+ * set, BM_END_OF_MAP is returned.
798869 *
799− * It is required to run memory_bm_position_reset() before the
800− * first call to this function.
870+ * It is required to run memory_bm_position_reset() before the first call to
871+ * this function for the given memory bitmap.
801872 */
802873 static unsigned long memory_bm_next_pfn(struct memory_bitmap *bm)
803874 {
@@ -819,11 +890,10 @@ static unsigned long memory_bm_next_pfn(struct memory_bitmap *bm) · 15 unmodified lines
819890 return BM_END_OF_MAP;
820891 }
821892
822−/**
823− * This structure represents a range of page frames the contents of which
824− * should not be saved during the suspend.
893+/*
894+ * This structure represents a range of page frames the contents of which
895+ * should not be saved during hibernation.
825896 */
826−
827897 struct nosave_region {
828898 struct list_head list;
829899 unsigned long start_pfn;
@@ -832,15 +902,42 @@ struct nosave_region { · 2 unmodified lines
832902
833903 static LIST_HEAD(nosave_regions);
834904
905+static void recycle_zone_bm_rtree(struct mem_zone_bm_rtree *zone)
906+{
907+ struct rtree_node *node;
908+
909+ list_for_each_entry(node, &zone->nodes, list)
910+ recycle_safe_page(node->data);
911+
912+ list_for_each_entry(node, &zone->leaves, list)
913+ recycle_safe_page(node->data);
914+}
915+
916+static void memory_bm_recycle(struct memory_bitmap *bm)
917+{
918+ struct mem_zone_bm_rtree *zone;
919+ struct linked_page *p_list;
920+
921+ list_for_each_entry(zone, &bm->zones, list)
922+ recycle_zone_bm_rtree(zone);
923+
924+ p_list = bm->p_list;
925+ while (p_list) {
926+ struct linked_page *lp = p_list;
927+
928+ p_list = lp->next;
929+ recycle_safe_page(lp);
930+ }
931+}
932+
835933 /**
836− * register_nosave_region - register a range of page frames the contents
837− * of which should not be saved during the suspend (to be used in the early
838− * initialization code)
934+ * register_nosave_region - Register a region of unsaveable memory.
935+ *
936+ * Register a range of page frames the contents of which should not be saved
937+ * during hibernation (to be used in the early initialization code).
839938 */
840−
841−void __init
842−__register_nosave_region(unsigned long start_pfn, unsigned long end_pfn,
843− int use_kmalloc)
939+void __init __register_nosave_region(unsigned long start_pfn,
940+ unsigned long end_pfn, int use_kmalloc)
844941 {
845942 struct nosave_region *region;
846943
@@ -857,12 +954,13 @@ __register_nosave_region(unsigned long start_pfn, unsigned long end_pfn, · 10 unmodified lines
857954 }
858955 }
859956 if (use_kmalloc) {
860− /* during init, this shouldn't fail */
957+ /* During init, this shouldn't fail */
861958 region = kmalloc(sizeof(struct nosave_region), GFP_KERNEL);
862959 BUG_ON(!region);
863− } else
960+ } else {
864961 /* This allocation cannot fail */
865962 region = memblock_virt_alloc(sizeof(struct nosave_region), 0);
963+ }
866964 region->start_pfn = start_pfn;
867965 region->end_pfn = end_pfn;
868966 list_add_tail(&region->list, &nosave_regions);
@@ -923,10 +1021,12 @@ static void swsusp_unset_page_forbidden(struct page *page) · 54 unmodified lines
9231021 }
9241022
9251023 /**
926− * mark_nosave_pages - set bits corresponding to the page frames the
927− * contents of which should not be saved in a given bitmap.
1024+ * mark_nosave_pages - Mark pages that should not be saved.
1025+ * @bm: Memory bitmap.
1026+ *
1027+ * Set the bits in @bm that correspond to the page frames the contents of which
1028+ * should not be saved.
9281029 */
929−
9301030 static void mark_nosave_pages(struct memory_bitmap *bm)
9311031 {
9321032 struct nosave_region *region;
@@ -956,13 +1056,13 @@ static void mark_nosave_pages(struct memory_bitmap *bm) · 23 unmodified lines
9561056 }
9571057
9581058 /**
959− * create_basic_memory_bitmaps - create bitmaps needed for marking page
960− * frames that should not be saved and free page frames. The pointers
961− * forbidden_pages_map and free_pages_map are only modified if everything
962− * goes well, because we don't want the bits to be used before both bitmaps
963− * are set up.
1059+ * create_basic_memory_bitmaps - Create bitmaps to hold basic page information.
1060+ *
1061+ * Create bitmaps needed for marking page frames that should not be saved and
1062+ * free page frames. The forbidden_pages_map and free_pages_map pointers are
1063+ * only modified if everything goes well, because we don't want the bits to be
1064+ * touched before both bitmaps are set up.
9641065 */
965−
9661066 int create_basic_memory_bitmaps(void)
9671067 {
9681068 struct memory_bitmap *bm1, *bm2;
@@ -1007,12 +1107,12 @@ int create_basic_memory_bitmaps(void) · 38 unmodified lines
10071107 }
10081108
10091109 /**
1010− * free_basic_memory_bitmaps - free memory bitmaps allocated by
1011− * create_basic_memory_bitmaps(). The auxiliary pointers are necessary
1012− * so that the bitmaps themselves are not referred to while they are being
1013− * freed.
1110+ * free_basic_memory_bitmaps - Free memory bitmaps holding basic information.
1111+ *
1112+ * Free memory bitmaps allocated by create_basic_memory_bitmaps(). The
1113+ * auxiliary pointers are necessary so that the bitmaps themselves are not
1114+ * referred to while they are being freed.
10141115 */
1015−
10161116 void free_basic_memory_bitmaps(void)
10171117 {
10181118 struct memory_bitmap *bm1, *bm2;
@@ -1033,11 +1133,13 @@ void free_basic_memory_bitmaps(void) · 14 unmodified lines
10331133 }
10341134
10351135 /**
1036− * snapshot_additional_pages - estimate the number of additional pages
1037− * be needed for setting up the suspend image data structures for given
1038− * zone (usually the returned value is greater than the exact number)
1136+ * snapshot_additional_pages - Estimate the number of extra pages needed.
1137+ * @zone: Memory zone to carry out the computation for.
1138+ *
1139+ * Estimate the number of additional pages needed for setting up a hibernation
1140+ * image data structures for @zone (usually, the returned value is greater than
1141+ * the exact number).
10391142 */
1040−
10411143 unsigned int snapshot_additional_pages(struct zone *zone)
10421144 {
10431145 unsigned int rtree, nodes;
@@ -1055,10 +1157,10 @@ unsigned int snapshot_additional_pages(struct zone *zone) · 11 unmodified lines
10551157
10561158 #ifdef CONFIG_HIGHMEM
10571159 /**
1058− * count_free_highmem_pages - compute the total number of free highmem
1059− * pages, system-wide.
1160+ * count_free_highmem_pages - Compute the total number of free highmem pages.
1161+ *
1162+ * The returned number is system-wide.
10601163 */
1061−
10621164 static unsigned int count_free_highmem_pages(void)
10631165 {
10641166 struct zone *zone;
@@ -1072,11 +1174,12 @@ static unsigned int count_free_highmem_pages(void) · 7 unmodified lines
10721174 }
10731175
10741176 /**
1075− * saveable_highmem_page - Determine whether a highmem page should be
1076− * included in the suspend image.
1177+ * saveable_highmem_page - Check if a highmem page is saveable.
10771178 *
1078− * We should save the page if it isn't Nosave or NosaveFree, or Reserved,
1079− * and it isn't a part of a free chunk of pages.
1179+ * Determine whether a highmem page should be included in a hibernation image.
1180+ *
1181+ * We should save the page if it isn't Nosave or NosaveFree, or Reserved,
1182+ * and it isn't part of a free chunk of pages.
10801183 */
10811184 static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn)
10821185 {
@@ -1102,10 +1205,8 @@ static struct page *saveable_highmem_page(struct zone *zone, unsigned long pfn) · 19 unmodified lines
11021205 }
11031206
11041207 /**
1105− * count_highmem_pages - compute the total number of saveable highmem
1106− * pages.
1208+ * count_highmem_pages - Compute the total number of saveable highmem pages.
11071209 */
1108−
11091210 static unsigned int count_highmem_pages(void)
11101211 {
11111212 struct zone *zone;
@@ -1133,12 +1234,14 @@ static inline void *saveable_highmem_page(struct zone *z, unsigned long p) · 21 unmodified lines
11331234 #endif /* CONFIG_HIGHMEM */
11341235
11351236 /**
1136− * saveable_page - Determine whether a non-highmem page should be included
1137− * in the suspend image.
1237+ * saveable_page - Check if the given page is saveable.
11381238 *
1139− * We should save the page if it isn't Nosave, and is not in the range
1140− * of pages statically defined as 'unsaveable', and it isn't a part of
1141− * a free chunk of pages.
1239+ * Determine whether a non-highmem page should be included in a hibernation
1240+ * image.
1241+ *
1242+ * We should save the page if it isn't Nosave, and is not in the range
1243+ * of pages statically defined as 'unsaveable', and it isn't part of
1244+ * a free chunk of pages.
11421245 */
11431246 static struct page *saveable_page(struct zone *zone, unsigned long pfn)
11441247 {
@@ -1167,10 +1270,8 @@ static struct page *saveable_page(struct zone *zone, unsigned long pfn) · 22 unmodified lines
11671270 }
11681271
11691272 /**
1170− * count_data_pages - compute the total number of saveable non-highmem
1171− * pages.
1273+ * count_data_pages - Compute the total number of saveable non-highmem pages.
11721274 */
1173−
11741275 static unsigned int count_data_pages(void)
11751276 {
11761277 struct zone *zone;
@@ -1190,7 +1291,8 @@ static unsigned int count_data_pages(void) · 13 unmodified lines
11901291 return n;
11911292 }
11921293
1193−/* This is needed, because copy_page and memcpy are not usable for copying
1294+/*
1295+ * This is needed, because copy_page and memcpy are not usable for copying
11941296 * task structs.
11951297 */
11961298 static inline void do_copy_page(long *dst, long *src)
@@ -1201,12 +1303,12 @@ static inline void do_copy_page(long *dst, long *src) · 4 unmodified lines
12011303 *dst++ = *src++;
12021304 }
12031305
1204−
12051306 /**
1206− * safe_copy_page - check if the page we are going to copy is marked as
1207− * present in the kernel page tables (this always is the case if
1208− * CONFIG_DEBUG_PAGEALLOC is not set and in that case
1209− * kernel_page_present() always returns 'true').
1307+ * safe_copy_page - Copy a page in a safe way.
1308+ *
1309+ * Check if the page we are going to copy is marked as present in the kernel
1310+ * page tables (this always is the case if CONFIG_DEBUG_PAGEALLOC is not set
1311+ * and in that case kernel_page_present() always returns 'true').
12101312 */
12111313 static void safe_copy_page(void *dst, struct page *s_page)
12121314 {
@@ -1219,10 +1321,8 @@ static void safe_copy_page(void *dst, struct page *s_page) · 6 unmodified lines
12191321 }
12201322 }
12211323
1222−
12231324 #ifdef CONFIG_HIGHMEM
1224−static inline struct page *
1225−page_is_saveable(struct zone *zone, unsigned long pfn)
1325+static inline struct page *page_is_saveable(struct zone *zone, unsigned long pfn)
12261326 {
12271327 return is_highmem(zone) ?
12281328 saveable_highmem_page(zone, pfn) : saveable_page(zone, pfn);
@@ -1243,7 +1343,8 @@ static void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) · 14 unmodified lines
12431343 kunmap_atomic(src);
12441344 } else {
12451345 if (PageHighMem(d_page)) {
1246− /* Page pointed to by src may contain some kernel
1346+ /*
1347+ * The page pointed to by src may contain some kernel
12471348 * data modified by kmap_atomic()
12481349 */
12491350 safe_copy_page(buffer, s_page);
@@ -1265,8 +1366,8 @@ static inline void copy_data_page(unsigned long dst_pfn, unsigned long src_pfn) · 15 unmodified lines
12651366 }
12661367 #endif /* CONFIG_HIGHMEM */
12671368
1268−static void
1269−copy_data_pages(struct memory_bitmap *copy_bm, struct memory_bitmap *orig_bm)
1369+static void copy_data_pages(struct memory_bitmap *copy_bm,
1370+ struct memory_bitmap *orig_bm)
12701371 {
12711372 struct zone *zone;
12721373 unsigned long pfn;
@@ -1315,12 +1416,11 @@ static struct memory_bitmap orig_bm; · 42 unmodified lines
13151416 static struct memory_bitmap copy_bm;
13161417
13171418 /**
1318− * swsusp_free - free pages allocated for the suspend.
1419+ * swsusp_free - Free pages allocated for hibernation image.
13191420 *
1320− * Suspend pages are alocated before the atomic copy is made, so we
1321− * need to release them after the resume.
1421+ * Image pages are alocated before snapshot creation, so they need to be
1422+ * released after resume.
13221423 */
1323−
13241424 void swsusp_free(void)
13251425 {
13261426 unsigned long fb_pfn, fr_pfn;
@@ -1351,6 +1451,7 @@ loop: · 24 unmodified lines
13511451
13521452 memory_bm_clear_current(forbidden_pages_map);
13531453 memory_bm_clear_current(free_pages_map);
1454+ hibernate_restore_unprotect_page(page_address(page));
13541455 __free_page(page);
13551456 goto loop;
13561457 }
@@ -1362,6 +1463,7 @@ out: · 5 unmodified lines
13621463 buffer = NULL;
13631464 alloc_normal = 0;
13641465 alloc_highmem = 0;
1466+ hibernate_restore_protection_end();
13651467 }
13661468
13671469 /* Helper functions used for the shrinking of memory. */
@@ -1369,7 +1471,7 @@ out: · 1 unmodified line
13691471 #define GFP_IMAGE (GFP_KERNEL | __GFP_NOWARN)
13701472
13711473 /**
1372− * preallocate_image_pages - Allocate a number of pages for hibernation image
1474+ * preallocate_image_pages - Allocate a number of pages for hibernation image.
13731475 * @nr_pages: Number of page frames to allocate.
13741476 * @mask: GFP flags to use for the allocation.
13751477 *
@@ -1419,7 +1521,7 @@ static unsigned long preallocate_image_highmem(unsigned long nr_pages) · 43 unmodified lines
14191521 }
14201522
14211523 /**
1422− * __fraction - Compute (an approximation of) x * (multiplier / base)
1524+ * __fraction - Compute (an approximation of) x * (multiplier / base).
14231525 */
14241526 static unsigned long __fraction(u64 x, u64 multiplier, u64 base)
14251527 {
@@ -1429,8 +1531,8 @@ static unsigned long __fraction(u64 x, u64 multiplier, u64 base) · 3 unmodified lines
14291531 }
14301532
14311533 static unsigned long preallocate_highmem_fraction(unsigned long nr_pages,
1432− unsigned long highmem,
1433− unsigned long total)
1534+ unsigned long highmem,
1535+ unsigned long total)
14341536 {
14351537 unsigned long alloc = __fraction(nr_pages, highmem, total);
14361538
@@ -1443,15 +1545,15 @@ static inline unsigned long preallocate_image_highmem(unsigned long nr_pages) · 6 unmodified lines
14431545 }
14441546
14451547 static inline unsigned long preallocate_highmem_fraction(unsigned long nr_pages,
1446− unsigned long highmem,
1447− unsigned long total)
1548+ unsigned long highmem,
1549+ unsigned long total)
14481550 {
14491551 return 0;
14501552 }
14511553 #endif /* CONFIG_HIGHMEM */
14521554
14531555 /**
1454− * free_unnecessary_pages - Release preallocated pages not needed for the image
1556+ * free_unnecessary_pages - Release preallocated pages not needed for the image.
14551557 */
14561558 static unsigned long free_unnecessary_pages(void)
14571559 {
@@ -1505,7 +1607,7 @@ static unsigned long free_unnecessary_pages(void) · 47 unmodified lines
15051607 }
15061608
15071609 /**
1508− * minimum_image_size - Estimate the minimum acceptable size of an image
1610+ * minimum_image_size - Estimate the minimum acceptable size of an image.
15091611 * @saveable: Number of saveable pages in the system.
15101612 *
15111613 * We want to avoid attempting to free too much memory too hard, so estimate the
@@ -1535,7 +1637,7 @@ static unsigned long minimum_image_size(unsigned long saveable) · 23 unmodified lines
15351637 }
15361638
15371639 /**
1538− * hibernate_preallocate_memory - Preallocate memory for hibernation image
1640+ * hibernate_preallocate_memory - Preallocate memory for hibernation image.
15391641 *
15401642 * To create a hibernation image it is necessary to make a copy of every page
15411643 * frame in use. We also need a number of page frames to be free during
@@ -1708,10 +1810,11 @@ int hibernate_preallocate_memory(void) · 166 unmodified lines
17081810
17091811 #ifdef CONFIG_HIGHMEM
17101812 /**
1711− * count_pages_for_highmem - compute the number of non-highmem pages
1712− * that will be necessary for creating copies of highmem pages.
1713− */
1714−
1813+ * count_pages_for_highmem - Count non-highmem pages needed for copying highmem.
1814+ *
1815+ * Compute the number of non-highmem pages that will be necessary for creating
1816+ * copies of highmem pages.
1817+ */
17151818 static unsigned int count_pages_for_highmem(unsigned int nr_highmem)
17161819 {
17171820 unsigned int free_highmem = count_free_highmem_pages() + alloc_highmem;
@@ -1724,15 +1827,12 @@ static unsigned int count_pages_for_highmem(unsigned int nr_highmem) · 6 unmodified lines
17241827 return nr_highmem;
17251828 }
17261829 #else
1727−static unsigned int
1728−count_pages_for_highmem(unsigned int nr_highmem) { return 0; }
1830+static unsigned int count_pages_for_highmem(unsigned int nr_highmem) { return 0; }
17291831 #endif /* CONFIG_HIGHMEM */
17301832
17311833 /**
1732− * enough_free_mem - Make sure we have enough free memory for the
1733− * snapshot image.
1834+ * enough_free_mem - Check if there is enough free memory for the image.
17341835 */
1735−
17361836 static int enough_free_mem(unsigned int nr_pages, unsigned int nr_highmem)
17371837 {
17381838 struct zone *zone;
@@ -1751,10 +1851,11 @@ static int enough_free_mem(unsigned int nr_pages, unsigned int nr_highmem) · 12 unmodified lines
17511851
17521852 #ifdef CONFIG_HIGHMEM
17531853 /**
1754− * get_highmem_buffer - if there are some highmem pages in the suspend
1755− * image, we may need the buffer to copy them and/or load their data.
1854+ * get_highmem_buffer - Allocate a buffer for highmem pages.
1855+ *
1856+ * If there are some highmem pages in the hibernation image, we may need a
1857+ * buffer to copy them and/or load their data.
17561858 */
1757−
17581859 static inline int get_highmem_buffer(int safe_needed)
17591860 {
17601861 buffer = get_image_page(GFP_ATOMIC | __GFP_COLD, safe_needed);
@@ -1762,13 +1863,13 @@ static inline int get_highmem_buffer(int safe_needed) · 1 unmodified line
17621863 }
17631864
17641865 /**
1765− * alloc_highmem_image_pages - allocate some highmem pages for the image.
1766− * Try to allocate as many pages as needed, but if the number of free
1767− * highmem pages is lesser than that, allocate them all.
1866+ * alloc_highmem_image_pages - Allocate some highmem pages for the image.
1867+ *
1868+ * Try to allocate as many pages as needed, but if the number of free highmem
1869+ * pages is less than that, allocate them all.
17681870 */
1769−
1770−static inline unsigned int
1771−alloc_highmem_pages(struct memory_bitmap *bm, unsigned int nr_highmem)
1871+static inline unsigned int alloc_highmem_pages(struct memory_bitmap *bm,
1872+ unsigned int nr_highmem)
17721873 {
17731874 unsigned int to_alloc = count_free_highmem_pages();
17741875
@@ -1787,25 +1888,24 @@ alloc_highmem_pages(struct memory_bitmap *bm, unsigned int nr_highmem) · 12 unmodified lines
17871888 #else
17881889 static inline int get_highmem_buffer(int safe_needed) { return 0; }
17891890
1790−static inline unsigned int
1791−alloc_highmem_pages(struct memory_bitmap *bm, unsigned int n) { return 0; }
1891+static inline unsigned int alloc_highmem_pages(struct memory_bitmap *bm,
1892+ unsigned int n) { return 0; }
17921893 #endif /* CONFIG_HIGHMEM */
17931894
17941895 /**
1795− * swsusp_alloc - allocate memory for the suspend image
1896+ * swsusp_alloc - Allocate memory for hibernation image.
17961897 *
1797− * We first try to allocate as many highmem pages as there are
1798− * saveable highmem pages in the system. If that fails, we allocate
1799− * non-highmem pages for the copies of the remaining highmem ones.
1898+ * We first try to allocate as many highmem pages as there are
1899+ * saveable highmem pages in the system. If that fails, we allocate
1900+ * non-highmem pages for the copies of the remaining highmem ones.
18001901 *
1801− * In this approach it is likely that the copies of highmem pages will
1802− * also be located in the high memory, because of the way in which
1803− * copy_data_pages() works.
1902+ * In this approach it is likely that the copies of highmem pages will
1903+ * also be located in the high memory, because of the way in which
1904+ * copy_data_pages() works.
18041905 */
1805−
1806−static int
1807−swsusp_alloc(struct memory_bitmap *orig_bm, struct memory_bitmap *copy_bm,
1808− unsigned int nr_pages, unsigned int nr_highmem)
1906+static int swsusp_alloc(struct memory_bitmap *orig_bm,
1907+ struct memory_bitmap *copy_bm,
1908+ unsigned int nr_pages, unsigned int nr_highmem)
18091909 {
18101910 if (nr_highmem > 0) {
18111911 if (get_highmem_buffer(PG_ANY))
@@ -1855,7 +1955,8 @@ asmlinkage __visible int swsusp_save(void) · 43 unmodified lines
18551955 return -ENOMEM;
18561956 }
18571957
1858− /* During allocating of suspend pagedir, new cold pages may appear.
1958+ /*
1959+ * During allocating of suspend pagedir, new cold pages may appear.
18591960 * Kill them.
18601961 */
18611962 drain_local_pages(NULL);
@@ -1918,12 +2019,14 @@ static int init_header(struct swsusp_info *info) · 56 unmodified lines
19182019 }
19192020
19202021 /**
1921− * pack_pfns - pfns corresponding to the set bits found in the bitmap @bm
1922− * are stored in the array @buf[] (1 page at a time)
2022+ * pack_pfns - Prepare PFNs for saving.
2023+ * @bm: Memory bitmap.
2024+ * @buf: Memory buffer to store the PFNs in.
2025+ *
2026+ * PFNs corresponding to set bits in @bm are stored in the area of memory
2027+ * pointed to by @buf (1 page at a time).
19232028 */
1924−
1925−static inline void
1926−pack_pfns(unsigned long *buf, struct memory_bitmap *bm)
2029+static inline void pack_pfns(unsigned long *buf, struct memory_bitmap *bm)
19272030 {
19282031 int j;
19292032
@@ -1937,22 +2040,21 @@ pack_pfns(unsigned long *buf, struct memory_bitmap *bm) · 7 unmodified lines
19372040 }
19382041
19392042 /**
1940− * snapshot_read_next - used for reading the system memory snapshot.
2043+ * snapshot_read_next - Get the address to read the next image page from.
2044+ * @handle: Snapshot handle to be used for the reading.
19412045 *
1942− * On the first call to it @handle should point to a zeroed
1943− * snapshot_handle structure. The structure gets updated and a pointer
1944− * to it should be passed to this function every next time.
2046+ * On the first call, @handle should point to a zeroed snapshot_handle
2047+ * structure. The structure gets populated then and a pointer to it should be
2048+ * passed to this function every next time.
19452049 *
1946− * On success the function returns a positive number. Then, the caller
1947− * is allowed to read up to the returned number of bytes from the memory
1948− * location computed by the data_of() macro.
2050+ * On success, the function returns a positive number. Then, the caller
2051+ * is allowed to read up to the returned number of bytes from the memory
2052+ * location computed by the data_of() macro.
19492053 *
1950− * The function returns 0 to indicate the end of data stream condition,
1951− * and a negative number is returned on error. In such cases the
1952− * structure pointed to by @handle is not updated and should not be used
1953− * any more.
2054+ * The function returns 0 to indicate the end of the data stream condition,
2055+ * and negative numbers are returned on errors. If that happens, the structure
2056+ * pointed to by @handle is not updated and should not be used any more.
19542057 */
1955−
19562058 int snapshot_read_next(struct snapshot_handle *handle)
19572059 {
19582060 if (handle->cur > nr_meta_pages + nr_copy_pages)
@@ -1981,7 +2083,8 @@ int snapshot_read_next(struct snapshot_handle *handle) · 22 unmodified lines
19812083
19822084 page = pfn_to_page(memory_bm_next_pfn(&copy_bm));
19832085 if (PageHighMem(page)) {
1984− /* Highmem pages are copied to the buffer,
2086+ /*
2087+ * Highmem pages are copied to the buffer,
19852088 * because we can't return with a kmapped
19862089 * highmem page (we may not be called again).
19872090 */
@@ -1999,53 +2102,41 @@ int snapshot_read_next(struct snapshot_handle *handle) · 11 unmodified lines
19992102 return PAGE_SIZE;
20002103 }
20012104
2002−/**
2003− * mark_unsafe_pages - mark the pages that cannot be used for storing
2004− * the image during resume, because they conflict with the pages that
2005− * had been used before suspend
2006− */
2007−
2008−static int mark_unsafe_pages(struct memory_bitmap *bm)
2105+static void duplicate_memory_bitmap(struct memory_bitmap *dst,
2106+ struct memory_bitmap *src)
20092107 {
2010− struct zone *zone;
2011− unsigned long pfn, max_zone_pfn;
2108+ unsigned long pfn;
20122109
2013− /* Clear page flags */
2014− for_each_populated_zone(zone) {
2015− max_zone_pfn = zone_end_pfn(zone);
2016− for (pfn = zone->zone_start_pfn; pfn < max_zone_pfn; pfn++)
2017− if (pfn_valid(pfn))
2018− swsusp_unset_page_free(pfn_to_page(pfn));
2110+ memory_bm_position_reset(src);
2111+ pfn = memory_bm_next_pfn(src);
2112+ while (pfn != BM_END_OF_MAP) {
2113+ memory_bm_set_bit(dst, pfn);
2114+ pfn = memory_bm_next_pfn(src);
20192115 }
2020−
2021− /* Mark pages that correspond to the "original" pfns as "unsafe" */
2022− memory_bm_position_reset(bm);
2023− do {
2024− pfn = memory_bm_next_pfn(bm);
2025− if (likely(pfn != BM_END_OF_MAP)) {
2026− if (likely(pfn_valid(pfn)))
2027− swsusp_set_page_free(pfn_to_page(pfn));
2028− else
2029− return -EFAULT;
2030− }
2031− } while (pfn != BM_END_OF_MAP);
2032−
2033− allocated_unsafe_pages = 0;
2034−
2035− return 0;
20362116 }
20372117
2038−static void
2039−duplicate_memory_bitmap(struct memory_bitmap *dst, struct memory_bitmap *src)
2118+/**
2119+ * mark_unsafe_pages - Mark pages that were used before hibernation.
2120+ *
2121+ * Mark the pages that cannot be used for storing the image during restoration,
2122+ * because they conflict with the pages that had been used before hibernation.
2123+ */
2124+static void mark_unsafe_pages(struct memory_bitmap *bm)
20402125 {
20412126 unsigned long pfn;
20422127
2043− memory_bm_position_reset(src);
2044− pfn = memory_bm_next_pfn(src);
2128+ /* Clear the "free"/"unsafe" bit for all PFNs */
2129+ memory_bm_position_reset(free_pages_map);
2130+ pfn = memory_bm_next_pfn(free_pages_map);
20452131 while (pfn != BM_END_OF_MAP) {
2046− memory_bm_set_bit(dst, pfn);
2047− pfn = memory_bm_next_pfn(src);
2132+ memory_bm_clear_current(free_pages_map);
2133+ pfn = memory_bm_next_pfn(free_pages_map);
20482134 }
2135+
2136+ /* Mark pages that correspond to the "original" PFNs as "unsafe" */
2137+ duplicate_memory_bitmap(free_pages_map, bm);
2138+
2139+ allocated_unsafe_pages = 0;
20492140 }
20502141
20512142 static int check_header(struct swsusp_info *info)
@@ -2063,11 +2154,9 @@ static int check_header(struct swsusp_info *info) · 11 unmodified lines
20632154 }
20642155
20652156 /**
2066− * load header - check the image header and copy data from it
2157+ * load header - Check the image header and copy the data from it.
20672158 */
2068−
2069−static int
2070−load_header(struct swsusp_info *info)
2159+static int load_header(struct swsusp_info *info)
20712160 {
20722161 int error;
20732162
@@ -2081,8 +2170,12 @@ load_header(struct swsusp_info *info) · 7 unmodified lines
20812170 }
20822171
20832172 /**
2084− * unpack_orig_pfns - for each element of @buf[] (1 page at a time) set
2085− * the corresponding bit in the memory bitmap @bm
2173+ * unpack_orig_pfns - Set bits corresponding to given PFNs in a memory bitmap.
2174+ * @bm: Memory bitmap.
2175+ * @buf: Area of memory containing the PFNs.
2176+ *
2177+ * For each element of the array pointed to by @buf (1 page at a time), set the
2178+ * corresponding bit in @bm.
20862179 */
20872180 static int unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm)
20882181 {
@@ -2095,7 +2188,7 @@ static int unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm) · 6 unmodified lines
20952188 /* Extract and buffer page key for data page (s390 only). */
20962189 page_key_memorize(buf + j);
20972190
2098− if (memory_bm_pfn_present(bm, buf[j]))
2191+ if (pfn_valid(buf[j]) && memory_bm_pfn_present(bm, buf[j]))
20992192 memory_bm_set_bit(bm, buf[j]);
21002193 else
21012194 return -EFAULT;
@@ -2104,13 +2197,9 @@ static int unpack_orig_pfns(unsigned long *buf, struct memory_bitmap *bm) · 2 unmodified lines
21042197 return 0;
21052198 }
21062199
2107−/* List of "safe" pages that may be used to store data loaded from the suspend
2108− * image
2109− */
2110−static struct linked_page *safe_pages_list;
2111−
21122200 #ifdef CONFIG_HIGHMEM
2113−/* struct highmem_pbe is used for creating the list of highmem pages that
2201+/*
2202+ * struct highmem_pbe is used for creating the list of highmem pages that
21142203 * should be restored atomically during the resume from disk, because the page
21152204 * frames they have occupied before the suspend are in use.
21162205 */
@@ -2120,7 +2209,8 @@ struct highmem_pbe { · 3 unmodified lines
21202209 struct highmem_pbe *next;
21212210 };
21222211
2123−/* List of highmem PBEs needed for restoring the highmem pages that were
2212+/*
2213+ * List of highmem PBEs needed for restoring the highmem pages that were
21242214 * allocated before the suspend and included in the suspend image, but have
21252215 * also been allocated by the "resume" kernel, so their contents cannot be
21262216 * written directly to their "original" page frames.
@@ -2128,11 +2218,11 @@ struct highmem_pbe { · 1 unmodified line
21282218 static struct highmem_pbe *highmem_pblist;
21292219
21302220 /**
2131− * count_highmem_image_pages - compute the number of highmem pages in the
2132− * suspend image. The bits in the memory bitmap @bm that correspond to the
2133− * image pages are assumed to be set.
2221+ * count_highmem_image_pages - Compute the number of highmem pages in the image.
2222+ * @bm: Memory bitmap.
2223+ *
2224+ * The bits in @bm that correspond to image pages are assumed to be set.
21342225 */
2135−
21362226 static unsigned int count_highmem_image_pages(struct memory_bitmap *bm)
21372227 {
21382228 unsigned long pfn;
@@ -2149,24 +2239,25 @@ static unsigned int count_highmem_image_pages(struct memory_bitmap *bm) · 10 unmodified lines
21492239 return cnt;
21502240 }
21512241
2152−/**
2153− * prepare_highmem_image - try to allocate as many highmem pages as
2154− * there are highmem image pages (@nr_highmem_p points to the variable
2155− * containing the number of highmem image pages). The pages that are
2156− * "safe" (ie. will not be overwritten when the suspend image is
2157− * restored) have the corresponding bits set in @bm (it must be
2158− * unitialized).
2159− *
2160− * NOTE: This function should not be called if there are no highmem
2161− * image pages.
2162− */
2163−
21642242 static unsigned int safe_highmem_pages;
21652243
21662244 static struct memory_bitmap *safe_highmem_bm;
21672245
2168−static int
2169−prepare_highmem_image(struct memory_bitmap *bm, unsigned int *nr_highmem_p)
2246+/**
2247+ * prepare_highmem_image - Allocate memory for loading highmem data from image.
2248+ * @bm: Pointer to an uninitialized memory bitmap structure.
2249+ * @nr_highmem_p: Pointer to the number of highmem image pages.
2250+ *
2251+ * Try to allocate as many highmem pages as there are highmem image pages
2252+ * (@nr_highmem_p points to the variable containing the number of highmem image
2253+ * pages). The pages that are "safe" (ie. will not be overwritten when the
2254+ * hibernation image is restored entirely) have the corresponding bits set in
2255+ * @bm (it must be unitialized).
2256+ *
2257+ * NOTE: This function should not be called if there are no highmem image pages.
2258+ */
2259+static int prepare_highmem_image(struct memory_bitmap *bm,
2260+ unsigned int *nr_highmem_p)
21702261 {
21712262 unsigned int to_alloc;
21722263
@@ -2201,39 +2292,42 @@ prepare_highmem_image(struct memory_bitmap *bm, unsigned int *nr_highmem_p) · 28 unmodified lines
22012292 return 0;
22022293 }
22032294
2295+static struct page *last_highmem_page;
2296+
22042297 /**
2205− * get_highmem_page_buffer - for given highmem image page find the buffer
2206− * that suspend_write_next() should set for its caller to write to.
2298+ * get_highmem_page_buffer - Prepare a buffer to store a highmem image page.
22072299 *
2208− * If the page is to be saved to its "original" page frame or a copy of
2209− * the page is to be made in the highmem, @buffer is returned. Otherwise,
2210− * the copy of the page is to be made in normal memory, so the address of
2211− * the copy is returned.
2300+ * For a given highmem image page get a buffer that suspend_write_next() should
2301+ * return to its caller to write to.
22122302 *
2213− * If @buffer is returned, the caller of suspend_write_next() will write
2214− * the page's contents to @buffer, so they will have to be copied to the
2215− * right location on the next call to suspend_write_next() and it is done
2216− * with the help of copy_last_highmem_page(). For this purpose, if
2217− * @buffer is returned, @last_highmem page is set to the page to which
2218− * the data will have to be copied from @buffer.
2303+ * If the page is to be saved to its "original" page frame or a copy of
2304+ * the page is to be made in the highmem, @buffer is returned. Otherwise,
2305+ * the copy of the page is to be made in normal memory, so the address of
2306+ * the copy is returned.
2307+ *
2308+ * If @buffer is returned, the caller of suspend_write_next() will write
2309+ * the page's contents to @buffer, so they will have to be copied to the
2310+ * right location on the next call to suspend_write_next() and it is done
2311+ * with the help of copy_last_highmem_page(). For this purpose, if
2312+ * @buffer is returned, @last_highmem_page is set to the page to which
2313+ * the data will have to be copied from @buffer.
22192314 */
2220−
2221−static struct page *last_highmem_page;
2222−
2223−static void *
2224−get_highmem_page_buffer(struct page *page, struct chain_allocator *ca)
2315+static void *get_highmem_page_buffer(struct page *page,
2316+ struct chain_allocator *ca)
22252317 {
22262318 struct highmem_pbe *pbe;
22272319 void *kaddr;
22282320
22292321 if (swsusp_page_is_forbidden(page) && swsusp_page_is_free(page)) {
2230− /* We have allocated the "original" page frame and we can
2322+ /*
2323+ * We have allocated the "original" page frame and we can
22312324 * use it directly to store the loaded page.
22322325 */
22332326 last_highmem_page = page;
22342327 return buffer;
22352328 }
2236− /* The "original" page frame has not been allocated and we have to
2329+ /*
2330+ * The "original" page frame has not been allocated and we have to
22372331 * use a "safe" page frame to store the loaded page.
22382332 */
22392333 pbe = chain_alloc(ca, sizeof(struct highmem_pbe));
@@ -2263,11 +2357,12 @@ get_highmem_page_buffer(struct page *page, struct chain_allocator *ca) · 23 unmodified lines
22632357 }
22642358
22652359 /**
2266− * copy_last_highmem_page - copy the contents of a highmem image from
2267− * @buffer, where the caller of snapshot_write_next() has place them,
2268− * to the right location represented by @last_highmem_page .
2360+ * copy_last_highmem_page - Copy most the most recent highmem image page.
2361+ *
2362+ * Copy the contents of a highmem image from @buffer, where the caller of
2363+ * snapshot_write_next() has stored them, to the right location represented by
2364+ * @last_highmem_page .
22692365 */
2270−
22712366 static void copy_last_highmem_page(void)
22722367 {
22732368 if (last_highmem_page) {
@@ -2294,17 +2389,13 @@ static inline void free_highmem_data(void) · 20 unmodified lines
22942389 free_image_page(buffer, PG_UNSAFE_CLEAR);
22952390 }
22962391 #else
2297−static unsigned int
2298−count_highmem_image_pages(struct memory_bitmap *bm) { return 0; }
2392+static unsigned int count_highmem_image_pages(struct memory_bitmap *bm) { return 0; }
22992393
2300−static inline int
2301−prepare_highmem_image(struct memory_bitmap *bm, unsigned int *nr_highmem_p)
2302−{
2303− return 0;
2304−}
2394+static inline int prepare_highmem_image(struct memory_bitmap *bm,
2395+ unsigned int *nr_highmem_p) { return 0; }
23052396
2306−static inline void *
2307−get_highmem_page_buffer(struct page *page, struct chain_allocator *ca)
2397+static inline void *get_highmem_page_buffer(struct page *page,
2398+ struct chain_allocator *ca)
23082399 {
23092400 return ERR_PTR(-EINVAL);
23102401 }
@@ -2314,27 +2405,27 @@ static inline int last_highmem_page_copied(void) { return 1; } · 3 unmodified lines
23142405 static inline void free_highmem_data(void) {}
23152406 #endif /* CONFIG_HIGHMEM */
23162407
2408+#define PBES_PER_LINKED_PAGE (LINKED_PAGE_DATA_SIZE / sizeof(struct pbe))
2409+
23172410 /**
2318− * prepare_image - use the memory bitmap @bm to mark the pages that will
2319− * be overwritten in the process of restoring the system memory state
2320− * from the suspend image ("unsafe" pages) and allocate memory for the
2321− * image.
2411+ * prepare_image - Make room for loading hibernation image.
2412+ * @new_bm: Unitialized memory bitmap structure.
2413+ * @bm: Memory bitmap with unsafe pages marked.
2414+ *
2415+ * Use @bm to mark the pages that will be overwritten in the process of
2416+ * restoring the system memory state from the suspend image ("unsafe" pages)
2417+ * and allocate memory for the image.
23222418 *
2323− * The idea is to allocate a new memory bitmap first and then allocate
2324− * as many pages as needed for the image data, but not to assign these
2325− * pages to specific tasks initially. Instead, we just mark them as
2326− * allocated and create a lists of "safe" pages that will be used
2327− * later. On systems with high memory a list of "safe" highmem pages is
2328− * also created.
2419+ * The idea is to allocate a new memory bitmap first and then allocate
2420+ * as many pages as needed for image data, but without specifying what those
2421+ * pages will be used for just yet. Instead, we mark them all as allocated and
2422+ * create a lists of "safe" pages to be used later. On systems with high
2423+ * memory a list of "safe" highmem pages is created too.
23292424 */
2330−
2331−#define PBES_PER_LINKED_PAGE (LINKED_PAGE_DATA_SIZE / sizeof(struct pbe))
2332−
2333−static int
2334−prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm)
2425+static int prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm)
23352426 {
23362427 unsigned int nr_pages, nr_highmem;
2337− struct linked_page *sp_list, *lp;
2428+ struct linked_page *lp;
23382429 int error;
23392430
23402431 /* If there is no highmem, the buffer will not be necessary */
@@ -2342,9 +2433,7 @@ prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm) · 1 unmodified line
23422433 buffer = NULL;
23432434
23442435 nr_highmem = count_highmem_image_pages(bm);
2345− error = mark_unsafe_pages(bm);
2346− if (error)
2347− goto Free;
2436+ mark_unsafe_pages(bm);
23482437
23492438 error = memory_bm_create(new_bm, GFP_ATOMIC, PG_SAFE);
23502439 if (error)
@@ -2357,14 +2446,15 @@ prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm) · 6 unmodified lines
23572446 if (error)
23582447 goto Free;
23592448 }
2360− /* Reserve some safe pages for potential later use.
2449+ /*
2450+ * Reserve some safe pages for potential later use.
23612451 *
23622452 * NOTE: This way we make sure there will be enough safe pages for the
23632453 * chain_alloc() in get_buffer(). It is a bit wasteful, but
23642454 * nr_copy_pages cannot be greater than 50% of the memory anyway.
2455+ *
2456+ * nr_copy_pages cannot be less than allocated_unsafe_pages too.
23652457 */
2366− sp_list = NULL;
2367− /* nr_copy_pages cannot be lesser than allocated_unsafe_pages */
23682458 nr_pages = nr_copy_pages - nr_highmem - allocated_unsafe_pages;
23692459 nr_pages = DIV_ROUND_UP(nr_pages, PBES_PER_LINKED_PAGE);
23702460 while (nr_pages > 0) {
@@ -2373,12 +2463,11 @@ prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm) · 2 unmodified lines
23732463 error = -ENOMEM;
23742464 goto Free;
23752465 }
2376− lp->next = sp_list;
2377− sp_list = lp;
2466+ lp->next = safe_pages_list;
2467+ safe_pages_list = lp;
23782468 nr_pages--;
23792469 }
23802470 /* Preallocate memory for the image */
2381− safe_pages_list = NULL;
23822471 nr_pages = nr_copy_pages - nr_highmem - allocated_unsafe_pages;
23832472 while (nr_pages > 0) {
23842473 lp = (struct linked_page *)get_zeroed_page(GFP_ATOMIC);
@@ -2396,12 +2485,6 @@ prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm) · 11 unmodified lines
23962485 swsusp_set_page_free(virt_to_page(lp));
23972486 nr_pages--;
23982487 }
2399− /* Free the reserved safe pages so that chain_alloc() can use them */
2400− while (sp_list) {
2401− lp = sp_list->next;
2402− free_image_page(sp_list, PG_UNSAFE_CLEAR);
2403− sp_list = lp;
2404− }
24052488 return 0;
24062489
24072490 Free:
@@ -2410,10 +2493,11 @@ prepare_image(struct memory_bitmap *new_bm, struct memory_bitmap *bm) · 2 unmodified lines
24102493 }
24112494
24122495 /**
2413− * get_buffer - compute the address that snapshot_write_next() should
2414− * set for its caller to write to.
2496+ * get_buffer - Get the address to store the next image data page.
2497+ *
2498+ * Get the address that snapshot_write_next() should return to its caller to
2499+ * write to.
24152500 */
2416−
24172501 static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca)
24182502 {
24192503 struct pbe *pbe;
@@ -2428,12 +2512,14 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca) · 8 unmodified lines
24282512 return get_highmem_page_buffer(page, ca);
24292513
24302514 if (swsusp_page_is_forbidden(page) && swsusp_page_is_free(page))
2431− /* We have allocated the "original" page frame and we can
2515+ /*
2516+ * We have allocated the "original" page frame and we can
24322517 * use it directly to store the loaded page.
24332518 */
24342519 return page_address(page);
24352520
2436− /* The "original" page frame has not been allocated and we have to
2521+ /*
2522+ * The "original" page frame has not been allocated and we have to
24372523 * use a "safe" page frame to store the loaded page.
24382524 */
24392525 pbe = chain_alloc(ca, sizeof(struct pbe));
@@ -2450,22 +2536,21 @@ static void *get_buffer(struct memory_bitmap *bm, struct chain_allocator *ca) · 10 unmodified lines
24502536 }
24512537
24522538 /**
2453− * snapshot_write_next - used for writing the system memory snapshot.
2539+ * snapshot_write_next - Get the address to store the next image page.
2540+ * @handle: Snapshot handle structure to guide the writing.
24542541 *
2455− * On the first call to it @handle should point to a zeroed
2456− * snapshot_handle structure. The structure gets updated and a pointer
2457− * to it should be passed to this function every next time.
2542+ * On the first call, @handle should point to a zeroed snapshot_handle
2543+ * structure. The structure gets populated then and a pointer to it should be
2544+ * passed to this function every next time.
24582545 *
2459− * On success the function returns a positive number. Then, the caller
2460− * is allowed to write up to the returned number of bytes to the memory
2461− * location computed by the data_of() macro.
2546+ * On success, the function returns a positive number. Then, the caller
2547+ * is allowed to write up to the returned number of bytes to the memory
2548+ * location computed by the data_of() macro.
24622549 *
2463− * The function returns 0 to indicate the "end of file" condition,
2464− * and a negative number is returned on error. In such cases the
2465− * structure pointed to by @handle is not updated and should not be used
2466− * any more.
2550+ * The function returns 0 to indicate the "end of file" condition. Negative
2551+ * numbers are returned on errors, in which cases the structure pointed to by
2552+ * @handle is not updated and should not be used any more.
24672553 */
2468−
24692554 int snapshot_write_next(struct snapshot_handle *handle)
24702555 {
24712556 static struct chain_allocator ca;
@@ -2491,6 +2576,8 @@ int snapshot_write_next(struct snapshot_handle *handle) · 19 unmodified lines
24912576 if (error)
24922577 return error;
24932578
2579+ safe_pages_list = NULL;
2580+
24942581 error = memory_bm_create(&copy_bm, GFP_ATOMIC, PG_ANY);
24952582 if (error)
24962583 return error;
@@ -2500,6 +2587,7 @@ int snapshot_write_next(struct snapshot_handle *handle) · 3 unmodified lines
25002587 if (error)
25012588 return error;
25022589
2590+ hibernate_restore_protection_begin();
25032591 } else if (handle->cur <= nr_meta_pages + 1) {
25042592 error = unpack_orig_pfns(buffer, &copy_bm);
25052593 if (error)
@@ -2522,6 +2610,7 @@ int snapshot_write_next(struct snapshot_handle *handle) · 16 unmodified lines
25222610 copy_last_highmem_page();
25232611 /* Restore page key for data page (s390 only). */
25242612 page_key_write(handle->buffer);
2613+ hibernate_restore_protect_page(handle->buffer);
25252614 handle->buffer = get_buffer(&orig_bm, &ca);
25262615 if (IS_ERR(handle->buffer))
25272616 return PTR_ERR(handle->buffer);
@@ -2533,22 +2622,23 @@ int snapshot_write_next(struct snapshot_handle *handle) · 5 unmodified lines
25332622 }
25342623
25352624 /**
2536− * snapshot_write_finalize - must be called after the last call to
2537− * snapshot_write_next() in case the last page in the image happens
2538− * to be a highmem page and its contents should be stored in the
2539− * highmem. Additionally, it releases the memory that will not be
2540− * used any more.
2625+ * snapshot_write_finalize - Complete the loading of a hibernation image.
2626+ *
2627+ * Must be called after the last call to snapshot_write_next() in case the last
2628+ * page in the image happens to be a highmem page and its contents should be
2629+ * stored in highmem. Additionally, it recycles bitmap memory that's not
2630+ * necessary any more.
25412631 */
2542−
25432632 void snapshot_write_finalize(struct snapshot_handle *handle)
25442633 {
25452634 copy_last_highmem_page();
25462635 /* Restore page key for data page (s390 only). */
25472636 page_key_write(handle->buffer);
25482637 page_key_free();
2549− /* Free only if we have loaded the image entirely */
2638+ hibernate_restore_protect_page(handle->buffer);
2639+ /* Do that only if we have loaded the image entirely */
25502640 if (handle->cur > 1 && handle->cur > nr_meta_pages + nr_copy_pages) {
2551− memory_bm_free(&orig_bm, PG_UNSAFE_CLEAR);
2641+ memory_bm_recycle(&orig_bm);
25522642 free_highmem_data();
25532643 }
25542644 }
@@ -2561,8 +2651,8 @@ int snapshot_image_loaded(struct snapshot_handle *handle) · 6 unmodified lines
25612651
25622652 #ifdef CONFIG_HIGHMEM
25632653 /* Assumes that @buf is ready and points to a "safe" page */
2564−static inline void
2565−swap_two_pages_data(struct page *p1, struct page *p2, void *buf)
2654+static inline void swap_two_pages_data(struct page *p1, struct page *p2,
2655+ void *buf)
25662656 {
25672657 void *kaddr1, *kaddr2;
25682658
@@ -2576,15 +2666,15 @@ swap_two_pages_data(struct page *p1, struct page *p2, void *buf) · 7 unmodified lines
25762666 }
25772667
25782668 /**
2579− * restore_highmem - for each highmem page that was allocated before
2580− * the suspend and included in the suspend image, and also has been
2581− * allocated by the "resume" kernel swap its current (ie. "before
2582− * resume") contents with the previous (ie. "before suspend") one.
2669+ * restore_highmem - Put highmem image pages into their original locations.
2670+ *
2671+ * For each highmem page that was in use before hibernation and is included in
2672+ * the image, and also has been allocated by the "restore" kernel, swap its
2673+ * current contents with the previous (ie. "before hibernation") ones.
25832674 *
2584− * If the resume eventually fails, we can call this function once
2585− * again and restore the "before resume" highmem state.
2675+ * If the restore eventually fails, we can call this function once again and
2676+ * restore the highmem state as seen by the restore kernel.
25862677 */
2587−
25882678 int restore_highmem(void)
25892679 {
25902680 struct highmem_pbe *pbe = highmem_pblist;
kernel/power/suspend.c+6−4
@@ -266,16 +266,18 @@ static int suspend_test(int level) · 265 unmodified lines
266266 */
267267 static int suspend_prepare(suspend_state_t state)
268268 {
269− int error;
269+ int error, nr_calls = 0;
270270
271271 if (!sleep_state_supported(state))
272272 return -EPERM;
273273
274274 pm_prepare_console();
275275
276− error = pm_notifier_call_chain(PM_SUSPEND_PREPARE);
277− if (error)
276+ error = __pm_notifier_call_chain(PM_SUSPEND_PREPARE, -1, &nr_calls);
277+ if (error) {
278+ nr_calls--;
278279 goto Finish;
280+ }
279281
280282 trace_suspend_resume(TPS("freeze_processes"), 0, true);
281283 error = suspend_freeze_processes();
@@ -286,7 +288,7 @@ static int suspend_prepare(suspend_state_t state) · 4 unmodified lines
286288 suspend_stats.failed_freeze++;
287289 dpm_save_failed_step(SUSPEND_FREEZE);
288290 Finish:
289− pm_notifier_call_chain(PM_POST_SUSPEND);
291+ __pm_notifier_call_chain(PM_POST_SUSPEND, nr_calls, NULL);
290292 pm_restore_console();
291293 return error;
292294 }
kernel/power/swap.c+6−0
@@ -350,6 +350,12 @@ static int swsusp_swap_check(void) · 349 unmodified lines
350350 if (res < 0)
351351 blkdev_put(hib_resume_bdev, FMODE_WRITE);
352352
353+ /*
354+ * Update the resume device to the one actually used,
355+ * so the test_resume mode can use it in case it is
356+ * invoked from hibernate() to test the snapshot.
357+ */
358+ swsusp_resume_device = hib_resume_bdev->bd_dev;
353359 return res;
354360 }
355361
kernel/power/user.c+8−6
@@ -47,7 +47,7 @@ atomic_t snapshot_device_available = ATOMIC_INIT(1); · 46 unmodified lines
4747 static int snapshot_open(struct inode *inode, struct file *filp)
4848 {
4949 struct snapshot_data *data;
50− int error;
50+ int error, nr_calls = 0;
5151
5252 if (!hibernation_available())
5353 return -EPERM;
@@ -74,9 +74,9 @@ static int snapshot_open(struct inode *inode, struct file *filp) · 20 unmodified lines
7474 swap_type_of(swsusp_resume_device, 0, NULL) : -1;
7575 data->mode = O_RDONLY;
7676 data->free_bitmaps = false;
77− error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
77+ error = __pm_notifier_call_chain(PM_HIBERNATION_PREPARE, -1, &nr_calls);
7878 if (error)
79− pm_notifier_call_chain(PM_POST_HIBERNATION);
79+ __pm_notifier_call_chain(PM_POST_HIBERNATION, --nr_calls, NULL);
8080 } else {
8181 /*
8282 * Resuming. We may need to wait for the image device to
@@ -86,13 +86,15 @@ static int snapshot_open(struct inode *inode, struct file *filp) · 3 unmodified lines
8686
8787 data->swap = -1;
8888 data->mode = O_WRONLY;
89− error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
89+ error = __pm_notifier_call_chain(PM_RESTORE_PREPARE, -1, &nr_calls);
9090 if (!error) {
9191 error = create_basic_memory_bitmaps();
9292 data->free_bitmaps = !error;
93− }
93+ } else
94+ nr_calls--;
95+
9496 if (error)
95− pm_notifier_call_chain(PM_POST_RESTORE);
97+ __pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL);
9698 }
9799 if (error)
98100 atomic_inc(&snapshot_device_available);
kernel/sched/cpufreq_schedutil.c+32−42
@@ -47,6 +47,8 @@ struct sugov_cpu { · 46 unmodified lines
4747 struct update_util_data update_util;
4848 struct sugov_policy *sg_policy;
4949
50+ unsigned int cached_raw_freq;
51+
5052 /* The fields below are only needed when sharing a policy. */
5153 unsigned long util;
5254 unsigned long max;
@@ -106,7 +108,7 @@ static void sugov_update_commit(struct sugov_policy *sg_policy, u64 time, · 53 unmodified lines
106108
107109 /**
108110 * get_next_freq - Compute a new frequency for a given cpufreq policy.
109− * @policy: cpufreq policy object to compute the new frequency for.
111+ * @sg_cpu: schedutil cpu object to compute the new frequency for.
110112 * @util: Current CPU utilization.
111113 * @max: CPU capacity.
112114 *
@@ -121,14 +123,25 @@ static void sugov_update_commit(struct sugov_policy *sg_policy, u64 time, · 8 unmodified lines
121123 * next_freq = C * curr_freq * util_raw / max
122124 *
123125 * Take C = 1.25 for the frequency tipping point at (util / max) = 0.8.
126+ *
127+ * The lowest driver-supported frequency which is equal or greater than the raw
128+ * next_freq (as calculated above) is returned, subject to policy min/max and
129+ * cpufreq driver limitations.
124130 */
125−static unsigned int get_next_freq(struct cpufreq_policy *policy,
126− unsigned long util, unsigned long max)
131+static unsigned int get_next_freq(struct sugov_cpu *sg_cpu, unsigned long util,
132+ unsigned long max)
127133 {
134+ struct sugov_policy *sg_policy = sg_cpu->sg_policy;
135+ struct cpufreq_policy *policy = sg_policy->policy;
128136 unsigned int freq = arch_scale_freq_invariant() ?
129137 policy->cpuinfo.max_freq : policy->cur;
130138
131− return (freq + (freq >> 2)) * util / max;
139+ freq = (freq + (freq >> 2)) * util / max;
140+
141+ if (freq == sg_cpu->cached_raw_freq && sg_policy->next_freq != UINT_MAX)
142+ return sg_policy->next_freq;
143+ sg_cpu->cached_raw_freq = freq;
144+ return cpufreq_driver_resolve_freq(policy, freq);
132145 }
133146
134147 static void sugov_update_single(struct update_util_data *hook, u64 time,
@@ -143,13 +156,14 @@ static void sugov_update_single(struct update_util_data *hook, u64 time, · 8 unmodified lines
143156 return;
144157
145158 next_f = util == ULONG_MAX ? policy->cpuinfo.max_freq :
146− get_next_freq(policy, util, max);
159+ get_next_freq(sg_cpu, util, max);
147160 sugov_update_commit(sg_policy, time, next_f);
148161 }
149162
150−static unsigned int sugov_next_freq_shared(struct sugov_policy *sg_policy,
163+static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu,
151164 unsigned long util, unsigned long max)
152165 {
166+ struct sugov_policy *sg_policy = sg_cpu->sg_policy;
153167 struct cpufreq_policy *policy = sg_policy->policy;
154168 unsigned int max_f = policy->cpuinfo.max_freq;
155169 u64 last_freq_update_time = sg_policy->last_freq_update_time;
@@ -189,7 +203,7 @@ static unsigned int sugov_next_freq_shared(struct sugov_policy *sg_policy, · 33 unmodified lines
189203 }
190204 }
191205
192− return get_next_freq(policy, util, max);
206+ return get_next_freq(sg_cpu, util, max);
193207 }
194208
195209 static void sugov_update_shared(struct update_util_data *hook, u64 time,
@@ -206,7 +220,7 @@ static void sugov_update_shared(struct update_util_data *hook, u64 time, · 10 unmodified lines
206220 sg_cpu->last_update = time;
207221
208222 if (sugov_should_update_freq(sg_policy, time)) {
209− next_f = sugov_next_freq_shared(sg_policy, util, max);
223+ next_f = sugov_next_freq_shared(sg_cpu, util, max);
210224 sugov_update_commit(sg_policy, time, next_f);
211225 }
212226
@@ -394,7 +408,7 @@ static int sugov_init(struct cpufreq_policy *policy) · 181 unmodified lines
394408 return ret;
395409 }
396410
397−static int sugov_exit(struct cpufreq_policy *policy)
411+static void sugov_exit(struct cpufreq_policy *policy)
398412 {
399413 struct sugov_policy *sg_policy = policy->governor_data;
400414 struct sugov_tunables *tunables = sg_policy->tunables;
@@ -412,7 +426,6 @@ static int sugov_exit(struct cpufreq_policy *policy) · 11 unmodified lines
412426 mutex_unlock(&global_tunables_lock);
413427
414428 sugov_policy_free(sg_policy);
415− return 0;
416429 }
417430
418431 static int sugov_start(struct cpufreq_policy *policy)
@@ -434,6 +447,7 @@ static int sugov_start(struct cpufreq_policy *policy) · 15 unmodified lines
434447 sg_cpu->util = ULONG_MAX;
435448 sg_cpu->max = 0;
436449 sg_cpu->last_update = 0;
450+ sg_cpu->cached_raw_freq = 0;
437451 cpufreq_add_update_util_hook(cpu, &sg_cpu->update_util,
438452 sugov_update_shared);
439453 } else {
@@ -444,7 +458,7 @@ static int sugov_start(struct cpufreq_policy *policy) · 4 unmodified lines
444458 return 0;
445459 }
446460
447−static int sugov_stop(struct cpufreq_policy *policy)
461+static void sugov_stop(struct cpufreq_policy *policy)
448462 {
449463 struct sugov_policy *sg_policy = policy->governor_data;
450464 unsigned int cpu;
@@ -456,53 +470,29 @@ static int sugov_stop(struct cpufreq_policy *policy) · 5 unmodified lines
456470
457471 irq_work_sync(&sg_policy->irq_work);
458472 cancel_work_sync(&sg_policy->work);
459− return 0;
460473 }
461474
462−static int sugov_limits(struct cpufreq_policy *policy)
475+static void sugov_limits(struct cpufreq_policy *policy)
463476 {
464477 struct sugov_policy *sg_policy = policy->governor_data;
465478
466479 if (!policy->fast_switch_enabled) {
467480 mutex_lock(&sg_policy->work_lock);
468−
469− if (policy->max < policy->cur)
470− __cpufreq_driver_target(policy, policy->max,
471− CPUFREQ_RELATION_H);
472− else if (policy->min > policy->cur)
473− __cpufreq_driver_target(policy, policy->min,
474− CPUFREQ_RELATION_L);
475−
481+ cpufreq_policy_apply_limits(policy);
476482 mutex_unlock(&sg_policy->work_lock);
477483 }
478484
479485 sg_policy->need_freq_update = true;
480− return 0;
481−}
482−
483−int sugov_governor(struct cpufreq_policy *policy, unsigned int event)
484−{
485− if (event == CPUFREQ_GOV_POLICY_INIT) {
486− return sugov_init(policy);
487− } else if (policy->governor_data) {
488− switch (event) {
489− case CPUFREQ_GOV_POLICY_EXIT:
490− return sugov_exit(policy);
491− case CPUFREQ_GOV_START:
492− return sugov_start(policy);
493− case CPUFREQ_GOV_STOP:
494− return sugov_stop(policy);
495− case CPUFREQ_GOV_LIMITS:
496− return sugov_limits(policy);
497− }
498− }
499− return -EINVAL;
500486 }
501487
502488 static struct cpufreq_governor schedutil_gov = {
503489 .name = "schedutil",
504− .governor = sugov_governor,
505490 .owner = THIS_MODULE,
491+ .init = sugov_init,
492+ .exit = sugov_exit,
493+ .start = sugov_start,
494+ .stop = sugov_stop,
495+ .limits = sugov_limits,
506496 };
507497
508498 static int __init sugov_module_init(void)
kernel/workqueue.c+2−2
@@ -4369,8 +4369,8 @@ static void show_pwq(struct pool_workqueue *pwq) · 4368 unmodified lines
43694369 /**
43704370 * show_workqueue_state - dump workqueue state
43714371 *
4372− * Called from a sysrq handler and prints out all busy workqueues and
4373− * pools.
4372+ * Called from a sysrq handler or try_to_freeze_tasks() and prints out
4373+ * all busy workqueues and pools.
43744374 */
43754375 void show_workqueue_state(void)
43764376 {
scripts/analyze_suspend.py+2474−1167
@@ -19,6 +19,17 @@ · 18 unmodified lines
1919 # Authors:
2020 # Todd Brandt <todd.e.brandt@linux.intel.com>
2121 #
22+# Links:
23+# Home Page
24+# https://01.org/suspendresume
25+# Source repo
26+# https://github.com/01org/suspendresume
27+# Documentation
28+# Getting Started
29+# https://01.org/suspendresume/documentation/getting-started
30+# Command List:
31+# https://01.org/suspendresume/documentation/command-list
32+#
2233 # Description:
2334 # This tool is designed to assist kernel and OS developers in optimizing
2435 # their linux stack's suspend/resume time. Using a kernel image built
@@ -35,6 +46,8 @@ · 10 unmodified lines
3546 # CONFIG_FTRACE=y
3647 # CONFIG_FUNCTION_TRACER=y
3748 # CONFIG_FUNCTION_GRAPH_TRACER=y
49+# CONFIG_KPROBES=y
50+# CONFIG_KPROBES_ON_FTRACE=y
3851 #
3952 # For kernel versions older than 3.15:
4053 # The following additional kernel parameters are required:
@@ -52,6 +65,7 @@ import re · 11 unmodified lines
5265 import platform
5366 from datetime import datetime
5467 import struct
68+import ConfigParser
5569
5670 # ----------------- CLASSES --------------------
5771
@@ -60,8 +74,15 @@ import struct · 2 unmodified lines
6074 # A global, single-instance container used to
6175 # store system values and test parameters
6276 class SystemValues:
63− version = 3.0
77+ ansi = False
78+ version = '4.2'
6479 verbose = False
80+ addlogs = False
81+ mindevlen = 0.001
82+ mincglen = 1.0
83+ srgap = 0
84+ cgexp = False
85+ outdir = ''
6586 testdir = '.'
6687 tpath = '/sys/kernel/debug/tracing/'
6788 fpdtpath = '/sys/firmware/acpi/tables/FPDT'
@@ -71,26 +92,21 @@ class SystemValues: · 3 unmodified lines
7192 'device_pm_callback_end',
7293 'device_pm_callback_start'
7394 ]
74− modename = {
75− 'freeze': 'Suspend-To-Idle (S0)',
76− 'standby': 'Power-On Suspend (S1)',
77− 'mem': 'Suspend-to-RAM (S3)',
78− 'disk': 'Suspend-to-disk (S4)'
79− }
95+ testcommand = ''
8096 mempath = '/dev/mem'
8197 powerfile = '/sys/power/state'
8298 suspendmode = 'mem'
8399 hostname = 'localhost'
84100 prefix = 'test'
85101 teststamp = ''
102+ dmesgstart = 0.0
86103 dmesgfile = ''
87104 ftracefile = ''
88105 htmlfile = ''
106+ embedded = False
89107 rtcwake = False
90108 rtcwaketime = 10
91109 rtcpath = ''
92− android = False
93− adb = 'adb'
94110 devicefilter = []
95111 stamp = 0
96112 execcount = 1
@@ -98,16 +114,90 @@ class SystemValues: · 1 unmodified line
98114 usecallgraph = False
99115 usetraceevents = False
100116 usetraceeventsonly = False
117+ usetracemarkers = True
118+ usekprobes = True
119+ usedevsrc = False
101120 notestrun = False
102− altdevname = dict()
121+ devprops = dict()
103122 postresumetime = 0
123+ devpropfmt = '# Device Properties: .*'
104124 tracertypefmt = '# tracer: (?P<t>.*)'
105125 firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$'
106126 postresumefmt = '# post resume time (?P<t>[0-9]*)$'
107127 stampfmt = '# suspend-(?P<m>[0-9]{2})(?P<d>[0-9]{2})(?P<y>[0-9]{2})-'+\
108128 '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\
109129 ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$'
130+ kprobecolor = 'rgba(204,204,204,0.5)'
131+ synccolor = 'rgba(204,204,204,0.5)'
132+ debugfuncs = []
133+ tracefuncs = {
134+ 'sys_sync': dict(),
135+ 'pm_prepare_console': dict(),
136+ 'pm_notifier_call_chain': dict(),
137+ 'freeze_processes': dict(),
138+ 'freeze_kernel_threads': dict(),
139+ 'pm_restrict_gfp_mask': dict(),
140+ 'acpi_suspend_begin': dict(),
141+ 'suspend_console': dict(),
142+ 'acpi_pm_prepare': dict(),
143+ 'syscore_suspend': dict(),
144+ 'arch_enable_nonboot_cpus_end': dict(),
145+ 'syscore_resume': dict(),
146+ 'acpi_pm_finish': dict(),
147+ 'resume_console': dict(),
148+ 'acpi_pm_end': dict(),
149+ 'pm_restore_gfp_mask': dict(),
150+ 'thaw_processes': dict(),
151+ 'pm_restore_console': dict(),
152+ 'CPU_OFF': {
153+ 'func':'_cpu_down',
154+ 'args_x86_64': {'cpu':'%di:s32'},
155+ 'format': 'CPU_OFF[{cpu}]',
156+ 'mask': 'CPU_.*_DOWN'
157+ },
158+ 'CPU_ON': {
159+ 'func':'_cpu_up',
160+ 'args_x86_64': {'cpu':'%di:s32'},
161+ 'format': 'CPU_ON[{cpu}]',
162+ 'mask': 'CPU_.*_UP'
163+ },
164+ }
165+ dev_tracefuncs = {
166+ # general wait/delay/sleep
167+ 'msleep': { 'args_x86_64': {'time':'%di:s32'} },
168+ 'udelay': { 'func':'__const_udelay', 'args_x86_64': {'loops':'%di:s32'} },
169+ 'acpi_os_stall': dict(),
170+ # ACPI
171+ 'acpi_resume_power_resources': dict(),
172+ 'acpi_ps_parse_aml': dict(),
173+ # filesystem
174+ 'ext4_sync_fs': dict(),
175+ # ATA
176+ 'ata_eh_recover': { 'args_x86_64': {'port':'+36(%di):s32'} },
177+ # i915
178+ 'i915_gem_restore_gtt_mappings': dict(),
179+ 'intel_opregion_setup': dict(),
180+ 'intel_dp_detect': dict(),
181+ 'intel_hdmi_detect': dict(),
182+ 'intel_opregion_init': dict(),
183+ }
184+ kprobes_postresume = [
185+ {
186+ 'name': 'ataportrst',
187+ 'func': 'ata_eh_recover',
188+ 'args': {'port':'+36(%di):s32'},
189+ 'format': 'ata{port}_port_reset',
190+ 'mask': 'ata.*_port_reset'
191+ }
192+ ]
193+ kprobes = dict()
194+ timeformat = '%.3f'
110195 def __init__(self):
196+ # if this is a phoronix test run, set some default options
197+ if('LOG_FILE' in os.environ and 'TEST_RESULTS_IDENTIFIER' in os.environ):
198+ self.embedded = True
199+ self.addlogs = True
200+ self.htmlfile = os.environ['LOG_FILE']
111201 self.hostname = platform.node()
112202 if(self.hostname == ''):
113203 self.hostname = 'localhost'
@@ -118,6 +208,12 @@ class SystemValues: · 4 unmodified lines
118208 if os.path.exists(rtc) and os.path.exists(rtc+'/date') and \
119209 os.path.exists(rtc+'/time') and os.path.exists(rtc+'/wakealarm'):
120210 self.rtcpath = rtc
211+ if (hasattr(sys.stdout, 'isatty') and sys.stdout.isatty()):
212+ self.ansi = True
213+ def setPrecision(self, num):
214+ if num < 0 or num > 6:
215+ return
216+ self.timeformat = '%.{0}f'.format(num)
121217 def setOutputFile(self):
122218 if((self.htmlfile == '') and (self.dmesgfile != '')):
123219 m = re.match('(?P<name>.*)_dmesg\.txt$', self.dmesgfile)
@@ -129,32 +225,37 @@ class SystemValues: · 5 unmodified lines
129225 self.htmlfile = m.group('name')+'.html'
130226 if(self.htmlfile == ''):
131227 self.htmlfile = 'output.html'
132− def initTestOutput(self, subdir):
133− if(not self.android):
134− self.prefix = self.hostname
135− v = open('/proc/version', 'r').read().strip()
136− kver = string.split(v)[2]
137− else:
138− self.prefix = 'android'
139− v = os.popen(self.adb+' shell cat /proc/version').read().strip()
140− kver = string.split(v)[2]
141− testtime = datetime.now().strftime('suspend-%m%d%y-%H%M%S')
228+ def initTestOutput(self, subdir, testpath=''):
229+ self.prefix = self.hostname
230+ v = open('/proc/version', 'r').read().strip()
231+ kver = string.split(v)[2]
232+ n = datetime.now()
233+ testtime = n.strftime('suspend-%m%d%y-%H%M%S')
234+ if not testpath:
235+ testpath = n.strftime('suspend-%y%m%d-%H%M%S')
142236 if(subdir != "."):
143− self.testdir = subdir+"/"+testtime
237+ self.testdir = subdir+"/"+testpath
144238 else:
145− self.testdir = testtime
239+ self.testdir = testpath
146240 self.teststamp = \
147241 '# '+testtime+' '+self.prefix+' '+self.suspendmode+' '+kver
242+ if(self.embedded):
243+ self.dmesgfile = \
244+ '/tmp/'+testtime+'_'+self.suspendmode+'_dmesg.txt'
245+ self.ftracefile = \
246+ '/tmp/'+testtime+'_'+self.suspendmode+'_ftrace.txt'
247+ return
148248 self.dmesgfile = \
149249 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_dmesg.txt'
150250 self.ftracefile = \
151251 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'_ftrace.txt'
152252 self.htmlfile = \
153253 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html'
154− os.mkdir(self.testdir)
254+ if not os.path.isdir(self.testdir):
255+ os.mkdir(self.testdir)
155256 def setDeviceFilter(self, devnames):
156257 self.devicefilter = string.split(devnames)
157− def rtcWakeAlarm(self):
258+ def rtcWakeAlarmOn(self):
158259 os.system('echo 0 > '+self.rtcpath+'/wakealarm')
159260 outD = open(self.rtcpath+'/date', 'r').read().strip()
160261 outT = open(self.rtcpath+'/time', 'r').read().strip()
@@ -172,9 +273,361 @@ class SystemValues: · 11 unmodified lines
172273 nowtime = int(datetime.now().strftime('%s'))
173274 alarm = nowtime + self.rtcwaketime
174275 os.system('echo %d > %s/wakealarm' % (alarm, self.rtcpath))
276+ def rtcWakeAlarmOff(self):
277+ os.system('echo 0 > %s/wakealarm' % self.rtcpath)
278+ def initdmesg(self):
279+ # get the latest time stamp from the dmesg log
280+ fp = os.popen('dmesg')
281+ ktime = '0'
282+ for line in fp:
283+ line = line.replace('\r\n', '')
284+ idx = line.find('[')
285+ if idx > 1:
286+ line = line[idx:]
287+ m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
288+ if(m):
289+ ktime = m.group('ktime')
290+ fp.close()
291+ self.dmesgstart = float(ktime)
292+ def getdmesg(self):
293+ # store all new dmesg lines since initdmesg was called
294+ fp = os.popen('dmesg')
295+ op = open(self.dmesgfile, 'a')
296+ for line in fp:
297+ line = line.replace('\r\n', '')
298+ idx = line.find('[')
299+ if idx > 1:
300+ line = line[idx:]
301+ m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
302+ if(not m):
303+ continue
304+ ktime = float(m.group('ktime'))
305+ if ktime > self.dmesgstart:
306+ op.write(line)
307+ fp.close()
308+ op.close()
309+ def addFtraceFilterFunctions(self, file):
310+ fp = open(file)
311+ list = fp.read().split('\n')
312+ fp.close()
313+ for i in list:
314+ if len(i) < 2:
315+ continue
316+ self.tracefuncs[i] = dict()
317+ def getFtraceFilterFunctions(self, current):
318+ rootCheck(True)
319+ if not current:
320+ os.system('cat '+self.tpath+'available_filter_functions')
321+ return
322+ fp = open(self.tpath+'available_filter_functions')
323+ master = fp.read().split('\n')
324+ fp.close()
325+ if len(self.debugfuncs) > 0:
326+ for i in self.debugfuncs:
327+ if i in master:
328+ print i
329+ else:
330+ print self.colorText(i)
331+ else:
332+ for i in self.tracefuncs:
333+ if 'func' in self.tracefuncs[i]:
334+ i = self.tracefuncs[i]['func']
335+ if i in master:
336+ print i
337+ else:
338+ print self.colorText(i)
339+ def setFtraceFilterFunctions(self, list):
340+ fp = open(self.tpath+'available_filter_functions')
341+ master = fp.read().split('\n')
342+ fp.close()
343+ flist = ''
344+ for i in list:
345+ if i not in master:
346+ continue
347+ if ' [' in i:
348+ flist += i.split(' ')[0]+'\n'
349+ else:
350+ flist += i+'\n'
351+ fp = open(self.tpath+'set_graph_function', 'w')
352+ fp.write(flist)
353+ fp.close()
354+ def kprobeMatch(self, name, target):
355+ if name not in self.kprobes:
356+ return False
357+ if re.match(self.kprobes[name]['mask'], target):
358+ return True
359+ return False
360+ def basicKprobe(self, name):
361+ self.kprobes[name] = {'name': name,'func': name,'args': dict(),'format': name,'mask': name}
362+ def defaultKprobe(self, name, kdata):
363+ k = kdata
364+ for field in ['name', 'format', 'mask', 'func']:
365+ if field not in k:
366+ k[field] = name
367+ archargs = 'args_'+platform.machine()
368+ if archargs in k:
369+ k['args'] = k[archargs]
370+ else:
371+ k['args'] = dict()
372+ k['format'] = name
373+ self.kprobes[name] = k
374+ def kprobeColor(self, name):
375+ if name not in self.kprobes or 'color' not in self.kprobes[name]:
376+ return ''
377+ return self.kprobes[name]['color']
378+ def kprobeDisplayName(self, name, dataraw):
379+ if name not in self.kprobes:
380+ self.basicKprobe(name)
381+ data = ''
382+ quote=0
383+ # first remvoe any spaces inside quotes, and the quotes
384+ for c in dataraw:
385+ if c == '"':
386+ quote = (quote + 1) % 2
387+ if quote and c == ' ':
388+ data += '_'
389+ elif c != '"':
390+ data += c
391+ fmt, args = self.kprobes[name]['format'], self.kprobes[name]['args']
392+ arglist = dict()
393+ # now process the args
394+ for arg in sorted(args):
395+ arglist[arg] = ''
396+ m = re.match('.* '+arg+'=(?P<arg>.*) ', data);
397+ if m:
398+ arglist[arg] = m.group('arg')
399+ else:
400+ m = re.match('.* '+arg+'=(?P<arg>.*)', data);
401+ if m:
402+ arglist[arg] = m.group('arg')
403+ out = fmt.format(**arglist)
404+ out = out.replace(' ', '_').replace('"', '')
405+ return out
406+ def kprobeText(self, kprobe):
407+ name, fmt, func, args = kprobe['name'], kprobe['format'], kprobe['func'], kprobe['args']
408+ if re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', func):
409+ doError('Kprobe "%s" has format info in the function name "%s"' % (name, func), False)
410+ for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', fmt):
411+ if arg not in args:
412+ doError('Kprobe "%s" is missing argument "%s"' % (name, arg), False)
413+ val = 'p:%s_cal %s' % (name, func)
414+ for i in sorted(args):
415+ val += ' %s=%s' % (i, args[i])
416+ val += '\nr:%s_ret %s $retval\n' % (name, func)
417+ return val
418+ def addKprobes(self):
419+ # first test each kprobe
420+ print('INITIALIZING KPROBES...')
421+ rejects = []
422+ for name in sorted(self.kprobes):
423+ if not self.testKprobe(self.kprobes[name]):
424+ rejects.append(name)
425+ # remove all failed ones from the list
426+ for name in rejects:
427+ vprint('Skipping KPROBE: %s' % name)
428+ self.kprobes.pop(name)
429+ self.fsetVal('', 'kprobe_events')
430+ kprobeevents = ''
431+ # set the kprobes all at once
432+ for kp in self.kprobes:
433+ val = self.kprobeText(self.kprobes[kp])
434+ vprint('Adding KPROBE: %s\n%s' % (kp, val.strip()))
435+ kprobeevents += self.kprobeText(self.kprobes[kp])
436+ self.fsetVal(kprobeevents, 'kprobe_events')
437+ # verify that the kprobes were set as ordered
438+ check = self.fgetVal('kprobe_events')
439+ linesout = len(kprobeevents.split('\n'))
440+ linesack = len(check.split('\n'))
441+ if linesack < linesout:
442+ # if not, try appending the kprobes 1 by 1
443+ for kp in self.kprobes:
444+ kprobeevents = self.kprobeText(self.kprobes[kp])
445+ self.fsetVal(kprobeevents, 'kprobe_events', 'a')
446+ self.fsetVal('1', 'events/kprobes/enable')
447+ def testKprobe(self, kprobe):
448+ kprobeevents = self.kprobeText(kprobe)
449+ if not kprobeevents:
450+ return False
451+ try:
452+ self.fsetVal(kprobeevents, 'kprobe_events')
453+ check = self.fgetVal('kprobe_events')
454+ except:
455+ return False
456+ linesout = len(kprobeevents.split('\n'))
457+ linesack = len(check.split('\n'))
458+ if linesack < linesout:
459+ return False
460+ return True
461+ def fsetVal(self, val, path, mode='w'):
462+ file = self.tpath+path
463+ if not os.path.exists(file):
464+ return False
465+ try:
466+ fp = open(file, mode)
467+ fp.write(val)
468+ fp.close()
469+ except:
470+ pass
471+ return True
472+ def fgetVal(self, path):
473+ file = self.tpath+path
474+ res = ''
475+ if not os.path.exists(file):
476+ return res
477+ try:
478+ fp = open(file, 'r')
479+ res = fp.read()
480+ fp.close()
481+ except:
482+ pass
483+ return res
484+ def cleanupFtrace(self):
485+ if(self.usecallgraph or self.usetraceevents):
486+ self.fsetVal('0', 'events/kprobes/enable')
487+ self.fsetVal('', 'kprobe_events')
488+ def setupAllKprobes(self):
489+ for name in self.tracefuncs:
490+ self.defaultKprobe(name, self.tracefuncs[name])
491+ for name in self.dev_tracefuncs:
492+ self.defaultKprobe(name, self.dev_tracefuncs[name])
493+ def isCallgraphFunc(self, name):
494+ if len(self.debugfuncs) < 1 and self.suspendmode == 'command':
495+ return True
496+ if name in self.debugfuncs:
497+ return True
498+ funclist = []
499+ for i in self.tracefuncs:
500+ if 'func' in self.tracefuncs[i]:
501+ funclist.append(self.tracefuncs[i]['func'])
502+ else:
503+ funclist.append(i)
504+ if name in funclist:
505+ return True
506+ return False
507+ def initFtrace(self, testing=False):
508+ tp = self.tpath
509+ print('INITIALIZING FTRACE...')
510+ # turn trace off
511+ self.fsetVal('0', 'tracing_on')
512+ self.cleanupFtrace()
513+ # set the trace clock to global
514+ self.fsetVal('global', 'trace_clock')
515+ # set trace buffer to a huge value
516+ self.fsetVal('nop', 'current_tracer')
517+ self.fsetVal('100000', 'buffer_size_kb')
518+ # go no further if this is just a status check
519+ if testing:
520+ return
521+ if self.usekprobes:
522+ # add tracefunc kprobes so long as were not using full callgraph
523+ if(not self.usecallgraph or len(self.debugfuncs) > 0):
524+ for name in self.tracefuncs:
525+ self.defaultKprobe(name, self.tracefuncs[name])
526+ if self.usedevsrc:
527+ for name in self.dev_tracefuncs:
528+ self.defaultKprobe(name, self.dev_tracefuncs[name])
529+ else:
530+ self.usedevsrc = False
531+ self.addKprobes()
532+ # initialize the callgraph trace, unless this is an x2 run
533+ if(self.usecallgraph):
534+ # set trace type
535+ self.fsetVal('function_graph', 'current_tracer')
536+ self.fsetVal('', 'set_ftrace_filter')
537+ # set trace format options
538+ self.fsetVal('print-parent', 'trace_options')
539+ self.fsetVal('funcgraph-abstime', 'trace_options')
540+ self.fsetVal('funcgraph-cpu', 'trace_options')
541+ self.fsetVal('funcgraph-duration', 'trace_options')
542+ self.fsetVal('funcgraph-proc', 'trace_options')
543+ self.fsetVal('funcgraph-tail', 'trace_options')
544+ self.fsetVal('nofuncgraph-overhead', 'trace_options')
545+ self.fsetVal('context-info', 'trace_options')
546+ self.fsetVal('graph-time', 'trace_options')
547+ self.fsetVal('0', 'max_graph_depth')
548+ if len(self.debugfuncs) > 0:
549+ self.setFtraceFilterFunctions(self.debugfuncs)
550+ elif self.suspendmode == 'command':
551+ self.fsetVal('', 'set_graph_function')
552+ else:
553+ cf = ['dpm_run_callback']
554+ if(self.usetraceeventsonly):
555+ cf += ['dpm_prepare', 'dpm_complete']
556+ for fn in self.tracefuncs:
557+ if 'func' in self.tracefuncs[fn]:
558+ cf.append(self.tracefuncs[fn]['func'])
559+ else:
560+ cf.append(fn)
561+ self.setFtraceFilterFunctions(cf)
562+ if(self.usetraceevents):
563+ # turn trace events on
564+ events = iter(self.traceevents)
565+ for e in events:
566+ self.fsetVal('1', 'events/power/'+e+'/enable')
567+ # clear the trace buffer
568+ self.fsetVal('', 'trace')
569+ def verifyFtrace(self):
570+ # files needed for any trace data
571+ files = ['buffer_size_kb', 'current_tracer', 'trace', 'trace_clock',
572+ 'trace_marker', 'trace_options', 'tracing_on']
573+ # files needed for callgraph trace data
574+ tp = self.tpath
575+ if(self.usecallgraph):
576+ files += [
577+ 'available_filter_functions',
578+ 'set_ftrace_filter',
579+ 'set_graph_function'
580+ ]
581+ for f in files:
582+ if(os.path.exists(tp+f) == False):
583+ return False
584+ return True
585+ def verifyKprobes(self):
586+ # files needed for kprobes to work
587+ files = ['kprobe_events', 'events']
588+ tp = self.tpath
589+ for f in files:
590+ if(os.path.exists(tp+f) == False):
591+ return False
592+ return True
593+ def colorText(self, str):
594+ if not self.ansi:
595+ return str
596+ return '\x1B[31;40m'+str+'\x1B[m'
175597
176598 sysvals = SystemValues()
177599
600+# Class: DevProps
601+# Description:
602+# Simple class which holds property values collected
603+# for all the devices used in the timeline.
604+class DevProps:
605+ syspath = ''
606+ altname = ''
607+ async = True
608+ xtraclass = ''
609+ xtrainfo = ''
610+ def out(self, dev):
611+ return '%s,%s,%d;' % (dev, self.altname, self.async)
612+ def debug(self, dev):
613+ print '%s:\n\taltname = %s\n\t async = %s' % (dev, self.altname, self.async)
614+ def altName(self, dev):
615+ if not self.altname or self.altname == dev:
616+ return dev
617+ return '%s [%s]' % (self.altname, dev)
618+ def xtraClass(self):
619+ if self.xtraclass:
620+ return ' '+self.xtraclass
621+ if not self.async:
622+ return ' sync'
623+ return ''
624+ def xtraInfo(self):
625+ if self.xtraclass:
626+ return ' '+self.xtraclass
627+ if self.async:
628+ return ' async'
629+ return ' sync'
630+
178631 # Class: DeviceNode
179632 # Description:
180633 # A container used to create a device hierachy, with a single root node
@@ -228,6 +681,7 @@ class Data: · 47 unmodified lines
228681 html_device_id = 0
229682 stamp = 0
230683 outfile = ''
684+ dev_ubiquitous = ['msleep', 'udelay']
231685 def __init__(self, num):
232686 idchar = 'abcdefghijklmnopqrstuvwxyz'
233687 self.testnumber = num
@@ -257,6 +711,9 @@ class Data: · 23 unmodified lines
257711 'row': 0, 'color': '#FFFFCC', 'order': 9}
258712 }
259713 self.phases = self.sortedPhases()
714+ self.devicegroups = []
715+ for phase in self.phases:
716+ self.devicegroups.append([phase])
260717 def getStart(self):
261718 return self.dmesg[self.phases[0]]['start']
262719 def setStart(self, time):
@@ -273,51 +730,61 @@ class Data: · 10 unmodified lines
273730 for dev in list:
274731 d = list[dev]
275732 if(d['pid'] == pid and time >= d['start'] and
276− time <= d['end']):
733+ time < d['end']):
277734 return False
278735 return True
279− def addIntraDevTraceEvent(self, action, name, pid, time):
280− if(action == 'mutex_lock_try'):
281− color = 'red'
282− elif(action == 'mutex_lock_pass'):
283− color = 'green'
284− elif(action == 'mutex_unlock'):
285− color = 'blue'
286− else:
287− # create separate colors based on the name
288− v1 = len(name)*10 % 256
289− v2 = string.count(name, 'e')*100 % 256
290− v3 = ord(name[0])*20 % 256
291− color = '#%06X' % ((v1*0x10000) + (v2*0x100) + v3)
292− for phase in self.phases:
736+ def targetDevice(self, phaselist, start, end, pid=-1):
737+ tgtdev = ''
738+ for phase in phaselist:
293739 list = self.dmesg[phase]['list']
294− for dev in list:
295− d = list[dev]
296− if(d['pid'] == pid and time >= d['start'] and
297− time <= d['end']):
298− e = TraceEvent(action, name, color, time)
299− if('traceevents' not in d):
300− d['traceevents'] = []
301− d['traceevents'].append(e)
302− return d
303− break
304− return 0
305− def capIntraDevTraceEvent(self, action, name, pid, time):
306− for phase in self.phases:
307− list = self.dmesg[phase]['list']
308− for dev in list:
309− d = list[dev]
310− if(d['pid'] == pid and time >= d['start'] and
311− time <= d['end']):
312− if('traceevents' not in d):
313− return
314− for e in d['traceevents']:
315− if(e.action == action and
316− e.name == name and not e.ready):
317− e.length = time - e.time
318− e.ready = True
319− break
320− return
740+ for devname in list:
741+ dev = list[devname]
742+ if(pid >= 0 and dev['pid'] != pid):
743+ continue
744+ devS = dev['start']
745+ devE = dev['end']
746+ if(start < devS or start >= devE or end <= devS or end > devE):
747+ continue
748+ tgtdev = dev
749+ break
750+ return tgtdev
751+ def addDeviceFunctionCall(self, displayname, kprobename, proc, pid, start, end, cdata, rdata):
752+ machstart = self.dmesg['suspend_machine']['start']
753+ machend = self.dmesg['resume_machine']['end']
754+ tgtdev = self.targetDevice(self.phases, start, end, pid)
755+ if not tgtdev and start >= machstart and end < machend:
756+ # device calls in machine phases should be serial
757+ tgtdev = self.targetDevice(['suspend_machine', 'resume_machine'], start, end)
758+ if not tgtdev:
759+ if 'scsi_eh' in proc:
760+ self.newActionGlobal(proc, start, end, pid)
761+ self.addDeviceFunctionCall(displayname, kprobename, proc, pid, start, end, cdata, rdata)
762+ else:
763+ vprint('IGNORE: %s[%s](%d) [%f - %f] | %s | %s | %s' % (displayname, kprobename,
764+ pid, start, end, cdata, rdata, proc))
765+ return False
766+ # detail block fits within tgtdev
767+ if('src' not in tgtdev):
768+ tgtdev['src'] = []
769+ title = cdata+' '+rdata
770+ mstr = '\(.*\) *(?P<args>.*) *\((?P<caller>.*)\+.* arg1=(?P<ret>.*)'
771+ m = re.match(mstr, title)
772+ if m:
773+ c = m.group('caller')
774+ a = m.group('args').strip()
775+ r = m.group('ret')
776+ if len(r) > 6:
777+ r = ''
778+ else:
779+ r = 'ret=%s ' % r
780+ l = '%0.3fms' % ((end - start) * 1000)
781+ if kprobename in self.dev_ubiquitous:
782+ title = '%s(%s) <- %s, %s(%s)' % (displayname, a, c, r, l)
783+ else:
784+ title = '%s(%s) %s(%s)' % (displayname, a, r, l)
785+ e = TraceEvent(title, kprobename, start, end - start)
786+ tgtdev['src'].append(e)
787+ return True
321788 def trimTimeVal(self, t, t0, dT, left):
322789 if left:
323790 if(t > t0):
@@ -353,11 +820,11 @@ class Data: · 29 unmodified lines
353820 cg.end = self.trimTimeVal(cg.end, t0, dT, left)
354821 for line in cg.list:
355822 line.time = self.trimTimeVal(line.time, t0, dT, left)
356− if('traceevents' in d):
357− for e in d['traceevents']:
823+ if('src' in d):
824+ for e in d['src']:
358825 e.time = self.trimTimeVal(e.time, t0, dT, left)
359826 def normalizeTime(self, tZero):
360− # first trim out any standby or freeze clock time
827+ # trim out any standby or freeze clock time
361828 if(self.tSuspended != self.tResumed):
362829 if(self.tResumed > tZero):
363830 self.trimTime(self.tSuspended, \
@@ -365,29 +832,6 @@ class Data: · 1 unmodified line
365832 else:
366833 self.trimTime(self.tSuspended, \
367834 self.tResumed-self.tSuspended, False)
368− # shift the timeline so that tZero is the new 0
369− self.tSuspended -= tZero
370− self.tResumed -= tZero
371− self.start -= tZero
372− self.end -= tZero
373− for phase in self.phases:
374− p = self.dmesg[phase]
375− p['start'] -= tZero
376− p['end'] -= tZero
377− list = p['list']
378− for name in list:
379− d = list[name]
380− d['start'] -= tZero
381− d['end'] -= tZero
382− if('ftrace' in d):
383− cg = d['ftrace']
384− cg.start -= tZero
385− cg.end -= tZero
386− for line in cg.list:
387− line.time -= tZero
388− if('traceevents' in d):
389− for e in d['traceevents']:
390− e.time -= tZero
391835 def newPhaseWithSingleAction(self, phasename, devname, start, end, color):
392836 for phase in self.phases:
393837 self.dmesg[phase]['order'] += 1
@@ -417,6 +861,7 @@ class Data: · 23 unmodified lines
417861 {'list': list, 'start': start, 'end': end,
418862 'row': 0, 'color': color, 'order': order}
419863 self.phases = self.sortedPhases()
864+ self.devicegroups.append([phasename])
420865 def setPhase(self, phase, ktime, isbegin):
421866 if(isbegin):
422867 self.dmesg[phase]['start'] = ktime
@@ -442,7 +887,10 @@ class Data: · 19 unmodified lines
442887 for devname in phaselist:
443888 dev = phaselist[devname]
444889 if(dev['end'] < 0):
445− dev['end'] = end
890+ for p in self.phases:
891+ if self.dmesg[p]['end'] > dev['start']:
892+ dev['end'] = self.dmesg[p]['end']
893+ break
446894 vprint('%s (%s): callback didnt return' % (devname, phase))
447895 def deviceFilter(self, devicefilter):
448896 # remove all by the relatives of the filter devnames
@@ -472,22 +920,58 @@ class Data: · 23 unmodified lines
472920 # if any calls never returned, clip them at system resume end
473921 for phase in self.phases:
474922 self.fixupInitcalls(phase, self.getEnd())
475− def newActionGlobal(self, name, start, end):
923+ def isInsideTimeline(self, start, end):
924+ if(self.start <= start and self.end > start):
925+ return True
926+ return False
927+ def phaseOverlap(self, phases):
928+ rmgroups = []
929+ newgroup = []
930+ for group in self.devicegroups:
931+ for phase in phases:
932+ if phase not in group:
933+ continue
934+ for p in group:
935+ if p not in newgroup:
936+ newgroup.append(p)
937+ if group not in rmgroups:
938+ rmgroups.append(group)
939+ for group in rmgroups:
940+ self.devicegroups.remove(group)
941+ self.devicegroups.append(newgroup)
942+ def newActionGlobal(self, name, start, end, pid=-1, color=''):
943+ # if event starts before timeline start, expand timeline
944+ if(start < self.start):
945+ self.setStart(start)
946+ # if event ends after timeline end, expand the timeline
947+ if(end > self.end):
948+ self.setEnd(end)
476949 # which phase is this device callback or action "in"
477950 targetphase = "none"
951+ htmlclass = ''
478952 overlap = 0.0
953+ phases = []
479954 for phase in self.phases:
480955 pstart = self.dmesg[phase]['start']
481956 pend = self.dmesg[phase]['end']
482957 o = max(0, min(end, pend) - max(start, pstart))
483− if(o > overlap):
958+ if o > 0:
959+ phases.append(phase)
960+ if o > overlap:
961+ if overlap > 0 and phase == 'post_resume':
962+ continue
484963 targetphase = phase
485964 overlap = o
965+ if pid == -2:
966+ htmlclass = ' bg'
967+ if len(phases) > 1:
968+ htmlclass = ' bg'
969+ self.phaseOverlap(phases)
486970 if targetphase in self.phases:
487− self.newAction(targetphase, name, -1, '', start, end, '')
488− return True
971+ newname = self.newAction(targetphase, name, pid, '', start, end, '', htmlclass, color)
972+ return (targetphase, newname)
489973 return False
490− def newAction(self, phase, name, pid, parent, start, end, drv):
974+ def newAction(self, phase, name, pid, parent, start, end, drv, htmlclass='', color=''):
491975 # new device callback for a specific phase
492976 self.html_device_id += 1
493977 devid = '%s%d' % (self.idstr, self.html_device_id)
@@ -495,8 +979,19 @@ class Data: · 1 unmodified line
495979 length = -1.0
496980 if(start >= 0 and end >= 0):
497981 length = end - start
982+ if pid == -2:
983+ i = 2
984+ origname = name
985+ while(name in list):
986+ name = '%s[%d]' % (origname, i)
987+ i += 1
498988 list[name] = {'start': start, 'end': end, 'pid': pid, 'par': parent,
499989 'length': length, 'row': 0, 'id': devid, 'drv': drv }
990+ if htmlclass:
991+ list[name]['htmlclass'] = htmlclass
992+ if color:
993+ list[name]['color'] = color
994+ return name
500995 def deviceIDs(self, devlist, phase):
501996 idlist = []
502997 list = self.dmesg[phase]['list']
@@ -536,10 +1031,21 @@ class Data: · 33 unmodified lines
5361031 vprint(' %16s: %f - %f (%d devices)' % (phase, \
5371032 self.dmesg[phase]['start'], self.dmesg[phase]['end'], dc))
5381033 vprint(' test end: %f' % self.end)
1034+ def deviceChildrenAllPhases(self, devname):
1035+ devlist = []
1036+ for phase in self.phases:
1037+ list = self.deviceChildren(devname, phase)
1038+ for dev in list:
1039+ if dev not in devlist:
1040+ devlist.append(dev)
1041+ return devlist
5391042 def masterTopology(self, name, list, depth):
5401043 node = DeviceNode(name, depth)
5411044 for cname in list:
542− clist = self.deviceChildren(cname, 'resume')
1045+ # avoid recursions
1046+ if name == cname:
1047+ continue
1048+ clist = self.deviceChildrenAllPhases(cname)
5431049 cnode = self.masterTopology(cname, clist, depth+1)
5441050 node.children.append(cnode)
5451051 return node
@@ -580,7 +1086,8 @@ class Data: · 34 unmodified lines
5801086 list = self.dmesg[phase]['list']
5811087 for dev in list:
5821088 pdev = list[dev]['par']
583− if(re.match('[0-9]*-[0-9]*\.[0-9]*[\.0-9]*\:[\.0-9]*$', pdev)):
1089+ pid = list[dev]['pid']
1090+ if(pid < 0 or re.match('[0-9]*-[0-9]*\.[0-9]*[\.0-9]*\:[\.0-9]*$', pdev)):
5841091 continue
5851092 if pdev and pdev not in real and pdev not in rootlist:
5861093 rootlist.append(pdev)
@@ -589,22 +1096,33 @@ class Data: · 2 unmodified lines
5891096 rootlist = self.rootDeviceList()
5901097 master = self.masterTopology('', rootlist, 0)
5911098 return self.printTopology(master)
1099+ def selectTimelineDevices(self, widfmt, tTotal, mindevlen):
1100+ # only select devices that will actually show up in html
1101+ self.tdevlist = dict()
1102+ for phase in self.dmesg:
1103+ devlist = []
1104+ list = self.dmesg[phase]['list']
1105+ for dev in list:
1106+ length = (list[dev]['end'] - list[dev]['start']) * 1000
1107+ width = widfmt % (((list[dev]['end']-list[dev]['start'])*100)/tTotal)
1108+ if width != '0.000000' and length >= mindevlen:
1109+ devlist.append(dev)
1110+ self.tdevlist[phase] = devlist
5921111
5931112 # Class: TraceEvent
5941113 # Description:
5951114 # A container for trace event data found in the ftrace file
5961115 class TraceEvent:
597− ready = False
598− name = ''
1116+ text = ''
5991117 time = 0.0
600− color = '#FFFFFF'
6011118 length = 0.0
602− action = ''
603− def __init__(self, a, n, c, t):
604− self.action = a
605− self.name = n
606− self.color = c
1119+ title = ''
1120+ row = 0
1121+ def __init__(self, a, n, t, l):
1122+ self.title = a
1123+ self.text = n
6071124 self.time = t
1125+ self.length = l
6081126
6091127 # Class: FTraceLine
6101128 # Description:
@@ -623,11 +1141,14 @@ class FTraceLine: · 12 unmodified lines
6231141 fcall = False
6241142 freturn = False
6251143 fevent = False
1144+ fkprobe = False
6261145 depth = 0
6271146 name = ''
6281147 type = ''
629− def __init__(self, t, m, d):
1148+ def __init__(self, t, m='', d=''):
6301149 self.time = float(t)
1150+ if not m and not d:
1151+ return
6311152 # is this a trace event
6321153 if(d == 'traceevent' or re.match('^ *\/\* *(?P<msg>.*) \*\/ *$', m)):
6331154 if(d == 'traceevent'):
@@ -644,6 +1165,18 @@ class FTraceLine: · 10 unmodified lines
6441165 self.type = emm.group('call')
6451166 else:
6461167 self.name = msg
1168+ km = re.match('^(?P<n>.*)_cal$', self.type)
1169+ if km:
1170+ self.fcall = True
1171+ self.fkprobe = True
1172+ self.type = km.group('n')
1173+ return
1174+ km = re.match('^(?P<n>.*)_ret$', self.type)
1175+ if km:
1176+ self.freturn = True
1177+ self.fkprobe = True
1178+ self.type = km.group('n')
1179+ return
6471180 self.fevent = True
6481181 return
6491182 # convert the duration to seconds
@@ -662,7 +1195,7 @@ class FTraceLine: · 12 unmodified lines
6621195 # includes comment with function name
6631196 match = re.match('^} *\/\* *(?P<n>.*) *\*\/$', m)
6641197 if(match):
665− self.name = match.group('n')
1198+ self.name = match.group('n').strip()
6661199 # function call
6671200 else:
6681201 self.fcall = True
@@ -670,19 +1203,19 @@ class FTraceLine: · 1 unmodified line
6701203 if(m[-1] == '{'):
6711204 match = re.match('^(?P<n>.*) *\(.*', m)
6721205 if(match):
673− self.name = match.group('n')
1206+ self.name = match.group('n').strip()
6741207 # function call with no children (leaf)
6751208 elif(m[-1] == ';'):
6761209 self.freturn = True
6771210 match = re.match('^(?P<n>.*) *\(.*', m)
6781211 if(match):
679− self.name = match.group('n')
1212+ self.name = match.group('n').strip()
6801213 # something else (possibly a trace marker)
6811214 else:
6821215 self.name = m
6831216 def getDepth(self, str):
6841217 return len(str)/2
685− def debugPrint(self, dev):
1218+ def debugPrint(self, dev=''):
6861219 if(self.freturn and self.fcall):
6871220 print('%s -- %f (%02d): %s(); (%.3f us)' % (dev, self.time, \
6881221 self.depth, self.name, self.length*1000000))
@@ -692,6 +1225,33 @@ class FTraceLine: · 3 unmodified lines
6921225 else:
6931226 print('%s -- %f (%02d): %s() { (%.3f us)' % (dev, self.time, \
6941227 self.depth, self.name, self.length*1000000))
1228+ def startMarker(self):
1229+ global sysvals
1230+ # Is this the starting line of a suspend?
1231+ if not self.fevent:
1232+ return False
1233+ if sysvals.usetracemarkers:
1234+ if(self.name == 'SUSPEND START'):
1235+ return True
1236+ return False
1237+ else:
1238+ if(self.type == 'suspend_resume' and
1239+ re.match('suspend_enter\[.*\] begin', self.name)):
1240+ return True
1241+ return False
1242+ def endMarker(self):
1243+ # Is this the ending line of a resume?
1244+ if not self.fevent:
1245+ return False
1246+ if sysvals.usetracemarkers:
1247+ if(self.name == 'RESUME COMPLETE'):
1248+ return True
1249+ return False
1250+ else:
1251+ if(self.type == 'suspend_resume' and
1252+ re.match('thaw_processes\[.*\] end', self.name)):
1253+ return True
1254+ return False
6951255
6961256 # Class: FTraceCallGraph
6971257 # Description:
@@ -705,54 +1265,124 @@ class FTraceCallGraph: · 7 unmodified lines
7051265 list = []
7061266 invalid = False
7071267 depth = 0
708− def __init__(self):
1268+ pid = 0
1269+ def __init__(self, pid):
7091270 self.start = -1.0
7101271 self.end = -1.0
7111272 self.list = []
7121273 self.depth = 0
713− def setDepth(self, line):
1274+ self.pid = pid
1275+ def addLine(self, line, debug=False):
1276+ # if this is already invalid, just leave
1277+ if(self.invalid):
1278+ return False
1279+ # invalidate on too much data or bad depth
1280+ if(len(self.list) >= 1000000 or self.depth < 0):
1281+ self.invalidate(line)
1282+ return False
1283+ # compare current depth with this lines pre-call depth
1284+ prelinedep = line.depth
1285+ if(line.freturn and not line.fcall):
1286+ prelinedep += 1
1287+ last = 0
1288+ lasttime = line.time
1289+ virtualfname = 'execution_misalignment'
1290+ if len(self.list) > 0:
1291+ last = self.list[-1]
1292+ lasttime = last.time
1293+ # handle low misalignments by inserting returns
1294+ if prelinedep < self.depth:
1295+ if debug and last:
1296+ print '-------- task %d --------' % self.pid
1297+ last.debugPrint()
1298+ idx = 0
1299+ # add return calls to get the depth down
1300+ while prelinedep < self.depth:
1301+ if debug:
1302+ print 'MISALIGN LOW (add returns): C%d - eC%d' % (self.depth, prelinedep)
1303+ self.depth -= 1
1304+ if idx == 0 and last and last.fcall and not last.freturn:
1305+ # special case, turn last call into a leaf
1306+ last.depth = self.depth
1307+ last.freturn = True
1308+ last.length = line.time - last.time
1309+ if debug:
1310+ last.debugPrint()
1311+ else:
1312+ vline = FTraceLine(lasttime)
1313+ vline.depth = self.depth
1314+ vline.name = virtualfname
1315+ vline.freturn = True
1316+ self.list.append(vline)
1317+ if debug:
1318+ vline.debugPrint()
1319+ idx += 1
1320+ if debug:
1321+ line.debugPrint()
1322+ print ''
1323+ # handle high misalignments by inserting calls
1324+ elif prelinedep > self.depth:
1325+ if debug and last:
1326+ print '-------- task %d --------' % self.pid
1327+ last.debugPrint()
1328+ idx = 0
1329+ # add calls to get the depth up
1330+ while prelinedep > self.depth:
1331+ if debug:
1332+ print 'MISALIGN HIGH (add calls): C%d - eC%d' % (self.depth, prelinedep)
1333+ if idx == 0 and line.freturn and not line.fcall:
1334+ # special case, turn this return into a leaf
1335+ line.fcall = True
1336+ prelinedep -= 1
1337+ else:
1338+ vline = FTraceLine(lasttime)
1339+ vline.depth = self.depth
1340+ vline.name = virtualfname
1341+ vline.fcall = True
1342+ if debug:
1343+ vline.debugPrint()
1344+ self.list.append(vline)
1345+ self.depth += 1
1346+ if not last:
1347+ self.start = vline.time
1348+ idx += 1
1349+ if debug:
1350+ line.debugPrint()
1351+ print ''
1352+ # process the call and set the new depth
7141353 if(line.fcall and not line.freturn):
715− line.depth = self.depth
7161354 self.depth += 1
7171355 elif(line.freturn and not line.fcall):
7181356 self.depth -= 1
719− line.depth = self.depth
720− else:
721− line.depth = self.depth
722− def addLine(self, line, match):
723− if(not self.invalid):
724− self.setDepth(line)
1357+ if len(self.list) < 1:
1358+ self.start = line.time
1359+ self.list.append(line)
7251360 if(line.depth == 0 and line.freturn):
7261361 if(self.start < 0):
7271362 self.start = line.time
7281363 self.end = line.time
729− self.list.append(line)
1364+ if line.fcall:
1365+ self.end += line.length
1366+ if self.list[0].name == virtualfname:
1367+ self.invalid = True
7301368 return True
731− if(self.invalid):
732− return False
733− if(len(self.list) >= 1000000 or self.depth < 0):
734− if(len(self.list) > 0):
735− first = self.list[0]
736− self.list = []
737− self.list.append(first)
738− self.invalid = True
739− if(not match):
740− return False
741− id = 'task %s cpu %s' % (match.group('pid'), match.group('cpu'))
742− window = '(%f - %f)' % (self.start, line.time)
743− if(self.depth < 0):
744− print('Too much data for '+id+\
745− ' (buffer overflow), ignoring this callback')
746− else:
747− print('Too much data for '+id+\
748− ' '+window+', ignoring this callback')
749− return False
750− self.list.append(line)
751− if(self.start < 0):
752− self.start = line.time
7531369 return False
1370+ def invalidate(self, line):
1371+ if(len(self.list) > 0):
1372+ first = self.list[0]
1373+ self.list = []
1374+ self.list.append(first)
1375+ self.invalid = True
1376+ id = 'task %s' % (self.pid)
1377+ window = '(%f - %f)' % (self.start, line.time)
1378+ if(self.depth < 0):
1379+ vprint('Too much data for '+id+\
1380+ ' (buffer overflow), ignoring this callback')
1381+ else:
1382+ vprint('Too much data for '+id+\
1383+ ' '+window+', ignoring this callback')
7541384 def slice(self, t0, tN):
755− minicg = FTraceCallGraph()
1385+ minicg = FTraceCallGraph(0)
7561386 count = -1
7571387 firstdepth = 0
7581388 for l in self.list:
@@ -764,13 +1394,26 @@ class FTraceCallGraph: · 5 unmodified lines
7641394 firstdepth = l.depth
7651395 count = 0
7661396 l.depth -= firstdepth
767− minicg.addLine(l, 0)
1397+ minicg.addLine(l)
7681398 if((count == 0 and l.freturn and l.fcall) or
7691399 (count > 0 and l.depth <= 0)):
7701400 break
7711401 count += 1
7721402 return minicg
773− def sanityCheck(self):
1403+ def repair(self, enddepth):
1404+ # bring the depth back to 0 with additional returns
1405+ fixed = False
1406+ last = self.list[-1]
1407+ for i in reversed(range(enddepth)):
1408+ t = FTraceLine(last.time)
1409+ t.depth = i
1410+ t.freturn = True
1411+ fixed = self.addLine(t)
1412+ if fixed:
1413+ self.end = last.time
1414+ return True
1415+ return False
1416+ def postProcess(self, debug=False):
7741417 stack = dict()
7751418 cnt = 0
7761419 for l in self.list:
@@ -779,98 +1422,317 @@ class FTraceCallGraph: · 2 unmodified lines
7791422 cnt += 1
7801423 elif(l.freturn and not l.fcall):
7811424 if(l.depth not in stack):
1425+ if debug:
1426+ print 'Post Process Error: Depth missing'
1427+ l.debugPrint()
7821428 return False
1429+ # transfer total time from return line to call line
7831430 stack[l.depth].length = l.length
784− stack[l.depth] = 0
1431+ stack.pop(l.depth)
7851432 l.length = 0
7861433 cnt -= 1
7871434 if(cnt == 0):
1435+ # trace caught the whole call tree
7881436 return True
789− return False
790− def debugPrint(self, filename):
791− if(filename == 'stdout'):
792− print('[%f - %f]') % (self.start, self.end)
793− for l in self.list:
794− if(l.freturn and l.fcall):
795− print('%f (%02d): %s(); (%.3f us)' % (l.time, \
796− l.depth, l.name, l.length*1000000))
797− elif(l.freturn):
798− print('%f (%02d): %s} (%.3f us)' % (l.time, \
799− l.depth, l.name, l.length*1000000))
800− else:
801− print('%f (%02d): %s() { (%.3f us)' % (l.time, \
802− l.depth, l.name, l.length*1000000))
803− print(' ')
804− else:
805− fp = open(filename, 'w')
806− print(filename)
807− for l in self.list:
808− if(l.freturn and l.fcall):
809− fp.write('%f (%02d): %s(); (%.3f us)\n' % (l.time, \
810− l.depth, l.name, l.length*1000000))
811− elif(l.freturn):
812− fp.write('%f (%02d): %s} (%.3f us)\n' % (l.time, \
813− l.depth, l.name, l.length*1000000))
814− else:
815− fp.write('%f (%02d): %s() { (%.3f us)\n' % (l.time, \
816− l.depth, l.name, l.length*1000000))
817− fp.close()
1437+ elif(cnt < 0):
1438+ if debug:
1439+ print 'Post Process Error: Depth is less than 0'
1440+ return False
1441+ # trace ended before call tree finished
1442+ return self.repair(cnt)
1443+ def deviceMatch(self, pid, data):
1444+ found = False
1445+ # add the callgraph data to the device hierarchy
1446+ borderphase = {
1447+ 'dpm_prepare': 'suspend_prepare',
1448+ 'dpm_complete': 'resume_complete'
1449+ }
1450+ if(self.list[0].name in borderphase):
1451+ p = borderphase[self.list[0].name]
1452+ list = data.dmesg[p]['list']
1453+ for devname in list:
1454+ dev = list[devname]
1455+ if(pid == dev['pid'] and
1456+ self.start <= dev['start'] and
1457+ self.end >= dev['end']):
1458+ dev['ftrace'] = self.slice(dev['start'], dev['end'])
1459+ found = True
1460+ return found
1461+ for p in data.phases:
1462+ if(data.dmesg[p]['start'] <= self.start and
1463+ self.start <= data.dmesg[p]['end']):
1464+ list = data.dmesg[p]['list']
1465+ for devname in list:
1466+ dev = list[devname]
1467+ if(pid == dev['pid'] and
1468+ self.start <= dev['start'] and
1469+ self.end >= dev['end']):
1470+ dev['ftrace'] = self
1471+ found = True
1472+ break
1473+ break
1474+ return found
1475+ def newActionFromFunction(self, data):
1476+ name = self.list[0].name
1477+ if name in ['dpm_run_callback', 'dpm_prepare', 'dpm_complete']:
1478+ return
1479+ fs = self.start
1480+ fe = self.end
1481+ if fs < data.start or fe > data.end:
1482+ return
1483+ phase = ''
1484+ for p in data.phases:
1485+ if(data.dmesg[p]['start'] <= self.start and
1486+ self.start < data.dmesg[p]['end']):
1487+ phase = p
1488+ break
1489+ if not phase:
1490+ return
1491+ out = data.newActionGlobal(name, fs, fe, -2)
1492+ if out:
1493+ phase, myname = out
1494+ data.dmesg[phase]['list'][myname]['ftrace'] = self
1495+ def debugPrint(self):
1496+ print('[%f - %f] %s (%d)') % (self.start, self.end, self.list[0].name, self.pid)
1497+ for l in self.list:
1498+ if(l.freturn and l.fcall):
1499+ print('%f (%02d): %s(); (%.3f us)' % (l.time, \
1500+ l.depth, l.name, l.length*1000000))
1501+ elif(l.freturn):
1502+ print('%f (%02d): %s} (%.3f us)' % (l.time, \
1503+ l.depth, l.name, l.length*1000000))
1504+ else:
1505+ print('%f (%02d): %s() { (%.3f us)' % (l.time, \
1506+ l.depth, l.name, l.length*1000000))
1507+ print(' ')
8181508
8191509 # Class: Timeline
8201510 # Description:
821−# A container for a suspend/resume html timeline. In older versions
822−# of the script there were multiple timelines, but in the latest
823−# there is only one.
1511+# A container for a device timeline which calculates
1512+# all the html properties to display it correctly
8241513 class Timeline:
8251514 html = {}
826− scaleH = 0.0 # height of the row as a percent of the timeline height
827− rowH = 0.0 # height of each row in percent of the timeline height
828− row_height_pixels = 30
829− maxrows = 0
830− height = 0
831− def __init__(self):
1515+ height = 0 # total timeline height
1516+ scaleH = 20 # timescale (top) row height
1517+ rowH = 30 # device row height
1518+ bodyH = 0 # body height
1519+ rows = 0 # total timeline rows
1520+ phases = []
1521+ rowmaxlines = dict()
1522+ rowcount = dict()
1523+ rowheight = dict()
1524+ def __init__(self, rowheight):
1525+ self.rowH = rowheight
8321526 self.html = {
1527+ 'header': '',
8331528 'timeline': '',
8341529 'legend': '',
835− 'scale': ''
8361530 }
837− def setRows(self, rows):
838− self.maxrows = int(rows)
839− self.scaleH = 100.0/float(self.maxrows)
840− self.height = self.maxrows*self.row_height_pixels
841− r = float(self.maxrows - 1)
842− if(r < 1.0):
843− r = 1.0
844− self.rowH = (100.0 - self.scaleH)/r
1531+ # Function: getDeviceRows
1532+ # Description:
1533+ # determine how may rows the device funcs will take
1534+ # Arguments:
1535+ # rawlist: the list of devices/actions for a single phase
1536+ # Output:
1537+ # The total number of rows needed to display this phase of the timeline
1538+ def getDeviceRows(self, rawlist):
1539+ # clear all rows and set them to undefined
1540+ lendict = dict()
1541+ for item in rawlist:
1542+ item.row = -1
1543+ lendict[item] = item.length
1544+ list = []
1545+ for i in sorted(lendict, key=lendict.get, reverse=True):
1546+ list.append(i)
1547+ remaining = len(list)
1548+ rowdata = dict()
1549+ row = 1
1550+ # try to pack each row with as many ranges as possible
1551+ while(remaining > 0):
1552+ if(row not in rowdata):
1553+ rowdata[row] = []
1554+ for i in list:
1555+ if(i.row >= 0):
1556+ continue
1557+ s = i.time
1558+ e = i.time + i.length
1559+ valid = True
1560+ for ritem in rowdata[row]:
1561+ rs = ritem.time
1562+ re = ritem.time + ritem.length
1563+ if(not (((s <= rs) and (e <= rs)) or
1564+ ((s >= re) and (e >= re)))):
1565+ valid = False
1566+ break
1567+ if(valid):
1568+ rowdata[row].append(i)
1569+ i.row = row
1570+ remaining -= 1
1571+ row += 1
1572+ return row
1573+ # Function: getPhaseRows
1574+ # Description:
1575+ # Organize the timeline entries into the smallest
1576+ # number of rows possible, with no entry overlapping
1577+ # Arguments:
1578+ # list: the list of devices/actions for a single phase
1579+ # devlist: string list of device names to use
1580+ # Output:
1581+ # The total number of rows needed to display this phase of the timeline
1582+ def getPhaseRows(self, dmesg, devlist):
1583+ # clear all rows and set them to undefined
1584+ remaining = len(devlist)
1585+ rowdata = dict()
1586+ row = 0
1587+ lendict = dict()
1588+ myphases = []
1589+ for item in devlist:
1590+ if item[0] not in self.phases:
1591+ self.phases.append(item[0])
1592+ if item[0] not in myphases:
1593+ myphases.append(item[0])
1594+ self.rowmaxlines[item[0]] = dict()
1595+ self.rowheight[item[0]] = dict()
1596+ dev = dmesg[item[0]]['list'][item[1]]
1597+ dev['row'] = -1
1598+ lendict[item] = float(dev['end']) - float(dev['start'])
1599+ if 'src' in dev:
1600+ dev['devrows'] = self.getDeviceRows(dev['src'])
1601+ lenlist = []
1602+ for i in sorted(lendict, key=lendict.get, reverse=True):
1603+ lenlist.append(i)
1604+ orderedlist = []
1605+ for item in lenlist:
1606+ dev = dmesg[item[0]]['list'][item[1]]
1607+ if dev['pid'] == -2:
1608+ orderedlist.append(item)
1609+ for item in lenlist:
1610+ if item not in orderedlist:
1611+ orderedlist.append(item)
1612+ # try to pack each row with as many ranges as possible
1613+ while(remaining > 0):
1614+ rowheight = 1
1615+ if(row not in rowdata):
1616+ rowdata[row] = []
1617+ for item in orderedlist:
1618+ dev = dmesg[item[0]]['list'][item[1]]
1619+ if(dev['row'] < 0):
1620+ s = dev['start']
1621+ e = dev['end']
1622+ valid = True
1623+ for ritem in rowdata[row]:
1624+ rs = ritem['start']
1625+ re = ritem['end']
1626+ if(not (((s <= rs) and (e <= rs)) or
1627+ ((s >= re) and (e >= re)))):
1628+ valid = False
1629+ break
1630+ if(valid):
1631+ rowdata[row].append(dev)
1632+ dev['row'] = row
1633+ remaining -= 1
1634+ if 'devrows' in dev and dev['devrows'] > rowheight:
1635+ rowheight = dev['devrows']
1636+ for phase in myphases:
1637+ self.rowmaxlines[phase][row] = rowheight
1638+ self.rowheight[phase][row] = rowheight * self.rowH
1639+ row += 1
1640+ if(row > self.rows):
1641+ self.rows = int(row)
1642+ for phase in myphases:
1643+ self.rowcount[phase] = row
1644+ return row
1645+ def phaseRowHeight(self, phase, row):
1646+ return self.rowheight[phase][row]
1647+ def phaseRowTop(self, phase, row):
1648+ top = 0
1649+ for i in sorted(self.rowheight[phase]):
1650+ if i >= row:
1651+ break
1652+ top += self.rowheight[phase][i]
1653+ return top
1654+ # Function: calcTotalRows
1655+ # Description:
1656+ # Calculate the heights and offsets for the header and rows
1657+ def calcTotalRows(self):
1658+ maxrows = 0
1659+ standardphases = []
1660+ for phase in self.phases:
1661+ total = 0
1662+ for i in sorted(self.rowmaxlines[phase]):
1663+ total += self.rowmaxlines[phase][i]
1664+ if total > maxrows:
1665+ maxrows = total
1666+ if total == self.rowcount[phase]:
1667+ standardphases.append(phase)
1668+ self.height = self.scaleH + (maxrows*self.rowH)
1669+ self.bodyH = self.height - self.scaleH
1670+ for phase in standardphases:
1671+ for i in sorted(self.rowheight[phase]):
1672+ self.rowheight[phase][i] = self.bodyH/self.rowcount[phase]
1673+ # Function: createTimeScale
1674+ # Description:
1675+ # Create the timescale for a timeline block
1676+ # Arguments:
1677+ # m0: start time (mode begin)
1678+ # mMax: end time (mode end)
1679+ # tTotal: total timeline time
1680+ # mode: suspend or resume
1681+ # Output:
1682+ # The html code needed to display the time scale
1683+ def createTimeScale(self, m0, mMax, tTotal, mode):
1684+ timescale = '<div class="t" style="right:{0}%">{1}</div>\n'
1685+ rline = '<div class="t" style="left:0;border-left:1px solid black;border-right:0;">Resume</div>\n'
1686+ output = '<div class="timescale">\n'
1687+ # set scale for timeline
1688+ mTotal = mMax - m0
1689+ tS = 0.1
1690+ if(tTotal <= 0):
1691+ return output+'</div>\n'
1692+ if(tTotal > 4):
1693+ tS = 1
1694+ divTotal = int(mTotal/tS) + 1
1695+ divEdge = (mTotal - tS*(divTotal-1))*100/mTotal
1696+ for i in range(divTotal):
1697+ htmlline = ''
1698+ if(mode == 'resume'):
1699+ pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal))
1700+ val = '%0.fms' % (float(i)*tS*1000)
1701+ htmlline = timescale.format(pos, val)
1702+ if(i == 0):
1703+ htmlline = rline
1704+ else:
1705+ pos = '%0.3f' % (100 - ((float(i)*tS*100)/mTotal) - divEdge)
1706+ val = '%0.fms' % (float(i-divTotal+1)*tS*1000)
1707+ if(i == divTotal - 1):
1708+ val = 'Suspend'
1709+ htmlline = timescale.format(pos, val)
1710+ output += htmlline
1711+ output += '</div>\n'
1712+ return output
8451713
846−# Class: TestRun
1714+# Class: TestProps
8471715 # Description:
848−# A container for a suspend/resume test run. This is necessary as
849−# there could be more than one, and they need to be separate.
850−class TestRun:
1716+# A list of values describing the properties of these test runs
1717+class TestProps:
1718+ stamp = ''
1719+ tracertype = ''
1720+ S0i3 = False
1721+ fwdata = []
8511722 ftrace_line_fmt_fg = \
8521723 '^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\
8531724 ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\
854− '[ +!]*(?P<dur>[0-9\.]*) .*\| (?P<msg>.*)'
1725+ '[ +!#\*@$]*(?P<dur>[0-9\.]*) .*\| (?P<msg>.*)'
8551726 ftrace_line_fmt_nop = \
8561727 ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\[(?P<cpu>[0-9]*)\] *'+\
8571728 '(?P<flags>.{4}) *(?P<time>[0-9\.]*): *'+\
8581729 '(?P<msg>.*)'
8591730 ftrace_line_fmt = ftrace_line_fmt_nop
8601731 cgformat = False
861− ftemp = dict()
862− ttemp = dict()
863− inthepipe = False
864− tracertype = ''
8651732 data = 0
866− def __init__(self, dataobj):
867− self.data = dataobj
868− self.ftemp = dict()
869− self.ttemp = dict()
870− def isReady(self):
871− if(tracertype == '' or not data):
872− return False
873− return True
1733+ ktemp = dict()
1734+ def __init__(self):
1735+ self.ktemp = dict()
8741736 def setTracerType(self, tracer):
8751737 self.tracertype = tracer
8761738 if(tracer == 'function_graph'):
@@ -881,6 +1743,19 @@ class TestRun: · 4 unmodified lines
8811743 else:
8821744 doError('Invalid tracer format: [%s]' % tracer, False)
8831745
1746+# Class: TestRun
1747+# Description:
1748+# A container for a suspend/resume test run. This is necessary as
1749+# there could be more than one, and they need to be separate.
1750+class TestRun:
1751+ ftemp = dict()
1752+ ttemp = dict()
1753+ data = 0
1754+ def __init__(self, dataobj):
1755+ self.data = dataobj
1756+ self.ftemp = dict()
1757+ self.ttemp = dict()
1758+
8841759 # ----------------- FUNCTIONS --------------------
8851760
8861761 # Function: vprint
@@ -893,104 +1768,16 @@ def vprint(msg): · 6 unmodified lines
8931768 if(sysvals.verbose):
8941769 print(msg)
8951770
896−# Function: initFtrace
897−# Description:
898−# Configure ftrace to use trace events and/or a callgraph
899−def initFtrace():
900− global sysvals
901−
902− tp = sysvals.tpath
903− cf = 'dpm_run_callback'
904− if(sysvals.usetraceeventsonly):
905− cf = '-e dpm_prepare -e dpm_complete -e dpm_run_callback'
906− if(sysvals.usecallgraph or sysvals.usetraceevents):
907− print('INITIALIZING FTRACE...')
908− # turn trace off
909− os.system('echo 0 > '+tp+'tracing_on')
910− # set the trace clock to global
911− os.system('echo global > '+tp+'trace_clock')
912− # set trace buffer to a huge value
913− os.system('echo nop > '+tp+'current_tracer')
914− os.system('echo 100000 > '+tp+'buffer_size_kb')
915− # initialize the callgraph trace, unless this is an x2 run
916− if(sysvals.usecallgraph and sysvals.execcount == 1):
917− # set trace type
918− os.system('echo function_graph > '+tp+'current_tracer')
919− os.system('echo "" > '+tp+'set_ftrace_filter')
920− # set trace format options
921− os.system('echo funcgraph-abstime > '+tp+'trace_options')
922− os.system('echo funcgraph-proc > '+tp+'trace_options')
923− # focus only on device suspend and resume
924− os.system('cat '+tp+'available_filter_functions | grep '+\
925− cf+' > '+tp+'set_graph_function')
926− if(sysvals.usetraceevents):
927− # turn trace events on
928− events = iter(sysvals.traceevents)
929− for e in events:
930− os.system('echo 1 > '+sysvals.epath+e+'/enable')
931− # clear the trace buffer
932− os.system('echo "" > '+tp+'trace')
933−
934−# Function: initFtraceAndroid
935−# Description:
936−# Configure ftrace to capture trace events
937−def initFtraceAndroid():
938− global sysvals
939−
940− tp = sysvals.tpath
941− if(sysvals.usetraceevents):
942− print('INITIALIZING FTRACE...')
943− # turn trace off
944− os.system(sysvals.adb+" shell 'echo 0 > "+tp+"tracing_on'")
945− # set the trace clock to global
946− os.system(sysvals.adb+" shell 'echo global > "+tp+"trace_clock'")
947− # set trace buffer to a huge value
948− os.system(sysvals.adb+" shell 'echo nop > "+tp+"current_tracer'")
949− os.system(sysvals.adb+" shell 'echo 10000 > "+tp+"buffer_size_kb'")
950− # turn trace events on
951− events = iter(sysvals.traceevents)
952− for e in events:
953− os.system(sysvals.adb+" shell 'echo 1 > "+\
954− sysvals.epath+e+"/enable'")
955− # clear the trace buffer
956− os.system(sysvals.adb+" shell 'echo \"\" > "+tp+"trace'")
957−
958−# Function: verifyFtrace
959−# Description:
960−# Check that ftrace is working on the system
961−# Output:
962−# True or False
963−def verifyFtrace():
964− global sysvals
965− # files needed for any trace data
966− files = ['buffer_size_kb', 'current_tracer', 'trace', 'trace_clock',
967− 'trace_marker', 'trace_options', 'tracing_on']
968− # files needed for callgraph trace data
969− tp = sysvals.tpath
970− if(sysvals.usecallgraph):
971− files += [
972− 'available_filter_functions',
973− 'set_ftrace_filter',
974− 'set_graph_function'
975− ]
976− for f in files:
977− if(sysvals.android):
978− out = os.popen(sysvals.adb+' shell ls '+tp+f).read().strip()
979− if(out != tp+f):
980− return False
981− else:
982− if(os.path.exists(tp+f) == False):
983− return False
984− return True
985−
9861771 # Function: parseStamp
9871772 # Description:
9881773 # Pull in the stamp comment line from the data file(s),
9891774 # create the stamp, and add it to the global sysvals object
9901775 # Arguments:
9911776 # m: the valid re.match output for the stamp line
992−def parseStamp(m, data):
1777+def parseStamp(line, data):
9931778 global sysvals
1779+
1780+ m = re.match(sysvals.stampfmt, line)
9941781 data.stamp = {'time': '', 'host': '', 'mode': ''}
9951782 dt = datetime(int(m.group('y'))+2000, int(m.group('m')),
9961783 int(m.group('d')), int(m.group('H')), int(m.group('M')),
@@ -999,6 +1786,7 @@ def parseStamp(m, data): · 2 unmodified lines
9991786 data.stamp['host'] = m.group('host')
10001787 data.stamp['mode'] = m.group('mode')
10011788 data.stamp['kernel'] = m.group('kernel')
1789+ sysvals.hostname = data.stamp['host']
10021790 sysvals.suspendmode = data.stamp['mode']
10031791 if not sysvals.stamp:
10041792 sysvals.stamp = data.stamp
@@ -1031,14 +1819,35 @@ def diffStamp(stamp1, stamp2): · 26 unmodified lines
10311819 def doesTraceLogHaveTraceEvents():
10321820 global sysvals
10331821
1822+ # check for kprobes
1823+ sysvals.usekprobes = False
1824+ out = os.system('grep -q "_cal: (" '+sysvals.ftracefile)
1825+ if(out == 0):
1826+ sysvals.usekprobes = True
1827+ # check for callgraph data on trace event blocks
1828+ out = os.system('grep -q "_cpu_down()" '+sysvals.ftracefile)
1829+ if(out == 0):
1830+ sysvals.usekprobes = True
1831+ out = os.popen('head -1 '+sysvals.ftracefile).read().replace('\n', '')
1832+ m = re.match(sysvals.stampfmt, out)
1833+ if m and m.group('mode') == 'command':
1834+ sysvals.usetraceeventsonly = True
1835+ sysvals.usetraceevents = True
1836+ return
1837+ # figure out what level of trace events are supported
10341838 sysvals.usetraceeventsonly = True
10351839 sysvals.usetraceevents = False
10361840 for e in sysvals.traceevents:
1037− out = os.popen('cat '+sysvals.ftracefile+' | grep "'+e+': "').read()
1038− if(not out):
1841+ out = os.system('grep -q "'+e+': " '+sysvals.ftracefile)
1842+ if(out != 0):
10391843 sysvals.usetraceeventsonly = False
1040− if(e == 'suspend_resume' and out):
1844+ if(e == 'suspend_resume' and out == 0):
10411845 sysvals.usetraceevents = True
1846+ # determine is this log is properly formatted
1847+ for e in ['SUSPEND START', 'RESUME COMPLETE']:
1848+ out = os.system('grep -q "'+e+'" '+sysvals.ftracefile)
1849+ if(out != 0):
1850+ sysvals.usetracemarkers = False
10421851
10431852 # Function: appendIncompleteTraceLog
10441853 # Description:
@@ -1055,44 +1864,42 @@ def appendIncompleteTraceLog(testruns): · 10 unmodified lines
10551864
10561865 # create TestRun vessels for ftrace parsing
10571866 testcnt = len(testruns)
1058− testidx = -1
1867+ testidx = 0
10591868 testrun = []
10601869 for data in testruns:
10611870 testrun.append(TestRun(data))
10621871
10631872 # extract the callgraph and traceevent data
10641873 vprint('Analyzing the ftrace data...')
1874+ tp = TestProps()
10651875 tf = open(sysvals.ftracefile, 'r')
1876+ data = 0
10661877 for line in tf:
10671878 # remove any latent carriage returns
10681879 line = line.replace('\r\n', '')
1069− # grab the time stamp first (signifies the start of the test run)
1880+ # grab the time stamp
10701881 m = re.match(sysvals.stampfmt, line)
10711882 if(m):
1072− testidx += 1
1073− parseStamp(m, testrun[testidx].data)
1074− continue
1075− # pull out any firmware data
1076− if(re.match(sysvals.firmwarefmt, line)):
1077− continue
1078− # if we havent found a test time stamp yet keep spinning til we do
1079− if(testidx < 0):
1883+ tp.stamp = line
10801884 continue
10811885 # determine the trace data type (required for further parsing)
10821886 m = re.match(sysvals.tracertypefmt, line)
10831887 if(m):
1084− tracer = m.group('t')
1085− testrun[testidx].setTracerType(tracer)
1888+ tp.setTracerType(m.group('t'))
1889+ continue
1890+ # device properties line
1891+ if(re.match(sysvals.devpropfmt, line)):
1892+ devProps(line)
10861893 continue
1087− # parse only valid lines, if this isnt one move on
1088− m = re.match(testrun[testidx].ftrace_line_fmt, line)
1894+ # parse only valid lines, if this is not one move on
1895+ m = re.match(tp.ftrace_line_fmt, line)
10891896 if(not m):
10901897 continue
10911898 # gather the basic message data from the line
10921899 m_time = m.group('time')
10931900 m_pid = m.group('pid')
10941901 m_msg = m.group('msg')
1095− if(testrun[testidx].cgformat):
1902+ if(tp.cgformat):
10961903 m_param3 = m.group('dur')
10971904 else:
10981905 m_param3 = 'traceevent'
@@ -1104,119 +1911,114 @@ def appendIncompleteTraceLog(testruns): · 5 unmodified lines
11041911 # the line should be a call, return, or event
11051912 if(not t.fcall and not t.freturn and not t.fevent):
11061913 continue
1107− # only parse the ftrace data during suspend/resume
1108− data = testrun[testidx].data
1109− if(not testrun[testidx].inthepipe):
1110− # look for the suspend start marker
1111− if(t.fevent):
1112− if(t.name == 'SUSPEND START'):
1113− testrun[testidx].inthepipe = True
1114− data.setStart(t.time)
1914+ # look for the suspend start marker
1915+ if(t.startMarker()):
1916+ data = testrun[testidx].data
1917+ parseStamp(tp.stamp, data)
1918+ data.setStart(t.time)
1919+ continue
1920+ if(not data):
1921+ continue
1922+ # find the end of resume
1923+ if(t.endMarker()):
1924+ data.setEnd(t.time)
1925+ testidx += 1
1926+ if(testidx >= testcnt):
1927+ break
1928+ continue
1929+ # trace event processing
1930+ if(t.fevent):
1931+ # general trace events have two types, begin and end
1932+ if(re.match('(?P<name>.*) begin$', t.name)):
1933+ isbegin = True
1934+ elif(re.match('(?P<name>.*) end$', t.name)):
1935+ isbegin = False
1936+ else:
11151937 continue
1116− else:
1117− # trace event processing
1118− if(t.fevent):
1119− if(t.name == 'RESUME COMPLETE'):
1120− testrun[testidx].inthepipe = False
1121− data.setEnd(t.time)
1122− if(testidx == testcnt - 1):
1123− break
1124− continue
1125− # general trace events have two types, begin and end
1126− if(re.match('(?P<name>.*) begin$', t.name)):
1127− isbegin = True
1128− elif(re.match('(?P<name>.*) end$', t.name)):
1129− isbegin = False
1938+ m = re.match('(?P<name>.*)\[(?P<val>[0-9]*)\] .*', t.name)
1939+ if(m):
1940+ val = m.group('val')
1941+ if val == '0':
1942+ name = m.group('name')
11301943 else:
1131− continue
1132− m = re.match('(?P<name>.*)\[(?P<val>[0-9]*)\] .*', t.name)
1133− if(m):
1134− val = m.group('val')
1135− if val == '0':
1136− name = m.group('name')
1137− else:
1138− name = m.group('name')+'['+val+']'
1944+ name = m.group('name')+'['+val+']'
1945+ else:
1946+ m = re.match('(?P<name>.*) .*', t.name)
1947+ name = m.group('name')
1948+ # special processing for trace events
1949+ if re.match('dpm_prepare\[.*', name):
1950+ continue
1951+ elif re.match('machine_suspend.*', name):
1952+ continue
1953+ elif re.match('suspend_enter\[.*', name):
1954+ if(not isbegin):
1955+ data.dmesg['suspend_prepare']['end'] = t.time
1956+ continue
1957+ elif re.match('dpm_suspend\[.*', name):
1958+ if(not isbegin):
1959+ data.dmesg['suspend']['end'] = t.time
1960+ continue
1961+ elif re.match('dpm_suspend_late\[.*', name):
1962+ if(isbegin):
1963+ data.dmesg['suspend_late']['start'] = t.time
11391964 else:
1140− m = re.match('(?P<name>.*) .*', t.name)
1141− name = m.group('name')
1142− # special processing for trace events
1143− if re.match('dpm_prepare\[.*', name):
1144− continue
1145− elif re.match('machine_suspend.*', name):
1146− continue
1147− elif re.match('suspend_enter\[.*', name):
1148− if(not isbegin):
1149− data.dmesg['suspend_prepare']['end'] = t.time
1150− continue
1151− elif re.match('dpm_suspend\[.*', name):
1152− if(not isbegin):
1153− data.dmesg['suspend']['end'] = t.time
1154− continue
1155− elif re.match('dpm_suspend_late\[.*', name):
1156− if(isbegin):
1157− data.dmesg['suspend_late']['start'] = t.time
1158− else:
1159− data.dmesg['suspend_late']['end'] = t.time
1160− continue
1161− elif re.match('dpm_suspend_noirq\[.*', name):
1162− if(isbegin):
1163− data.dmesg['suspend_noirq']['start'] = t.time
1164− else:
1165− data.dmesg['suspend_noirq']['end'] = t.time
1166− continue
1167− elif re.match('dpm_resume_noirq\[.*', name):
1168− if(isbegin):
1169− data.dmesg['resume_machine']['end'] = t.time
1170− data.dmesg['resume_noirq']['start'] = t.time
1171− else:
1172− data.dmesg['resume_noirq']['end'] = t.time
1173− continue
1174− elif re.match('dpm_resume_early\[.*', name):
1175− if(isbegin):
1176− data.dmesg['resume_early']['start'] = t.time
1177− else:
1178− data.dmesg['resume_early']['end'] = t.time
1179− continue
1180− elif re.match('dpm_resume\[.*', name):
1181− if(isbegin):
1182− data.dmesg['resume']['start'] = t.time
1183− else:
1184− data.dmesg['resume']['end'] = t.time
1185− continue
1186− elif re.match('dpm_complete\[.*', name):
1187− if(isbegin):
1188− data.dmesg['resume_complete']['start'] = t.time
1189− else:
1190− data.dmesg['resume_complete']['end'] = t.time
1191− continue
1192− # is this trace event outside of the devices calls
1193− if(data.isTraceEventOutsideDeviceCalls(pid, t.time)):
1194− # global events (outside device calls) are simply graphed
1195− if(isbegin):
1196− # store each trace event in ttemp
1197− if(name not in testrun[testidx].ttemp):
1198− testrun[testidx].ttemp[name] = []
1199− testrun[testidx].ttemp[name].append(\
1200− {'begin': t.time, 'end': t.time})
1201− else:
1202− # finish off matching trace event in ttemp
1203− if(name in testrun[testidx].ttemp):
1204− testrun[testidx].ttemp[name][-1]['end'] = t.time
1965+ data.dmesg['suspend_late']['end'] = t.time
1966+ continue
1967+ elif re.match('dpm_suspend_noirq\[.*', name):
1968+ if(isbegin):
1969+ data.dmesg['suspend_noirq']['start'] = t.time
12051970 else:
1206− if(isbegin):
1207− data.addIntraDevTraceEvent('', name, pid, t.time)
1208− else:
1209− data.capIntraDevTraceEvent('', name, pid, t.time)
1210− # call/return processing
1211− elif sysvals.usecallgraph:
1212− # create a callgraph object for the data
1213− if(pid not in testrun[testidx].ftemp):
1214− testrun[testidx].ftemp[pid] = []
1215− testrun[testidx].ftemp[pid].append(FTraceCallGraph())
1216− # when the call is finished, see which device matches it
1217− cg = testrun[testidx].ftemp[pid][-1]
1218− if(cg.addLine(t, m)):
1219− testrun[testidx].ftemp[pid].append(FTraceCallGraph())
1971+ data.dmesg['suspend_noirq']['end'] = t.time
1972+ continue
1973+ elif re.match('dpm_resume_noirq\[.*', name):
1974+ if(isbegin):
1975+ data.dmesg['resume_machine']['end'] = t.time
1976+ data.dmesg['resume_noirq']['start'] = t.time
1977+ else:
1978+ data.dmesg['resume_noirq']['end'] = t.time
1979+ continue
1980+ elif re.match('dpm_resume_early\[.*', name):
1981+ if(isbegin):
1982+ data.dmesg['resume_early']['start'] = t.time
1983+ else:
1984+ data.dmesg['resume_early']['end'] = t.time
1985+ continue
1986+ elif re.match('dpm_resume\[.*', name):
1987+ if(isbegin):
1988+ data.dmesg['resume']['start'] = t.time
1989+ else:
1990+ data.dmesg['resume']['end'] = t.time
1991+ continue
1992+ elif re.match('dpm_complete\[.*', name):
1993+ if(isbegin):
1994+ data.dmesg['resume_complete']['start'] = t.time
1995+ else:
1996+ data.dmesg['resume_complete']['end'] = t.time
1997+ continue
1998+ # skip trace events inside devices calls
1999+ if(not data.isTraceEventOutsideDeviceCalls(pid, t.time)):
2000+ continue
2001+ # global events (outside device calls) are simply graphed
2002+ if(isbegin):
2003+ # store each trace event in ttemp
2004+ if(name not in testrun[testidx].ttemp):
2005+ testrun[testidx].ttemp[name] = []
2006+ testrun[testidx].ttemp[name].append(\
2007+ {'begin': t.time, 'end': t.time})
2008+ else:
2009+ # finish off matching trace event in ttemp
2010+ if(name in testrun[testidx].ttemp):
2011+ testrun[testidx].ttemp[name][-1]['end'] = t.time
2012+ # call/return processing
2013+ elif sysvals.usecallgraph:
2014+ # create a callgraph object for the data
2015+ if(pid not in testrun[testidx].ftemp):
2016+ testrun[testidx].ftemp[pid] = []
2017+ testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid))
2018+ # when the call is finished, see which device matches it
2019+ cg = testrun[testidx].ftemp[pid][-1]
2020+ if(cg.addLine(t)):
2021+ testrun[testidx].ftemp[pid].append(FTraceCallGraph(pid))
12202022 tf.close()
12212023
12222024 for test in testrun:
@@ -1224,20 +2026,14 @@ def appendIncompleteTraceLog(testruns): · 1 unmodified line
12242026 if(sysvals.usetraceevents):
12252027 for name in test.ttemp:
12262028 for event in test.ttemp[name]:
1227− begin = event['begin']
1228− end = event['end']
1229− # if event starts before timeline start, expand timeline
1230− if(begin < test.data.start):
1231− test.data.setStart(begin)
1232− # if event ends after timeline end, expand the timeline
1233− if(end > test.data.end):
1234− test.data.setEnd(end)
1235− test.data.newActionGlobal(name, begin, end)
2029+ test.data.newActionGlobal(name, event['begin'], event['end'])
12362030
12372031 # add the callgraph data to the device hierarchy
12382032 for pid in test.ftemp:
12392033 for cg in test.ftemp[pid]:
1240− if(not cg.sanityCheck()):
2034+ if len(cg.list) < 1 or cg.invalid:
2035+ continue
2036+ if(not cg.postProcess()):
12412037 id = 'task %s cpu %s' % (pid, m.group('cpu'))
12422038 vprint('Sanity check failed for '+\
12432039 id+', ignoring this callback')
@@ -1259,14 +2055,6 @@ def appendIncompleteTraceLog(testruns): · 15 unmodified lines
12592055 if(sysvals.verbose):
12602056 test.data.printDetails()
12612057
1262−
1263− # add the time in between the tests as a new phase so we can see it
1264− if(len(testruns) > 1):
1265− t1e = testruns[0].getEnd()
1266− t2s = testruns[-1].getStart()
1267− testruns[-1].newPhaseWithSingleAction('user mode', \
1268− 'user mode', t1e, t2s, '#FF9966')
1269−
12702058 # Function: parseTraceLog
12712059 # Description:
12722060 # Analyze an ftrace log output file generated from this app during
@@ -1280,9 +2068,16 @@ def parseTraceLog(): · 7 unmodified lines
12802068
12812069 vprint('Analyzing the ftrace data...')
12822070 if(os.path.exists(sysvals.ftracefile) == False):
1283− doError('%s doesnt exist' % sysvals.ftracefile, False)
2071+ doError('%s does not exist' % sysvals.ftracefile, False)
2072+
2073+ sysvals.setupAllKprobes()
2074+ tracewatch = ['suspend_enter']
2075+ if sysvals.usekprobes:
2076+ tracewatch += ['sync_filesystems', 'freeze_processes', 'syscore_suspend',
2077+ 'syscore_resume', 'resume_console', 'thaw_processes', 'CPU_ON', 'CPU_OFF']
12842078
12852079 # extract the callgraph and traceevent data
2080+ tp = TestProps()
12862081 testruns = []
12872082 testdata = []
12882083 testrun = 0
@@ -1295,27 +2090,17 @@ def parseTraceLog(): · 6 unmodified lines
12952090 # stamp line: each stamp means a new test run
12962091 m = re.match(sysvals.stampfmt, line)
12972092 if(m):
1298− data = Data(len(testdata))
1299− testdata.append(data)
1300− testrun = TestRun(data)
1301− testruns.append(testrun)
1302− parseStamp(m, data)
1303− continue
1304− if(not data):
2093+ tp.stamp = line
13052094 continue
13062095 # firmware line: pull out any firmware data
13072096 m = re.match(sysvals.firmwarefmt, line)
13082097 if(m):
1309− data.fwSuspend = int(m.group('s'))
1310− data.fwResume = int(m.group('r'))
1311− if(data.fwSuspend > 0 or data.fwResume > 0):
1312− data.fwValid = True
2098+ tp.fwdata.append((int(m.group('s')), int(m.group('r'))))
13132099 continue
13142100 # tracer type line: determine the trace data type
13152101 m = re.match(sysvals.tracertypefmt, line)
13162102 if(m):
1317− tracer = m.group('t')
1318− testrun.setTracerType(tracer)
2103+ tp.setTracerType(m.group('t'))
13192104 continue
13202105 # post resume time line: did this test run include post-resume data
13212106 m = re.match(sysvals.postresumefmt, line)
@@ -1324,15 +2109,20 @@ def parseTraceLog(): · 2 unmodified lines
13242109 if(t > 0):
13252110 sysvals.postresumetime = t
13262111 continue
2112+ # device properties line
2113+ if(re.match(sysvals.devpropfmt, line)):
2114+ devProps(line)
2115+ continue
13272116 # ftrace line: parse only valid lines
1328− m = re.match(testrun.ftrace_line_fmt, line)
2117+ m = re.match(tp.ftrace_line_fmt, line)
13292118 if(not m):
13302119 continue
13312120 # gather the basic message data from the line
13322121 m_time = m.group('time')
2122+ m_proc = m.group('proc')
13332123 m_pid = m.group('pid')
13342124 m_msg = m.group('msg')
1335− if(testrun.cgformat):
2125+ if(tp.cgformat):
13362126 m_param3 = m.group('dur')
13372127 else:
13382128 m_param3 = 'traceevent'
@@ -1344,24 +2134,38 @@ def parseTraceLog(): · 5 unmodified lines
13442134 # the line should be a call, return, or event
13452135 if(not t.fcall and not t.freturn and not t.fevent):
13462136 continue
1347− # only parse the ftrace data during suspend/resume
1348− if(not testrun.inthepipe):
1349− # look for the suspend start marker
1350− if(t.fevent):
1351− if(t.name == 'SUSPEND START'):
1352− testrun.inthepipe = True
1353− data.setStart(t.time)
2137+ # find the start of suspend
2138+ if(t.startMarker()):
2139+ phase = 'suspend_prepare'
2140+ data = Data(len(testdata))
2141+ testdata.append(data)
2142+ testrun = TestRun(data)
2143+ testruns.append(testrun)
2144+ parseStamp(tp.stamp, data)
2145+ if len(tp.fwdata) > data.testnumber:
2146+ data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber]
2147+ if(data.fwSuspend > 0 or data.fwResume > 0):
2148+ data.fwValid = True
2149+ data.setStart(t.time)
2150+ continue
2151+ if(not data):
2152+ continue
2153+ # find the end of resume
2154+ if(t.endMarker()):
2155+ if(sysvals.usetracemarkers and sysvals.postresumetime > 0):
2156+ phase = 'post_resume'
2157+ data.newPhase(phase, t.time, t.time, '#F0F0F0', -1)
2158+ data.setEnd(t.time)
2159+ if(not sysvals.usetracemarkers):
2160+ # no trace markers? then quit and be sure to finish recording
2161+ # the event we used to trigger resume end
2162+ if(len(testrun.ttemp['thaw_processes']) > 0):
2163+ # if an entry exists, assume this is its end
2164+ testrun.ttemp['thaw_processes'][-1]['end'] = t.time
2165+ break
13542166 continue
13552167 # trace event processing
13562168 if(t.fevent):
1357− if(t.name == 'RESUME COMPLETE'):
1358− if(sysvals.postresumetime > 0):
1359− phase = 'post_resume'
1360− data.newPhase(phase, t.time, t.time, '#FF9966', -1)
1361− else:
1362− testrun.inthepipe = False
1363− data.setEnd(t.time)
1364− continue
13652169 if(phase == 'post_resume'):
13662170 data.setEnd(t.time)
13672171 if(t.type == 'suspend_resume'):
@@ -1383,8 +2187,7 @@ def parseTraceLog(): · 15 unmodified lines
13832187 m = re.match('(?P<name>.*) .*', t.name)
13842188 name = m.group('name')
13852189 # ignore these events
1386− if(re.match('acpi_suspend\[.*', t.name) or
1387− re.match('suspend_enter\[.*', name)):
2190+ if(name.split('[')[0] in tracewatch):
13882191 continue
13892192 # -- phase changes --
13902193 # suspend_prepare start
@@ -1418,7 +2221,7 @@ def parseTraceLog(): · 27 unmodified lines
14182221 data.dmesg[phase]['end'] = t.time
14192222 data.tSuspended = t.time
14202223 else:
1421− if(sysvals.suspendmode in ['mem', 'disk']):
2224+ if(sysvals.suspendmode in ['mem', 'disk'] and not tp.S0i3):
14222225 data.dmesg['suspend_machine']['end'] = t.time
14232226 data.tSuspended = t.time
14242227 phase = 'resume_machine'
@@ -1426,6 +2229,15 @@ def parseTraceLog(): · 1 unmodified line
14262229 data.tResumed = t.time
14272230 data.tLow = data.tResumed - data.tSuspended
14282231 continue
2232+ # acpi_suspend
2233+ elif(re.match('acpi_suspend\[.*', t.name)):
2234+ # acpi_suspend[0] S0i3
2235+ if(re.match('acpi_suspend\[0\] begin', t.name)):
2236+ if(sysvals.suspendmode == 'mem'):
2237+ tp.S0i3 = True
2238+ data.dmesg['suspend_machine']['end'] = t.time
2239+ data.tSuspended = t.time
2240+ continue
14292241 # resume_noirq start
14302242 elif(re.match('dpm_resume_noirq\[.*', t.name)):
14312243 phase = 'resume_noirq'
@@ -1449,30 +2261,25 @@ def parseTraceLog(): · 17 unmodified lines
14492261 if(isbegin):
14502262 data.dmesg[phase]['start'] = t.time
14512263 continue
1452−
1453− # is this trace event outside of the devices calls
1454− if(data.isTraceEventOutsideDeviceCalls(pid, t.time)):
1455− # global events (outside device calls) are simply graphed
1456− if(name not in testrun.ttemp):
1457− testrun.ttemp[name] = []
1458− if(isbegin):
1459− # create a new list entry
1460− testrun.ttemp[name].append(\
1461− {'begin': t.time, 'end': t.time})
1462− else:
1463− if(len(testrun.ttemp[name]) > 0):
1464− # if an antry exists, assume this is its end
1465− testrun.ttemp[name][-1]['end'] = t.time
1466− elif(phase == 'post_resume'):
1467− # post resume events can just have ends
1468− testrun.ttemp[name].append({
1469− 'begin': data.dmesg[phase]['start'],
1470− 'end': t.time})
2264+ # skip trace events inside devices calls
2265+ if(not data.isTraceEventOutsideDeviceCalls(pid, t.time)):
2266+ continue
2267+ # global events (outside device calls) are graphed
2268+ if(name not in testrun.ttemp):
2269+ testrun.ttemp[name] = []
2270+ if(isbegin):
2271+ # create a new list entry
2272+ testrun.ttemp[name].append(\
2273+ {'begin': t.time, 'end': t.time, 'pid': pid})
14712274 else:
1472− if(isbegin):
1473− data.addIntraDevTraceEvent('', name, pid, t.time)
1474− else:
1475− data.capIntraDevTraceEvent('', name, pid, t.time)
2275+ if(len(testrun.ttemp[name]) > 0):
2276+ # if an entry exists, assume this is its end
2277+ testrun.ttemp[name][-1]['end'] = t.time
2278+ elif(phase == 'post_resume'):
2279+ # post resume events can just have ends
2280+ testrun.ttemp[name].append({
2281+ 'begin': data.dmesg[phase]['start'],
2282+ 'end': t.time})
14762283 # device callback start
14772284 elif(t.type == 'device_pm_callback_start'):
14782285 m = re.match('(?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*',\
@@ -1495,75 +2302,127 @@ def parseTraceLog(): · 16 unmodified lines
14952302 dev = list[n]
14962303 dev['length'] = t.time - dev['start']
14972304 dev['end'] = t.time
2305+ # kprobe event processing
2306+ elif(t.fkprobe):
2307+ kprobename = t.type
2308+ kprobedata = t.name
2309+ key = (kprobename, pid)
2310+ # displayname is generated from kprobe data
2311+ displayname = ''
2312+ if(t.fcall):
2313+ displayname = sysvals.kprobeDisplayName(kprobename, kprobedata)
2314+ if not displayname:
2315+ continue
2316+ if(key not in tp.ktemp):
2317+ tp.ktemp[key] = []
2318+ tp.ktemp[key].append({
2319+ 'pid': pid,
2320+ 'begin': t.time,
2321+ 'end': t.time,
2322+ 'name': displayname,
2323+ 'cdata': kprobedata,
2324+ 'proc': m_proc,
2325+ })
2326+ elif(t.freturn):
2327+ if(key not in tp.ktemp) or len(tp.ktemp[key]) < 1:
2328+ continue
2329+ e = tp.ktemp[key][-1]
2330+ if e['begin'] < 0.0 or t.time - e['begin'] < 0.000001:
2331+ tp.ktemp[key].pop()
2332+ else:
2333+ e['end'] = t.time
2334+ e['rdata'] = kprobedata
14982335 # callgraph processing
14992336 elif sysvals.usecallgraph:
1500− # this shouldn't happen, but JIC, ignore callgraph data post-res
1501− if(phase == 'post_resume'):
1502− continue
15032337 # create a callgraph object for the data
1504− if(pid not in testrun.ftemp):
1505− testrun.ftemp[pid] = []
1506− testrun.ftemp[pid].append(FTraceCallGraph())
2338+ key = (m_proc, pid)
2339+ if(key not in testrun.ftemp):
2340+ testrun.ftemp[key] = []
2341+ testrun.ftemp[key].append(FTraceCallGraph(pid))
15072342 # when the call is finished, see which device matches it
1508− cg = testrun.ftemp[pid][-1]
1509− if(cg.addLine(t, m)):
1510− testrun.ftemp[pid].append(FTraceCallGraph())
2343+ cg = testrun.ftemp[key][-1]
2344+ if(cg.addLine(t)):
2345+ testrun.ftemp[key].append(FTraceCallGraph(pid))
15112346 tf.close()
15122347
2348+ if sysvals.suspendmode == 'command':
2349+ for test in testruns:
2350+ for p in test.data.phases:
2351+ if p == 'resume_complete':
2352+ test.data.dmesg[p]['start'] = test.data.start
2353+ test.data.dmesg[p]['end'] = test.data.end
2354+ else:
2355+ test.data.dmesg[p]['start'] = test.data.start
2356+ test.data.dmesg[p]['end'] = test.data.start
2357+ test.data.tSuspended = test.data.start
2358+ test.data.tResumed = test.data.start
2359+ test.data.tLow = 0
2360+ test.data.fwValid = False
2361+
15132362 for test in testruns:
15142363 # add the traceevent data to the device hierarchy
15152364 if(sysvals.usetraceevents):
2365+ # add actual trace funcs
15162366 for name in test.ttemp:
15172367 for event in test.ttemp[name]:
1518− begin = event['begin']
1519− end = event['end']
1520− # if event starts before timeline start, expand timeline
1521− if(begin < test.data.start):
1522− test.data.setStart(begin)
1523− # if event ends after timeline end, expand the timeline
1524− if(end > test.data.end):
1525− test.data.setEnd(end)
1526− test.data.newActionGlobal(name, begin, end)
1527−
1528− # add the callgraph data to the device hierarchy
1529− borderphase = {
1530− 'dpm_prepare': 'suspend_prepare',
1531− 'dpm_complete': 'resume_complete'
1532− }
1533− for pid in test.ftemp:
1534− for cg in test.ftemp[pid]:
1535− if len(cg.list) < 2:
2368+ test.data.newActionGlobal(name, event['begin'], event['end'], event['pid'])
2369+ # add the kprobe based virtual tracefuncs as actual devices
2370+ for key in tp.ktemp:
2371+ name, pid = key
2372+ if name not in sysvals.tracefuncs:
15362373 continue
1537− if(not cg.sanityCheck()):
1538− id = 'task %s cpu %s' % (pid, m.group('cpu'))
1539− vprint('Sanity check failed for '+\
1540− id+', ignoring this callback')
1541− continue
1542− callstart = cg.start
1543− callend = cg.end
1544− if(cg.list[0].name in borderphase):
1545− p = borderphase[cg.list[0].name]
1546− list = test.data.dmesg[p]['list']
1547− for devname in list:
1548− dev = list[devname]
1549− if(pid == dev['pid'] and
1550− callstart <= dev['start'] and
1551− callend >= dev['end']):
1552− dev['ftrace'] = cg.slice(dev['start'], dev['end'])
1553− continue
1554− if(cg.list[0].name != 'dpm_run_callback'):
2374+ for e in tp.ktemp[key]:
2375+ kb, ke = e['begin'], e['end']
2376+ if kb == ke or not test.data.isInsideTimeline(kb, ke):
2377+ continue
2378+ test.data.newActionGlobal(e['name'], kb, ke, pid)
2379+ # add config base kprobes and dev kprobes
2380+ for key in tp.ktemp:
2381+ name, pid = key
2382+ if name in sysvals.tracefuncs:
15552383 continue
1556− for p in test.data.phases:
1557− if(test.data.dmesg[p]['start'] <= callstart and
1558− callstart <= test.data.dmesg[p]['end']):
1559− list = test.data.dmesg[p]['list']
1560− for devname in list:
1561− dev = list[devname]
1562− if(pid == dev['pid'] and
1563− callstart <= dev['start'] and
1564− callend >= dev['end']):
1565− dev['ftrace'] = cg
1566− break
2384+ for e in tp.ktemp[key]:
2385+ kb, ke = e['begin'], e['end']
2386+ if kb == ke or not test.data.isInsideTimeline(kb, ke):
2387+ continue
2388+ color = sysvals.kprobeColor(e['name'])
2389+ if name not in sysvals.dev_tracefuncs:
2390+ # config base kprobe
2391+ test.data.newActionGlobal(e['name'], kb, ke, -2, color)
2392+ elif sysvals.usedevsrc:
2393+ # dev kprobe
2394+ data.addDeviceFunctionCall(e['name'], name, e['proc'], pid, kb,
2395+ ke, e['cdata'], e['rdata'])
2396+ if sysvals.usecallgraph:
2397+ # add the callgraph data to the device hierarchy
2398+ sortlist = dict()
2399+ for key in test.ftemp:
2400+ proc, pid = key
2401+ for cg in test.ftemp[key]:
2402+ if len(cg.list) < 1 or cg.invalid:
2403+ continue
2404+ if(not cg.postProcess()):
2405+ id = 'task %s' % (pid)
2406+ vprint('Sanity check failed for '+\
2407+ id+', ignoring this callback')
2408+ continue
2409+ # match cg data to devices
2410+ if sysvals.suspendmode == 'command' or not cg.deviceMatch(pid, test.data):
2411+ sortkey = '%f%f%d' % (cg.start, cg.end, pid)
2412+ sortlist[sortkey] = cg
2413+ # create blocks for orphan cg data
2414+ for sortkey in sorted(sortlist):
2415+ cg = sortlist[sortkey]
2416+ name = cg.list[0].name
2417+ if sysvals.isCallgraphFunc(name):
2418+ vprint('Callgraph found for task %d: %.3fms, %s' % (cg.pid, (cg.end - cg.start)*1000, name))
2419+ cg.newActionFromFunction(test.data)
2420+
2421+ if sysvals.suspendmode == 'command':
2422+ if(sysvals.verbose):
2423+ for data in testdata:
2424+ data.printDetails()
2425+ return testdata
15672426
15682427 # fill in any missing phases
15692428 for data in testdata:
@@ -1587,14 +2446,52 @@ def parseTraceLog(): · 17 unmodified lines
15872446 if(sysvals.verbose):
15882447 data.printDetails()
15892448
1590− # add the time in between the tests as a new phase so we can see it
1591− if(len(testdata) > 1):
1592− t1e = testdata[0].getEnd()
1593− t2s = testdata[-1].getStart()
1594− testdata[-1].newPhaseWithSingleAction('user mode', \
1595− 'user mode', t1e, t2s, '#FF9966')
15962449 return testdata
15972450
2451+# Function: loadRawKernelLog
2452+# Description:
2453+# Load a raw kernel log that wasn't created by this tool, it might be
2454+# possible to extract a valid suspend/resume log
2455+def loadRawKernelLog(dmesgfile):
2456+ global sysvals
2457+
2458+ stamp = {'time': '', 'host': '', 'mode': 'mem', 'kernel': ''}
2459+ stamp['time'] = datetime.now().strftime('%B %d %Y, %I:%M:%S %p')
2460+ stamp['host'] = sysvals.hostname
2461+
2462+ testruns = []
2463+ data = 0
2464+ lf = open(dmesgfile, 'r')
2465+ for line in lf:
2466+ line = line.replace('\r\n', '')
2467+ idx = line.find('[')
2468+ if idx > 1:
2469+ line = line[idx:]
2470+ m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
2471+ if(not m):
2472+ continue
2473+ msg = m.group("msg")
2474+ m = re.match('PM: Syncing filesystems.*', msg)
2475+ if(m):
2476+ if(data):
2477+ testruns.append(data)
2478+ data = Data(len(testruns))
2479+ data.stamp = stamp
2480+ if(data):
2481+ m = re.match('.* *(?P<k>[0-9]\.[0-9]{2}\.[0-9]-.*) .*', msg)
2482+ if(m):
2483+ stamp['kernel'] = m.group('k')
2484+ m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg)
2485+ if(m):
2486+ stamp['mode'] = m.group('m')
2487+ data.dmesgtext.append(line)
2488+ if(data):
2489+ testruns.append(data)
2490+ sysvals.stamp = stamp
2491+ sysvals.suspendmode = stamp['mode']
2492+ lf.close()
2493+ return testruns
2494+
15982495 # Function: loadKernelLog
15992496 # Description:
16002497 # [deprecated for kernel 3.15.0 or newer]
@@ -1607,9 +2504,10 @@ def loadKernelLog(): · 6 unmodified lines
16072504
16082505 vprint('Analyzing the dmesg data...')
16092506 if(os.path.exists(sysvals.dmesgfile) == False):
1610− doError('%s doesnt exist' % sysvals.dmesgfile, False)
2507+ doError('%s does not exist' % sysvals.dmesgfile, False)
16112508
1612− # there can be multiple test runs in a single file delineated by stamps
2509+ # there can be multiple test runs in a single file
2510+ tp = TestProps()
16132511 testruns = []
16142512 data = 0
16152513 lf = open(sysvals.dmesgfile, 'r')
@@ -1620,35 +2518,43 @@ def loadKernelLog(): · 4 unmodified lines
16202518 line = line[idx:]
16212519 m = re.match(sysvals.stampfmt, line)
16222520 if(m):
1623− if(data):
1624− testruns.append(data)
1625− data = Data(len(testruns))
1626− parseStamp(m, data)
1627− continue
1628− if(not data):
2521+ tp.stamp = line
16292522 continue
16302523 m = re.match(sysvals.firmwarefmt, line)
16312524 if(m):
1632− data.fwSuspend = int(m.group('s'))
1633− data.fwResume = int(m.group('r'))
1634− if(data.fwSuspend > 0 or data.fwResume > 0):
1635− data.fwValid = True
2525+ tp.fwdata.append((int(m.group('s')), int(m.group('r'))))
16362526 continue
16372527 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line)
1638− if(m):
1639− data.dmesgtext.append(line)
1640− if(re.match('ACPI: resume from mwait', m.group('msg'))):
1641− print('NOTE: This suspend appears to be freeze rather than'+\
1642− ' %s, it will be treated as such' % sysvals.suspendmode)
1643− sysvals.suspendmode = 'freeze'
1644− else:
1645− vprint('ignoring dmesg line: %s' % line.replace('\n', ''))
1646− testruns.append(data)
2528+ if(not m):
2529+ continue
2530+ msg = m.group("msg")
2531+ if(re.match('PM: Syncing filesystems.*', msg)):
2532+ if(data):
2533+ testruns.append(data)
2534+ data = Data(len(testruns))
2535+ parseStamp(tp.stamp, data)
2536+ if len(tp.fwdata) > data.testnumber:
2537+ data.fwSuspend, data.fwResume = tp.fwdata[data.testnumber]
2538+ if(data.fwSuspend > 0 or data.fwResume > 0):
2539+ data.fwValid = True
2540+ if(re.match('ACPI: resume from mwait', msg)):
2541+ print('NOTE: This suspend appears to be freeze rather than'+\
2542+ ' %s, it will be treated as such' % sysvals.suspendmode)
2543+ sysvals.suspendmode = 'freeze'
2544+ if(not data):
2545+ continue
2546+ data.dmesgtext.append(line)
2547+ if(data):
2548+ testruns.append(data)
16472549 lf.close()
16482550
1649− if(not data):
1650− print('ERROR: analyze_suspend header missing from dmesg log')
1651− sys.exit()
2551+ if(len(testruns) < 1):
2552+ # bad log, but see if you can extract something meaningful anyway
2553+ testruns = loadRawKernelLog(sysvals.dmesgfile)
2554+
2555+ if(len(testruns) < 1):
2556+ doError(' dmesg log is completely unreadable: %s' \
2557+ % sysvals.dmesgfile, False)
16522558
16532559 # fix lines with same timestamp/function with the call and return swapped
16542560 for data in testruns:
@@ -1865,7 +2771,8 @@ def parseKernelLog(data): · 210 unmodified lines
18652771 actions[a] = []
18662772 actions[a].append({'begin': ktime, 'end': ktime})
18672773 if(re.match(at[a]['emsg'], msg)):
1868− actions[a][-1]['end'] = ktime
2774+ if(a in actions):
2775+ actions[a][-1]['end'] = ktime
18692776 # now look for CPU on/off events
18702777 if(re.match('Disabling non-boot CPUs .*', msg)):
18712778 # start of first cpu suspend
@@ -1912,15 +2819,7 @@ def parseKernelLog(data): · 40 unmodified lines
19122819 # fill in any actions we've found
19132820 for name in actions:
19142821 for event in actions[name]:
1915− begin = event['begin']
1916− end = event['end']
1917− # if event starts before timeline start, expand timeline
1918− if(begin < data.start):
1919− data.setStart(begin)
1920− # if event ends after timeline end, expand the timeline
1921− if(end > data.end):
1922− data.setEnd(end)
1923− data.newActionGlobal(name, begin, end)
2822+ data.newActionGlobal(name, event['begin'], event['end'])
19242823
19252824 if(sysvals.verbose):
19262825 data.printDetails()
@@ -1929,92 +2828,6 @@ def parseKernelLog(data): · 2 unmodified lines
19292828 data.fixupInitcallsThatDidntReturn()
19302829 return True
19312830
1932−# Function: setTimelineRows
1933−# Description:
1934−# Organize the timeline entries into the smallest
1935−# number of rows possible, with no entry overlapping
1936−# Arguments:
1937−# list: the list of devices/actions for a single phase
1938−# sortedkeys: cronologically sorted key list to use
1939−# Output:
1940−# The total number of rows needed to display this phase of the timeline
1941−def setTimelineRows(list, sortedkeys):
1942−
1943− # clear all rows and set them to undefined
1944− remaining = len(list)
1945− rowdata = dict()
1946− row = 0
1947− for item in list:
1948− list[item]['row'] = -1
1949−
1950− # try to pack each row with as many ranges as possible
1951− while(remaining > 0):
1952− if(row not in rowdata):
1953− rowdata[row] = []
1954− for item in sortedkeys:
1955− if(list[item]['row'] < 0):
1956− s = list[item]['start']
1957− e = list[item]['end']
1958− valid = True
1959− for ritem in rowdata[row]:
1960− rs = ritem['start']
1961− re = ritem['end']
1962− if(not (((s <= rs) and (e <= rs)) or
1963− ((s >= re) and (e >= re)))):
1964− valid = False
1965− break
1966− if(valid):
1967− rowdata[row].append(list[item])
1968− list[item]['row'] = row
1969− remaining -= 1
1970− row += 1
1971− return row
1972−
1973−# Function: createTimeScale
1974−# Description:
1975−# Create the timescale header for the html timeline
1976−# Arguments:
1977−# t0: start time (suspend begin)
1978−# tMax: end time (resume end)
1979−# tSuspend: time when suspend occurs, i.e. the zero time
1980−# Output:
1981−# The html code needed to display the time scale
1982−def createTimeScale(t0, tMax, tSuspended):
1983− timescale = '<div class="t" style="right:{0}%">{1}</div>\n'
1984− output = '<div id="timescale">\n'
1985−
1986− # set scale for timeline
1987− tTotal = tMax - t0
1988− tS = 0.1
1989− if(tTotal <= 0):
1990− return output
1991− if(tTotal > 4):
1992− tS = 1
1993− if(tSuspended < 0):
1994− for i in range(int(tTotal/tS)+1):
1995− pos = '%0.3f' % (100 - ((float(i)*tS*100)/tTotal))
1996− if(i > 0):
1997− val = '%0.fms' % (float(i)*tS*1000)
1998− else:
1999− val = ''
2000− output += timescale.format(pos, val)
2001− else:
2002− tSuspend = tSuspended - t0
2003− divTotal = int(tTotal/tS) + 1
2004− divSuspend = int(tSuspend/tS)
2005− s0 = (tSuspend - tS*divSuspend)*100/tTotal
2006− for i in range(divTotal):
2007− pos = '%0.3f' % (100 - ((float(i)*tS*100)/tTotal) - s0)
2008− if((i == 0) and (s0 < 3)):
2009− val = ''
2010− elif(i == divSuspend):
2011− val = 'S/R'
2012− else:
2013− val = '%0.fms' % (float(i-divSuspend)*tS*1000)
2014− output += timescale.format(pos, val)
2015− output += '</div>\n'
2016− return output
2017−
20182831 # Function: createHTMLSummarySimple
20192832 # Description:
20202833 # Create summary html file for a series of tests
@@ -2146,6 +2959,32 @@ def createHTMLSummarySimple(testruns, htmlfile): · 125 unmodified lines
21462959 hf.write('</body>\n</html>\n')
21472960 hf.close()
21482961
2962+def htmlTitle():
2963+ global sysvals
2964+ modename = {
2965+ 'freeze': 'Freeze (S0)',
2966+ 'standby': 'Standby (S1)',
2967+ 'mem': 'Suspend (S3)',
2968+ 'disk': 'Hibernate (S4)'
2969+ }
2970+ kernel = sysvals.stamp['kernel']
2971+ host = sysvals.hostname[0].upper()+sysvals.hostname[1:]
2972+ mode = sysvals.suspendmode
2973+ if sysvals.suspendmode in modename:
2974+ mode = modename[sysvals.suspendmode]
2975+ return host+' '+mode+' '+kernel
2976+
2977+def ordinal(value):
2978+ suffix = 'th'
2979+ if value < 10 or value > 19:
2980+ if value % 10 == 1:
2981+ suffix = 'st'
2982+ elif value % 10 == 2:
2983+ suffix = 'nd'
2984+ elif value % 10 == 3:
2985+ suffix = 'rd'
2986+ return '%d%s' % (value, suffix)
2987+
21492988 # Function: createHTML
21502989 # Description:
21512990 # Create the output html file from the resident test data
@@ -2156,6 +2995,10 @@ def createHTMLSummarySimple(testruns, htmlfile): · 4 unmodified lines
21562995 def createHTML(testruns):
21572996 global sysvals
21582997
2998+ if len(testruns) < 1:
2999+ print('ERROR: Not enough test data to build a timeline')
3000+ return
3001+
21593002 for data in testruns:
21603003 data.normalizeTime(testruns[-1].tSuspended)
21613004
@@ -2163,16 +3006,18 @@ def createHTML(testruns): · 1 unmodified line
21633006 if len(testruns) > 1:
21643007 x2changes = ['1', 'relative']
21653008 # html function templates
3009+ headline_version = '<div class="version"><a href="https://01.org/suspendresume">AnalyzeSuspend v%s</a></div>' % sysvals.version
21663010 headline_stamp = '<div class="stamp">{0} {1} {2} {3}</div>\n'
21673011 html_devlist1 = '<button id="devlist1" class="devlist" style="float:left;">Device Detail%s</button>' % x2changes[0]
21683012 html_zoombox = '<center><button id="zoomin">ZOOM IN</button><button id="zoomout">ZOOM OUT</button><button id="zoomdef">ZOOM 1:1</button></center>\n'
21693013 html_devlist2 = '<button id="devlist2" class="devlist" style="float:right;">Device Detail2</button>\n'
21703014 html_timeline = '<div id="dmesgzoombox" class="zoombox">\n<div id="{0}" class="timeline" style="height:{1}px">\n'
2171− html_device = '<div id="{0}" title="{1}" class="thread" style="left:{2}%;top:{3}%;height:{4}%;width:{5}%;">{6}</div>\n'
2172− html_traceevent = '<div title="{0}" class="traceevent" style="left:{1}%;top:{2}%;height:{3}%;width:{4}%;border:1px solid {5};background-color:{5}">{6}</div>\n'
2173− html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}%;height:{3}%;background-color:{4}">{5}</div>\n'
3015+ html_tblock = '<div id="block{0}" class="tblock" style="left:{1}%;width:{2}%;">\n'
3016+ html_device = '<div id="{0}" title="{1}" class="thread{7}" style="left:{2}%;top:{3}px;height:{4}px;width:{5}%;{8}">{6}</div>\n'
3017+ html_traceevent = '<div title="{0}" class="traceevent" style="left:{1}%;top:{2}px;height:{3}px;width:{4}%;line-height:{3}px;">{5}</div>\n'
3018+ html_phase = '<div class="phase" style="left:{0}%;width:{1}%;top:{2}px;height:{3}px;background-color:{4}">{5}</div>\n'
21743019 html_phaselet = '<div id="{0}" class="phaselet" style="left:{1}%;width:{2}%;background-color:{3}"></div>\n'
2175− html_legend = '<div class="square" style="left:{0}%;background-color:{1}">&nbsp;{2}</div>\n'
3020+ html_legend = '<div id="p{3}" class="square" style="left:{0}%;background-color:{1}">&nbsp;{2}</div>\n'
21763021 html_timetotal = '<table class="time1">\n<tr>'\
21773022 '<td class="green">{2} Suspend Time: <b>{0} ms</b></td>'\
21783023 '<td class="yellow">{2} Resume Time: <b>{1} ms</b></td>'\
@@ -2182,6 +3027,10 @@ def createHTML(testruns): · 3 unmodified lines
21823027 '<td class="gray">'+sysvals.suspendmode+' time: <b>{1} ms</b></td>'\
21833028 '<td class="yellow">{3} Resume Time: <b>{2} ms</b></td>'\
21843029 '</tr>\n</table>\n'
3030+ html_timetotal3 = '<table class="time1">\n<tr>'\
3031+ '<td class="green">Execution Time: <b>{0} ms</b></td>'\
3032+ '<td class="yellow">Command: <b>{1}</b></td>'\
3033+ '</tr>\n</table>\n'
21853034 html_timegroups = '<table class="time2">\n<tr>'\
21863035 '<td class="green">{4}Kernel Suspend: {0} ms</td>'\
21873036 '<td class="purple">{4}Firmware Suspend: {1} ms</td>'\
@@ -2189,12 +3038,21 @@ def createHTML(testruns): · 1 unmodified line
21893038 '<td class="yellow">{4}Kernel Resume: {3} ms</td>'\
21903039 '</tr>\n</table>\n'
21913040
3041+ # html format variables
3042+ rowheight = 30
3043+ devtextS = '14px'
3044+ devtextH = '30px'
3045+ hoverZ = 'z-index:10;'
3046+
3047+ if sysvals.usedevsrc:
3048+ hoverZ = ''
3049+
21923050 # device timeline
21933051 vprint('Creating Device Timeline...')
2194− devtl = Timeline()
3052+
3053+ devtl = Timeline(rowheight)
21953054
21963055 # Generate the header for this timeline
2197− textnum = ['First', 'Second']
21983056 for data in testruns:
21993057 tTotal = data.end - data.start
22003058 tEnd = data.dmesg['resume_complete']['end']
@@ -2203,7 +3061,17 @@ def createHTML(testruns): · 2 unmodified lines
22033061 sys.exit()
22043062 if(data.tLow > 0):
22053063 low_time = '%.0f'%(data.tLow*1000)
2206− if data.fwValid:
3064+ if sysvals.suspendmode == 'command':
3065+ run_time = '%.0f'%((data.end-data.start)*1000)
3066+ if sysvals.testcommand:
3067+ testdesc = sysvals.testcommand
3068+ else:
3069+ testdesc = 'unknown'
3070+ if(len(testruns) > 1):
3071+ testdesc = ordinal(data.testnumber+1)+' '+testdesc
3072+ thtml = html_timetotal3.format(run_time, testdesc)
3073+ devtl.html['header'] += thtml
3074+ elif data.fwValid:
22073075 suspend_time = '%.0f'%((data.tSuspended-data.start)*1000 + \
22083076 (data.fwSuspend/1000000.0))
22093077 resume_time = '%.0f'%((tEnd-data.tSuspended)*1000 + \
@@ -2211,7 +3079,7 @@ def createHTML(testruns): · 1 unmodified line
22113079 testdesc1 = 'Total'
22123080 testdesc2 = ''
22133081 if(len(testruns) > 1):
2214− testdesc1 = testdesc2 = textnum[data.testnumber]
3082+ testdesc1 = testdesc2 = ordinal(data.testnumber+1)
22153083 testdesc2 += ' '
22163084 if(data.tLow == 0):
22173085 thtml = html_timetotal.format(suspend_time, \
@@ -2219,28 +3087,28 @@ def createHTML(testruns): · 1 unmodified line
22193087 else:
22203088 thtml = html_timetotal2.format(suspend_time, low_time, \
22213089 resume_time, testdesc1)
2222− devtl.html['timeline'] += thtml
3090+ devtl.html['header'] += thtml
22233091 sktime = '%.3f'%((data.dmesg['suspend_machine']['end'] - \
22243092 data.getStart())*1000)
22253093 sftime = '%.3f'%(data.fwSuspend / 1000000.0)
22263094 rftime = '%.3f'%(data.fwResume / 1000000.0)
2227− rktime = '%.3f'%((data.getEnd() - \
3095+ rktime = '%.3f'%((data.dmesg['resume_complete']['end'] - \
22283096 data.dmesg['resume_machine']['start'])*1000)
2229− devtl.html['timeline'] += html_timegroups.format(sktime, \
3097+ devtl.html['header'] += html_timegroups.format(sktime, \
22303098 sftime, rftime, rktime, testdesc2)
22313099 else:
22323100 suspend_time = '%.0f'%((data.tSuspended-data.start)*1000)
22333101 resume_time = '%.0f'%((tEnd-data.tSuspended)*1000)
22343102 testdesc = 'Kernel'
22353103 if(len(testruns) > 1):
2236− testdesc = textnum[data.testnumber]+' '+testdesc
3104+ testdesc = ordinal(data.testnumber+1)+' '+testdesc
22373105 if(data.tLow == 0):
22383106 thtml = html_timetotal.format(suspend_time, \
22393107 resume_time, testdesc)
22403108 else:
22413109 thtml = html_timetotal2.format(suspend_time, low_time, \
22423110 resume_time, testdesc)
2243− devtl.html['timeline'] += thtml
3111+ devtl.html['header'] += thtml
22443112
22453113 # time scale for potentially multiple datasets
22463114 t0 = testruns[0].start
@@ -2249,153 +3117,241 @@ def createHTML(testruns): · 2 unmodified lines
22493117 tTotal = tMax - t0
22503118
22513119 # determine the maximum number of rows we need to draw
2252− timelinerows = 0
22533120 for data in testruns:
2254− for phase in data.dmesg:
2255− list = data.dmesg[phase]['list']
2256− rows = setTimelineRows(list, list)
2257− data.dmesg[phase]['row'] = rows
2258− if(rows > timelinerows):
2259− timelinerows = rows
2260−
2261− # calculate the timeline height and create bounding box, add buttons
2262− devtl.setRows(timelinerows + 1)
2263− devtl.html['timeline'] += html_devlist1
2264− if len(testruns) > 1:
2265− devtl.html['timeline'] += html_devlist2
3121+ data.selectTimelineDevices('%f', tTotal, sysvals.mindevlen)
3122+ for group in data.devicegroups:
3123+ devlist = []
3124+ for phase in group:
3125+ for devname in data.tdevlist[phase]:
3126+ devlist.append((phase,devname))
3127+ devtl.getPhaseRows(data.dmesg, devlist)
3128+ devtl.calcTotalRows()
3129+
3130+ # create bounding box, add buttons
3131+ if sysvals.suspendmode != 'command':
3132+ devtl.html['timeline'] += html_devlist1
3133+ if len(testruns) > 1:
3134+ devtl.html['timeline'] += html_devlist2
22663135 devtl.html['timeline'] += html_zoombox
22673136 devtl.html['timeline'] += html_timeline.format('dmesg', devtl.height)
22683137
2269− # draw the colored boxes for each of the phases
2270− for data in testruns:
2271− for b in data.dmesg:
2272− phase = data.dmesg[b]
2273− length = phase['end']-phase['start']
2274− left = '%.3f' % (((phase['start']-t0)*100.0)/tTotal)
2275− width = '%.3f' % ((length*100.0)/tTotal)
2276− devtl.html['timeline'] += html_phase.format(left, width, \
2277− '%.3f'%devtl.scaleH, '%.3f'%(100-devtl.scaleH), \
2278− data.dmesg[b]['color'], '')
3138+ # draw the full timeline
3139+ phases = {'suspend':[],'resume':[]}
3140+ for phase in data.dmesg:
3141+ if 'resume' in phase:
3142+ phases['resume'].append(phase)
3143+ else:
3144+ phases['suspend'].append(phase)
22793145
2280− # draw the time scale, try to make the number of labels readable
2281− devtl.html['scale'] = createTimeScale(t0, tMax, tSuspended)
2282− devtl.html['timeline'] += devtl.html['scale']
2283− for data in testruns:
2284− for b in data.dmesg:
2285− phaselist = data.dmesg[b]['list']
2286− for d in phaselist:
2287− name = d
2288− drv = ''
2289− dev = phaselist[d]
2290− if(d in sysvals.altdevname):
2291− name = sysvals.altdevname[d]
2292− if('drv' in dev and dev['drv']):
2293− drv = ' {%s}' % dev['drv']
2294− height = (100.0 - devtl.scaleH)/data.dmesg[b]['row']
2295− top = '%.3f' % ((dev['row']*height) + devtl.scaleH)
2296− left = '%.3f' % (((dev['start']-t0)*100)/tTotal)
2297− width = '%.3f' % (((dev['end']-dev['start'])*100)/tTotal)
2298− length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000)
2299− color = 'rgba(204,204,204,0.5)'
2300− devtl.html['timeline'] += html_device.format(dev['id'], \
2301− d+drv+length+b, left, top, '%.3f'%height, width, name+drv)
2302−
2303− # draw any trace events found
3146+ # draw each test run chronologically
23043147 for data in testruns:
2305− for b in data.dmesg:
2306− phaselist = data.dmesg[b]['list']
2307− for name in phaselist:
2308− dev = phaselist[name]
2309− if('traceevents' in dev):
2310− vprint('Debug trace events found for device %s' % name)
2311− vprint('%20s %20s %10s %8s' % ('action', \
3148+ # if nore than one test, draw a block to represent user mode
3149+ if(data.testnumber > 0):
3150+ m0 = testruns[data.testnumber-1].end
3151+ mMax = testruns[data.testnumber].start
3152+ mTotal = mMax - m0
3153+ name = 'usermode%d' % data.testnumber
3154+ top = '%d' % devtl.scaleH
3155+ left = '%f' % (((m0-t0)*100.0)/tTotal)
3156+ width = '%f' % ((mTotal*100.0)/tTotal)
3157+ title = 'user mode (%0.3f ms) ' % (mTotal*1000)
3158+ devtl.html['timeline'] += html_device.format(name, \
3159+ title, left, top, '%d'%devtl.bodyH, width, '', '', '')
3160+ # now draw the actual timeline blocks
3161+ for dir in phases:
3162+ # draw suspend and resume blocks separately
3163+ bname = '%s%d' % (dir[0], data.testnumber)
3164+ if dir == 'suspend':
3165+ m0 = testruns[data.testnumber].start
3166+ mMax = testruns[data.testnumber].tSuspended
3167+ mTotal = mMax - m0
3168+ left = '%f' % (((m0-t0)*100.0)/tTotal)
3169+ else:
3170+ m0 = testruns[data.testnumber].tSuspended
3171+ mMax = testruns[data.testnumber].end
3172+ mTotal = mMax - m0
3173+ left = '%f' % ((((m0-t0)*100.0)+sysvals.srgap/2)/tTotal)
3174+ # if a timeline block is 0 length, skip altogether
3175+ if mTotal == 0:
3176+ continue
3177+ width = '%f' % (((mTotal*100.0)-sysvals.srgap/2)/tTotal)
3178+ devtl.html['timeline'] += html_tblock.format(bname, left, width)
3179+ for b in sorted(phases[dir]):
3180+ # draw the phase color background
3181+ phase = data.dmesg[b]
3182+ length = phase['end']-phase['start']
3183+ left = '%f' % (((phase['start']-m0)*100.0)/mTotal)
3184+ width = '%f' % ((length*100.0)/mTotal)
3185+ devtl.html['timeline'] += html_phase.format(left, width, \
3186+ '%.3f'%devtl.scaleH, '%.3f'%devtl.bodyH, \
3187+ data.dmesg[b]['color'], '')
3188+ # draw the devices for this phase
3189+ phaselist = data.dmesg[b]['list']
3190+ for d in data.tdevlist[b]:
3191+ name = d
3192+ drv = ''
3193+ dev = phaselist[d]
3194+ xtraclass = ''
3195+ xtrainfo = ''
3196+ xtrastyle = ''
3197+ if 'htmlclass' in dev:
3198+ xtraclass = dev['htmlclass']
3199+ xtrainfo = dev['htmlclass']
3200+ if 'color' in dev:
3201+ xtrastyle = 'background-color:%s;' % dev['color']
3202+ if(d in sysvals.devprops):
3203+ name = sysvals.devprops[d].altName(d)
3204+ xtraclass = sysvals.devprops[d].xtraClass()
3205+ xtrainfo = sysvals.devprops[d].xtraInfo()
3206+ if('drv' in dev and dev['drv']):
3207+ drv = ' {%s}' % dev['drv']
3208+ rowheight = devtl.phaseRowHeight(b, dev['row'])
3209+ rowtop = devtl.phaseRowTop(b, dev['row'])
3210+ top = '%.3f' % (rowtop + devtl.scaleH)
3211+ left = '%f' % (((dev['start']-m0)*100)/mTotal)
3212+ width = '%f' % (((dev['end']-dev['start'])*100)/mTotal)
3213+ length = ' (%0.3f ms) ' % ((dev['end']-dev['start'])*1000)
3214+ if sysvals.suspendmode == 'command':
3215+ title = name+drv+xtrainfo+length+'cmdexec'
3216+ else:
3217+ title = name+drv+xtrainfo+length+b
3218+ devtl.html['timeline'] += html_device.format(dev['id'], \
3219+ title, left, top, '%.3f'%rowheight, width, \
3220+ d+drv, xtraclass, xtrastyle)
3221+ if('src' not in dev):
3222+ continue
3223+ # draw any trace events for this device
3224+ vprint('Debug trace events found for device %s' % d)
3225+ vprint('%20s %20s %10s %8s' % ('title', \
23123226 'name', 'time(ms)', 'length(ms)'))
2313− for e in dev['traceevents']:
2314− vprint('%20s %20s %10.3f %8.3f' % (e.action, \
2315− e.name, e.time*1000, e.length*1000))
2316− height = (100.0 - devtl.scaleH)/data.dmesg[b]['row']
2317− top = '%.3f' % ((dev['row']*height) + devtl.scaleH)
2318− left = '%.3f' % (((e.time-t0)*100)/tTotal)
2319− width = '%.3f' % (e.length*100/tTotal)
3227+ for e in dev['src']:
3228+ vprint('%20s %20s %10.3f %8.3f' % (e.title, \
3229+ e.text, e.time*1000, e.length*1000))
3230+ height = devtl.rowH
3231+ top = '%.3f' % (rowtop + devtl.scaleH + (e.row*devtl.rowH))
3232+ left = '%f' % (((e.time-m0)*100)/mTotal)
3233+ width = '%f' % (e.length*100/mTotal)
23203234 color = 'rgba(204,204,204,0.5)'
23213235 devtl.html['timeline'] += \
2322− html_traceevent.format(e.action+' '+e.name, \
3236+ html_traceevent.format(e.title, \
23233237 left, top, '%.3f'%height, \
2324− width, e.color, '')
3238+ width, e.text)
3239+ # draw the time scale, try to make the number of labels readable
3240+ devtl.html['timeline'] += devtl.createTimeScale(m0, mMax, tTotal, dir)
3241+ devtl.html['timeline'] += '</div>\n'
23253242
23263243 # timeline is finished
23273244 devtl.html['timeline'] += '</div>\n</div>\n'
23283245
23293246 # draw a legend which describes the phases by color
2330− data = testruns[-1]
2331− devtl.html['legend'] = '<div class="legend">\n'
2332− pdelta = 100.0/len(data.phases)
2333− pmargin = pdelta / 4.0
2334− for phase in data.phases:
2335− order = '%.2f' % ((data.dmesg[phase]['order'] * pdelta) + pmargin)
2336− name = string.replace(phase, '_', ' &nbsp;')
2337− devtl.html['legend'] += html_legend.format(order, \
2338− data.dmesg[phase]['color'], name)
2339− devtl.html['legend'] += '</div>\n'
3247+ if sysvals.suspendmode != 'command':
3248+ data = testruns[-1]
3249+ devtl.html['legend'] = '<div class="legend">\n'
3250+ pdelta = 100.0/len(data.phases)
3251+ pmargin = pdelta / 4.0
3252+ for phase in data.phases:
3253+ tmp = phase.split('_')
3254+ id = tmp[0][0]
3255+ if(len(tmp) > 1):
3256+ id += tmp[1][0]
3257+ order = '%.2f' % ((data.dmesg[phase]['order'] * pdelta) + pmargin)
3258+ name = string.replace(phase, '_', ' &nbsp;')
3259+ devtl.html['legend'] += html_legend.format(order, \
3260+ data.dmesg[phase]['color'], name, id)
3261+ devtl.html['legend'] += '</div>\n'
23403262
23413263 hf = open(sysvals.htmlfile, 'w')
2342− thread_height = 0
3264+
3265+ if not sysvals.cgexp:
3266+ cgchk = 'checked'
3267+ cgnchk = 'not(:checked)'
3268+ else:
3269+ cgchk = 'not(:checked)'
3270+ cgnchk = 'checked'
23433271
23443272 # write the html header first (html head, css code, up to body start)
23453273 html_header = '<!DOCTYPE html>\n<html>\n<head>\n\
23463274 <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\
2347− <title>AnalyzeSuspend</title>\n\
3275+ <title>'+htmlTitle()+'</title>\n\
23483276 <style type=\'text/css\'>\n\
2349− body {overflow-y: scroll;}\n\
2350− .stamp {width: 100%;text-align:center;background-color:gray;line-height:30px;color:white;font: 25px Arial;}\n\
2351− .callgraph {margin-top: 30px;box-shadow: 5px 5px 20px black;}\n\
2352− .callgraph article * {padding-left: 28px;}\n\
2353− h1 {color:black;font: bold 30px Times;}\n\
2354− t0 {color:black;font: bold 30px Times;}\n\
2355− t1 {color:black;font: 30px Times;}\n\
2356− t2 {color:black;font: 25px Times;}\n\
2357− t3 {color:black;font: 20px Times;white-space:nowrap;}\n\
2358− t4 {color:black;font: bold 30px Times;line-height:60px;white-space:nowrap;}\n\
3277+ body {overflow-y:scroll;}\n\
3278+ .stamp {width:100%;text-align:center;background-color:gray;line-height:30px;color:white;font:25px Arial;}\n\
3279+ .callgraph {margin-top:30px;box-shadow:5px 5px 20px black;}\n\
3280+ .callgraph article * {padding-left:28px;}\n\
3281+ h1 {color:black;font:bold 30px Times;}\n\
3282+ t0 {color:black;font:bold 30px Times;}\n\
3283+ t1 {color:black;font:30px Times;}\n\
3284+ t2 {color:black;font:25px Times;}\n\
3285+ t3 {color:black;font:20px Times;white-space:nowrap;}\n\
3286+ t4 {color:black;font:bold 30px Times;line-height:60px;white-space:nowrap;}\n\
3287+ cS {color:blue;font:bold 11px Times;}\n\
3288+ cR {color:red;font:bold 11px Times;}\n\
23593289 table {width:100%;}\n\
23603290 .gray {background-color:rgba(80,80,80,0.1);}\n\
23613291 .green {background-color:rgba(204,255,204,0.4);}\n\
23623292 .purple {background-color:rgba(128,0,128,0.2);}\n\
23633293 .yellow {background-color:rgba(255,255,204,0.4);}\n\
2364− .time1 {font: 22px Arial;border:1px solid;}\n\
2365− .time2 {font: 15px Arial;border-bottom:1px solid;border-left:1px solid;border-right:1px solid;}\n\
2366− td {text-align: center;}\n\
3294+ .time1 {font:22px Arial;border:1px solid;}\n\
3295+ .time2 {font:15px Arial;border-bottom:1px solid;border-left:1px solid;border-right:1px solid;}\n\
3296+ td {text-align:center;}\n\
23673297 r {color:#500000;font:15px Tahoma;}\n\
23683298 n {color:#505050;font:15px Tahoma;}\n\
2369− .tdhl {color: red;}\n\
2370− .hide {display: none;}\n\
2371− .pf {display: none;}\n\
2372− .pf:checked + label {background: url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/><rect x="8" y="4" width="2" height="10" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\
2373− .pf:not(:checked) ~ label {background: url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\
2374− .pf:checked ~ *:not(:nth-child(2)) {display: none;}\n\
2375− .zoombox {position: relative; width: 100%; overflow-x: scroll;}\n\
2376− .timeline {position: relative; font-size: 14px;cursor: pointer;width: 100%; overflow: hidden; background-color:#dddddd;}\n\
2377− .thread {position: absolute; height: '+'%.3f'%thread_height+'%; overflow: hidden; line-height: 30px; border:1px solid;text-align:center;white-space:nowrap;background-color:rgba(204,204,204,0.5);}\n\
2378− .thread:hover {background-color:white;border:1px solid red;z-index:10;}\n\
2379− .hover {background-color:white;border:1px solid red;z-index:10;}\n\
2380− .traceevent {position: absolute;opacity: 0.3;height: '+'%.3f'%thread_height+'%;width:0;overflow:hidden;line-height:30px;text-align:center;white-space:nowrap;}\n\
2381− .phase {position: absolute;overflow: hidden;border:0px;text-align:center;}\n\
3299+ .tdhl {color:red;}\n\
3300+ .hide {display:none;}\n\
3301+ .pf {display:none;}\n\
3302+ .pf:'+cgchk+' + label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/><rect x="8" y="4" width="2" height="10" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\
3303+ .pf:'+cgnchk+' ~ label {background:url(\'data:image/svg+xml;utf,<?xml version="1.0" standalone="no"?><svg xmlns="http://www.w3.org/2000/svg" height="18" width="18" version="1.1"><circle cx="9" cy="9" r="8" stroke="black" stroke-width="1" fill="white"/><rect x="4" y="8" width="10" height="2" style="fill:black;stroke-width:0"/></svg>\') no-repeat left center;}\n\
3304+ .pf:'+cgchk+' ~ *:not(:nth-child(2)) {display:none;}\n\
3305+ .zoombox {position:relative;width:100%;overflow-x:scroll;}\n\
3306+ .timeline {position:relative;font-size:14px;cursor:pointer;width:100%; overflow:hidden;background:linear-gradient(#cccccc, white);}\n\
3307+ .thread {position:absolute;height:0%;overflow:hidden;line-height:'+devtextH+';font-size:'+devtextS+';border:1px solid;text-align:center;white-space:nowrap;background-color:rgba(204,204,204,0.5);}\n\
3308+ .thread.sync {background-color:'+sysvals.synccolor+';}\n\
3309+ .thread.bg {background-color:'+sysvals.kprobecolor+';}\n\
3310+ .thread:hover {background-color:white;border:1px solid red;'+hoverZ+'}\n\
3311+ .hover {background-color:white;border:1px solid red;'+hoverZ+'}\n\
3312+ .hover.sync {background-color:white;}\n\
3313+ .hover.bg {background-color:white;}\n\
3314+ .traceevent {position:absolute;font-size:10px;overflow:hidden;color:black;text-align:center;white-space:nowrap;border-radius:5px;border:1px solid black;background:linear-gradient(to bottom right,rgba(204,204,204,1),rgba(150,150,150,1));}\n\
3315+ .traceevent:hover {background:white;}\n\
3316+ .phase {position:absolute;overflow:hidden;border:0px;text-align:center;}\n\
23823317 .phaselet {position:absolute;overflow:hidden;border:0px;text-align:center;height:100px;font-size:24px;}\n\
2383− .t {position:absolute;top:0%;height:100%;border-right:1px solid black;}\n\
2384− .legend {position: relative; width: 100%; height: 40px; text-align: center;margin-bottom:20px}\n\
2385− .legend .square {position:absolute;top:10px; width: 0px;height: 20px;border:1px solid;padding-left:20px;}\n\
3318+ .t {z-index:2;position:absolute;pointer-events:none;top:0%;height:100%;border-right:1px solid black;}\n\
3319+ .legend {position:relative; width:100%; height:40px; text-align:center;margin-bottom:20px}\n\
3320+ .legend .square {position:absolute;cursor:pointer;top:10px; width:0px;height:20px;border:1px solid;padding-left:20px;}\n\
23863321 button {height:40px;width:200px;margin-bottom:20px;margin-top:20px;font-size:24px;}\n\
3322+ .logbtn {position:relative;float:right;height:25px;width:50px;margin-top:3px;margin-bottom:0;font-size:10px;text-align:center;}\n\
23873323 .devlist {position:'+x2changes[1]+';width:190px;}\n\
2388− #devicedetail {height:100px;box-shadow: 5px 5px 20px black;}\n\
3324+ a:link {color:white;text-decoration:none;}\n\
3325+ a:visited {color:white;}\n\
3326+ a:hover {color:white;}\n\
3327+ a:active {color:white;}\n\
3328+ .version {position:relative;float:left;color:white;font-size:10px;line-height:30px;margin-left:10px;}\n\
3329+ #devicedetail {height:100px;box-shadow:5px 5px 20px black;}\n\
3330+ .tblock {position:absolute;height:100%;}\n\
3331+ .bg {z-index:1;}\n\
23893332 </style>\n</head>\n<body>\n'
2390− hf.write(html_header)
3333+
3334+ # no header or css if its embedded
3335+ if(sysvals.embedded):
3336+ hf.write('pass True tSus %.3f tRes %.3f tLow %.3f fwvalid %s tSus %.3f tRes %.3f\n' %
3337+ (data.tSuspended-data.start, data.end-data.tSuspended, data.tLow, data.fwValid, \
3338+ data.fwSuspend/1000000, data.fwResume/1000000))
3339+ else:
3340+ hf.write(html_header)
23913341
23923342 # write the test title and general info header
23933343 if(sysvals.stamp['time'] != ""):
3344+ hf.write(headline_version)
3345+ if sysvals.addlogs and sysvals.dmesgfile:
3346+ hf.write('<button id="showdmesg" class="logbtn">dmesg</button>')
3347+ if sysvals.addlogs and sysvals.ftracefile:
3348+ hf.write('<button id="showftrace" class="logbtn">ftrace</button>')
23943349 hf.write(headline_stamp.format(sysvals.stamp['host'],
23953350 sysvals.stamp['kernel'], sysvals.stamp['mode'], \
23963351 sysvals.stamp['time']))
23973352
23983353 # write the device timeline
3354+ hf.write(devtl.html['header'])
23993355 hf.write(devtl.html['timeline'])
24003356 hf.write(devtl.html['legend'])
24013357 hf.write('<div id="devicedetailtitle"></div>\n')
@@ -2410,12 +3366,15 @@ def createHTML(testruns): · 8 unmodified lines
24103366 width = '%.3f' % ((length*100.0)/tTotal)
24113367 hf.write(html_phaselet.format(b, left, width, \
24123368 data.dmesg[b]['color']))
3369+ if sysvals.suspendmode == 'command':
3370+ hf.write(html_phaselet.format('cmdexec', '0', '0', \
3371+ data.dmesg['resume_complete']['color']))
24133372 hf.write('</div>\n')
24143373 hf.write('</div>\n')
24153374
24163375 # write the ftrace data (callgraph)
24173376 data = testruns[-1]
2418− if(sysvals.usecallgraph):
3377+ if(sysvals.usecallgraph and not sysvals.embedded):
24193378 hf.write('<section id="callgraphs" class="callgraph">\n')
24203379 # write out the ftrace data converted to html
24213380 html_func_top = '<article id="{0}" class="atop" style="background-color:{1}">\n<input type="checkbox" class="pf" id="f{2}" checked/><label for="f{2}">{3} {4}</label>\n'
@@ -2428,22 +3387,29 @@ def createHTML(testruns): · 6 unmodified lines
24283387 for devname in data.sortedDevices(p):
24293388 if('ftrace' not in list[devname]):
24303389 continue
2431− name = devname
2432− if(devname in sysvals.altdevname):
2433− name = sysvals.altdevname[devname]
24343390 devid = list[devname]['id']
24353391 cg = list[devname]['ftrace']
2436− flen = '<r>(%.3f ms @ %.3f to %.3f)</r>' % \
2437− ((cg.end - cg.start)*1000, cg.start*1000, cg.end*1000)
3392+ clen = (cg.end - cg.start) * 1000
3393+ if clen < sysvals.mincglen:
3394+ continue
3395+ fmt = '<r>(%.3f ms @ '+sysvals.timeformat+' to '+sysvals.timeformat+')</r>'
3396+ flen = fmt % (clen, cg.start, cg.end)
3397+ name = devname
3398+ if(devname in sysvals.devprops):
3399+ name = sysvals.devprops[devname].altName(devname)
3400+ if sysvals.suspendmode == 'command':
3401+ ftitle = name
3402+ else:
3403+ ftitle = name+' '+p
24383404 hf.write(html_func_top.format(devid, data.dmesg[p]['color'], \
2439− num, name+' '+p, flen))
3405+ num, ftitle, flen))
24403406 num += 1
24413407 for line in cg.list:
24423408 if(line.length < 0.000000001):
24433409 flen = ''
24443410 else:
2445− flen = '<n>(%.3f ms @ %.3f)</n>' % (line.length*1000, \
2446− line.time*1000)
3411+ fmt = '<n>(%.3f ms @ '+sysvals.timeformat+')</n>'
3412+ flen = fmt % (line.length*1000, line.time)
24473413 if(line.freturn and line.fcall):
24483414 hf.write(html_func_leaf.format(line.name, flen))
24493415 elif(line.freturn):
@@ -2453,9 +3419,40 @@ def createHTML(testruns): · 3 unmodified lines
24533419 num += 1
24543420 hf.write(html_func_end)
24553421 hf.write('\n\n </section>\n')
2456− # write the footer and close
2457− addScriptCode(hf, testruns)
2458− hf.write('</body>\n</html>\n')
3422+
3423+ # add the dmesg log as a hidden div
3424+ if sysvals.addlogs and sysvals.dmesgfile:
3425+ hf.write('<div id="dmesglog" style="display:none;">\n')
3426+ lf = open(sysvals.dmesgfile, 'r')
3427+ for line in lf:
3428+ hf.write(line)
3429+ lf.close()
3430+ hf.write('</div>\n')
3431+ # add the ftrace log as a hidden div
3432+ if sysvals.addlogs and sysvals.ftracefile:
3433+ hf.write('<div id="ftracelog" style="display:none;">\n')
3434+ lf = open(sysvals.ftracefile, 'r')
3435+ for line in lf:
3436+ hf.write(line)
3437+ lf.close()
3438+ hf.write('</div>\n')
3439+
3440+ if(not sysvals.embedded):
3441+ # write the footer and close
3442+ addScriptCode(hf, testruns)
3443+ hf.write('</body>\n</html>\n')
3444+ else:
3445+ # embedded out will be loaded in a page, skip the js
3446+ t0 = (testruns[0].start - testruns[-1].tSuspended) * 1000
3447+ tMax = (testruns[-1].end - testruns[-1].tSuspended) * 1000
3448+ # add js code in a div entry for later evaluation
3449+ detail = 'var bounds = [%f,%f];\n' % (t0, tMax)
3450+ detail += 'var devtable = [\n'
3451+ for data in testruns:
3452+ topo = data.deviceTopology()
3453+ detail += '\t"%s",\n' % (topo)
3454+ detail += '];\n'
3455+ hf.write('<div id=customcode style=display:none>\n'+detail+'</div>\n')
24593456 hf.close()
24603457 return True
24613458
@@ -2466,8 +3463,8 @@ def createHTML(testruns): · 4 unmodified lines
24663463 # hf: the open html file pointer
24673464 # testruns: array of Data objects from parseKernelLog or parseTraceLog
24683465 def addScriptCode(hf, testruns):
2469− t0 = (testruns[0].start - testruns[-1].tSuspended) * 1000
2470− tMax = (testruns[-1].end - testruns[-1].tSuspended) * 1000
3466+ t0 = testruns[0].start * 1000
3467+ tMax = testruns[-1].end * 1000
24713468 # create an array in javascript memory with the device details
24723469 detail = ' var devtable = [];\n'
24733470 for data in testruns:
@@ -2477,8 +3474,43 @@ def addScriptCode(hf, testruns): · 3 unmodified lines
24773474 # add the code which will manipulate the data in the browser
24783475 script_code = \
24793476 '<script type="text/javascript">\n'+detail+\
3477+ ' var resolution = -1;\n'\
3478+ ' function redrawTimescale(t0, tMax, tS) {\n'\
3479+ ' var rline = \'<div class="t" style="left:0;border-left:1px solid black;border-right:0;"><cR><-R</cR></div>\';\n'\
3480+ ' var tTotal = tMax - t0;\n'\
3481+ ' var list = document.getElementsByClassName("tblock");\n'\
3482+ ' for (var i = 0; i < list.length; i++) {\n'\
3483+ ' var timescale = list[i].getElementsByClassName("timescale")[0];\n'\
3484+ ' var m0 = t0 + (tTotal*parseFloat(list[i].style.left)/100);\n'\
3485+ ' var mTotal = tTotal*parseFloat(list[i].style.width)/100;\n'\
3486+ ' var mMax = m0 + mTotal;\n'\
3487+ ' var html = "";\n'\
3488+ ' var divTotal = Math.floor(mTotal/tS) + 1;\n'\
3489+ ' if(divTotal > 1000) continue;\n'\
3490+ ' var divEdge = (mTotal - tS*(divTotal-1))*100/mTotal;\n'\
3491+ ' var pos = 0.0, val = 0.0;\n'\
3492+ ' for (var j = 0; j < divTotal; j++) {\n'\
3493+ ' var htmlline = "";\n'\
3494+ ' if(list[i].id[5] == "r") {\n'\
3495+ ' pos = 100 - (((j)*tS*100)/mTotal);\n'\
3496+ ' val = (j)*tS;\n'\
3497+ ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\
3498+ ' if(j == 0)\n'\
3499+ ' htmlline = rline;\n'\
3500+ ' } else {\n'\
3501+ ' pos = 100 - (((j)*tS*100)/mTotal) - divEdge;\n'\
3502+ ' val = (j-divTotal+1)*tS;\n'\
3503+ ' if(j == divTotal - 1)\n'\
3504+ ' htmlline = \'<div class="t" style="right:\'+pos+\'%"><cS>S-></cS></div>\';\n'\
3505+ ' else\n'\
3506+ ' htmlline = \'<div class="t" style="right:\'+pos+\'%">\'+val+\'ms</div>\';\n'\
3507+ ' }\n'\
3508+ ' html += htmlline;\n'\
3509+ ' }\n'\
3510+ ' timescale.innerHTML = html;\n'\
3511+ ' }\n'\
3512+ ' }\n'\
24803513 ' function zoomTimeline() {\n'\
2481− ' var timescale = document.getElementById("timescale");\n'\
24823514 ' var dmesg = document.getElementById("dmesg");\n'\
24833515 ' var zoombox = document.getElementById("dmesgzoombox");\n'\
24843516 ' var val = parseFloat(dmesg.style.width);\n'\
@@ -2486,7 +3518,7 @@ def addScriptCode(hf, testruns): · 1 unmodified line
24863518 ' var sh = window.outerWidth / 2;\n'\
24873519 ' if(this.id == "zoomin") {\n'\
24883520 ' newval = val * 1.2;\n'\
2489− ' if(newval > 40000) newval = 40000;\n'\
3521+ ' if(newval > 910034) newval = 910034;\n'\
24903522 ' dmesg.style.width = newval+"%";\n'\
24913523 ' zoombox.scrollLeft = ((zoombox.scrollLeft + sh) * newval / val) - sh;\n'\
24923524 ' } else if (this.id == "zoomout") {\n'\
@@ -2498,19 +3530,17 @@ def addScriptCode(hf, testruns): · 5 unmodified lines
24983530 ' zoombox.scrollLeft = 0;\n'\
24993531 ' dmesg.style.width = "100%";\n'\
25003532 ' }\n'\
2501− ' var html = "";\n'\
3533+ ' var tS = [10000, 5000, 2000, 1000, 500, 200, 100, 50, 20, 10, 5, 2, 1];\n'\
25023534 ' var t0 = bounds[0];\n'\
25033535 ' var tMax = bounds[1];\n'\
25043536 ' var tTotal = tMax - t0;\n'\
25053537 ' var wTotal = tTotal * 100.0 / newval;\n'\
2506− ' for(var tS = 1000; (wTotal / tS) < 3; tS /= 10);\n'\
2507− ' if(tS < 1) tS = 1;\n'\
2508− ' for(var s = ((t0 / tS)|0) * tS; s < tMax; s += tS) {\n'\
2509− ' var pos = (tMax - s) * 100.0 / tTotal;\n'\
2510− ' var name = (s == 0)?"S/R":(s+"ms");\n'\
2511− ' html += "<div class=\\"t\\" style=\\"right:"+pos+"%\\">"+name+"</div>";\n'\
2512− ' }\n'\
2513− ' timescale.innerHTML = html;\n'\
3538+ ' var idx = 7*window.innerWidth/1100;\n'\
3539+ ' for(var i = 0; (i < tS.length)&&((wTotal / tS[i]) < idx); i++);\n'\
3540+ ' if(i >= tS.length) i = tS.length - 1;\n'\
3541+ ' if(tS[i] == resolution) return;\n'\
3542+ ' resolution = tS[i];\n'\
3543+ ' redrawTimescale(t0, tMax, tS[i]);\n'\
25143544 ' }\n'\
25153545 ' function deviceHover() {\n'\
25163546 ' var name = this.title.slice(0, this.title.indexOf(" ("));\n'\
@@ -2523,12 +3553,13 @@ def addScriptCode(hf, testruns): · 6 unmodified lines
25233553 ' cpu = parseInt(name.slice(8));\n'\
25243554 ' for (var i = 0; i < dev.length; i++) {\n'\
25253555 ' dname = dev[i].title.slice(0, dev[i].title.indexOf(" ("));\n'\
3556+ ' var cname = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\
25263557 ' if((cpu >= 0 && dname.match("CPU_O[NF]*\\\[*"+cpu+"\\\]")) ||\n'\
25273558 ' (name == dname))\n'\
25283559 ' {\n'\
2529− ' dev[i].className = "thread hover";\n'\
3560+ ' dev[i].className = "hover "+cname;\n'\
25303561 ' } else {\n'\
2531− ' dev[i].className = "thread";\n'\
3562+ ' dev[i].className = cname;\n'\
25323563 ' }\n'\
25333564 ' }\n'\
25343565 ' }\n'\
@@ -2536,7 +3567,7 @@ def addScriptCode(hf, testruns): · 1 unmodified line
25363567 ' var dmesg = document.getElementById("dmesg");\n'\
25373568 ' var dev = dmesg.getElementsByClassName("thread");\n'\
25383569 ' for (var i = 0; i < dev.length; i++) {\n'\
2539− ' dev[i].className = "thread";\n'\
3570+ ' dev[i].className = dev[i].className.slice(dev[i].className.indexOf("thread"));\n'\
25403571 ' }\n'\
25413572 ' }\n'\
25423573 ' function deviceTitle(title, total, cpu) {\n'\
@@ -2547,7 +3578,7 @@ def addScriptCode(hf, testruns): · 4 unmodified lines
25473578 ' total[2] = (total[2]+total[4])/2;\n'\
25483579 ' }\n'\
25493580 ' var devtitle = document.getElementById("devicedetailtitle");\n'\
2550− ' var name = title.slice(0, title.indexOf(" "));\n'\
3581+ ' var name = title.slice(0, title.indexOf(" ("));\n'\
25513582 ' if(cpu >= 0) name = "CPU"+cpu;\n'\
25523583 ' var driver = "";\n'\
25533584 ' var tS = "<t2>(</t2>";\n'\
@@ -2579,6 +3610,8 @@ def addScriptCode(hf, testruns): · 25 unmodified lines
25793610 ' var dev = dmesg.getElementsByClassName("thread");\n'\
25803611 ' var idlist = [];\n'\
25813612 ' var pdata = [[]];\n'\
3613+ ' if(document.getElementById("devicedetail1"))\n'\
3614+ ' pdata = [[], []];\n'\
25823615 ' var pd = pdata[0];\n'\
25833616 ' var total = [0.0, 0.0, 0.0];\n'\
25843617 ' for (var i = 0; i < dev.length; i++) {\n'\
@@ -2634,6 +3667,7 @@ def addScriptCode(hf, testruns): · 49 unmodified lines
26343667 ' var cglist = document.getElementById("callgraphs");\n'\
26353668 ' if(!cglist) return;\n'\
26363669 ' var cg = cglist.getElementsByClassName("atop");\n'\
3670+ ' if(cg.length < 10) return;\n'\
26373671 ' for (var i = 0; i < cg.length; i++) {\n'\
26383672 ' if(idlist.indexOf(cg[i].id) >= 0) {\n'\
26393673 ' cg[i].style.display = "block";\n'\
@@ -2658,15 +3692,32 @@ def addScriptCode(hf, testruns): · 18 unmodified lines
26583692 ' dt = devtable[1];\n'\
26593693 ' win.document.write(html+dt);\n'\
26603694 ' }\n'\
3695+ ' function logWindow(e) {\n'\
3696+ ' var name = e.target.id.slice(4);\n'\
3697+ ' var win = window.open();\n'\
3698+ ' var log = document.getElementById(name+"log");\n'\
3699+ ' var title = "<title>"+document.title.split(" ")[0]+" "+name+" log</title>";\n'\
3700+ ' win.document.write(title+"<pre>"+log.innerHTML+"</pre>");\n'\
3701+ ' win.document.close();\n'\
3702+ ' }\n'\
3703+ ' function onClickPhase(e) {\n'\
3704+ ' }\n'\
3705+ ' window.addEventListener("resize", function () {zoomTimeline();});\n'\
26613706 ' window.addEventListener("load", function () {\n'\
26623707 ' var dmesg = document.getElementById("dmesg");\n'\
26633708 ' dmesg.style.width = "100%"\n'\
26643709 ' document.getElementById("zoomin").onclick = zoomTimeline;\n'\
26653710 ' document.getElementById("zoomout").onclick = zoomTimeline;\n'\
26663711 ' document.getElementById("zoomdef").onclick = zoomTimeline;\n'\
2667− ' var devlist = document.getElementsByClassName("devlist");\n'\
2668− ' for (var i = 0; i < devlist.length; i++)\n'\
2669− ' devlist[i].onclick = devListWindow;\n'\
3712+ ' var list = document.getElementsByClassName("square");\n'\
3713+ ' for (var i = 0; i < list.length; i++)\n'\
3714+ ' list[i].onclick = onClickPhase;\n'\
3715+ ' var list = document.getElementsByClassName("logbtn");\n'\
3716+ ' for (var i = 0; i < list.length; i++)\n'\
3717+ ' list[i].onclick = logWindow;\n'\
3718+ ' list = document.getElementsByClassName("devlist");\n'\
3719+ ' for (var i = 0; i < list.length; i++)\n'\
3720+ ' list[i].onclick = devListWindow;\n'\
26703721 ' var dev = dmesg.getElementsByClassName("thread");\n'\
26713722 ' for (var i = 0; i < dev.length; i++) {\n'\
26723723 ' dev[i].onclick = deviceDetail;\n'\
@@ -2685,141 +3736,87 @@ def addScriptCode(hf, testruns): · 12 unmodified lines
26853736 def executeSuspend():
26863737 global sysvals
26873738
2688− detectUSB(False)
26893739 t0 = time.time()*1000
26903740 tp = sysvals.tpath
3741+ fwdata = []
3742+ # mark the start point in the kernel ring buffer just as we start
3743+ sysvals.initdmesg()
3744+ # start ftrace
3745+ if(sysvals.usecallgraph or sysvals.usetraceevents):
3746+ print('START TRACING')
3747+ sysvals.fsetVal('1', 'tracing_on')
26913748 # execute however many s/r runs requested
26923749 for count in range(1,sysvals.execcount+1):
2693− # clear the kernel ring buffer just as we start
2694− os.system('dmesg -C')
2695− # enable callgraph ftrace only for the second run
2696− if(sysvals.usecallgraph and count == 2):
2697− # set trace type
2698− os.system('echo function_graph > '+tp+'current_tracer')
2699− os.system('echo "" > '+tp+'set_ftrace_filter')
2700− # set trace format options
2701− os.system('echo funcgraph-abstime > '+tp+'trace_options')
2702− os.system('echo funcgraph-proc > '+tp+'trace_options')
2703− # focus only on device suspend and resume
2704− os.system('cat '+tp+'available_filter_functions | '+\
2705− 'grep dpm_run_callback > '+tp+'set_graph_function')
27063750 # if this is test2 and there's a delay, start here
27073751 if(count > 1 and sysvals.x2delay > 0):
27083752 tN = time.time()*1000
27093753 while (tN - t0) < sysvals.x2delay:
27103754 tN = time.time()*1000
27113755 time.sleep(0.001)
2712− # start ftrace
2713− if(sysvals.usecallgraph or sysvals.usetraceevents):
2714− print('START TRACING')
2715− os.system('echo 1 > '+tp+'tracing_on')
27163756 # initiate suspend
27173757 if(sysvals.usecallgraph or sysvals.usetraceevents):
2718− os.system('echo SUSPEND START > '+tp+'trace_marker')
2719− if(sysvals.rtcwake):
2720− print('SUSPEND START')
2721− print('will autoresume in %d seconds' % sysvals.rtcwaketime)
2722− sysvals.rtcWakeAlarm()
3758+ sysvals.fsetVal('SUSPEND START', 'trace_marker')
3759+ if sysvals.suspendmode == 'command':
3760+ print('COMMAND START')
3761+ if(sysvals.rtcwake):
3762+ print('will issue an rtcwake in %d seconds' % sysvals.rtcwaketime)
3763+ sysvals.rtcWakeAlarmOn()
3764+ os.system(sysvals.testcommand)
27233765 else:
2724− print('SUSPEND START (press a key to resume)')
2725− pf = open(sysvals.powerfile, 'w')
2726− pf.write(sysvals.suspendmode)
2727− # execution will pause here
2728− pf.close()
3766+ if(sysvals.rtcwake):
3767+ print('SUSPEND START')
3768+ print('will autoresume in %d seconds' % sysvals.rtcwaketime)
3769+ sysvals.rtcWakeAlarmOn()
3770+ else:
3771+ print('SUSPEND START (press a key to resume)')
3772+ pf = open(sysvals.powerfile, 'w')
3773+ pf.write(sysvals.suspendmode)
3774+ # execution will pause here
3775+ try:
3776+ pf.close()
3777+ except:
3778+ pass
27293779 t0 = time.time()*1000
3780+ if(sysvals.rtcwake):
3781+ sysvals.rtcWakeAlarmOff()
27303782 # return from suspend
27313783 print('RESUME COMPLETE')
27323784 if(sysvals.usecallgraph or sysvals.usetraceevents):
2733− os.system('echo RESUME COMPLETE > '+tp+'trace_marker')
2734− # see if there's firmware timing data to be had
2735− t = sysvals.postresumetime
2736− if(t > 0):
2737− print('Waiting %d seconds for POST-RESUME trace events...' % t)
2738− time.sleep(t)
2739− # stop ftrace
2740− if(sysvals.usecallgraph or sysvals.usetraceevents):
2741− os.system('echo 0 > '+tp+'tracing_on')
2742− print('CAPTURING TRACE')
2743− writeDatafileHeader(sysvals.ftracefile)
2744− os.system('cat '+tp+'trace >> '+sysvals.ftracefile)
2745− os.system('echo "" > '+tp+'trace')
2746− # grab a copy of the dmesg output
2747− print('CAPTURING DMESG')
2748− writeDatafileHeader(sysvals.dmesgfile)
2749− os.system('dmesg -c >> '+sysvals.dmesgfile)
2750−
2751−def writeDatafileHeader(filename):
3785+ sysvals.fsetVal('RESUME COMPLETE', 'trace_marker')
3786+ if(sysvals.suspendmode == 'mem'):
3787+ fwdata.append(getFPDT(False))
3788+ # look for post resume events after the last test run
3789+ t = sysvals.postresumetime
3790+ if(t > 0):
3791+ print('Waiting %d seconds for POST-RESUME trace events...' % t)
3792+ time.sleep(t)
3793+ # stop ftrace
3794+ if(sysvals.usecallgraph or sysvals.usetraceevents):
3795+ sysvals.fsetVal('0', 'tracing_on')
3796+ print('CAPTURING TRACE')
3797+ writeDatafileHeader(sysvals.ftracefile, fwdata)
3798+ os.system('cat '+tp+'trace >> '+sysvals.ftracefile)
3799+ sysvals.fsetVal('', 'trace')
3800+ devProps()
3801+ # grab a copy of the dmesg output
3802+ print('CAPTURING DMESG')
3803+ writeDatafileHeader(sysvals.dmesgfile, fwdata)
3804+ sysvals.getdmesg()
3805+
3806+def writeDatafileHeader(filename, fwdata):
27523807 global sysvals
27533808
2754− fw = getFPDT(False)
27553809 prt = sysvals.postresumetime
27563810 fp = open(filename, 'a')
27573811 fp.write(sysvals.teststamp+'\n')
2758− if(fw):
2759− fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1]))
3812+ if(sysvals.suspendmode == 'mem'):
3813+ for fw in fwdata:
3814+ if(fw):
3815+ fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1]))
27603816 if(prt > 0):
27613817 fp.write('# post resume time %u\n' % prt)
27623818 fp.close()
27633819
2764−# Function: executeAndroidSuspend
2765−# Description:
2766−# Execute system suspend through the sysfs interface
2767−# on a remote android device, then transfer the output
2768−# dmesg and ftrace files to the local output directory.
2769−def executeAndroidSuspend():
2770− global sysvals
2771−
2772− # check to see if the display is currently off
2773− tp = sysvals.tpath
2774− out = os.popen(sysvals.adb+\
2775− ' shell dumpsys power | grep mScreenOn').read().strip()
2776− # if so we need to turn it on so we can issue a new suspend
2777− if(out.endswith('false')):
2778− print('Waking the device up for the test...')
2779− # send the KEYPAD_POWER keyevent to wake it up
2780− os.system(sysvals.adb+' shell input keyevent 26')
2781− # wait a few seconds so the user can see the device wake up
2782− time.sleep(3)
2783− # execute however many s/r runs requested
2784− for count in range(1,sysvals.execcount+1):
2785− # clear the kernel ring buffer just as we start
2786− os.system(sysvals.adb+' shell dmesg -c > /dev/null 2>&1')
2787− # start ftrace
2788− if(sysvals.usetraceevents):
2789− print('START TRACING')
2790− os.system(sysvals.adb+" shell 'echo 1 > "+tp+"tracing_on'")
2791− # initiate suspend
2792− for count in range(1,sysvals.execcount+1):
2793− if(sysvals.usetraceevents):
2794− os.system(sysvals.adb+\
2795− " shell 'echo SUSPEND START > "+tp+"trace_marker'")
2796− print('SUSPEND START (press a key on the device to resume)')
2797− os.system(sysvals.adb+" shell 'echo "+sysvals.suspendmode+\
2798− " > "+sysvals.powerfile+"'")
2799− # execution will pause here, then adb will exit
2800− while(True):
2801− check = os.popen(sysvals.adb+\
2802− ' shell pwd 2>/dev/null').read().strip()
2803− if(len(check) > 0):
2804− break
2805− time.sleep(1)
2806− if(sysvals.usetraceevents):
2807− os.system(sysvals.adb+" shell 'echo RESUME COMPLETE > "+tp+\
2808− "trace_marker'")
2809− # return from suspend
2810− print('RESUME COMPLETE')
2811− # stop ftrace
2812− if(sysvals.usetraceevents):
2813− os.system(sysvals.adb+" shell 'echo 0 > "+tp+"tracing_on'")
2814− print('CAPTURING TRACE')
2815− os.system('echo "'+sysvals.teststamp+'" > '+sysvals.ftracefile)
2816− os.system(sysvals.adb+' shell cat '+tp+\
2817− 'trace >> '+sysvals.ftracefile)
2818− # grab a copy of the dmesg output
2819− print('CAPTURING DMESG')
2820− os.system('echo "'+sysvals.teststamp+'" > '+sysvals.dmesgfile)
2821− os.system(sysvals.adb+' shell dmesg >> '+sysvals.dmesgfile)
2822−
28233820 # Function: setUSBDevicesAuto
28243821 # Description:
28253822 # Set the autosuspend control parameter of all USB devices to auto
@@ -2829,7 +3826,7 @@ def executeAndroidSuspend(): · 3 unmodified lines
28293826 def setUSBDevicesAuto():
28303827 global sysvals
28313828
2832− rootCheck()
3829+ rootCheck(True)
28333830 for dirname, dirnames, filenames in os.walk('/sys/devices'):
28343831 if(re.match('.*/usb[0-9]*.*', dirname) and
28353832 'idVendor' in filenames and 'idProduct' in filenames):
@@ -2874,9 +3871,7 @@ def ms2nice(val): · 38 unmodified lines
28743871 # Description:
28753872 # Detect all the USB hosts and devices currently connected and add
28763873 # a list of USB device names to sysvals for better timeline readability
2877−# Arguments:
2878−# output: True to output the info to stdout, False otherwise
2879−def detectUSB(output):
3874+def detectUSB():
28803875 global sysvals
28813876
28823877 field = {'idVendor':'', 'idProduct':'', 'product':'', 'speed':''}
@@ -2887,18 +3882,18 @@ def detectUSB(output): · 4 unmodified lines
28873882 'runtime_suspended_time':'',
28883883 'active_duration':'',
28893884 'connected_duration':''}
2890− if(output):
2891− print('LEGEND')
2892− print('---------------------------------------------------------------------------------------------')
2893− print(' A = async/sync PM queue Y/N D = autosuspend delay (seconds)')
2894− print(' S = autosuspend Y/N rACTIVE = runtime active (min/sec)')
2895− print(' P = persist across suspend Y/N rSUSPEN = runtime suspend (min/sec)')
2896− print(' E = runtime suspend enabled/forbidden Y/N ACTIVE = active duration (min/sec)')
2897− print(' R = runtime status active/suspended Y/N CONNECT = connected duration (min/sec)')
2898− print(' U = runtime usage count')
2899− print('---------------------------------------------------------------------------------------------')
2900− print(' NAME ID DESCRIPTION SPEED A S P E R U D rACTIVE rSUSPEN ACTIVE CONNECT')
2901− print('---------------------------------------------------------------------------------------------')
3885+
3886+ print('LEGEND')
3887+ print('---------------------------------------------------------------------------------------------')
3888+ print(' A = async/sync PM queue Y/N D = autosuspend delay (seconds)')
3889+ print(' S = autosuspend Y/N rACTIVE = runtime active (min/sec)')
3890+ print(' P = persist across suspend Y/N rSUSPEN = runtime suspend (min/sec)')
3891+ print(' E = runtime suspend enabled/forbidden Y/N ACTIVE = active duration (min/sec)')
3892+ print(' R = runtime status active/suspended Y/N CONNECT = connected duration (min/sec)')
3893+ print(' U = runtime usage count')
3894+ print('---------------------------------------------------------------------------------------------')
3895+ print(' NAME ID DESCRIPTION SPEED A S P E R U D rACTIVE rSUSPEN ACTIVE CONNECT')
3896+ print('---------------------------------------------------------------------------------------------')
29023897
29033898 for dirname, dirnames, filenames in os.walk('/sys/devices'):
29043899 if(re.match('.*/usb[0-9]*.*', dirname) and
@@ -2907,35 +3902,149 @@ def detectUSB(output): · 2 unmodified lines
29073902 field[i] = os.popen('cat %s/%s 2>/dev/null' % \
29083903 (dirname, i)).read().replace('\n', '')
29093904 name = dirname.split('/')[-1]
2910− if(len(field['product']) > 0):
2911− sysvals.altdevname[name] = \
2912− '%s [%s]' % (field['product'], name)
3905+ for i in power:
3906+ power[i] = os.popen('cat %s/power/%s 2>/dev/null' % \
3907+ (dirname, i)).read().replace('\n', '')
3908+ if(re.match('usb[0-9]*', name)):
3909+ first = '%-8s' % name
29133910 else:
2914− sysvals.altdevname[name] = \
2915− '%s:%s [%s]' % (field['idVendor'], \
2916− field['idProduct'], name)
2917− if(output):
2918− for i in power:
2919− power[i] = os.popen('cat %s/power/%s 2>/dev/null' % \
2920− (dirname, i)).read().replace('\n', '')
2921− if(re.match('usb[0-9]*', name)):
2922− first = '%-8s' % name
2923− else:
2924− first = '%8s' % name
2925− print('%s [%s:%s] %-20s %-4s %1s %1s %1s %1s %1s %1s %1s %s %s %s %s' % \
2926− (first, field['idVendor'], field['idProduct'], \
2927− field['product'][0:20], field['speed'], \
2928− yesno(power['async']), \
2929− yesno(power['control']), \
2930− yesno(power['persist']), \
2931− yesno(power['runtime_enabled']), \
2932− yesno(power['runtime_status']), \
2933− power['runtime_usage'], \
2934− power['autosuspend'], \
2935− ms2nice(power['runtime_active_time']), \
2936− ms2nice(power['runtime_suspended_time']), \
2937− ms2nice(power['active_duration']), \
2938− ms2nice(power['connected_duration'])))
3911+ first = '%8s' % name
3912+ print('%s [%s:%s] %-20s %-4s %1s %1s %1s %1s %1s %1s %1s %s %s %s %s' % \
3913+ (first, field['idVendor'], field['idProduct'], \
3914+ field['product'][0:20], field['speed'], \
3915+ yesno(power['async']), \
3916+ yesno(power['control']), \
3917+ yesno(power['persist']), \
3918+ yesno(power['runtime_enabled']), \
3919+ yesno(power['runtime_status']), \
3920+ power['runtime_usage'], \
3921+ power['autosuspend'], \
3922+ ms2nice(power['runtime_active_time']), \
3923+ ms2nice(power['runtime_suspended_time']), \
3924+ ms2nice(power['active_duration']), \
3925+ ms2nice(power['connected_duration'])))
3926+
3927+# Function: devProps
3928+# Description:
3929+# Retrieve a list of properties for all devices in the trace log
3930+def devProps(data=0):
3931+ global sysvals
3932+ props = dict()
3933+
3934+ if data:
3935+ idx = data.index(': ') + 2
3936+ if idx >= len(data):
3937+ return
3938+ devlist = data[idx:].split(';')
3939+ for dev in devlist:
3940+ f = dev.split(',')
3941+ if len(f) < 3:
3942+ continue
3943+ dev = f[0]
3944+ props[dev] = DevProps()
3945+ props[dev].altname = f[1]
3946+ if int(f[2]):
3947+ props[dev].async = True
3948+ else:
3949+ props[dev].async = False
3950+ sysvals.devprops = props
3951+ if sysvals.suspendmode == 'command' and 'testcommandstring' in props:
3952+ sysvals.testcommand = props['testcommandstring'].altname
3953+ return
3954+
3955+ if(os.path.exists(sysvals.ftracefile) == False):
3956+ doError('%s does not exist' % sysvals.ftracefile, False)
3957+
3958+ # first get the list of devices we need properties for
3959+ msghead = 'Additional data added by AnalyzeSuspend'
3960+ alreadystamped = False
3961+ tp = TestProps()
3962+ tf = open(sysvals.ftracefile, 'r')
3963+ for line in tf:
3964+ if msghead in line:
3965+ alreadystamped = True
3966+ continue
3967+ # determine the trace data type (required for further parsing)
3968+ m = re.match(sysvals.tracertypefmt, line)
3969+ if(m):
3970+ tp.setTracerType(m.group('t'))
3971+ continue
3972+ # parse only valid lines, if this is not one move on
3973+ m = re.match(tp.ftrace_line_fmt, line)
3974+ if(not m or 'device_pm_callback_start' not in line):
3975+ continue
3976+ m = re.match('.*: (?P<drv>.*) (?P<d>.*), parent: *(?P<p>.*), .*', m.group('msg'));
3977+ if(not m):
3978+ continue
3979+ drv, dev, par = m.group('drv'), m.group('d'), m.group('p')
3980+ if dev not in props:
3981+ props[dev] = DevProps()
3982+ tf.close()
3983+
3984+ if not alreadystamped and sysvals.suspendmode == 'command':
3985+ out = '#\n# '+msghead+'\n# Device Properties: '
3986+ out += 'testcommandstring,%s,0;' % (sysvals.testcommand)
3987+ with open(sysvals.ftracefile, 'a') as fp:
3988+ fp.write(out+'\n')
3989+ sysvals.devprops = props
3990+ return
3991+
3992+ # now get the syspath for each of our target devices
3993+ for dirname, dirnames, filenames in os.walk('/sys/devices'):
3994+ if(re.match('.*/power', dirname) and 'async' in filenames):
3995+ dev = dirname.split('/')[-2]
3996+ if dev in props and (not props[dev].syspath or len(dirname) < len(props[dev].syspath)):
3997+ props[dev].syspath = dirname[:-6]
3998+
3999+ # now fill in the properties for our target devices
4000+ for dev in props:
4001+ dirname = props[dev].syspath
4002+ if not dirname or not os.path.exists(dirname):
4003+ continue
4004+ with open(dirname+'/power/async') as fp:
4005+ text = fp.read()
4006+ props[dev].async = False
4007+ if 'enabled' in text:
4008+ props[dev].async = True
4009+ fields = os.listdir(dirname)
4010+ if 'product' in fields:
4011+ with open(dirname+'/product') as fp:
4012+ props[dev].altname = fp.read()
4013+ elif 'name' in fields:
4014+ with open(dirname+'/name') as fp:
4015+ props[dev].altname = fp.read()
4016+ elif 'model' in fields:
4017+ with open(dirname+'/model') as fp:
4018+ props[dev].altname = fp.read()
4019+ elif 'description' in fields:
4020+ with open(dirname+'/description') as fp:
4021+ props[dev].altname = fp.read()
4022+ elif 'id' in fields:
4023+ with open(dirname+'/id') as fp:
4024+ props[dev].altname = fp.read()
4025+ elif 'idVendor' in fields and 'idProduct' in fields:
4026+ idv, idp = '', ''
4027+ with open(dirname+'/idVendor') as fp:
4028+ idv = fp.read().strip()
4029+ with open(dirname+'/idProduct') as fp:
4030+ idp = fp.read().strip()
4031+ props[dev].altname = '%s:%s' % (idv, idp)
4032+
4033+ if props[dev].altname:
4034+ out = props[dev].altname.strip().replace('\n', ' ')
4035+ out = out.replace(',', ' ')
4036+ out = out.replace(';', ' ')
4037+ props[dev].altname = out
4038+
4039+ # and now write the data to the ftrace file
4040+ if not alreadystamped:
4041+ out = '#\n# '+msghead+'\n# Device Properties: '
4042+ for dev in sorted(props):
4043+ out += props[dev].out(dev)
4044+ with open(sysvals.ftracefile, 'a') as fp:
4045+ fp.write(out+'\n')
4046+
4047+ sysvals.devprops = props
29394048
29404049 # Function: getModes
29414050 # Description:
@@ -2945,15 +4054,10 @@ def detectUSB(output): · 3 unmodified lines
29454054 def getModes():
29464055 global sysvals
29474056 modes = ''
2948− if(not sysvals.android):
2949− if(os.path.exists(sysvals.powerfile)):
2950− fp = open(sysvals.powerfile, 'r')
2951− modes = string.split(fp.read())
2952− fp.close()
2953− else:
2954− line = os.popen(sysvals.adb+' shell cat '+\
2955− sysvals.powerfile).read().strip()
2956− modes = string.split(line)
4057+ if(os.path.exists(sysvals.powerfile)):
4058+ fp = open(sysvals.powerfile, 'r')
4059+ modes = string.split(fp.read())
4060+ fp.close()
29574061 return modes
29584062
29594063 # Function: getFPDT
@@ -2971,22 +4075,22 @@ def getFPDT(output): · 11 unmodified lines
29714075 prectype[0] = 'Basic S3 Resume Performance Record'
29724076 prectype[1] = 'Basic S3 Suspend Performance Record'
29734077
2974− rootCheck()
4078+ rootCheck(True)
29754079 if(not os.path.exists(sysvals.fpdtpath)):
29764080 if(output):
2977− doError('file doesnt exist: %s' % sysvals.fpdtpath, False)
4081+ doError('file does not exist: %s' % sysvals.fpdtpath, False)
29784082 return False
29794083 if(not os.access(sysvals.fpdtpath, os.R_OK)):
29804084 if(output):
2981− doError('file isnt readable: %s' % sysvals.fpdtpath, False)
4085+ doError('file is not readable: %s' % sysvals.fpdtpath, False)
29824086 return False
29834087 if(not os.path.exists(sysvals.mempath)):
29844088 if(output):
2985− doError('file doesnt exist: %s' % sysvals.mempath, False)
4089+ doError('file does not exist: %s' % sysvals.mempath, False)
29864090 return False
29874091 if(not os.access(sysvals.mempath, os.R_OK)):
29884092 if(output):
2989− doError('file isnt readable: %s' % sysvals.mempath, False)
4093+ doError('file is not readable: %s' % sysvals.mempath, False)
29904094 return False
29914095
29924096 fp = open(sysvals.fpdtpath, 'rb')
@@ -3027,15 +4131,19 @@ def getFPDT(output): · 34 unmodified lines
30274131 while(i < len(records)):
30284132 header = struct.unpack('HBB', records[i:i+4])
30294133 if(header[0] not in rectype):
4134+ i += header[1]
30304135 continue
30314136 if(header[1] != 16):
4137+ i += header[1]
30324138 continue
30334139 addr = struct.unpack('Q', records[i+8:i+16])[0]
30344140 try:
30354141 fp.seek(addr)
30364142 first = fp.read(8)
30374143 except:
3038− doError('Bad address 0x%x in %s' % (addr, sysvals.mempath), False)
4144+ if(output):
4145+ print('Bad address 0x%x in %s' % (addr, sysvals.mempath))
4146+ return [0, 0]
30394147 rechead = struct.unpack('4sI', first)
30404148 recdata = fp.read(rechead[1]-8)
30414149 if(rechead[0] == 'FBPT'):
@@ -3090,89 +4198,60 @@ def getFPDT(output): · 48 unmodified lines
30904198 # print the results to the terminal
30914199 # Output:
30924200 # True if the test will work, False if not
3093−def statusCheck():
4201+def statusCheck(probecheck=False):
30944202 global sysvals
30954203 status = True
30964204
3097− if(sysvals.android):
3098− print('Checking the android system ...')
3099− else:
3100− print('Checking this system (%s)...' % platform.node())
3101−
3102− # check if adb is connected to a device
3103− if(sysvals.android):
3104− res = 'NO'
3105− out = os.popen(sysvals.adb+' get-state').read().strip()
3106− if(out == 'device'):
3107− res = 'YES'
3108− print(' is android device connected: %s' % res)
3109− if(res != 'YES'):
3110− print(' Please connect the device before using this tool')
3111− return False
4205+ print('Checking this system (%s)...' % platform.node())
31124206
31134207 # check we have root access
3114− res = 'NO (No features of this tool will work!)'
3115− if(sysvals.android):
3116− out = os.popen(sysvals.adb+' shell id').read().strip()
3117− if('root' in out):
3118− res = 'YES'
3119− else:
3120− if(os.environ['USER'] == 'root'):
3121− res = 'YES'
4208+ res = sysvals.colorText('NO (No features of this tool will work!)')
4209+ if(rootCheck(False)):
4210+ res = 'YES'
31224211 print(' have root access: %s' % res)
31234212 if(res != 'YES'):
3124− if(sysvals.android):
3125− print(' Try running "adb root" to restart the daemon as root')
3126− else:
3127− print(' Try running this script with sudo')
4213+ print(' Try running this script with sudo')
31284214 return False
31294215
31304216 # check sysfs is mounted
3131− res = 'NO (No features of this tool will work!)'
3132− if(sysvals.android):
3133− out = os.popen(sysvals.adb+' shell ls '+\
3134− sysvals.powerfile).read().strip()
3135− if(out == sysvals.powerfile):
3136− res = 'YES'
3137− else:
3138− if(os.path.exists(sysvals.powerfile)):
3139− res = 'YES'
4217+ res = sysvals.colorText('NO (No features of this tool will work!)')
4218+ if(os.path.exists(sysvals.powerfile)):
4219+ res = 'YES'
31404220 print(' is sysfs mounted: %s' % res)
31414221 if(res != 'YES'):
31424222 return False
31434223
31444224 # check target mode is a valid mode
3145− res = 'NO'
3146− modes = getModes()
3147− if(sysvals.suspendmode in modes):
3148− res = 'YES'
3149− else:
3150− status = False
3151− print(' is "%s" a valid power mode: %s' % (sysvals.suspendmode, res))
3152− if(res == 'NO'):
3153− print(' valid power modes are: %s' % modes)
3154− print(' please choose one with -m')
3155−
3156− # check if the tool can unlock the device
3157− if(sysvals.android):
3158− res = 'YES'
3159− out1 = os.popen(sysvals.adb+\
3160− ' shell dumpsys power | grep mScreenOn').read().strip()
3161− out2 = os.popen(sysvals.adb+\
3162− ' shell input').read().strip()
3163− if(not out1.startswith('mScreenOn') or not out2.startswith('usage')):
3164− res = 'NO (wake the android device up before running the test)'
3165− print(' can I unlock the screen: %s' % res)
4225+ if sysvals.suspendmode != 'command':
4226+ res = sysvals.colorText('NO')
4227+ modes = getModes()
4228+ if(sysvals.suspendmode in modes):
4229+ res = 'YES'
4230+ else:
4231+ status = False
4232+ print(' is "%s" a valid power mode: %s' % (sysvals.suspendmode, res))
4233+ if(res == 'NO'):
4234+ print(' valid power modes are: %s' % modes)
4235+ print(' please choose one with -m')
31664236
31674237 # check if ftrace is available
3168− res = 'NO'
3169− ftgood = verifyFtrace()
4238+ res = sysvals.colorText('NO')
4239+ ftgood = sysvals.verifyFtrace()
31704240 if(ftgood):
31714241 res = 'YES'
31724242 elif(sysvals.usecallgraph):
31734243 status = False
31744244 print(' is ftrace supported: %s' % res)
31754245
4246+ # check if kprobes are available
4247+ res = sysvals.colorText('NO')
4248+ sysvals.usekprobes = sysvals.verifyKprobes()
4249+ if(sysvals.usekprobes):
4250+ res = 'YES'
4251+ else:
4252+ sysvals.usedevsrc = False
4253+ print(' are kprobes supported: %s' % res)
4254+
31764255 # what data source are we using
31774256 res = 'DMESG'
31784257 if(ftgood):
@@ -3180,14 +4259,8 @@ def statusCheck(): · 1 unmodified line
31804259 sysvals.usetraceevents = False
31814260 for e in sysvals.traceevents:
31824261 check = False
3183− if(sysvals.android):
3184− out = os.popen(sysvals.adb+' shell ls -d '+\
3185− sysvals.epath+e).read().strip()
3186− if(out == sysvals.epath+e):
3187− check = True
3188− else:
3189− if(os.path.exists(sysvals.epath+e)):
3190− check = True
4262+ if(os.path.exists(sysvals.epath+e)):
4263+ check = True
31914264 if(not check):
31924265 sysvals.usetraceeventsonly = False
31934266 if(e == 'suspend_resume' and check):
@@ -3199,13 +4272,48 @@ def statusCheck(): · 5 unmodified lines
31994272 print(' timeline data source: %s' % res)
32004273
32014274 # check if rtcwake
3202− res = 'NO'
4275+ res = sysvals.colorText('NO')
32034276 if(sysvals.rtcpath != ''):
32044277 res = 'YES'
32054278 elif(sysvals.rtcwake):
32064279 status = False
32074280 print(' is rtcwake supported: %s' % res)
32084281
4282+ if not probecheck:
4283+ return status
4284+
4285+ if (sysvals.usecallgraph and len(sysvals.debugfuncs) > 0) or len(sysvals.kprobes) > 0:
4286+ sysvals.initFtrace(True)
4287+
4288+ # verify callgraph debugfuncs
4289+ if sysvals.usecallgraph and len(sysvals.debugfuncs) > 0:
4290+ print(' verifying these ftrace callgraph functions work:')
4291+ sysvals.setFtraceFilterFunctions(sysvals.debugfuncs)
4292+ fp = open(sysvals.tpath+'set_graph_function', 'r')
4293+ flist = fp.read().split('\n')
4294+ fp.close()
4295+ for func in sysvals.debugfuncs:
4296+ res = sysvals.colorText('NO')
4297+ if func in flist:
4298+ res = 'YES'
4299+ else:
4300+ for i in flist:
4301+ if ' [' in i and func == i.split(' ')[0]:
4302+ res = 'YES'
4303+ break
4304+ print(' %s: %s' % (func, res))
4305+
4306+ # verify kprobes
4307+ if len(sysvals.kprobes) > 0:
4308+ print(' verifying these kprobes work:')
4309+ for name in sorted(sysvals.kprobes):
4310+ if name in sysvals.tracefuncs:
4311+ continue
4312+ res = sysvals.colorText('NO')
4313+ if sysvals.testKprobe(sysvals.kprobes[name]):
4314+ res = 'YES'
4315+ print(' %s: %s' % (name, res))
4316+
32094317 return status
32104318
32114319 # Function: doError
@@ -3226,7 +4334,7 @@ def doError(msg, help): · 14 unmodified lines
32264334 # Arguments:
32274335 # msg: the warning message to print
32284336 # file: If not empty, a filename to request be sent to the owner for debug
3229−def doWarning(msg, file):
4337+def doWarning(msg, file=''):
32304338 print('/* %s */') % msg
32314339 if(file):
32324340 print('/* For a fix, please send this'+\
@@ -3235,18 +4343,25 @@ def doWarning(msg, file): · 2 unmodified lines
32354343 # Function: rootCheck
32364344 # Description:
32374345 # quick check to see if we have root access
3238−def rootCheck():
3239− if(os.environ['USER'] != 'root'):
3240− doError('This script must be run as root', False)
4346+def rootCheck(fatal):
4347+ global sysvals
4348+ if(os.access(sysvals.powerfile, os.W_OK)):
4349+ return True
4350+ if fatal:
4351+ doError('This command must be run as root', False)
4352+ return False
32414353
32424354 # Function: getArgInt
32434355 # Description:
32444356 # pull out an integer argument from the command line with checks
3245−def getArgInt(name, args, min, max):
3246− try:
3247− arg = args.next()
3248− except:
3249− doError(name+': no argument supplied', True)
4357+def getArgInt(name, args, min, max, main=True):
4358+ if main:
4359+ try:
4360+ arg = args.next()
4361+ except:
4362+ doError(name+': no argument supplied', True)
4363+ else:
4364+ arg = args
32504365 try:
32514366 val = int(arg)
32524367 except:
@@ -3255,6 +4370,25 @@ def getArgInt(name, args, min, max): · 2 unmodified lines
32554370 doError(name+': value should be between %d and %d' % (min, max), True)
32564371 return val
32574372
4373+# Function: getArgFloat
4374+# Description:
4375+# pull out a float argument from the command line with checks
4376+def getArgFloat(name, args, min, max, main=True):
4377+ if main:
4378+ try:
4379+ arg = args.next()
4380+ except:
4381+ doError(name+': no argument supplied', True)
4382+ else:
4383+ arg = args
4384+ try:
4385+ val = float(arg)
4386+ except:
4387+ doError(name+': non-numerical value given', True)
4388+ if(val < min or val > max):
4389+ doError(name+': value should be between %f and %f' % (min, max), True)
4390+ return val
4391+
32584392 # Function: rerunTest
32594393 # Description:
32604394 # generate an output from an existing set of ftrace/dmesg logs
@@ -3282,15 +4416,12 @@ def rerunTest(): · 21 unmodified lines
32824416 # Function: runTest
32834417 # Description:
32844418 # execute a suspend/resume, gather the logs, and generate the output
3285−def runTest(subdir):
4419+def runTest(subdir, testpath=''):
32864420 global sysvals
32874421
32884422 # prepare for the test
3289− if(not sysvals.android):
3290− initFtrace()
3291− else:
3292− initFtraceAndroid()
3293− sysvals.initTestOutput(subdir)
4423+ sysvals.initFtrace()
4424+ sysvals.initTestOutput(subdir, testpath)
32944425
32954426 vprint('Output files:\n %s' % sysvals.dmesgfile)
32964427 if(sysvals.usecallgraph or
@@ -3300,10 +4431,8 @@ def runTest(subdir): · 3 unmodified lines
33004431 vprint(' %s' % sysvals.htmlfile)
33014432
33024433 # execute the test
3303− if(not sysvals.android):
3304− executeSuspend()
3305− else:
3306− executeAndroidSuspend()
4434+ executeSuspend()
4435+ sysvals.cleanupFtrace()
33074436
33084437 # analyze the data and create the html output
33094438 print('PROCESSING DATA')
@@ -3367,6 +4496,153 @@ def runSummary(subdir, output): · 57 unmodified lines
33674496
33684497 createHTMLSummarySimple(testruns, subdir+'/summary.html')
33694498
4499+# Function: checkArgBool
4500+# Description:
4501+# check if a boolean string value is true or false
4502+def checkArgBool(value):
4503+ yes = ['1', 'true', 'yes', 'on']
4504+ if value.lower() in yes:
4505+ return True
4506+ return False
4507+
4508+# Function: configFromFile
4509+# Description:
4510+# Configure the script via the info in a config file
4511+def configFromFile(file):
4512+ global sysvals
4513+ Config = ConfigParser.ConfigParser()
4514+
4515+ ignorekprobes = False
4516+ Config.read(file)
4517+ sections = Config.sections()
4518+ if 'Settings' in sections:
4519+ for opt in Config.options('Settings'):
4520+ value = Config.get('Settings', opt).lower()
4521+ if(opt.lower() == 'verbose'):
4522+ sysvals.verbose = checkArgBool(value)
4523+ elif(opt.lower() == 'addlogs'):
4524+ sysvals.addlogs = checkArgBool(value)
4525+ elif(opt.lower() == 'dev'):
4526+ sysvals.usedevsrc = checkArgBool(value)
4527+ elif(opt.lower() == 'ignorekprobes'):
4528+ ignorekprobes = checkArgBool(value)
4529+ elif(opt.lower() == 'x2'):
4530+ if checkArgBool(value):
4531+ sysvals.execcount = 2
4532+ elif(opt.lower() == 'callgraph'):
4533+ sysvals.usecallgraph = checkArgBool(value)
4534+ elif(opt.lower() == 'callgraphfunc'):
4535+ sysvals.debugfuncs = []
4536+ if value:
4537+ value = value.split(',')
4538+ for i in value:
4539+ sysvals.debugfuncs.append(i.strip())
4540+ elif(opt.lower() == 'expandcg'):
4541+ sysvals.cgexp = checkArgBool(value)
4542+ elif(opt.lower() == 'srgap'):
4543+ if checkArgBool(value):
4544+ sysvals.srgap = 5
4545+ elif(opt.lower() == 'mode'):
4546+ sysvals.suspendmode = value
4547+ elif(opt.lower() == 'command'):
4548+ sysvals.testcommand = value
4549+ elif(opt.lower() == 'x2delay'):
4550+ sysvals.x2delay = getArgInt('-x2delay', value, 0, 60000, False)
4551+ elif(opt.lower() == 'postres'):
4552+ sysvals.postresumetime = getArgInt('-postres', value, 0, 3600, False)
4553+ elif(opt.lower() == 'rtcwake'):
4554+ sysvals.rtcwake = True
4555+ sysvals.rtcwaketime = getArgInt('-rtcwake', value, 0, 3600, False)
4556+ elif(opt.lower() == 'timeprec'):
4557+ sysvals.setPrecision(getArgInt('-timeprec', value, 0, 6, False))
4558+ elif(opt.lower() == 'mindev'):
4559+ sysvals.mindevlen = getArgFloat('-mindev', value, 0.0, 10000.0, False)
4560+ elif(opt.lower() == 'mincg'):
4561+ sysvals.mincglen = getArgFloat('-mincg', value, 0.0, 10000.0, False)
4562+ elif(opt.lower() == 'kprobecolor'):
4563+ try:
4564+ val = int(value, 16)
4565+ sysvals.kprobecolor = '#'+value
4566+ except:
4567+ sysvals.kprobecolor = value
4568+ elif(opt.lower() == 'synccolor'):
4569+ try:
4570+ val = int(value, 16)
4571+ sysvals.synccolor = '#'+value
4572+ except:
4573+ sysvals.synccolor = value
4574+ elif(opt.lower() == 'output-dir'):
4575+ args = dict()
4576+ n = datetime.now()
4577+ args['date'] = n.strftime('%y%m%d')
4578+ args['time'] = n.strftime('%H%M%S')
4579+ args['hostname'] = sysvals.hostname
4580+ sysvals.outdir = value.format(**args)
4581+
4582+ if sysvals.suspendmode == 'command' and not sysvals.testcommand:
4583+ doError('No command supplied for mode "command"', False)
4584+ if sysvals.usedevsrc and sysvals.usecallgraph:
4585+ doError('dev and callgraph cannot both be true', False)
4586+ if sysvals.usecallgraph and sysvals.execcount > 1:
4587+ doError('-x2 is not compatible with -f', False)
4588+
4589+ if ignorekprobes:
4590+ return
4591+
4592+ kprobes = dict()
4593+ archkprobe = 'Kprobe_'+platform.machine()
4594+ if archkprobe in sections:
4595+ for name in Config.options(archkprobe):
4596+ kprobes[name] = Config.get(archkprobe, name)
4597+ if 'Kprobe' in sections:
4598+ for name in Config.options('Kprobe'):
4599+ kprobes[name] = Config.get('Kprobe', name)
4600+
4601+ for name in kprobes:
4602+ function = name
4603+ format = name
4604+ color = ''
4605+ args = dict()
4606+ data = kprobes[name].split()
4607+ i = 0
4608+ for val in data:
4609+ # bracketted strings are special formatting, read them separately
4610+ if val[0] == '[' and val[-1] == ']':
4611+ for prop in val[1:-1].split(','):
4612+ p = prop.split('=')
4613+ if p[0] == 'color':
4614+ try:
4615+ color = int(p[1], 16)
4616+ color = '#'+p[1]
4617+ except:
4618+ color = p[1]
4619+ continue
4620+ # first real arg should be the format string
4621+ if i == 0:
4622+ format = val
4623+ # all other args are actual function args
4624+ else:
4625+ d = val.split('=')
4626+ args[d[0]] = d[1]
4627+ i += 1
4628+ if not function or not format:
4629+ doError('Invalid kprobe: %s' % name, False)
4630+ for arg in re.findall('{(?P<n>[a-z,A-Z,0-9]*)}', format):
4631+ if arg not in args:
4632+ doError('Kprobe "%s" is missing argument "%s"' % (name, arg), False)
4633+ if name in sysvals.kprobes:
4634+ doError('Duplicate kprobe found "%s"' % (name), False)
4635+ vprint('Adding KPROBE: %s %s %s %s' % (name, function, format, args))
4636+ sysvals.kprobes[name] = {
4637+ 'name': name,
4638+ 'func': function,
4639+ 'format': format,
4640+ 'args': args,
4641+ 'mask': re.sub('{(?P<n>[a-z,A-Z,0-9]*)}', '.*', format)
4642+ }
4643+ if color:
4644+ sysvals.kprobes[name]['color'] = color
4645+
33704646 # Function: printHelp
33714647 # Description:
33724648 # print out the help text
@@ -3375,7 +4651,7 @@ def printHelp(): · 2 unmodified lines
33754651 modes = getModes()
33764652
33774653 print('')
3378− print('AnalyzeSuspend v%.1f' % sysvals.version)
4654+ print('AnalyzeSuspend v%s' % sysvals.version)
33794655 print('Usage: sudo analyze_suspend.py <options>')
33804656 print('')
33814657 print('Description:')
@@ -3396,27 +4672,38 @@ def printHelp(): · 14 unmodified lines
33964672 print(' [general]')
33974673 print(' -h Print this help text')
33984674 print(' -v Print the current tool version')
4675+ print(' -config file Pull arguments and config options from a file')
33994676 print(' -verbose Print extra information during execution and analysis')
34004677 print(' -status Test to see if the system is enabled to run this tool')
34014678 print(' -modes List available suspend modes')
34024679 print(' -m mode Mode to initiate for suspend %s (default: %s)') % (modes, sysvals.suspendmode)
3403− print(' -rtcwake t Use rtcwake to autoresume after <t> seconds (default: disabled)')
4680+ print(' -o subdir Override the output subdirectory')
34044681 print(' [advanced]')
4682+ print(' -rtcwake t Use rtcwake to autoresume after <t> seconds (default: disabled)')
4683+ print(' -addlogs Add the dmesg and ftrace logs to the html output')
4684+ print(' -multi n d Execute <n> consecutive tests at <d> seconds intervals. The outputs will')
4685+ print(' be created in a new subdirectory with a summary page.')
4686+ print(' -srgap Add a visible gap in the timeline between sus/res (default: disabled)')
4687+ print(' -cmd {s} Instead of suspend/resume, run a command, e.g. "sync -d"')
4688+ print(' -mindev ms Discard all device blocks shorter than ms milliseconds (e.g. 0.001 for us)')
4689+ print(' -mincg ms Discard all callgraphs shorter than ms milliseconds (e.g. 0.001 for us)')
4690+ print(' -timeprec N Number of significant digits in timestamps (0:S, [3:ms], 6:us)')
4691+ print(' [debug]')
34054692 print(' -f Use ftrace to create device callgraphs (default: disabled)')
3406− print(' -filter "d1 d2 ..." Filter out all but this list of dev names')
4693+ print(' -expandcg pre-expand the callgraph data in the html output (default: disabled)')
4694+ print(' -flist Print the list of functions currently being captured in ftrace')
4695+ print(' -flistall Print all functions capable of being captured in ftrace')
4696+ print(' -fadd file Add functions to be graphed in the timeline from a list in a text file')
4697+ print(' -filter "d1 d2 ..." Filter out all but this list of device names')
4698+ print(' -dev Display common low level functions in the timeline')
4699+ print(' [post-resume task analysis]')
34074700 print(' -x2 Run two suspend/resumes back to back (default: disabled)')
34084701 print(' -x2delay t Minimum millisecond delay <t> between the two test runs (default: 0 ms)')
34094702 print(' -postres t Time after resume completion to wait for post-resume events (default: 0 S)')
3410− print(' -multi n d Execute <n> consecutive tests at <d> seconds intervals. The outputs will')
3411− print(' be created in a new subdirectory with a summary page.')
34124703 print(' [utilities]')
34134704 print(' -fpdt Print out the contents of the ACPI Firmware Performance Data Table')
34144705 print(' -usbtopo Print out the current USB topology with power info')
34154706 print(' -usbauto Enable autosuspend for all connected USB devices')
3416− print(' [android testing]')
3417− print(' -adb binary Use the given adb binary to run the test on an android device.')
3418− print(' The device should already be connected and with root access.')
3419− print(' Commands will be executed on the device using "adb shell"')
34204707 print(' [re-analyze data from previous runs]')
34214708 print(' -ftrace ftracefile Create HTML output using ftrace input')
34224709 print(' -dmesg dmesgfile Create HTML output using dmesg (not needed for kernel >= 3.15)')
@@ -3430,6 +4717,7 @@ if __name__ == '__main__': · 7 unmodified lines
34304717 cmd = ''
34314718 cmdarg = ''
34324719 multitest = {'run': False, 'count': 0, 'delay': 0}
4720+ simplecmds = ['-modes', '-fpdt', '-flist', '-flistall', '-usbtopo', '-usbauto', '-status']
34334721 # loop through the command line arguments
34344722 args = iter(sys.argv[1:])
34354723 for arg in args:
@@ -3438,58 +4726,85 @@ if __name__ == '__main__': · 2 unmodified lines
34384726 val = args.next()
34394727 except:
34404728 doError('No mode supplied', True)
4729+ if val == 'command' and not sysvals.testcommand:
4730+ doError('No command supplied for mode "command"', True)
34414731 sysvals.suspendmode = val
3442− elif(arg == '-adb'):
3443− try:
3444− val = args.next()
3445− except:
3446− doError('No adb binary supplied', True)
3447− if(not os.path.exists(val)):
3448− doError('file doesnt exist: %s' % val, False)
3449− if(not os.access(val, os.X_OK)):
3450− doError('file isnt executable: %s' % val, False)
3451− try:
3452− check = os.popen(val+' version').read().strip()
3453− except:
3454− doError('adb version failed to execute', False)
3455− if(not re.match('Android Debug Bridge .*', check)):
3456− doError('adb version failed to execute', False)
3457− sysvals.adb = val
3458− sysvals.android = True
4732+ elif(arg in simplecmds):
4733+ cmd = arg[1:]
4734+ elif(arg == '-h'):
4735+ printHelp()
4736+ sys.exit()
4737+ elif(arg == '-v'):
4738+ print("Version %s" % sysvals.version)
4739+ sys.exit()
34594740 elif(arg == '-x2'):
3460− if(sysvals.postresumetime > 0):
3461− doError('-x2 is not compatible with -postres', False)
34624741 sysvals.execcount = 2
4742+ if(sysvals.usecallgraph):
4743+ doError('-x2 is not compatible with -f', False)
34634744 elif(arg == '-x2delay'):
34644745 sysvals.x2delay = getArgInt('-x2delay', args, 0, 60000)
34654746 elif(arg == '-postres'):
3466− if(sysvals.execcount != 1):
3467− doError('-x2 is not compatible with -postres', False)
34684747 sysvals.postresumetime = getArgInt('-postres', args, 0, 3600)
34694748 elif(arg == '-f'):
34704749 sysvals.usecallgraph = True
3471− elif(arg == '-modes'):
3472− cmd = 'modes'
3473− elif(arg == '-fpdt'):
3474− cmd = 'fpdt'
3475− elif(arg == '-usbtopo'):
3476− cmd = 'usbtopo'
3477− elif(arg == '-usbauto'):
3478− cmd = 'usbauto'
3479− elif(arg == '-status'):
3480− cmd = 'status'
4750+ if(sysvals.execcount > 1):
4751+ doError('-x2 is not compatible with -f', False)
4752+ if(sysvals.usedevsrc):
4753+ doError('-dev is not compatible with -f', False)
4754+ elif(arg == '-addlogs'):
4755+ sysvals.addlogs = True
34814756 elif(arg == '-verbose'):
34824757 sysvals.verbose = True
3483− elif(arg == '-v'):
3484− print("Version %.1f" % sysvals.version)
3485− sys.exit()
4758+ elif(arg == '-dev'):
4759+ sysvals.usedevsrc = True
4760+ if(sysvals.usecallgraph):
4761+ doError('-dev is not compatible with -f', False)
34864762 elif(arg == '-rtcwake'):
34874763 sysvals.rtcwake = True
34884764 sysvals.rtcwaketime = getArgInt('-rtcwake', args, 0, 3600)
4765+ elif(arg == '-timeprec'):
4766+ sysvals.setPrecision(getArgInt('-timeprec', args, 0, 6))
4767+ elif(arg == '-mindev'):
4768+ sysvals.mindevlen = getArgFloat('-mindev', args, 0.0, 10000.0)
4769+ elif(arg == '-mincg'):
4770+ sysvals.mincglen = getArgFloat('-mincg', args, 0.0, 10000.0)
4771+ elif(arg == '-cmd'):
4772+ try:
4773+ val = args.next()
4774+ except:
4775+ doError('No command string supplied', True)
4776+ sysvals.testcommand = val
4777+ sysvals.suspendmode = 'command'
4778+ elif(arg == '-expandcg'):
4779+ sysvals.cgexp = True
4780+ elif(arg == '-srgap'):
4781+ sysvals.srgap = 5
34894782 elif(arg == '-multi'):
34904783 multitest['run'] = True
34914784 multitest['count'] = getArgInt('-multi n (exec count)', args, 2, 1000000)
34924785 multitest['delay'] = getArgInt('-multi d (delay between tests)', args, 0, 3600)
4786+ elif(arg == '-o'):
4787+ try:
4788+ val = args.next()
4789+ except:
4790+ doError('No subdirectory name supplied', True)
4791+ sysvals.outdir = val
4792+ elif(arg == '-config'):
4793+ try:
4794+ val = args.next()
4795+ except:
4796+ doError('No text file supplied', True)
4797+ if(os.path.exists(val) == False):
4798+ doError('%s does not exist' % val, False)
4799+ configFromFile(val)
4800+ elif(arg == '-fadd'):
4801+ try:
4802+ val = args.next()
4803+ except:
4804+ doError('No text file supplied', True)
4805+ if(os.path.exists(val) == False):
4806+ doError('%s does not exist' % val, False)
4807+ sysvals.addFtraceFilterFunctions(val)
34934808 elif(arg == '-dmesg'):
34944809 try:
34954810 val = args.next()
@@ -3498,17 +4813,16 @@ if __name__ == '__main__': · 2 unmodified lines
34984813 sysvals.notestrun = True
34994814 sysvals.dmesgfile = val
35004815 if(os.path.exists(sysvals.dmesgfile) == False):
3501− doError('%s doesnt exist' % sysvals.dmesgfile, False)
4816+ doError('%s does not exist' % sysvals.dmesgfile, False)
35024817 elif(arg == '-ftrace'):
35034818 try:
35044819 val = args.next()
35054820 except:
35064821 doError('No ftrace file supplied', True)
35074822 sysvals.notestrun = True
3508− sysvals.usecallgraph = True
35094823 sysvals.ftracefile = val
35104824 if(os.path.exists(sysvals.ftracefile) == False):
3511− doError('%s doesnt exist' % sysvals.ftracefile, False)
4825+ doError('%s does not exist' % sysvals.ftracefile, False)
35124826 elif(arg == '-summary'):
35134827 try:
35144828 val = args.next()
@@ -3518,35 +4832,35 @@ if __name__ == '__main__': · 3 unmodified lines
35184832 cmdarg = val
35194833 sysvals.notestrun = True
35204834 if(os.path.isdir(val) == False):
3521− doError('%s isnt accesible' % val, False)
4835+ doError('%s is not accesible' % val, False)
35224836 elif(arg == '-filter'):
35234837 try:
35244838 val = args.next()
35254839 except:
35264840 doError('No devnames supplied', True)
35274841 sysvals.setDeviceFilter(val)
3528− elif(arg == '-h'):
3529− printHelp()
3530− sys.exit()
35314842 else:
35324843 doError('Invalid argument: '+arg, True)
35334844
4845+ # callgraph size cannot exceed device size
4846+ if sysvals.mincglen < sysvals.mindevlen:
4847+ sysvals.mincglen = sysvals.mindevlen
4848+
35344849 # just run a utility command and exit
35354850 if(cmd != ''):
35364851 if(cmd == 'status'):
3537− statusCheck()
4852+ statusCheck(True)
35384853 elif(cmd == 'fpdt'):
3539− if(sysvals.android):
3540− doError('cannot read FPDT on android device', False)
35414854 getFPDT(True)
35424855 elif(cmd == 'usbtopo'):
3543− if(sysvals.android):
3544− doError('cannot read USB topology '+\
3545− 'on an android device', False)
3546− detectUSB(True)
4856+ detectUSB()
35474857 elif(cmd == 'modes'):
35484858 modes = getModes()
35494859 print modes
4860+ elif(cmd == 'flist'):
4861+ sysvals.getFtraceFilterFunctions(True)
4862+ elif(cmd == 'flistall'):
4863+ sysvals.getFtraceFilterFunctions(False)
35504864 elif(cmd == 'usbauto'):
35514865 setUSBDevicesAuto()
35524866 elif(cmd == 'summary'):
@@ -3554,15 +4868,6 @@ if __name__ == '__main__': · 1 unmodified line
35544868 runSummary(cmdarg, True)
35554869 sys.exit()
35564870
3557− # run test on android device
3558− if(sysvals.android):
3559− if(sysvals.usecallgraph):
3560− doError('ftrace (-f) is not yet supported '+\
3561− 'in the android kernel', False)
3562− if(sysvals.notestrun):
3563− doError('cannot analyze test files on the '+\
3564− 'android device', False)
3565−
35664871 # if instructed, re-analyze existing data files
35674872 if(sysvals.notestrun):
35684873 rerunTest()
@@ -3574,18 +4879,20 @@ if __name__ == '__main__': · 5 unmodified lines
35744879 sys.exit()
35754880
35764881 if multitest['run']:
3577− # run multiple tests in a separte subdirectory
4882+ # run multiple tests in a separate subdirectory
35784883 s = 'x%d' % multitest['count']
3579− subdir = datetime.now().strftime('suspend-'+s+'-%m%d%y-%H%M%S')
3580− os.mkdir(subdir)
4884+ if not sysvals.outdir:
4885+ sysvals.outdir = datetime.now().strftime('suspend-'+s+'-%m%d%y-%H%M%S')
4886+ if not os.path.isdir(sysvals.outdir):
4887+ os.mkdir(sysvals.outdir)
35814888 for i in range(multitest['count']):
35824889 if(i != 0):
35834890 print('Waiting %d seconds...' % (multitest['delay']))
35844891 time.sleep(multitest['delay'])
35854892 print('TEST (%d/%d) START' % (i+1, multitest['count']))
3586− runTest(subdir)
4893+ runTest(sysvals.outdir)
35874894 print('TEST (%d/%d) COMPLETE' % (i+1, multitest['count']))
3588− runSummary(subdir, False)
4895+ runSummary(sysvals.outdir, False)
35894896 else:
35904897 # run the test in the current directory
3591− runTest(".")
4898+ runTest('.', sysvals.outdir)
tools/power/x86/turbostat/Makefile+2−2
@@ -1,7 +1,7 @@
11 CC = $(CROSS_COMPILE)gcc
22 BUILD_OUTPUT := $(CURDIR)
3−PREFIX := /usr
4−DESTDIR :=
3+PREFIX ?= /usr
4+DESTDIR ?=
55
66 ifeq ("$(origin O)", "command line")
77 BUILD_OUTPUT := $(O)
tools/power/x86/turbostat/turbostat.8+1−1
@@ -123,7 +123,7 @@ cpu0: MSR_NHM_PLATFORM_INFO: 0x80838f3012300 · 122 unmodified lines
123123 35 * 100 = 3500 MHz TSC frequency
124124 cpu0: MSR_IA32_POWER_CTL: 0x0004005d (C1E auto-promotion: DISabled)
125125 cpu0: MSR_NHM_SNB_PKG_CST_CFG_CTL: 0x1e000400 (UNdemote-C3, UNdemote-C1, demote-C3, demote-C1, UNlocked: pkg-cstate-limit=0: pc0)
126−cpu0: MSR_NHM_TURBO_RATIO_LIMIT: 0x25262727
126+cpu0: MSR_TURBO_RATIO_LIMIT: 0x25262727
127127 37 * 100 = 3700 MHz max turbo 4 active cores
128128 38 * 100 = 3800 MHz max turbo 3 active cores
129129 39 * 100 = 3900 MHz max turbo 2 active cores
tools/power/x86/turbostat/turbostat.c+1−1
@@ -1480,7 +1480,7 @@ dump_knl_turbo_ratio_limits(void) · 1479 unmodified lines
14801480 unsigned int cores[buckets_no];
14811481 unsigned int ratio[buckets_no];
14821482
1483− get_msr(base_cpu, MSR_NHM_TURBO_RATIO_LIMIT, &msr);
1483+ get_msr(base_cpu, MSR_TURBO_RATIO_LIMIT, &msr);
14841484
14851485 fprintf(outf, "cpu%d: MSR_TURBO_RATIO_LIMIT: 0x%08llx\n",
14861486 base_cpu, msr);

Keyboard shortcuts

General

Show keyboard shortcuts
?
Focus the current search
/

Issues and pull requests

Open filters
f

Issues, pull requests and Inbox

Select next item
j↓
Select previous item
k↑
Open selected item
Enter
Dismiss filters or clear selection
Esc

Repository code

Go to file
t