Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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

Pull power management updates from Rafael Wysocki:
"These update PCI and ACPI power management (improved handling of ACPI
power resources and PCIe link delays, fixes related to corner cases,
hibernation handling rework), fix and extend the operating performance
points (OPP) framework, add new cpufreq drivers for Raspberry Pi and
imx8m chips, update some other cpufreq drivers, clean up assorted
pieces of PM code and documentation and update tools.

Specifics:

- Improve the handling of shared ACPI power resources in the PCI bus
type layer (Mika Westerberg).

- Make the PCI layer take link delays required by the PCIe spec into
account as appropriate and avoid polling devices in D3cold for PME
(Mika Westerberg).

- Fix some corner case issues in ACPI device power management and in
the PCI bus type layer, optimiza and clean up the handling of
runtime-suspended PCI devices during system-wide transitions to
sleep states (Rafael Wysocki).

- Rework hibernation handling in the ACPI core and the PCI bus type
to resume runtime-suspended devices before hibernation (which
allows some functional problems to be avoided) and fix some ACPI
power management issues related to hiberation (Rafael Wysocki).

- Extend the operating performance points (OPP) framework to support
a wider range of devices (Rajendra Nayak, Stehpen Boyd).

- Fix issues related to genpd_virt_devs and issues with platforms
using the set_opp() callback in the OPP framework (Viresh Kumar,
Dmitry Osipenko).

- Add new cpufreq driver for Raspberry Pi (Nicolas Saenz Julienne).

- Add new cpufreq driver for imx8m and imx7d chips (Leonard Crestez).

- Fix and clean up the pcc-cpufreq, brcmstb-avs-cpufreq, s5pv210, and
armada-37xx cpufreq drivers (David Arcari, Florian Fainelli, Paweł
Chmiel, YueHaibing).

- Clean up and fix the cpufreq core (Viresh Kumar, Daniel Lezcano).

- Fix minor issue in the ACPI system sleep support code and export
one function from it (Lenny Szubowicz, Dexuan Cui).

- Clean up assorted pieces of PM code and documentation (Kefeng Wang,
Andy Shevchenko, Bart Van Assche, Greg Kroah-Hartman, Fuqian Huang,
Geert Uytterhoeven, Mathieu Malaterre, Rafael Wysocki).

- Update the pm-graph utility to v5.4 (Todd Brandt).

- Fix and clean up the cpupower utility (Abhishek Goel, Nick Black)"

* tag 'pm-5.3-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (57 commits)
ACPI: PM: Make acpi_sleep_state_supported() non-static
PM: sleep: Drop dev_pm_skip_next_resume_phases()
ACPI: PM: Unexport acpi_device_get_power()
Documentation: ABI: power: Add missing newline at end of file
ACPI: PM: Drop unused function and function header
ACPI: PM: Introduce "poweroff" callbacks for ACPI PM domain and LPSS
ACPI: PM: Simplify and fix PM domain hibernation callbacks
PCI: PM: Simplify bus-level hibernation callbacks
PM: ACPI/PCI: Resume all devices during hibernation
cpufreq: Avoid calling cpufreq_verify_current_freq() from handle_update()
cpufreq: Consolidate cpufreq_update_current_freq() and __cpufreq_get()
kernel: power: swap: use kzalloc() instead of kmalloc() followed by memset()
cpufreq: Don't skip frequency validation for has_target() drivers
PCI: PM/ACPI: Refresh all stale power state data in pci_pm_complete()
PCI / ACPI: Add _PR0 dependent devices
ACPI / PM: Introduce concept of a _PR0 dependent device
PCI / ACPI: Use cached ACPI device state to get PCI device power state
ACPI: PM: Allow transitions to D0 to occur in special cases
ACPI: PM: Avoid evaluating _PS3 on transitions from D3hot to D3cold
cpufreq: Use has_target() instead of !setpolicy
...

+2335 -641
Documentation/ABI/testing/sysfs-power
+37
Documentation/devicetree/bindings/cpufreq/imx-cpufreq-dt.txt
··· 1 + i.MX CPUFreq-DT OPP bindings 2 + ================================ 3 + 4 + Certain i.MX SoCs support different OPPs depending on the "market segment" and 5 + "speed grading" value which are written in fuses. These bits are combined with 6 + the opp-supported-hw values for each OPP to check if the OPP is allowed. 7 + 8 + Required properties: 9 + -------------------- 10 + 11 + For each opp entry in 'operating-points-v2' table: 12 + - opp-supported-hw: Two bitmaps indicating: 13 + - Supported speed grade mask 14 + - Supported market segment mask 15 + 0: Consumer 16 + 1: Extended Consumer 17 + 2: Industrial 18 + 3: Automotive 19 + 20 + Example: 21 + -------- 22 + 23 + opp_table { 24 + compatible = "operating-points-v2"; 25 + opp-1000000000 { 26 + opp-hz = /bits/ 64 <1000000000>; 27 + /* grade >= 0, consumer only */ 28 + opp-supported-hw = <0xf>, <0x3>; 29 + }; 30 + 31 + opp-1300000000 { 32 + opp-hz = /bits/ 64 <1300000000>; 33 + opp-microvolt = <1000000>; 34 + /* grade >= 1, all segments */ 35 + opp-supported-hw = <0xe>, <0x7>; 36 + }; 37 + }
+1
arch/powerpc/kernel/suspend.c
··· 7 7 */ 8 8 9 9 #include <linux/mm.h> 10 + #include <linux/suspend.h> 10 11 #include <asm/page.h> 11 12 #include <asm/sections.h> 12 13
-1
arch/s390/kernel/entry.h
··· 63 63 void die(struct pt_regs *regs, const char *str); 64 64 int setup_profiling_timer(unsigned int multiplier); 65 65 void __init time_init(void); 66 - int pfn_is_nosave(unsigned long); 67 66 void s390_early_resume(void); 68 67 unsigned long prepare_ftrace_return(unsigned long parent, unsigned long sp, unsigned long ip); 69 68
+3 -4
drivers/acpi/acpi_lpit.c
··· 129 129 130 130 static void lpit_process(u64 begin, u64 end) 131 131 { 132 - while (begin + sizeof(struct acpi_lpit_native) < end) { 132 + while (begin + sizeof(struct acpi_lpit_native) <= end) { 133 133 struct acpi_lpit_native *lpit_native = (struct acpi_lpit_native *)begin; 134 134 135 135 if (!lpit_native->header.type && !lpit_native->header.flags) { ··· 148 148 void acpi_init_lpit(void) 149 149 { 150 150 acpi_status status; 151 - u64 lpit_begin; 152 151 struct acpi_table_lpit *lpit; 153 152 154 153 status = acpi_get_table(ACPI_SIG_LPIT, 0, (struct acpi_table_header **)&lpit); ··· 155 156 if (ACPI_FAILURE(status)) 156 157 return; 157 158 158 - lpit_begin = (u64)lpit + sizeof(*lpit); 159 - lpit_process(lpit_begin, lpit_begin + lpit->header.length); 159 + lpit_process((u64)lpit + sizeof(*lpit), 160 + (u64)lpit + lpit->header.length); 160 161 }
+99 -12
drivers/acpi/acpi_lpss.c
··· 1061 1061 int ret; 1062 1062 1063 1063 if (pdata->dev_desc->resume_from_noirq) { 1064 + /* 1065 + * The driver's ->suspend_late callback will be invoked by 1066 + * acpi_lpss_do_suspend_late(), with the assumption that the 1067 + * driver really wanted to run that code in ->suspend_noirq, but 1068 + * it could not run after acpi_dev_suspend() and the driver 1069 + * expected the latter to be called in the "late" phase. 1070 + */ 1064 1071 ret = acpi_lpss_do_suspend_late(dev); 1065 1072 if (ret) 1066 1073 return ret; ··· 1098 1091 struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); 1099 1092 int ret; 1100 1093 1101 - ret = acpi_subsys_resume_noirq(dev); 1094 + /* Follow acpi_subsys_resume_noirq(). */ 1095 + if (dev_pm_may_skip_resume(dev)) 1096 + return 0; 1097 + 1098 + if (dev_pm_smart_suspend_and_suspended(dev)) 1099 + pm_runtime_set_active(dev); 1100 + 1101 + ret = pm_generic_resume_noirq(dev); 1102 1102 if (ret) 1103 1103 return ret; 1104 1104 1105 - if (!dev_pm_may_skip_resume(dev) && pdata->dev_desc->resume_from_noirq) 1106 - ret = acpi_lpss_do_resume_early(dev); 1105 + if (!pdata->dev_desc->resume_from_noirq) 1106 + return 0; 1107 1107 1108 - return ret; 1108 + /* 1109 + * The driver's ->resume_early callback will be invoked by 1110 + * acpi_lpss_do_resume_early(), with the assumption that the driver 1111 + * really wanted to run that code in ->resume_noirq, but it could not 1112 + * run before acpi_dev_resume() and the driver expected the latter to be 1113 + * called in the "early" phase. 1114 + */ 1115 + return acpi_lpss_do_resume_early(dev); 1109 1116 } 1110 1117 1118 + static int acpi_lpss_do_restore_early(struct device *dev) 1119 + { 1120 + int ret = acpi_lpss_resume(dev); 1121 + 1122 + return ret ? ret : pm_generic_restore_early(dev); 1123 + } 1124 + 1125 + static int acpi_lpss_restore_early(struct device *dev) 1126 + { 1127 + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); 1128 + 1129 + if (pdata->dev_desc->resume_from_noirq) 1130 + return 0; 1131 + 1132 + return acpi_lpss_do_restore_early(dev); 1133 + } 1134 + 1135 + static int acpi_lpss_restore_noirq(struct device *dev) 1136 + { 1137 + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); 1138 + int ret; 1139 + 1140 + ret = pm_generic_restore_noirq(dev); 1141 + if (ret) 1142 + return ret; 1143 + 1144 + if (!pdata->dev_desc->resume_from_noirq) 1145 + return 0; 1146 + 1147 + /* This is analogous to what happens in acpi_lpss_resume_noirq(). */ 1148 + return acpi_lpss_do_restore_early(dev); 1149 + } 1150 + 1151 + static int acpi_lpss_do_poweroff_late(struct device *dev) 1152 + { 1153 + int ret = pm_generic_poweroff_late(dev); 1154 + 1155 + return ret ? ret : acpi_lpss_suspend(dev, device_may_wakeup(dev)); 1156 + } 1157 + 1158 + static int acpi_lpss_poweroff_late(struct device *dev) 1159 + { 1160 + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); 1161 + 1162 + if (dev_pm_smart_suspend_and_suspended(dev)) 1163 + return 0; 1164 + 1165 + if (pdata->dev_desc->resume_from_noirq) 1166 + return 0; 1167 + 1168 + return acpi_lpss_do_poweroff_late(dev); 1169 + } 1170 + 1171 + static int acpi_lpss_poweroff_noirq(struct device *dev) 1172 + { 1173 + struct lpss_private_data *pdata = acpi_driver_data(ACPI_COMPANION(dev)); 1174 + 1175 + if (dev_pm_smart_suspend_and_suspended(dev)) 1176 + return 0; 1177 + 1178 + if (pdata->dev_desc->resume_from_noirq) { 1179 + /* This is analogous to the acpi_lpss_suspend_noirq() case. */ 1180 + int ret = acpi_lpss_do_poweroff_late(dev); 1181 + if (ret) 1182 + return ret; 1183 + } 1184 + 1185 + return pm_generic_poweroff_noirq(dev); 1186 + } 1111 1187 #endif /* CONFIG_PM_SLEEP */ 1112 1188 1113 1189 static int acpi_lpss_runtime_suspend(struct device *dev) ··· 1224 1134 .resume_noirq = acpi_lpss_resume_noirq, 1225 1135 .resume_early = acpi_lpss_resume_early, 1226 1136 .freeze = acpi_subsys_freeze, 1227 - .freeze_late = acpi_subsys_freeze_late, 1228 - .freeze_noirq = acpi_subsys_freeze_noirq, 1229 - .thaw_noirq = acpi_subsys_thaw_noirq, 1230 - .poweroff = acpi_subsys_suspend, 1231 - .poweroff_late = acpi_lpss_suspend_late, 1232 - .poweroff_noirq = acpi_lpss_suspend_noirq, 1233 - .restore_noirq = acpi_lpss_resume_noirq, 1234 - .restore_early = acpi_lpss_resume_early, 1137 + .poweroff = acpi_subsys_poweroff, 1138 + .poweroff_late = acpi_lpss_poweroff_late, 1139 + .poweroff_noirq = acpi_lpss_poweroff_noirq, 1140 + .restore_noirq = acpi_lpss_restore_noirq, 1141 + .restore_early = acpi_lpss_restore_early, 1235 1142 #endif 1236 1143 .runtime_suspend = acpi_lpss_runtime_suspend, 1237 1144 .runtime_resume = acpi_lpss_runtime_resume,
+118 -61
drivers/acpi/device_pm.c
··· 45 45 } 46 46 } 47 47 48 + static int acpi_dev_pm_explicit_get(struct acpi_device *device, int *state) 49 + { 50 + unsigned long long psc; 51 + acpi_status status; 52 + 53 + status = acpi_evaluate_integer(device->handle, "_PSC", NULL, &psc); 54 + if (ACPI_FAILURE(status)) 55 + return -ENODEV; 56 + 57 + *state = psc; 58 + return 0; 59 + } 60 + 48 61 /** 49 62 * acpi_device_get_power - Get power state of an ACPI device. 50 63 * @device: Device to get the power state of. ··· 66 53 * This function does not update the device's power.state field, but it may 67 54 * update its parent's power.state field (when the parent's power state is 68 55 * unknown and the device's power state turns out to be D0). 56 + * 57 + * Also, it does not update power resource reference counters to ensure that 58 + * the power state returned by it will be persistent and it may return a power 59 + * state shallower than previously set by acpi_device_set_power() for @device 60 + * (if that power state depends on any power resources). 69 61 */ 70 62 int acpi_device_get_power(struct acpi_device *device, int *state) 71 63 { 72 64 int result = ACPI_STATE_UNKNOWN; 65 + int error; 73 66 74 67 if (!device || !state) 75 68 return -EINVAL; ··· 92 73 * if available. 93 74 */ 94 75 if (device->power.flags.power_resources) { 95 - int error = acpi_power_get_inferred_state(device, &result); 76 + error = acpi_power_get_inferred_state(device, &result); 96 77 if (error) 97 78 return error; 98 79 } 99 80 if (device->power.flags.explicit_get) { 100 - acpi_handle handle = device->handle; 101 - unsigned long long psc; 102 - acpi_status status; 81 + int psc; 103 82 104 - status = acpi_evaluate_integer(handle, "_PSC", NULL, &psc); 105 - if (ACPI_FAILURE(status)) 106 - return -ENODEV; 83 + error = acpi_dev_pm_explicit_get(device, &psc); 84 + if (error) 85 + return error; 107 86 108 87 /* 109 88 * The power resources settings may indicate a power state ··· 135 118 136 119 return 0; 137 120 } 138 - EXPORT_SYMBOL(acpi_device_get_power); 139 121 140 122 static int acpi_dev_pm_explicit_set(struct acpi_device *adev, int state) 141 123 { ··· 168 152 169 153 /* Make sure this is a valid target state */ 170 154 171 - if (state == device->power.state) { 155 + /* There is a special case for D0 addressed below. */ 156 + if (state > ACPI_STATE_D0 && state == device->power.state) { 172 157 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Device [%s] already in %s\n", 173 158 device->pnp.bus_id, 174 159 acpi_power_state_string(state))); ··· 219 202 return -ENODEV; 220 203 } 221 204 222 - result = acpi_dev_pm_explicit_set(device, state); 223 - if (result) 224 - goto end; 205 + /* 206 + * If the device goes from D3hot to D3cold, _PS3 has been 207 + * evaluated for it already, so skip it in that case. 208 + */ 209 + if (device->power.state < ACPI_STATE_D3_HOT) { 210 + result = acpi_dev_pm_explicit_set(device, state); 211 + if (result) 212 + goto end; 213 + } 225 214 226 215 if (device->power.flags.power_resources) 227 216 result = acpi_power_transition(device, target_state); ··· 237 214 if (result) 238 215 goto end; 239 216 } 217 + 218 + if (device->power.state == ACPI_STATE_D0) { 219 + int psc; 220 + 221 + /* Nothing to do here if _PSC is not present. */ 222 + if (!device->power.flags.explicit_get) 223 + return 0; 224 + 225 + /* 226 + * The power state of the device was set to D0 last 227 + * time, but that might have happened before a 228 + * system-wide transition involving the platform 229 + * firmware, so it may be necessary to evaluate _PS0 230 + * for the device here. However, use extra care here 231 + * and evaluate _PSC to check the device's current power 232 + * state, and only invoke _PS0 if the evaluation of _PSC 233 + * is successful and it returns a power state different 234 + * from D0. 235 + */ 236 + result = acpi_dev_pm_explicit_get(device, &psc); 237 + if (result || psc == ACPI_STATE_D0) 238 + return 0; 239 + } 240 + 240 241 result = acpi_dev_pm_explicit_set(device, ACPI_STATE_D0); 241 242 } 242 243 ··· 1120 1073 * acpi_subsys_resume_noirq - Run the device driver's "noirq" resume callback. 1121 1074 * @dev: Device to handle. 1122 1075 */ 1123 - int acpi_subsys_resume_noirq(struct device *dev) 1076 + static int acpi_subsys_resume_noirq(struct device *dev) 1124 1077 { 1125 1078 if (dev_pm_may_skip_resume(dev)) 1126 1079 return 0; ··· 1135 1088 1136 1089 return pm_generic_resume_noirq(dev); 1137 1090 } 1138 - EXPORT_SYMBOL_GPL(acpi_subsys_resume_noirq); 1139 1091 1140 1092 /** 1141 1093 * acpi_subsys_resume_early - Resume device using ACPI. ··· 1144 1098 * generic early resume procedure for it during system transition into the 1145 1099 * working state. 1146 1100 */ 1147 - int acpi_subsys_resume_early(struct device *dev) 1101 + static int acpi_subsys_resume_early(struct device *dev) 1148 1102 { 1149 1103 int ret = acpi_dev_resume(dev); 1150 1104 return ret ? ret : pm_generic_resume_early(dev); 1151 1105 } 1152 - EXPORT_SYMBOL_GPL(acpi_subsys_resume_early); 1153 1106 1154 1107 /** 1155 1108 * acpi_subsys_freeze - Run the device driver's freeze callback. ··· 1157 1112 int acpi_subsys_freeze(struct device *dev) 1158 1113 { 1159 1114 /* 1160 - * This used to be done in acpi_subsys_prepare() for all devices and 1161 - * some drivers may depend on it, so do it here. Ideally, however, 1162 - * runtime-suspended devices should not be touched during freeze/thaw 1163 - * transitions. 1115 + * Resume all runtime-suspended devices before creating a snapshot 1116 + * image of system memory, because the restore kernel generally cannot 1117 + * be expected to always handle them consistently and they need to be 1118 + * put into the runtime-active metastate during system resume anyway, 1119 + * so it is better to ensure that the state saved in the image will be 1120 + * always consistent with that. 1164 1121 */ 1165 - if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND)) 1166 - pm_runtime_resume(dev); 1122 + pm_runtime_resume(dev); 1167 1123 1168 1124 return pm_generic_freeze(dev); 1169 1125 } 1170 1126 EXPORT_SYMBOL_GPL(acpi_subsys_freeze); 1171 1127 1172 1128 /** 1173 - * acpi_subsys_freeze_late - Run the device driver's "late" freeze callback. 1174 - * @dev: Device to handle. 1129 + * acpi_subsys_restore_early - Restore device using ACPI. 1130 + * @dev: Device to restore. 1175 1131 */ 1176 - int acpi_subsys_freeze_late(struct device *dev) 1132 + int acpi_subsys_restore_early(struct device *dev) 1177 1133 { 1134 + int ret = acpi_dev_resume(dev); 1135 + return ret ? ret : pm_generic_restore_early(dev); 1136 + } 1137 + EXPORT_SYMBOL_GPL(acpi_subsys_restore_early); 1138 + 1139 + /** 1140 + * acpi_subsys_poweroff - Run the device driver's poweroff callback. 1141 + * @dev: Device to handle. 1142 + * 1143 + * Follow PCI and resume devices from runtime suspend before running their 1144 + * system poweroff callbacks, unless the driver can cope with runtime-suspended 1145 + * devices during system suspend and there are no ACPI-specific reasons for 1146 + * resuming them. 1147 + */ 1148 + int acpi_subsys_poweroff(struct device *dev) 1149 + { 1150 + if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) || 1151 + acpi_dev_needs_resume(dev, ACPI_COMPANION(dev))) 1152 + pm_runtime_resume(dev); 1153 + 1154 + return pm_generic_poweroff(dev); 1155 + } 1156 + EXPORT_SYMBOL_GPL(acpi_subsys_poweroff); 1157 + 1158 + /** 1159 + * acpi_subsys_poweroff_late - Run the device driver's poweroff callback. 1160 + * @dev: Device to handle. 1161 + * 1162 + * Carry out the generic late poweroff procedure for @dev and use ACPI to put 1163 + * it into a low-power state during system transition into a sleep state. 1164 + */ 1165 + static int acpi_subsys_poweroff_late(struct device *dev) 1166 + { 1167 + int ret; 1178 1168 1179 1169 if (dev_pm_smart_suspend_and_suspended(dev)) 1180 1170 return 0; 1181 1171 1182 - return pm_generic_freeze_late(dev); 1172 + ret = pm_generic_poweroff_late(dev); 1173 + if (ret) 1174 + return ret; 1175 + 1176 + return acpi_dev_suspend(dev, device_may_wakeup(dev)); 1183 1177 } 1184 - EXPORT_SYMBOL_GPL(acpi_subsys_freeze_late); 1185 1178 1186 1179 /** 1187 - * acpi_subsys_freeze_noirq - Run the device driver's "noirq" freeze callback. 1188 - * @dev: Device to handle. 1180 + * acpi_subsys_poweroff_noirq - Run the driver's "noirq" poweroff callback. 1181 + * @dev: Device to suspend. 1189 1182 */ 1190 - int acpi_subsys_freeze_noirq(struct device *dev) 1183 + static int acpi_subsys_poweroff_noirq(struct device *dev) 1191 1184 { 1192 - 1193 1185 if (dev_pm_smart_suspend_and_suspended(dev)) 1194 1186 return 0; 1195 1187 1196 - return pm_generic_freeze_noirq(dev); 1188 + return pm_generic_poweroff_noirq(dev); 1197 1189 } 1198 - EXPORT_SYMBOL_GPL(acpi_subsys_freeze_noirq); 1199 - 1200 - /** 1201 - * acpi_subsys_thaw_noirq - Run the device driver's "noirq" thaw callback. 1202 - * @dev: Device to handle. 1203 - */ 1204 - int acpi_subsys_thaw_noirq(struct device *dev) 1205 - { 1206 - /* 1207 - * If the device is in runtime suspend, the "thaw" code may not work 1208 - * correctly with it, so skip the driver callback and make the PM core 1209 - * skip all of the subsequent "thaw" callbacks for the device. 1210 - */ 1211 - if (dev_pm_smart_suspend_and_suspended(dev)) { 1212 - dev_pm_skip_next_resume_phases(dev); 1213 - return 0; 1214 - } 1215 - 1216 - return pm_generic_thaw_noirq(dev); 1217 - } 1218 - EXPORT_SYMBOL_GPL(acpi_subsys_thaw_noirq); 1219 1190 #endif /* CONFIG_PM_SLEEP */ 1220 1191 1221 1192 static struct dev_pm_domain acpi_general_pm_domain = { ··· 1247 1186 .resume_noirq = acpi_subsys_resume_noirq, 1248 1187 .resume_early = acpi_subsys_resume_early, 1249 1188 .freeze = acpi_subsys_freeze, 1250 - .freeze_late = acpi_subsys_freeze_late, 1251 - .freeze_noirq = acpi_subsys_freeze_noirq, 1252 - .thaw_noirq = acpi_subsys_thaw_noirq, 1253 - .poweroff = acpi_subsys_suspend, 1254 - .poweroff_late = acpi_subsys_suspend_late, 1255 - .poweroff_noirq = acpi_subsys_suspend_noirq, 1256 - .restore_noirq = acpi_subsys_resume_noirq, 1257 - .restore_early = acpi_subsys_resume_early, 1189 + .poweroff = acpi_subsys_poweroff, 1190 + .poweroff_late = acpi_subsys_poweroff_late, 1191 + .poweroff_noirq = acpi_subsys_poweroff_noirq, 1192 + .restore_early = acpi_subsys_restore_early, 1258 1193 #endif 1259 1194 }, 1260 1195 };
+7
drivers/acpi/internal.h
··· 139 139 int acpi_power_on_resources(struct acpi_device *device, int state); 140 140 int acpi_power_transition(struct acpi_device *device, int state); 141 141 142 + /* -------------------------------------------------------------------------- 143 + Device Power Management 144 + -------------------------------------------------------------------------- */ 145 + int acpi_device_get_power(struct acpi_device *device, int *state); 142 146 int acpi_wakeup_device_init(void); 143 147 148 + /* -------------------------------------------------------------------------- 149 + Processor 150 + -------------------------------------------------------------------------- */ 144 151 #ifdef CONFIG_ARCH_MIGHT_HAVE_ACPI_PDC 145 152 void acpi_early_processor_set_pdc(void); 146 153 #else
+135
drivers/acpi/power.c
··· 42 42 #define ACPI_POWER_RESOURCE_STATE_ON 0x01 43 43 #define ACPI_POWER_RESOURCE_STATE_UNKNOWN 0xFF 44 44 45 + struct acpi_power_dependent_device { 46 + struct device *dev; 47 + struct list_head node; 48 + }; 49 + 45 50 struct acpi_power_resource { 46 51 struct acpi_device device; 47 52 struct list_head list_node; ··· 56 51 unsigned int ref_count; 57 52 bool wakeup_enabled; 58 53 struct mutex resource_lock; 54 + struct list_head dependents; 59 55 }; 60 56 61 57 struct acpi_power_resource_entry { ··· 238 232 return 0; 239 233 } 240 234 235 + static int 236 + acpi_power_resource_add_dependent(struct acpi_power_resource *resource, 237 + struct device *dev) 238 + { 239 + struct acpi_power_dependent_device *dep; 240 + int ret = 0; 241 + 242 + mutex_lock(&resource->resource_lock); 243 + list_for_each_entry(dep, &resource->dependents, node) { 244 + /* Only add it once */ 245 + if (dep->dev == dev) 246 + goto unlock; 247 + } 248 + 249 + dep = kzalloc(sizeof(*dep), GFP_KERNEL); 250 + if (!dep) { 251 + ret = -ENOMEM; 252 + goto unlock; 253 + } 254 + 255 + dep->dev = dev; 256 + list_add_tail(&dep->node, &resource->dependents); 257 + dev_dbg(dev, "added power dependency to [%s]\n", resource->name); 258 + 259 + unlock: 260 + mutex_unlock(&resource->resource_lock); 261 + return ret; 262 + } 263 + 264 + static void 265 + acpi_power_resource_remove_dependent(struct acpi_power_resource *resource, 266 + struct device *dev) 267 + { 268 + struct acpi_power_dependent_device *dep; 269 + 270 + mutex_lock(&resource->resource_lock); 271 + list_for_each_entry(dep, &resource->dependents, node) { 272 + if (dep->dev == dev) { 273 + list_del(&dep->node); 274 + kfree(dep); 275 + dev_dbg(dev, "removed power dependency to [%s]\n", 276 + resource->name); 277 + break; 278 + } 279 + } 280 + mutex_unlock(&resource->resource_lock); 281 + } 282 + 283 + /** 284 + * acpi_device_power_add_dependent - Add dependent device of this ACPI device 285 + * @adev: ACPI device pointer 286 + * @dev: Dependent device 287 + * 288 + * If @adev has non-empty _PR0 the @dev is added as dependent device to all 289 + * power resources returned by it. This means that whenever these power 290 + * resources are turned _ON the dependent devices get runtime resumed. This 291 + * is needed for devices such as PCI to allow its driver to re-initialize 292 + * it after it went to D0uninitialized. 293 + * 294 + * If @adev does not have _PR0 this does nothing. 295 + * 296 + * Returns %0 in case of success and negative errno otherwise. 297 + */ 298 + int acpi_device_power_add_dependent(struct acpi_device *adev, 299 + struct device *dev) 300 + { 301 + struct acpi_power_resource_entry *entry; 302 + struct list_head *resources; 303 + int ret; 304 + 305 + if (!adev->flags.power_manageable) 306 + return 0; 307 + 308 + resources = &adev->power.states[ACPI_STATE_D0].resources; 309 + list_for_each_entry(entry, resources, node) { 310 + ret = acpi_power_resource_add_dependent(entry->resource, dev); 311 + if (ret) 312 + goto err; 313 + } 314 + 315 + return 0; 316 + 317 + err: 318 + list_for_each_entry(entry, resources, node) 319 + acpi_power_resource_remove_dependent(entry->resource, dev); 320 + 321 + return ret; 322 + } 323 + 324 + /** 325 + * acpi_device_power_remove_dependent - Remove dependent device 326 + * @adev: ACPI device pointer 327 + * @dev: Dependent device 328 + * 329 + * Does the opposite of acpi_device_power_add_dependent() and removes the 330 + * dependent device if it is found. Can be called to @adev that does not 331 + * have _PR0 as well. 332 + */ 333 + void acpi_device_power_remove_dependent(struct acpi_device *adev, 334 + struct device *dev) 335 + { 336 + struct acpi_power_resource_entry *entry; 337 + struct list_head *resources; 338 + 339 + if (!adev->flags.power_manageable) 340 + return; 341 + 342 + resources = &adev->power.states[ACPI_STATE_D0].resources; 343 + list_for_each_entry_reverse(entry, resources, node) 344 + acpi_power_resource_remove_dependent(entry->resource, dev); 345 + } 346 + 241 347 static int __acpi_power_on(struct acpi_power_resource *resource) 242 348 { 349 + struct acpi_power_dependent_device *dep; 243 350 acpi_status status = AE_OK; 244 351 245 352 status = acpi_evaluate_object(resource->device.handle, "_ON", NULL, NULL); ··· 361 242 362 243 ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Power resource [%s] turned on\n", 363 244 resource->name)); 245 + 246 + /* 247 + * If there are other dependents on this power resource we need to 248 + * resume them now so that their drivers can re-initialize the 249 + * hardware properly after it went back to D0. 250 + */ 251 + if (list_empty(&resource->dependents) || 252 + list_is_singular(&resource->dependents)) 253 + return 0; 254 + 255 + list_for_each_entry(dep, &resource->dependents, node) { 256 + dev_dbg(dep->dev, "runtime resuming because [%s] turned on\n", 257 + resource->name); 258 + pm_request_resume(dep->dev); 259 + } 364 260 365 261 return 0; 366 262 } ··· 944 810 ACPI_STA_DEFAULT); 945 811 mutex_init(&resource->resource_lock); 946 812 INIT_LIST_HEAD(&resource->list_node); 813 + INIT_LIST_HEAD(&resource->dependents); 947 814 resource->name = device->pnp.bus_id; 948 815 strcpy(acpi_device_name(device), ACPI_POWER_DEVICE_NAME); 949 816 strcpy(acpi_device_class(device), ACPI_POWER_CLASS);
+7 -15
drivers/acpi/sleep.c
··· 77 77 return 0; 78 78 } 79 79 80 - static bool acpi_sleep_state_supported(u8 sleep_state) 80 + bool acpi_sleep_state_supported(u8 sleep_state) 81 81 { 82 82 acpi_status status; 83 83 u8 type_a, type_b; ··· 452 452 return error; 453 453 } 454 454 455 - static int find_powerf_dev(struct device *dev, void *data) 456 - { 457 - struct acpi_device *device = to_acpi_device(dev); 458 - const char *hid = acpi_device_hid(device); 459 - 460 - return !strcmp(hid, ACPI_BUTTON_HID_POWERF); 461 - } 462 - 463 455 /** 464 456 * acpi_pm_finish - Instruct the platform to leave a sleep state. 465 457 * ··· 460 468 */ 461 469 static void acpi_pm_finish(void) 462 470 { 463 - struct device *pwr_btn_dev; 471 + struct acpi_device *pwr_btn_adev; 464 472 u32 acpi_state = acpi_target_sleep_state; 465 473 466 474 acpi_ec_unblock_transactions(); ··· 491 499 return; 492 500 493 501 pwr_btn_event_pending = false; 494 - pwr_btn_dev = bus_find_device(&acpi_bus_type, NULL, NULL, 495 - find_powerf_dev); 496 - if (pwr_btn_dev) { 497 - pm_wakeup_event(pwr_btn_dev, 0); 498 - put_device(pwr_btn_dev); 502 + pwr_btn_adev = acpi_dev_get_first_match_dev(ACPI_BUTTON_HID_POWERF, 503 + NULL, -1); 504 + if (pwr_btn_adev) { 505 + pm_wakeup_event(&pwr_btn_adev->dev, 0); 506 + acpi_dev_put(pwr_btn_adev); 499 507 } 500 508 } 501 509
+2 -4
drivers/base/power/clock_ops.c
··· 12 12 #include <linux/pm_clock.h> 13 13 #include <linux/clk.h> 14 14 #include <linux/clkdev.h> 15 + #include <linux/of_clk.h> 15 16 #include <linux/slab.h> 16 17 #include <linux/err.h> 17 18 #include <linux/pm_domain.h> ··· 93 92 if (con_id) { 94 93 ce->con_id = kstrdup(con_id, GFP_KERNEL); 95 94 if (!ce->con_id) { 96 - dev_err(dev, 97 - "Not enough memory for clock connection ID.\n"); 98 95 kfree(ce); 99 96 return -ENOMEM; 100 97 } ··· 194 195 if (!dev || !dev->of_node) 195 196 return -EINVAL; 196 197 197 - count = of_count_phandle_with_args(dev->of_node, "clocks", 198 - "#clock-cells"); 198 + count = of_clk_get_parent_count(dev->of_node); 199 199 if (count <= 0) 200 200 return -ENODEV; 201 201
+14 -22
drivers/base/power/main.c
··· 530 530 /*------------------------- Resume routines -------------------------*/ 531 531 532 532 /** 533 - * dev_pm_skip_next_resume_phases - Skip next system resume phases for device. 534 - * @dev: Target device. 535 - * 536 - * Make the core skip the "early resume" and "resume" phases for @dev. 537 - * 538 - * This function can be called by middle-layer code during the "noirq" phase of 539 - * system resume if necessary, but not by device drivers. 540 - */ 541 - void dev_pm_skip_next_resume_phases(struct device *dev) 542 - { 543 - dev->power.is_late_suspended = false; 544 - dev->power.is_suspended = false; 545 - } 546 - 547 - /** 548 533 * suspend_event - Return a "suspend" message for given "resume" one. 549 534 * @resume_msg: PM message representing a system-wide resume transition. 550 535 */ ··· 666 681 dev->power.is_noirq_suspended = false; 667 682 668 683 if (skip_resume) { 684 + /* Make the next phases of resume skip the device. */ 685 + dev->power.is_late_suspended = false; 686 + dev->power.is_suspended = false; 669 687 /* 670 688 * The device is going to be left in suspend, but it might not 671 689 * have been in runtime suspend before the system suspended, so ··· 677 689 * device again. 678 690 */ 679 691 pm_runtime_set_suspended(dev); 680 - dev_pm_skip_next_resume_phases(dev); 681 692 } 682 693 683 694 Out: ··· 1618 1631 */ 1619 1632 int dpm_suspend_end(pm_message_t state) 1620 1633 { 1621 - int error = dpm_suspend_late(state); 1634 + ktime_t starttime = ktime_get(); 1635 + int error; 1636 + 1637 + error = dpm_suspend_late(state); 1622 1638 if (error) 1623 - return error; 1639 + goto out; 1624 1640 1625 1641 error = dpm_suspend_noirq(state); 1626 - if (error) { 1642 + if (error) 1627 1643 dpm_resume_early(resume_event(state)); 1628 - return error; 1629 - } 1630 1644 1631 - return 0; 1645 + out: 1646 + dpm_show_time(starttime, state, error, "end"); 1647 + return error; 1632 1648 } 1633 1649 EXPORT_SYMBOL_GPL(dpm_suspend_end); 1634 1650 ··· 2024 2034 */ 2025 2035 int dpm_suspend_start(pm_message_t state) 2026 2036 { 2037 + ktime_t starttime = ktime_get(); 2027 2038 int error; 2028 2039 2029 2040 error = dpm_prepare(state); ··· 2033 2042 dpm_save_failed_step(SUSPEND_PREPARE); 2034 2043 } else 2035 2044 error = dpm_suspend(state); 2045 + dpm_show_time(starttime, state, error, "start"); 2036 2046 return error; 2037 2047 } 2038 2048 EXPORT_SYMBOL_GPL(dpm_suspend_start);
+2 -4
drivers/base/power/wakeup.c
··· 968 968 } 969 969 #endif /* CONFIG_PM_AUTOSLEEP */ 970 970 971 - static struct dentry *wakeup_sources_stats_dentry; 972 - 973 971 /** 974 972 * print_wakeup_source_stats - Print wakeup source statistics information. 975 973 * @m: seq_file to print the statistics into. ··· 1097 1099 1098 1100 static int __init wakeup_sources_debugfs_init(void) 1099 1101 { 1100 - wakeup_sources_stats_dentry = debugfs_create_file("wakeup_sources", 1101 - S_IRUGO, NULL, NULL, &wakeup_sources_stats_fops); 1102 + debugfs_create_file("wakeup_sources", S_IRUGO, NULL, NULL, 1103 + &wakeup_sources_stats_fops); 1102 1104 return 0; 1103 1105 } 1104 1106
+17
drivers/cpufreq/Kconfig.arm
··· 93 93 94 94 If in doubt, say N. 95 95 96 + config ARM_IMX_CPUFREQ_DT 97 + tristate "Freescale i.MX8M cpufreq support" 98 + depends on ARCH_MXC && CPUFREQ_DT 99 + help 100 + This adds cpufreq driver support for Freescale i.MX8M series SoCs, 101 + based on cpufreq-dt. 102 + 103 + If in doubt, say N. 104 + 96 105 config ARM_KIRKWOOD_CPUFREQ 97 106 def_bool MACH_KIRKWOOD 98 107 help ··· 141 132 in this engine exposes a programming interface to the OS. 142 133 The driver implements the cpufreq interface for this HW engine. 143 134 Say Y if you want to support CPUFreq HW. 135 + 136 + config ARM_RASPBERRYPI_CPUFREQ 137 + tristate "Raspberry Pi cpufreq support" 138 + depends on CLK_RASPBERRYPI || COMPILE_TEST 139 + help 140 + This adds the CPUFreq driver for Raspberry Pi 141 + 142 + If in doubt, say N. 144 143 145 144 config ARM_S3C_CPUFREQ 146 145 bool
+2
drivers/cpufreq/Makefile
··· 56 56 obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o 57 57 obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o 58 58 obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o 59 + obj-$(CONFIG_ARM_IMX_CPUFREQ_DT) += imx-cpufreq-dt.o 59 60 obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o 60 61 obj-$(CONFIG_ARM_MEDIATEK_CPUFREQ) += mediatek-cpufreq.o 61 62 obj-$(CONFIG_MACH_MVEBU_V7) += mvebu-cpufreq.o ··· 65 64 obj-$(CONFIG_PXA3xx) += pxa3xx-cpufreq.o 66 65 obj-$(CONFIG_ARM_QCOM_CPUFREQ_HW) += qcom-cpufreq-hw.o 67 66 obj-$(CONFIG_ARM_QCOM_CPUFREQ_KRYO) += qcom-cpufreq-kryo.o 67 + obj-$(CONFIG_ARM_RASPBERRYPI_CPUFREQ) += raspberrypi-cpufreq.o 68 68 obj-$(CONFIG_ARM_S3C2410_CPUFREQ) += s3c2410-cpufreq.o 69 69 obj-$(CONFIG_ARM_S3C2412_CPUFREQ) += s3c2412-cpufreq.o 70 70 obj-$(CONFIG_ARM_S3C2416_CPUFREQ) += s3c2416-cpufreq.o
+1 -3
drivers/cpufreq/armada-37xx-cpufreq.c
··· 257 257 static void __init armada37xx_cpufreq_avs_setup(struct regmap *base, 258 258 struct armada_37xx_dvfs *dvfs) 259 259 { 260 - unsigned int avs_val = 0, freq; 260 + unsigned int avs_val = 0; 261 261 int load_level = 0; 262 262 263 263 if (base == NULL) ··· 275 275 276 276 277 277 for (load_level = 1; load_level < LOAD_LEVEL_NR; load_level++) { 278 - freq = dvfs->cpu_freq_max / dvfs->divider[load_level]; 279 - 280 278 avs_val = dvfs->avs[load_level]; 281 279 regmap_update_bits(base, ARMADA_37XX_AVS_VSET(load_level-1), 282 280 ARMADA_37XX_AVS_VDD_MASK << ARMADA_37XX_AVS_HIGH_VDD_LIMIT |
+6 -6
drivers/cpufreq/brcmstb-avs-cpufreq.c
··· 384 384 return __issue_avs_command(priv, AVS_CMD_SET_PSTATE, true, args); 385 385 } 386 386 387 - static unsigned long brcm_avs_get_voltage(void __iomem *base) 387 + static u32 brcm_avs_get_voltage(void __iomem *base) 388 388 { 389 389 return readl(base + AVS_MBOX_VOLTAGE1); 390 390 } 391 391 392 - static unsigned long brcm_avs_get_frequency(void __iomem *base) 392 + static u32 brcm_avs_get_frequency(void __iomem *base) 393 393 { 394 394 return readl(base + AVS_MBOX_FREQUENCY) * 1000; /* in kHz */ 395 395 } ··· 446 446 rc = brcm_avs_get_pmap(priv, NULL); 447 447 magic = readl(priv->base + AVS_MBOX_MAGIC); 448 448 449 - return (magic == AVS_FIRMWARE_MAGIC) && (rc != -ENOTSUPP) && 450 - (rc != -EINVAL); 449 + return (magic == AVS_FIRMWARE_MAGIC) && ((rc != -ENOTSUPP) || 450 + (rc != -EINVAL)); 451 451 } 452 452 453 453 static unsigned int brcm_avs_cpufreq_get(unsigned int cpu) ··· 653 653 { 654 654 struct private_data *priv = policy->driver_data; 655 655 656 - return sprintf(buf, "0x%08lx\n", brcm_avs_get_voltage(priv->base)); 656 + return sprintf(buf, "0x%08x\n", brcm_avs_get_voltage(priv->base)); 657 657 } 658 658 659 659 static ssize_t show_brcm_avs_frequency(struct cpufreq_policy *policy, char *buf) 660 660 { 661 661 struct private_data *priv = policy->driver_data; 662 662 663 - return sprintf(buf, "0x%08lx\n", brcm_avs_get_frequency(priv->base)); 663 + return sprintf(buf, "0x%08x\n", brcm_avs_get_frequency(priv->base)); 664 664 } 665 665 666 666 cpufreq_freq_attr_ro(brcm_avs_pstate);
+4 -1
drivers/cpufreq/cpufreq-dt-platdev.c
··· 37 37 { .compatible = "fsl,imx27", }, 38 38 { .compatible = "fsl,imx51", }, 39 39 { .compatible = "fsl,imx53", }, 40 - { .compatible = "fsl,imx7d", }, 41 40 42 41 { .compatible = "marvell,berlin", }, 43 42 { .compatible = "marvell,pxa250", }, ··· 103 104 static const struct of_device_id blacklist[] __initconst = { 104 105 { .compatible = "calxeda,highbank", }, 105 106 { .compatible = "calxeda,ecx-2000", }, 107 + 108 + { .compatible = "fsl,imx7d", }, 109 + { .compatible = "fsl,imx8mq", }, 110 + { .compatible = "fsl,imx8mm", }, 106 111 107 112 { .compatible = "marvell,armadaxp", }, 108 113
+54 -67
drivers/cpufreq/cpufreq.c
··· 356 356 * which is not equal to what the cpufreq core thinks is 357 357 * "old frequency". 358 358 */ 359 - if (!(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { 360 - if (policy->cur && (policy->cur != freqs->old)) { 361 - pr_debug("Warning: CPU frequency is %u, cpufreq assumed %u kHz\n", 362 - freqs->old, policy->cur); 363 - freqs->old = policy->cur; 364 - } 359 + if (policy->cur && policy->cur != freqs->old) { 360 + pr_debug("Warning: CPU frequency is %u, cpufreq assumed %u kHz\n", 361 + freqs->old, policy->cur); 362 + freqs->old = policy->cur; 365 363 } 366 364 367 365 srcu_notifier_call_chain(&cpufreq_transition_notifier_list, ··· 629 631 } 630 632 631 633 /** 632 - * cpufreq_parse_governor - parse a governor string only for !setpolicy 634 + * cpufreq_parse_governor - parse a governor string only for has_target() 633 635 */ 634 636 static int cpufreq_parse_governor(char *str_governor, 635 637 struct cpufreq_policy *policy) ··· 1112 1114 return ret; 1113 1115 } 1114 1116 1117 + static void refresh_frequency_limits(struct cpufreq_policy *policy) 1118 + { 1119 + struct cpufreq_policy new_policy = *policy; 1120 + 1121 + pr_debug("updating policy for CPU %u\n", policy->cpu); 1122 + 1123 + new_policy.min = policy->user_policy.min; 1124 + new_policy.max = policy->user_policy.max; 1125 + 1126 + cpufreq_set_policy(policy, &new_policy); 1127 + } 1128 + 1115 1129 static void handle_update(struct work_struct *work) 1116 1130 { 1117 1131 struct cpufreq_policy *policy = 1118 1132 container_of(work, struct cpufreq_policy, update); 1119 - unsigned int cpu = policy->cpu; 1120 - pr_debug("handle_update for cpu %u called\n", cpu); 1121 - cpufreq_update_policy(cpu); 1133 + 1134 + pr_debug("handle_update for cpu %u called\n", policy->cpu); 1135 + refresh_frequency_limits(policy); 1122 1136 } 1123 1137 1124 1138 static struct cpufreq_policy *cpufreq_policy_alloc(unsigned int cpu) ··· 1310 1300 policy->max = policy->user_policy.max; 1311 1301 } 1312 1302 1313 - if (cpufreq_driver->get && !cpufreq_driver->setpolicy) { 1303 + if (cpufreq_driver->get && has_target()) { 1314 1304 policy->cur = cpufreq_driver->get(policy->cpu); 1315 1305 if (!policy->cur) { 1316 1306 pr_err("%s: ->get() failed\n", __func__); ··· 1385 1375 if (cpufreq_driver->ready) 1386 1376 cpufreq_driver->ready(policy); 1387 1377 1388 - if (IS_ENABLED(CONFIG_CPU_THERMAL) && 1389 - cpufreq_driver->flags & CPUFREQ_IS_COOLING_DEV) 1378 + if (cpufreq_thermal_control_enabled(cpufreq_driver)) 1390 1379 policy->cdev = of_cpufreq_cooling_register(policy); 1391 1380 1392 1381 pr_debug("initialization complete\n"); ··· 1475 1466 goto unlock; 1476 1467 } 1477 1468 1478 - if (IS_ENABLED(CONFIG_CPU_THERMAL) && 1479 - cpufreq_driver->flags & CPUFREQ_IS_COOLING_DEV) { 1469 + if (cpufreq_thermal_control_enabled(cpufreq_driver)) { 1480 1470 cpufreq_cooling_unregister(policy->cdev); 1481 1471 policy->cdev = NULL; 1482 1472 } ··· 1554 1546 cpufreq_freq_transition_end(policy, &freqs, 0); 1555 1547 } 1556 1548 1549 + static unsigned int cpufreq_verify_current_freq(struct cpufreq_policy *policy, bool update) 1550 + { 1551 + unsigned int new_freq; 1552 + 1553 + new_freq = cpufreq_driver->get(policy->cpu); 1554 + if (!new_freq) 1555 + return 0; 1556 + 1557 + /* 1558 + * If fast frequency switching is used with the given policy, the check 1559 + * against policy->cur is pointless, so skip it in that case. 1560 + */ 1561 + if (policy->fast_switch_enabled || !has_target()) 1562 + return new_freq; 1563 + 1564 + if (policy->cur != new_freq) { 1565 + cpufreq_out_of_sync(policy, new_freq); 1566 + if (update) 1567 + schedule_work(&policy->update); 1568 + } 1569 + 1570 + return new_freq; 1571 + } 1572 + 1557 1573 /** 1558 1574 * cpufreq_quick_get - get the CPU frequency (in kHz) from policy->cur 1559 1575 * @cpu: CPU number ··· 1633 1601 1634 1602 static unsigned int __cpufreq_get(struct cpufreq_policy *policy) 1635 1603 { 1636 - unsigned int ret_freq = 0; 1637 - 1638 1604 if (unlikely(policy_is_inactive(policy))) 1639 - return ret_freq; 1605 + return 0; 1640 1606 1641 - ret_freq = cpufreq_driver->get(policy->cpu); 1642 - 1643 - /* 1644 - * If fast frequency switching is used with the given policy, the check 1645 - * against policy->cur is pointless, so skip it in that case too. 1646 - */ 1647 - if (policy->fast_switch_enabled) 1648 - return ret_freq; 1649 - 1650 - if (ret_freq && policy->cur && 1651 - !(cpufreq_driver->flags & CPUFREQ_CONST_LOOPS)) { 1652 - /* verify no discrepancy between actual and 1653 - saved value exists */ 1654 - if (unlikely(ret_freq != policy->cur)) { 1655 - cpufreq_out_of_sync(policy, ret_freq); 1656 - schedule_work(&policy->update); 1657 - } 1658 - } 1659 - 1660 - return ret_freq; 1607 + return cpufreq_verify_current_freq(policy, true); 1661 1608 } 1662 1609 1663 1610 /** ··· 1662 1651 return ret_freq; 1663 1652 } 1664 1653 EXPORT_SYMBOL(cpufreq_get); 1665 - 1666 - static unsigned int cpufreq_update_current_freq(struct cpufreq_policy *policy) 1667 - { 1668 - unsigned int new_freq; 1669 - 1670 - new_freq = cpufreq_driver->get(policy->cpu); 1671 - if (!new_freq) 1672 - return 0; 1673 - 1674 - if (!policy->cur) { 1675 - pr_debug("cpufreq: Driver did not initialize current freq\n"); 1676 - policy->cur = new_freq; 1677 - } else if (policy->cur != new_freq && has_target()) { 1678 - cpufreq_out_of_sync(policy, new_freq); 1679 - } 1680 - 1681 - return new_freq; 1682 - } 1683 1654 1684 1655 static struct subsys_interface cpufreq_interface = { 1685 1656 .name = "cpufreq", ··· 2143 2150 2144 2151 pr_debug("%s: for CPU %u\n", __func__, policy->cpu); 2145 2152 2146 - if (cpufreq_driver->get && !cpufreq_driver->setpolicy) 2147 - cpufreq_update_current_freq(policy); 2153 + if (cpufreq_driver->get) 2154 + cpufreq_verify_current_freq(policy, false); 2148 2155 2149 2156 if (policy->governor->start) { 2150 2157 ret = policy->governor->start(policy); ··· 2385 2392 void cpufreq_update_policy(unsigned int cpu) 2386 2393 { 2387 2394 struct cpufreq_policy *policy = cpufreq_cpu_acquire(cpu); 2388 - struct cpufreq_policy new_policy; 2389 2395 2390 2396 if (!policy) 2391 2397 return; ··· 2393 2401 * BIOS might change freq behind our back 2394 2402 * -> ask driver for current freq and notify governors about a change 2395 2403 */ 2396 - if (cpufreq_driver->get && !cpufreq_driver->setpolicy && 2397 - (cpufreq_suspended || WARN_ON(!cpufreq_update_current_freq(policy)))) 2404 + if (cpufreq_driver->get && has_target() && 2405 + (cpufreq_suspended || WARN_ON(!cpufreq_verify_current_freq(policy, false)))) 2398 2406 goto unlock; 2399 2407 2400 - pr_debug("updating policy for CPU %u\n", cpu); 2401 - memcpy(&new_policy, policy, sizeof(*policy)); 2402 - new_policy.min = policy->user_policy.min; 2403 - new_policy.max = policy->user_policy.max; 2404 - 2405 - cpufreq_set_policy(policy, &new_policy); 2408 + refresh_frequency_limits(policy); 2406 2409 2407 2410 unlock: 2408 2411 cpufreq_cpu_release(policy);
+97
drivers/cpufreq/imx-cpufreq-dt.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Copyright 2019 NXP 4 + */ 5 + 6 + #include <linux/cpu.h> 7 + #include <linux/err.h> 8 + #include <linux/init.h> 9 + #include <linux/kernel.h> 10 + #include <linux/module.h> 11 + #include <linux/nvmem-consumer.h> 12 + #include <linux/of.h> 13 + #include <linux/platform_device.h> 14 + #include <linux/pm_opp.h> 15 + #include <linux/slab.h> 16 + 17 + #define OCOTP_CFG3_SPEED_GRADE_SHIFT 8 18 + #define OCOTP_CFG3_SPEED_GRADE_MASK (0x3 << 8) 19 + #define OCOTP_CFG3_MKT_SEGMENT_SHIFT 6 20 + #define OCOTP_CFG3_MKT_SEGMENT_MASK (0x3 << 6) 21 + 22 + /* cpufreq-dt device registered by imx-cpufreq-dt */ 23 + static struct platform_device *cpufreq_dt_pdev; 24 + static struct opp_table *cpufreq_opp_table; 25 + 26 + static int imx_cpufreq_dt_probe(struct platform_device *pdev) 27 + { 28 + struct device *cpu_dev = get_cpu_device(0); 29 + u32 cell_value, supported_hw[2]; 30 + int speed_grade, mkt_segment; 31 + int ret; 32 + 33 + ret = nvmem_cell_read_u32(cpu_dev, "speed_grade", &cell_value); 34 + if (ret) 35 + return ret; 36 + 37 + speed_grade = (cell_value & OCOTP_CFG3_SPEED_GRADE_MASK) >> OCOTP_CFG3_SPEED_GRADE_SHIFT; 38 + mkt_segment = (cell_value & OCOTP_CFG3_MKT_SEGMENT_MASK) >> OCOTP_CFG3_MKT_SEGMENT_SHIFT; 39 + 40 + /* 41 + * Early samples without fuses written report "0 0" which means 42 + * consumer segment and minimum speed grading. 43 + * 44 + * According to datasheet minimum speed grading is not supported for 45 + * consumer parts so clamp to 1 to avoid warning for "no OPPs" 46 + * 47 + * Applies to 8mq and 8mm. 48 + */ 49 + if (mkt_segment == 0 && speed_grade == 0 && ( 50 + of_machine_is_compatible("fsl,imx8mm") || 51 + of_machine_is_compatible("fsl,imx8mq"))) 52 + speed_grade = 1; 53 + 54 + supported_hw[0] = BIT(speed_grade); 55 + supported_hw[1] = BIT(mkt_segment); 56 + dev_info(&pdev->dev, "cpu speed grade %d mkt segment %d supported-hw %#x %#x\n", 57 + speed_grade, mkt_segment, supported_hw[0], supported_hw[1]); 58 + 59 + cpufreq_opp_table = dev_pm_opp_set_supported_hw(cpu_dev, supported_hw, 2); 60 + if (IS_ERR(cpufreq_opp_table)) { 61 + ret = PTR_ERR(cpufreq_opp_table); 62 + dev_err(&pdev->dev, "Failed to set supported opp: %d\n", ret); 63 + return ret; 64 + } 65 + 66 + cpufreq_dt_pdev = platform_device_register_data( 67 + &pdev->dev, "cpufreq-dt", -1, NULL, 0); 68 + if (IS_ERR(cpufreq_dt_pdev)) { 69 + dev_pm_opp_put_supported_hw(cpufreq_opp_table); 70 + ret = PTR_ERR(cpufreq_dt_pdev); 71 + dev_err(&pdev->dev, "Failed to register cpufreq-dt: %d\n", ret); 72 + return ret; 73 + } 74 + 75 + return 0; 76 + } 77 + 78 + static int imx_cpufreq_dt_remove(struct platform_device *pdev) 79 + { 80 + platform_device_unregister(cpufreq_dt_pdev); 81 + dev_pm_opp_put_supported_hw(cpufreq_opp_table); 82 + 83 + return 0; 84 + } 85 + 86 + static struct platform_driver imx_cpufreq_dt_driver = { 87 + .probe = imx_cpufreq_dt_probe, 88 + .remove = imx_cpufreq_dt_remove, 89 + .driver = { 90 + .name = "imx-cpufreq-dt", 91 + }, 92 + }; 93 + module_platform_driver(imx_cpufreq_dt_driver); 94 + 95 + MODULE_ALIAS("platform:imx-cpufreq-dt"); 96 + MODULE_DESCRIPTION("Freescale i.MX cpufreq speed grading driver"); 97 + MODULE_LICENSE("GPL v2");
+2 -2
drivers/cpufreq/pcc-cpufreq.c
··· 582 582 583 583 /* Skip initialization if another cpufreq driver is there. */ 584 584 if (cpufreq_get_current_driver()) 585 - return 0; 585 + return -EEXIST; 586 586 587 587 if (acpi_disabled) 588 - return 0; 588 + return -ENODEV; 589 589 590 590 ret = pcc_cpufreq_probe(); 591 591 if (ret) {
+97
drivers/cpufreq/raspberrypi-cpufreq.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Raspberry Pi cpufreq driver 4 + * 5 + * Copyright (C) 2019, Nicolas Saenz Julienne <nsaenzjulienne@suse.de> 6 + */ 7 + 8 + #include <linux/clk.h> 9 + #include <linux/cpu.h> 10 + #include <linux/cpufreq.h> 11 + #include <linux/module.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/pm_opp.h> 14 + 15 + #define RASPBERRYPI_FREQ_INTERVAL 100000000 16 + 17 + static struct platform_device *cpufreq_dt; 18 + 19 + static int raspberrypi_cpufreq_probe(struct platform_device *pdev) 20 + { 21 + struct device *cpu_dev; 22 + unsigned long min, max; 23 + unsigned long rate; 24 + struct clk *clk; 25 + int ret; 26 + 27 + cpu_dev = get_cpu_device(0); 28 + if (!cpu_dev) { 29 + pr_err("Cannot get CPU for cpufreq driver\n"); 30 + return -ENODEV; 31 + } 32 + 33 + clk = clk_get(cpu_dev, NULL); 34 + if (IS_ERR(clk)) { 35 + dev_err(cpu_dev, "Cannot get clock for CPU0\n"); 36 + return PTR_ERR(clk); 37 + } 38 + 39 + /* 40 + * The max and min frequencies are configurable in the Raspberry Pi 41 + * firmware, so we query them at runtime. 42 + */ 43 + min = roundup(clk_round_rate(clk, 0), RASPBERRYPI_FREQ_INTERVAL); 44 + max = roundup(clk_round_rate(clk, ULONG_MAX), RASPBERRYPI_FREQ_INTERVAL); 45 + clk_put(clk); 46 + 47 + for (rate = min; rate <= max; rate += RASPBERRYPI_FREQ_INTERVAL) { 48 + ret = dev_pm_opp_add(cpu_dev, rate, 0); 49 + if (ret) 50 + goto remove_opp; 51 + } 52 + 53 + cpufreq_dt = platform_device_register_simple("cpufreq-dt", -1, NULL, 0); 54 + ret = PTR_ERR_OR_ZERO(cpufreq_dt); 55 + if (ret) { 56 + dev_err(cpu_dev, "Failed to create platform device, %d\n", ret); 57 + goto remove_opp; 58 + } 59 + 60 + return 0; 61 + 62 + remove_opp: 63 + dev_pm_opp_remove_all_dynamic(cpu_dev); 64 + 65 + return ret; 66 + } 67 + 68 + static int raspberrypi_cpufreq_remove(struct platform_device *pdev) 69 + { 70 + struct device *cpu_dev; 71 + 72 + cpu_dev = get_cpu_device(0); 73 + if (cpu_dev) 74 + dev_pm_opp_remove_all_dynamic(cpu_dev); 75 + 76 + platform_device_unregister(cpufreq_dt); 77 + 78 + return 0; 79 + } 80 + 81 + /* 82 + * Since the driver depends on clk-raspberrypi, which may return EPROBE_DEFER, 83 + * all the activity is performed in the probe, which may be defered as well. 84 + */ 85 + static struct platform_driver raspberrypi_cpufreq_driver = { 86 + .driver = { 87 + .name = "raspberrypi-cpufreq", 88 + }, 89 + .probe = raspberrypi_cpufreq_probe, 90 + .remove = raspberrypi_cpufreq_remove, 91 + }; 92 + module_platform_driver(raspberrypi_cpufreq_driver); 93 + 94 + MODULE_AUTHOR("Nicolas Saenz Julienne <nsaenzjulienne@suse.de"); 95 + MODULE_DESCRIPTION("Raspberry Pi cpufreq driver"); 96 + MODULE_LICENSE("GPL"); 97 + MODULE_ALIAS("platform:raspberrypi-cpufreq");
+1 -1
drivers/cpufreq/s5pv210-cpufreq.c
··· 478 478 arm_volt, arm_volt_max); 479 479 } 480 480 481 - printk(KERN_DEBUG "Perf changed[L%d]\n", index); 481 + pr_debug("Perf changed[L%d]\n", index); 482 482 483 483 exit: 484 484 mutex_unlock(&set_freq_lock);
+1 -1
drivers/input/serio/i8042.c
··· 1406 1406 * behavior on many platforms using suspend-to-RAM (ACPI S3) 1407 1407 * by default. 1408 1408 */ 1409 - if (pm_suspend_via_s2idle() && i == I8042_KBD_PORT_NO) 1409 + if (pm_suspend_default_s2idle() && i == I8042_KBD_PORT_NO) 1410 1410 device_set_wakeup_enable(&serio->dev, true); 1411 1411 } 1412 1412 }
+119 -63
drivers/opp/core.c
··· 682 682 683 683 data->old_opp.rate = old_freq; 684 684 size = sizeof(*old_supply) * opp_table->regulator_count; 685 - if (IS_ERR(old_supply)) 685 + if (!old_supply) 686 686 memset(data->old_opp.supplies, 0, size); 687 687 else 688 688 memcpy(data->old_opp.supplies, old_supply, size); ··· 708 708 709 709 /* Single genpd case */ 710 710 if (!genpd_virt_devs) { 711 - pstate = opp->required_opps[0]->pstate; 711 + pstate = likely(opp) ? opp->required_opps[0]->pstate : 0; 712 712 ret = dev_pm_genpd_set_performance_state(dev, pstate); 713 713 if (ret) { 714 714 dev_err(dev, "Failed to set performance state of %s: %d (%d)\n", ··· 726 726 mutex_lock(&opp_table->genpd_virt_dev_lock); 727 727 728 728 for (i = 0; i < opp_table->required_opp_count; i++) { 729 - pstate = opp->required_opps[i]->pstate; 729 + pstate = likely(opp) ? opp->required_opps[i]->pstate : 0; 730 730 731 731 if (!genpd_virt_devs[i]) 732 732 continue; ··· 748 748 * @dev: device for which we do this operation 749 749 * @target_freq: frequency to achieve 750 750 * 751 - * This configures the power-supplies and clock source to the levels specified 752 - * by the OPP corresponding to the target_freq. 751 + * This configures the power-supplies to the levels specified by the OPP 752 + * corresponding to the target_freq, and programs the clock to a value <= 753 + * target_freq, as rounded by clk_round_rate(). Device wanting to run at fmax 754 + * provided by the opp, should have already rounded to the target OPP's 755 + * frequency. 753 756 */ 754 757 int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq) 755 758 { 756 759 struct opp_table *opp_table; 757 - unsigned long freq, old_freq; 760 + unsigned long freq, old_freq, temp_freq; 758 761 struct dev_pm_opp *old_opp, *opp; 759 762 struct clk *clk; 760 763 int ret; 761 - 762 - if (unlikely(!target_freq)) { 763 - dev_err(dev, "%s: Invalid target frequency %lu\n", __func__, 764 - target_freq); 765 - return -EINVAL; 766 - } 767 764 768 765 opp_table = _find_opp_table(dev); 769 766 if (IS_ERR(opp_table)) { 770 767 dev_err(dev, "%s: device opp doesn't exist\n", __func__); 771 768 return PTR_ERR(opp_table); 769 + } 770 + 771 + if (unlikely(!target_freq)) { 772 + if (opp_table->required_opp_tables) { 773 + ret = _set_required_opps(dev, opp_table, NULL); 774 + } else { 775 + dev_err(dev, "target frequency can't be 0\n"); 776 + ret = -EINVAL; 777 + } 778 + 779 + goto put_opp_table; 772 780 } 773 781 774 782 clk = opp_table->clk; ··· 801 793 goto put_opp_table; 802 794 } 803 795 804 - old_opp = _find_freq_ceil(opp_table, &old_freq); 796 + temp_freq = old_freq; 797 + old_opp = _find_freq_ceil(opp_table, &temp_freq); 805 798 if (IS_ERR(old_opp)) { 806 799 dev_err(dev, "%s: failed to find current OPP for freq %lu (%ld)\n", 807 800 __func__, old_freq, PTR_ERR(old_opp)); 808 801 } 809 802 810 - opp = _find_freq_ceil(opp_table, &freq); 803 + temp_freq = freq; 804 + opp = _find_freq_ceil(opp_table, &temp_freq); 811 805 if (IS_ERR(opp)) { 812 806 ret = PTR_ERR(opp); 813 807 dev_err(dev, "%s: failed to find OPP for freq %lu (%d)\n", ··· 1751 1741 } 1752 1742 EXPORT_SYMBOL_GPL(dev_pm_opp_unregister_set_opp_helper); 1753 1743 1744 + static void _opp_detach_genpd(struct opp_table *opp_table) 1745 + { 1746 + int index; 1747 + 1748 + for (index = 0; index < opp_table->required_opp_count; index++) { 1749 + if (!opp_table->genpd_virt_devs[index]) 1750 + continue; 1751 + 1752 + dev_pm_domain_detach(opp_table->genpd_virt_devs[index], false); 1753 + opp_table->genpd_virt_devs[index] = NULL; 1754 + } 1755 + 1756 + kfree(opp_table->genpd_virt_devs); 1757 + opp_table->genpd_virt_devs = NULL; 1758 + } 1759 + 1754 1760 /** 1755 - * dev_pm_opp_set_genpd_virt_dev - Set virtual genpd device for an index 1756 - * @dev: Consumer device for which the genpd device is getting set. 1757 - * @virt_dev: virtual genpd device. 1758 - * @index: index. 1761 + * dev_pm_opp_attach_genpd - Attach genpd(s) for the device and save virtual device pointer 1762 + * @dev: Consumer device for which the genpd is getting attached. 1763 + * @names: Null terminated array of pointers containing names of genpd to attach. 1759 1764 * 1760 1765 * Multiple generic power domains for a device are supported with the help of 1761 1766 * virtual genpd devices, which are created for each consumer device - genpd 1762 1767 * pair. These are the device structures which are attached to the power domain 1763 1768 * and are required by the OPP core to set the performance state of the genpd. 1769 + * The same API also works for the case where single genpd is available and so 1770 + * we don't need to support that separately. 1764 1771 * 1765 1772 * This helper will normally be called by the consumer driver of the device 1766 - * "dev", as only that has details of the genpd devices. 1773 + * "dev", as only that has details of the genpd names. 1767 1774 * 1768 - * This helper needs to be called once for each of those virtual devices, but 1769 - * only if multiple domains are available for a device. Otherwise the original 1770 - * device structure will be used instead by the OPP core. 1775 + * This helper needs to be called once with a list of all genpd to attach. 1776 + * Otherwise the original device structure will be used instead by the OPP core. 1771 1777 */ 1772 - struct opp_table *dev_pm_opp_set_genpd_virt_dev(struct device *dev, 1773 - struct device *virt_dev, 1774 - int index) 1778 + struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names) 1775 1779 { 1776 1780 struct opp_table *opp_table; 1781 + struct device *virt_dev; 1782 + int index, ret = -EINVAL; 1783 + const char **name = names; 1777 1784 1778 1785 opp_table = dev_pm_opp_get_opp_table(dev); 1779 1786 if (!opp_table) 1780 1787 return ERR_PTR(-ENOMEM); 1781 1788 1782 - mutex_lock(&opp_table->genpd_virt_dev_lock); 1783 - 1784 - if (unlikely(!opp_table->genpd_virt_devs || 1785 - index >= opp_table->required_opp_count || 1786 - opp_table->genpd_virt_devs[index])) { 1787 - 1788 - dev_err(dev, "Invalid request to set required device\n"); 1789 - dev_pm_opp_put_opp_table(opp_table); 1790 - mutex_unlock(&opp_table->genpd_virt_dev_lock); 1791 - 1792 - return ERR_PTR(-EINVAL); 1789 + /* 1790 + * If the genpd's OPP table isn't already initialized, parsing of the 1791 + * required-opps fail for dev. We should retry this after genpd's OPP 1792 + * table is added. 1793 + */ 1794 + if (!opp_table->required_opp_count) { 1795 + ret = -EPROBE_DEFER; 1796 + goto put_table; 1793 1797 } 1794 1798 1795 - opp_table->genpd_virt_devs[index] = virt_dev; 1799 + mutex_lock(&opp_table->genpd_virt_dev_lock); 1800 + 1801 + opp_table->genpd_virt_devs = kcalloc(opp_table->required_opp_count, 1802 + sizeof(*opp_table->genpd_virt_devs), 1803 + GFP_KERNEL); 1804 + if (!opp_table->genpd_virt_devs) 1805 + goto unlock; 1806 + 1807 + while (*name) { 1808 + index = of_property_match_string(dev->of_node, 1809 + "power-domain-names", *name); 1810 + if (index < 0) { 1811 + dev_err(dev, "Failed to find power domain: %s (%d)\n", 1812 + *name, index); 1813 + goto err; 1814 + } 1815 + 1816 + if (index >= opp_table->required_opp_count) { 1817 + dev_err(dev, "Index can't be greater than required-opp-count - 1, %s (%d : %d)\n", 1818 + *name, opp_table->required_opp_count, index); 1819 + goto err; 1820 + } 1821 + 1822 + if (opp_table->genpd_virt_devs[index]) { 1823 + dev_err(dev, "Genpd virtual device already set %s\n", 1824 + *name); 1825 + goto err; 1826 + } 1827 + 1828 + virt_dev = dev_pm_domain_attach_by_name(dev, *name); 1829 + if (IS_ERR(virt_dev)) { 1830 + ret = PTR_ERR(virt_dev); 1831 + dev_err(dev, "Couldn't attach to pm_domain: %d\n", ret); 1832 + goto err; 1833 + } 1834 + 1835 + opp_table->genpd_virt_devs[index] = virt_dev; 1836 + name++; 1837 + } 1838 + 1796 1839 mutex_unlock(&opp_table->genpd_virt_dev_lock); 1797 1840 1798 1841 return opp_table; 1842 + 1843 + err: 1844 + _opp_detach_genpd(opp_table); 1845 + unlock: 1846 + mutex_unlock(&opp_table->genpd_virt_dev_lock); 1847 + 1848 + put_table: 1849 + dev_pm_opp_put_opp_table(opp_table); 1850 + 1851 + return ERR_PTR(ret); 1799 1852 } 1853 + EXPORT_SYMBOL_GPL(dev_pm_opp_attach_genpd); 1800 1854 1801 1855 /** 1802 - * dev_pm_opp_put_genpd_virt_dev() - Releases resources blocked for genpd device. 1803 - * @opp_table: OPP table returned by dev_pm_opp_set_genpd_virt_dev(). 1804 - * @virt_dev: virtual genpd device. 1856 + * dev_pm_opp_detach_genpd() - Detach genpd(s) from the device. 1857 + * @opp_table: OPP table returned by dev_pm_opp_attach_genpd(). 1805 1858 * 1806 - * This releases the resource previously acquired with a call to 1807 - * dev_pm_opp_set_genpd_virt_dev(). The consumer driver shall call this helper 1808 - * if it doesn't want OPP core to update performance state of a power domain 1809 - * anymore. 1859 + * This detaches the genpd(s), resets the virtual device pointers, and puts the 1860 + * OPP table. 1810 1861 */ 1811 - void dev_pm_opp_put_genpd_virt_dev(struct opp_table *opp_table, 1812 - struct device *virt_dev) 1862 + void dev_pm_opp_detach_genpd(struct opp_table *opp_table) 1813 1863 { 1814 - int i; 1815 - 1816 1864 /* 1817 1865 * Acquire genpd_virt_dev_lock to make sure virt_dev isn't getting 1818 1866 * used in parallel. 1819 1867 */ 1820 1868 mutex_lock(&opp_table->genpd_virt_dev_lock); 1821 - 1822 - for (i = 0; i < opp_table->required_opp_count; i++) { 1823 - if (opp_table->genpd_virt_devs[i] != virt_dev) 1824 - continue; 1825 - 1826 - opp_table->genpd_virt_devs[i] = NULL; 1827 - dev_pm_opp_put_opp_table(opp_table); 1828 - 1829 - /* Drop the vote */ 1830 - dev_pm_genpd_set_performance_state(virt_dev, 0); 1831 - break; 1832 - } 1833 - 1869 + _opp_detach_genpd(opp_table); 1834 1870 mutex_unlock(&opp_table->genpd_virt_dev_lock); 1835 1871 1836 - if (unlikely(i == opp_table->required_opp_count)) 1837 - dev_err(virt_dev, "Failed to find required device entry\n"); 1872 + dev_pm_opp_put_opp_table(opp_table); 1838 1873 } 1874 + EXPORT_SYMBOL_GPL(dev_pm_opp_detach_genpd); 1839 1875 1840 1876 /** 1841 1877 * dev_pm_opp_xlate_performance_state() - Find required OPP's pstate for src_table.
+2 -28
drivers/opp/of.c
··· 138 138 static void _opp_table_free_required_tables(struct opp_table *opp_table) 139 139 { 140 140 struct opp_table **required_opp_tables = opp_table->required_opp_tables; 141 - struct device **genpd_virt_devs = opp_table->genpd_virt_devs; 142 141 int i; 143 142 144 143 if (!required_opp_tables) ··· 151 152 } 152 153 153 154 kfree(required_opp_tables); 154 - kfree(genpd_virt_devs); 155 155 156 156 opp_table->required_opp_count = 0; 157 - opp_table->genpd_virt_devs = NULL; 158 157 opp_table->required_opp_tables = NULL; 159 158 } 160 159 ··· 165 168 struct device_node *opp_np) 166 169 { 167 170 struct opp_table **required_opp_tables; 168 - struct device **genpd_virt_devs = NULL; 169 171 struct device_node *required_np, *np; 170 - int count, count_pd, i; 172 + int count, i; 171 173 172 174 /* Traversing the first OPP node is all we need */ 173 175 np = of_get_next_available_child(opp_np, NULL); ··· 179 183 if (!count) 180 184 goto put_np; 181 185 182 - /* 183 - * Check the number of power-domains to know if we need to deal 184 - * with virtual devices. In some cases we have devices with multiple 185 - * power domains but with only one of them being scalable, hence 186 - * 'count' could be 1, but we still have to deal with multiple genpds 187 - * and virtual devices. 188 - */ 189 - count_pd = of_count_phandle_with_args(dev->of_node, "power-domains", 190 - "#power-domain-cells"); 191 - if (!count_pd) 192 - goto put_np; 193 - 194 - if (count_pd > 1) { 195 - genpd_virt_devs = kcalloc(count, sizeof(*genpd_virt_devs), 196 - GFP_KERNEL); 197 - if (!genpd_virt_devs) 198 - goto put_np; 199 - } 200 - 201 186 required_opp_tables = kcalloc(count, sizeof(*required_opp_tables), 202 187 GFP_KERNEL); 203 - if (!required_opp_tables) { 204 - kfree(genpd_virt_devs); 188 + if (!required_opp_tables) 205 189 goto put_np; 206 - } 207 190 208 - opp_table->genpd_virt_devs = genpd_virt_devs; 209 191 opp_table->required_opp_tables = required_opp_tables; 210 192 opp_table->required_opp_count = count; 211 193
+13 -1
drivers/pci/pci-acpi.c
··· 685 685 if (!adev || !acpi_device_power_manageable(adev)) 686 686 return PCI_UNKNOWN; 687 687 688 - if (acpi_device_get_power(adev, &state) || state == ACPI_STATE_UNKNOWN) 688 + state = adev->power.state; 689 + if (state == ACPI_STATE_UNKNOWN) 689 690 return PCI_UNKNOWN; 690 691 691 692 return state_conv[state]; 693 + } 694 + 695 + static void acpi_pci_refresh_power_state(struct pci_dev *dev) 696 + { 697 + struct acpi_device *adev = ACPI_COMPANION(&dev->dev); 698 + 699 + if (adev && acpi_device_power_manageable(adev)) 700 + acpi_device_update_power(adev, NULL); 692 701 } 693 702 694 703 static int acpi_pci_propagate_wakeup(struct pci_bus *bus, bool enable) ··· 757 748 .is_manageable = acpi_pci_power_manageable, 758 749 .set_state = acpi_pci_set_power_state, 759 750 .get_state = acpi_pci_get_power_state, 751 + .refresh_state = acpi_pci_refresh_power_state, 760 752 .choose_state = acpi_pci_choose_state, 761 753 .set_wakeup = acpi_pci_wakeup, 762 754 .need_resume = acpi_pci_need_resume, ··· 911 901 device_wakeup_enable(dev); 912 902 913 903 acpi_pci_wakeup(pci_dev, false); 904 + acpi_device_power_add_dependent(adev, dev); 914 905 } 915 906 916 907 static void pci_acpi_cleanup(struct device *dev) ··· 924 913 925 914 pci_acpi_remove_pm_notifier(adev); 926 915 if (adev->wakeup.flags.valid) { 916 + acpi_device_power_remove_dependent(adev, dev); 927 917 if (pci_dev->bridge_d3) 928 918 device_wakeup_disable(dev); 929 919
+34 -40
drivers/pci/pci-driver.c
··· 678 678 static int pci_pm_prepare(struct device *dev) 679 679 { 680 680 struct device_driver *drv = dev->driver; 681 + struct pci_dev *pci_dev = to_pci_dev(dev); 681 682 682 683 if (drv && drv->pm && drv->pm->prepare) { 683 684 int error = drv->pm->prepare(dev); ··· 688 687 if (!error && dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_PREPARE)) 689 688 return 0; 690 689 } 691 - return pci_dev_keep_suspended(to_pci_dev(dev)); 690 + if (pci_dev_need_resume(pci_dev)) 691 + return 0; 692 + 693 + /* 694 + * The PME setting needs to be adjusted here in case the direct-complete 695 + * optimization is used with respect to this device. 696 + */ 697 + pci_dev_adjust_pme(pci_dev); 698 + return 1; 692 699 } 693 700 694 701 static void pci_pm_complete(struct device *dev) ··· 710 701 if (pm_runtime_suspended(dev) && pm_resume_via_firmware()) { 711 702 pci_power_t pre_sleep_state = pci_dev->current_state; 712 703 713 - pci_update_current_state(pci_dev, pci_dev->current_state); 704 + pci_refresh_power_state(pci_dev); 705 + /* 706 + * On platforms with ACPI this check may also trigger for 707 + * devices sharing power resources if one of those power 708 + * resources has been activated as a result of a change of the 709 + * power state of another device sharing it. However, in that 710 + * case it is also better to resume the device, in general. 711 + */ 714 712 if (pci_dev->current_state < pre_sleep_state) 715 713 pm_request_resume(dev); 716 714 } ··· 773 757 * better to resume the device from runtime suspend here. 774 758 */ 775 759 if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) || 776 - !pci_dev_keep_suspended(pci_dev)) { 760 + pci_dev_need_resume(pci_dev)) { 777 761 pm_runtime_resume(dev); 778 762 pci_dev->state_saved = false; 763 + } else { 764 + pci_dev_adjust_pme(pci_dev); 779 765 } 780 766 781 767 if (pm->suspend) { ··· 1012 994 } 1013 995 1014 996 /* 1015 - * This used to be done in pci_pm_prepare() for all devices and some 1016 - * drivers may depend on it, so do it here. Ideally, runtime-suspended 1017 - * devices should not be touched during freeze/thaw transitions, 1018 - * however. 997 + * Resume all runtime-suspended devices before creating a snapshot 998 + * image of system memory, because the restore kernel generally cannot 999 + * be expected to always handle them consistently and they need to be 1000 + * put into the runtime-active metastate during system resume anyway, 1001 + * so it is better to ensure that the state saved in the image will be 1002 + * always consistent with that. 1019 1003 */ 1020 - if (!dev_pm_smart_suspend_and_suspended(dev)) { 1021 - pm_runtime_resume(dev); 1022 - pci_dev->state_saved = false; 1023 - } 1004 + pm_runtime_resume(dev); 1005 + pci_dev->state_saved = false; 1024 1006 1025 1007 if (pm->freeze) { 1026 1008 int error; ··· 1034 1016 return 0; 1035 1017 } 1036 1018 1037 - static int pci_pm_freeze_late(struct device *dev) 1038 - { 1039 - if (dev_pm_smart_suspend_and_suspended(dev)) 1040 - return 0; 1041 - 1042 - return pm_generic_freeze_late(dev); 1043 - } 1044 - 1045 1019 static int pci_pm_freeze_noirq(struct device *dev) 1046 1020 { 1047 1021 struct pci_dev *pci_dev = to_pci_dev(dev); 1048 1022 struct device_driver *drv = dev->driver; 1049 - 1050 - if (dev_pm_smart_suspend_and_suspended(dev)) 1051 - return 0; 1052 1023 1053 1024 if (pci_has_legacy_pm_support(pci_dev)) 1054 1025 return pci_legacy_suspend_late(dev, PMSG_FREEZE); ··· 1067 1060 struct pci_dev *pci_dev = to_pci_dev(dev); 1068 1061 struct device_driver *drv = dev->driver; 1069 1062 int error = 0; 1070 - 1071 - /* 1072 - * If the device is in runtime suspend, the code below may not work 1073 - * correctly with it, so skip that code and make the PM core skip all of 1074 - * the subsequent "thaw" callbacks for the device. 1075 - */ 1076 - if (dev_pm_smart_suspend_and_suspended(dev)) { 1077 - dev_pm_skip_next_resume_phases(dev); 1078 - return 0; 1079 - } 1080 1063 1081 1064 if (pcibios_pm_ops.thaw_noirq) { 1082 1065 error = pcibios_pm_ops.thaw_noirq(dev); ··· 1127 1130 1128 1131 /* The reason to do that is the same as in pci_pm_suspend(). */ 1129 1132 if (!dev_pm_test_driver_flags(dev, DPM_FLAG_SMART_SUSPEND) || 1130 - !pci_dev_keep_suspended(pci_dev)) 1133 + pci_dev_need_resume(pci_dev)) { 1131 1134 pm_runtime_resume(dev); 1135 + pci_dev->state_saved = false; 1136 + } else { 1137 + pci_dev_adjust_pme(pci_dev); 1138 + } 1132 1139 1133 - pci_dev->state_saved = false; 1134 1140 if (pm->poweroff) { 1135 1141 int error; 1136 1142 ··· 1205 1205 struct device_driver *drv = dev->driver; 1206 1206 int error = 0; 1207 1207 1208 - /* This is analogous to the pci_pm_resume_noirq() case. */ 1209 - if (dev_pm_smart_suspend_and_suspended(dev)) 1210 - pm_runtime_set_active(dev); 1211 - 1212 1208 if (pcibios_pm_ops.restore_noirq) { 1213 1209 error = pcibios_pm_ops.restore_noirq(dev); 1214 1210 if (error) ··· 1254 1258 #else /* !CONFIG_HIBERNATE_CALLBACKS */ 1255 1259 1256 1260 #define pci_pm_freeze NULL 1257 - #define pci_pm_freeze_late NULL 1258 1261 #define pci_pm_freeze_noirq NULL 1259 1262 #define pci_pm_thaw NULL 1260 1263 #define pci_pm_thaw_noirq NULL ··· 1379 1384 .suspend_late = pci_pm_suspend_late, 1380 1385 .resume = pci_pm_resume, 1381 1386 .freeze = pci_pm_freeze, 1382 - .freeze_late = pci_pm_freeze_late, 1383 1387 .thaw = pci_pm_thaw, 1384 1388 .poweroff = pci_pm_poweroff, 1385 1389 .poweroff_late = pci_pm_poweroff_late,
+82 -34
drivers/pci/pci.c
··· 777 777 return pci_platform_pm ? pci_platform_pm->get_state(dev) : PCI_UNKNOWN; 778 778 } 779 779 780 + static inline void platform_pci_refresh_power_state(struct pci_dev *dev) 781 + { 782 + if (pci_platform_pm && pci_platform_pm->refresh_state) 783 + pci_platform_pm->refresh_state(dev); 784 + } 785 + 780 786 static inline pci_power_t platform_pci_choose_state(struct pci_dev *dev) 781 787 { 782 788 return pci_platform_pm ? ··· 944 938 } 945 939 946 940 /** 941 + * pci_refresh_power_state - Refresh the given device's power state data 942 + * @dev: Target PCI device. 943 + * 944 + * Ask the platform to refresh the devices power state information and invoke 945 + * pci_update_current_state() to update its current PCI power state. 946 + */ 947 + void pci_refresh_power_state(struct pci_dev *dev) 948 + { 949 + if (platform_pci_power_manageable(dev)) 950 + platform_pci_refresh_power_state(dev); 951 + 952 + pci_update_current_state(dev, dev->current_state); 953 + } 954 + 955 + /** 947 956 * pci_power_up - Put the given device into D0 forcibly 948 957 * @dev: PCI device to power up 949 958 */ ··· 1025 1004 if (state == PCI_D0) { 1026 1005 pci_platform_power_transition(dev, PCI_D0); 1027 1006 /* 1028 - * Mandatory power management transition delays, see 1029 - * PCI Express Base Specification Revision 2.0 Section 1030 - * 6.6.1: Conventional Reset. Do not delay for 1031 - * devices powered on/off by corresponding bridge, 1032 - * because have already delayed for the bridge. 1007 + * Mandatory power management transition delays are 1008 + * handled in the PCIe portdrv resume hooks. 1033 1009 */ 1034 1010 if (dev->runtime_d3cold) { 1035 - if (dev->d3cold_delay && !dev->imm_ready) 1036 - msleep(dev->d3cold_delay); 1037 1011 /* 1038 1012 * When powering on a bridge from D3cold, the 1039 1013 * whole hierarchy may be powered on into ··· 2081 2065 */ 2082 2066 if (bridge && bridge->current_state != PCI_D0) 2083 2067 continue; 2068 + /* 2069 + * If the device is in D3cold it should not be 2070 + * polled either. 2071 + */ 2072 + if (pme_dev->dev->current_state == PCI_D3cold) 2073 + continue; 2074 + 2084 2075 pci_pme_wakeup(pme_dev->dev, NULL); 2085 2076 } else { 2086 2077 list_del(&pme_dev->list); ··· 2482 2459 EXPORT_SYMBOL_GPL(pci_dev_run_wake); 2483 2460 2484 2461 /** 2485 - * pci_dev_keep_suspended - Check if the device can stay in the suspended state. 2462 + * pci_dev_need_resume - Check if it is necessary to resume the device. 2486 2463 * @pci_dev: Device to check. 2487 2464 * 2488 - * Return 'true' if the device is runtime-suspended, it doesn't have to be 2465 + * Return 'true' if the device is not runtime-suspended or it has to be 2489 2466 * reconfigured due to wakeup settings difference between system and runtime 2490 - * suspend and the current power state of it is suitable for the upcoming 2491 - * (system) transition. 2492 - * 2493 - * If the device is not configured for system wakeup, disable PME for it before 2494 - * returning 'true' to prevent it from waking up the system unnecessarily. 2467 + * suspend, or the current power state of it is not suitable for the upcoming 2468 + * (system-wide) transition. 2495 2469 */ 2496 - bool pci_dev_keep_suspended(struct pci_dev *pci_dev) 2470 + bool pci_dev_need_resume(struct pci_dev *pci_dev) 2497 2471 { 2498 2472 struct device *dev = &pci_dev->dev; 2499 - bool wakeup = device_may_wakeup(dev); 2473 + pci_power_t target_state; 2500 2474 2501 - if (!pm_runtime_suspended(dev) 2502 - || pci_target_state(pci_dev, wakeup) != pci_dev->current_state 2503 - || platform_pci_need_resume(pci_dev)) 2504 - return false; 2475 + if (!pm_runtime_suspended(dev) || platform_pci_need_resume(pci_dev)) 2476 + return true; 2477 + 2478 + target_state = pci_target_state(pci_dev, device_may_wakeup(dev)); 2505 2479 2506 2480 /* 2507 - * At this point the device is good to go unless it's been configured 2508 - * to generate PME at the runtime suspend time, but it is not supposed 2509 - * to wake up the system. In that case, simply disable PME for it 2510 - * (it will have to be re-enabled on exit from system resume). 2511 - * 2512 - * If the device's power state is D3cold and the platform check above 2513 - * hasn't triggered, the device's configuration is suitable and we don't 2514 - * need to manipulate it at all. 2481 + * If the earlier platform check has not triggered, D3cold is just power 2482 + * removal on top of D3hot, so no need to resume the device in that 2483 + * case. 2515 2484 */ 2485 + return target_state != pci_dev->current_state && 2486 + target_state != PCI_D3cold && 2487 + pci_dev->current_state != PCI_D3hot; 2488 + } 2489 + 2490 + /** 2491 + * pci_dev_adjust_pme - Adjust PME setting for a suspended device. 2492 + * @pci_dev: Device to check. 2493 + * 2494 + * If the device is suspended and it is not configured for system wakeup, 2495 + * disable PME for it to prevent it from waking up the system unnecessarily. 2496 + * 2497 + * Note that if the device's power state is D3cold and the platform check in 2498 + * pci_dev_need_resume() has not triggered, the device's configuration need not 2499 + * be changed. 2500 + */ 2501 + void pci_dev_adjust_pme(struct pci_dev *pci_dev) 2502 + { 2503 + struct device *dev = &pci_dev->dev; 2504 + 2516 2505 spin_lock_irq(&dev->power.lock); 2517 2506 2518 - if (pm_runtime_suspended(dev) && pci_dev->current_state < PCI_D3cold && 2519 - !wakeup) 2507 + if (pm_runtime_suspended(dev) && !device_may_wakeup(dev) && 2508 + pci_dev->current_state < PCI_D3cold) 2520 2509 __pci_pme_active(pci_dev, false); 2521 2510 2522 2511 spin_unlock_irq(&dev->power.lock); 2523 - return true; 2524 2512 } 2525 2513 2526 2514 /** ··· 4602 4568 4603 4569 return pci_dev_wait(dev, "PM D3->D0", PCIE_RESET_READY_POLL_MS); 4604 4570 } 4571 + 4605 4572 /** 4606 - * pcie_wait_for_link - Wait until link is active or inactive 4573 + * pcie_wait_for_link_delay - Wait until link is active or inactive 4607 4574 * @pdev: Bridge device 4608 4575 * @active: waiting for active or inactive? 4576 + * @delay: Delay to wait after link has become active (in ms) 4609 4577 * 4610 4578 * Use this to wait till link becomes active or inactive. 4611 4579 */ 4612 - bool pcie_wait_for_link(struct pci_dev *pdev, bool active) 4580 + bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active, int delay) 4613 4581 { 4614 4582 int timeout = 1000; 4615 4583 bool ret; ··· 4648 4612 timeout -= 10; 4649 4613 } 4650 4614 if (active && ret) 4651 - msleep(100); 4615 + msleep(delay); 4652 4616 else if (ret != active) 4653 4617 pci_info(pdev, "Data Link Layer Link Active not %s in 1000 msec\n", 4654 4618 active ? "set" : "cleared"); 4655 4619 return ret == active; 4620 + } 4621 + 4622 + /** 4623 + * pcie_wait_for_link - Wait until link is active or inactive 4624 + * @pdev: Bridge device 4625 + * @active: waiting for active or inactive? 4626 + * 4627 + * Use this to wait till link becomes active or inactive. 4628 + */ 4629 + bool pcie_wait_for_link(struct pci_dev *pdev, bool active) 4630 + { 4631 + return pcie_wait_for_link_delay(pdev, active, 100); 4656 4632 } 4657 4633 4658 4634 void pci_reset_secondary_bus(struct pci_dev *dev)
+7 -1
drivers/pci/pci.h
··· 51 51 * 52 52 * @get_state: queries the platform firmware for a device's current power state 53 53 * 54 + * @refresh_state: asks the platform to refresh the device's power state data 55 + * 54 56 * @choose_state: returns PCI power state of given device preferred by the 55 57 * platform; to be used during system-wide transitions from a 56 58 * sleeping state to the working state and vice versa ··· 71 69 bool (*is_manageable)(struct pci_dev *dev); 72 70 int (*set_state)(struct pci_dev *dev, pci_power_t state); 73 71 pci_power_t (*get_state)(struct pci_dev *dev); 72 + void (*refresh_state)(struct pci_dev *dev); 74 73 pci_power_t (*choose_state)(struct pci_dev *dev); 75 74 int (*set_wakeup)(struct pci_dev *dev, bool enable); 76 75 bool (*need_resume)(struct pci_dev *dev); ··· 79 76 80 77 int pci_set_platform_pm(const struct pci_platform_pm_ops *ops); 81 78 void pci_update_current_state(struct pci_dev *dev, pci_power_t state); 79 + void pci_refresh_power_state(struct pci_dev *dev); 82 80 void pci_power_up(struct pci_dev *dev); 83 81 void pci_disable_enabled_device(struct pci_dev *dev); 84 82 int pci_finish_runtime_suspend(struct pci_dev *dev); 85 83 void pcie_clear_root_pme_status(struct pci_dev *dev); 86 84 int __pci_pme_wakeup(struct pci_dev *dev, void *ign); 87 85 void pci_pme_restore(struct pci_dev *dev); 88 - bool pci_dev_keep_suspended(struct pci_dev *dev); 86 + bool pci_dev_need_resume(struct pci_dev *dev); 87 + void pci_dev_adjust_pme(struct pci_dev *dev); 89 88 void pci_dev_complete_resume(struct pci_dev *pci_dev); 90 89 void pci_config_pm_runtime_get(struct pci_dev *dev); 91 90 void pci_config_pm_runtime_put(struct pci_dev *dev); ··· 498 493 void pcie_do_recovery(struct pci_dev *dev, enum pci_channel_state state, 499 494 u32 service); 500 495 496 + bool pcie_wait_for_link_delay(struct pci_dev *pdev, bool active, int delay); 501 497 bool pcie_wait_for_link(struct pci_dev *pdev, bool active); 502 498 #ifdef CONFIG_PCIEASPM 503 499 void pcie_aspm_init_link_state(struct pci_dev *pdev);
+66
drivers/pci/pcie/portdrv_core.c
··· 9 9 #include <linux/module.h> 10 10 #include <linux/pci.h> 11 11 #include <linux/kernel.h> 12 + #include <linux/delay.h> 12 13 #include <linux/errno.h> 13 14 #include <linux/pm.h> 14 15 #include <linux/pm_runtime.h> ··· 379 378 return 0; 380 379 } 381 380 381 + static int get_downstream_delay(struct pci_bus *bus) 382 + { 383 + struct pci_dev *pdev; 384 + int min_delay = 100; 385 + int max_delay = 0; 386 + 387 + list_for_each_entry(pdev, &bus->devices, bus_list) { 388 + if (!pdev->imm_ready) 389 + min_delay = 0; 390 + else if (pdev->d3cold_delay < min_delay) 391 + min_delay = pdev->d3cold_delay; 392 + if (pdev->d3cold_delay > max_delay) 393 + max_delay = pdev->d3cold_delay; 394 + } 395 + 396 + return max(min_delay, max_delay); 397 + } 398 + 399 + /* 400 + * wait_for_downstream_link - Wait for downstream link to establish 401 + * @pdev: PCIe port whose downstream link is waited 402 + * 403 + * Handle delays according to PCIe 4.0 section 6.6.1 before configuration 404 + * access to the downstream component is permitted. 405 + * 406 + * This blocks PCI core resume of the hierarchy below this port until the 407 + * link is trained. Should be called before resuming port services to 408 + * prevent pciehp from starting to tear-down the hierarchy too soon. 409 + */ 410 + static void wait_for_downstream_link(struct pci_dev *pdev) 411 + { 412 + int delay; 413 + 414 + if (pci_pcie_type(pdev) != PCI_EXP_TYPE_ROOT_PORT && 415 + pci_pcie_type(pdev) != PCI_EXP_TYPE_DOWNSTREAM) 416 + return; 417 + 418 + if (pci_dev_is_disconnected(pdev)) 419 + return; 420 + 421 + if (!pdev->subordinate || list_empty(&pdev->subordinate->devices) || 422 + !pdev->bridge_d3) 423 + return; 424 + 425 + delay = get_downstream_delay(pdev->subordinate); 426 + if (!delay) 427 + return; 428 + 429 + dev_dbg(&pdev->dev, "waiting downstream link for %d ms\n", delay); 430 + 431 + /* 432 + * If downstream port does not support speeds greater than 5 GT/s 433 + * need to wait 100ms. For higher speeds (gen3) we need to wait 434 + * first for the data link layer to become active. 435 + */ 436 + if (pcie_get_speed_cap(pdev) <= PCIE_SPEED_5_0GT) 437 + msleep(delay); 438 + else 439 + pcie_wait_for_link_delay(pdev, true, delay); 440 + } 441 + 382 442 /** 383 443 * pcie_port_device_suspend - suspend port services associated with a PCIe port 384 444 * @dev: PCI Express port to handle ··· 453 391 int pcie_port_device_resume_noirq(struct device *dev) 454 392 { 455 393 size_t off = offsetof(struct pcie_port_service_driver, resume_noirq); 394 + 395 + wait_for_downstream_link(to_pci_dev(dev)); 456 396 return device_for_each_child(dev, &off, pm_iter); 457 397 } 458 398 ··· 485 421 int pcie_port_device_runtime_resume(struct device *dev) 486 422 { 487 423 size_t off = offsetof(struct pcie_port_service_driver, runtime_resume); 424 + 425 + wait_for_downstream_link(to_pci_dev(dev)); 488 426 return device_for_each_child(dev, &off, pm_iter); 489 427 } 490 428 #endif /* PM */
+11 -30
drivers/power/avs/smartreflex.c
··· 899 899 } 900 900 901 901 dev_info(&pdev->dev, "%s: SmartReflex driver initialized\n", __func__); 902 - if (!sr_dbg_dir) { 902 + if (!sr_dbg_dir) 903 903 sr_dbg_dir = debugfs_create_dir("smartreflex", NULL); 904 - if (IS_ERR_OR_NULL(sr_dbg_dir)) { 905 - ret = PTR_ERR(sr_dbg_dir); 906 - pr_err("%s:sr debugfs dir creation failed(%d)\n", 907 - __func__, ret); 908 - goto err_list_del; 909 - } 910 - } 911 904 912 905 sr_info->dbg_dir = debugfs_create_dir(sr_info->name, sr_dbg_dir); 913 - if (IS_ERR_OR_NULL(sr_info->dbg_dir)) { 914 - dev_err(&pdev->dev, "%s: Unable to create debugfs directory\n", 915 - __func__); 916 - ret = PTR_ERR(sr_info->dbg_dir); 917 - goto err_debugfs; 918 - } 919 906 920 - (void) debugfs_create_file("autocomp", S_IRUGO | S_IWUSR, 921 - sr_info->dbg_dir, (void *)sr_info, &pm_sr_fops); 922 - (void) debugfs_create_x32("errweight", S_IRUGO, sr_info->dbg_dir, 923 - &sr_info->err_weight); 924 - (void) debugfs_create_x32("errmaxlimit", S_IRUGO, sr_info->dbg_dir, 925 - &sr_info->err_maxlimit); 907 + debugfs_create_file("autocomp", S_IRUGO | S_IWUSR, sr_info->dbg_dir, 908 + (void *)sr_info, &pm_sr_fops); 909 + debugfs_create_x32("errweight", S_IRUGO, sr_info->dbg_dir, 910 + &sr_info->err_weight); 911 + debugfs_create_x32("errmaxlimit", S_IRUGO, sr_info->dbg_dir, 912 + &sr_info->err_maxlimit); 926 913 927 914 nvalue_dir = debugfs_create_dir("nvalue", sr_info->dbg_dir); 928 - if (IS_ERR_OR_NULL(nvalue_dir)) { 929 - dev_err(&pdev->dev, "%s: Unable to create debugfs directory for n-values\n", 930 - __func__); 931 - ret = PTR_ERR(nvalue_dir); 932 - goto err_debugfs; 933 - } 934 915 935 916 if (sr_info->nvalue_count == 0 || !sr_info->nvalue_table) { 936 917 dev_warn(&pdev->dev, "%s: %s: No Voltage table for the corresponding vdd. Cannot create debugfs entries for n-values\n", ··· 926 945 927 946 snprintf(name, sizeof(name), "volt_%lu", 928 947 sr_info->nvalue_table[i].volt_nominal); 929 - (void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir, 930 - &(sr_info->nvalue_table[i].nvalue)); 948 + debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir, 949 + &(sr_info->nvalue_table[i].nvalue)); 931 950 snprintf(name, sizeof(name), "errminlimit_%lu", 932 951 sr_info->nvalue_table[i].volt_nominal); 933 - (void) debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir, 934 - &(sr_info->nvalue_table[i].errminlimit)); 952 + debugfs_create_x32(name, S_IRUGO | S_IWUSR, nvalue_dir, 953 + &(sr_info->nvalue_table[i].errminlimit)); 935 954 936 955 } 937 956
+3
drivers/soc/imx/soc-imx8.c
··· 103 103 if (IS_ERR(soc_dev)) 104 104 goto free_rev; 105 105 106 + if (IS_ENABLED(CONFIG_ARM_IMX_CPUFREQ_DT)) 107 + platform_device_register_simple("imx-cpufreq-dt", -1, NULL, 0); 108 + 106 109 return 0; 107 110 108 111 free_rev:
+10 -1
include/acpi/acpi_bus.h
··· 506 506 507 507 int acpi_bus_set_power(acpi_handle handle, int state); 508 508 const char *acpi_power_state_string(int state); 509 - int acpi_device_get_power(struct acpi_device *device, int *state); 510 509 int acpi_device_set_power(struct acpi_device *device, int state); 511 510 int acpi_bus_init_power(struct acpi_device *device); 512 511 int acpi_device_fix_up_power(struct acpi_device *device); 513 512 int acpi_bus_update_power(acpi_handle handle, int *state_p); 514 513 int acpi_device_update_power(struct acpi_device *device, int *state_p); 515 514 bool acpi_bus_power_manageable(acpi_handle handle); 515 + int acpi_device_power_add_dependent(struct acpi_device *adev, 516 + struct device *dev); 517 + void acpi_device_power_remove_dependent(struct acpi_device *adev, 518 + struct device *dev); 516 519 517 520 #ifdef CONFIG_PM 518 521 bool acpi_bus_can_wakeup(acpi_handle handle); ··· 652 649 { 653 650 return -ENODEV; 654 651 } 652 + #endif 653 + 654 + #ifdef CONFIG_ACPI_SYSTEM_POWER_STATES_SUPPORT 655 + bool acpi_sleep_state_supported(u8 sleep_state); 656 + #else 657 + static inline bool acpi_sleep_state_supported(u8 sleep_state) { return false; } 655 658 #endif 656 659 657 660 #ifdef CONFIG_ACPI_SLEEP
+2 -12
include/linux/acpi.h
··· 920 920 #endif 921 921 922 922 #if defined(CONFIG_ACPI) && defined(CONFIG_PM_SLEEP) 923 - int acpi_dev_suspend_late(struct device *dev); 924 923 int acpi_subsys_prepare(struct device *dev); 925 924 void acpi_subsys_complete(struct device *dev); 926 925 int acpi_subsys_suspend_late(struct device *dev); 927 926 int acpi_subsys_suspend_noirq(struct device *dev); 928 - int acpi_subsys_resume_noirq(struct device *dev); 929 - int acpi_subsys_resume_early(struct device *dev); 930 927 int acpi_subsys_suspend(struct device *dev); 931 928 int acpi_subsys_freeze(struct device *dev); 932 - int acpi_subsys_freeze_late(struct device *dev); 933 - int acpi_subsys_freeze_noirq(struct device *dev); 934 - int acpi_subsys_thaw_noirq(struct device *dev); 929 + int acpi_subsys_poweroff(struct device *dev); 935 930 #else 936 - static inline int acpi_dev_resume_early(struct device *dev) { return 0; } 937 931 static inline int acpi_subsys_prepare(struct device *dev) { return 0; } 938 932 static inline void acpi_subsys_complete(struct device *dev) {} 939 933 static inline int acpi_subsys_suspend_late(struct device *dev) { return 0; } 940 934 static inline int acpi_subsys_suspend_noirq(struct device *dev) { return 0; } 941 - static inline int acpi_subsys_resume_noirq(struct device *dev) { return 0; } 942 - static inline int acpi_subsys_resume_early(struct device *dev) { return 0; } 943 935 static inline int acpi_subsys_suspend(struct device *dev) { return 0; } 944 936 static inline int acpi_subsys_freeze(struct device *dev) { return 0; } 945 - static inline int acpi_subsys_freeze_late(struct device *dev) { return 0; } 946 - static inline int acpi_subsys_freeze_noirq(struct device *dev) { return 0; } 947 - static inline int acpi_subsys_thaw_noirq(struct device *dev) { return 0; } 937 + static inline int acpi_subsys_poweroff(struct device *dev) { return 0; } 948 938 #endif 949 939 950 940 #ifdef CONFIG_ACPI
+6
include/linux/cpufreq.h
··· 406 406 const char *cpufreq_get_current_driver(void); 407 407 void *cpufreq_get_driver_data(void); 408 408 409 + static inline int cpufreq_thermal_control_enabled(struct cpufreq_driver *drv) 410 + { 411 + return IS_ENABLED(CONFIG_CPU_THERMAL) && 412 + (drv->flags & CPUFREQ_IS_COOLING_DEV); 413 + } 414 + 409 415 static inline void cpufreq_verify_within_limits(struct cpufreq_policy *policy, 410 416 unsigned int min, unsigned int max) 411 417 {
-1
include/linux/pm.h
··· 760 760 extern int pm_generic_poweroff(struct device *dev); 761 761 extern void pm_generic_complete(struct device *dev); 762 762 763 - extern void dev_pm_skip_next_resume_phases(struct device *dev); 764 763 extern bool dev_pm_may_skip_resume(struct device *dev); 765 764 extern bool dev_pm_smart_suspend_and_suspended(struct device *dev); 766 765
+4 -4
include/linux/pm_opp.h
··· 128 128 void dev_pm_opp_put_clkname(struct opp_table *opp_table); 129 129 struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data)); 130 130 void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table); 131 - struct opp_table *dev_pm_opp_set_genpd_virt_dev(struct device *dev, struct device *virt_dev, int index); 132 - void dev_pm_opp_put_genpd_virt_dev(struct opp_table *opp_table, struct device *virt_dev); 131 + struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names); 132 + void dev_pm_opp_detach_genpd(struct opp_table *opp_table); 133 133 int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate); 134 134 int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq); 135 135 int dev_pm_opp_set_sharing_cpus(struct device *cpu_dev, const struct cpumask *cpumask); ··· 292 292 293 293 static inline void dev_pm_opp_put_clkname(struct opp_table *opp_table) {} 294 294 295 - static inline struct opp_table *dev_pm_opp_set_genpd_virt_dev(struct device *dev, struct device *virt_dev, int index) 295 + static inline struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names) 296 296 { 297 297 return ERR_PTR(-ENOTSUPP); 298 298 } 299 299 300 - static inline void dev_pm_opp_put_genpd_virt_dev(struct opp_table *opp_table, struct device *virt_dev) {} 300 + static inline void dev_pm_opp_detach_genpd(struct opp_table *opp_table) {} 301 301 302 302 static inline int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate) 303 303 {
+1 -1
include/linux/pm_wakeup.h
··· 36 36 * @expire_count: Number of times the wakeup source's timeout has expired. 37 37 * @wakeup_count: Number of times the wakeup source might abort suspend. 38 38 * @active: Status of the wakeup source. 39 - * @has_timeout: The wakeup source has been activated with a timeout. 39 + * @autosleep_enabled: Autosleep is active, so update @prevent_sleep_time. 40 40 */ 41 41 struct wakeup_source { 42 42 const char *name;
+3 -2
include/linux/suspend.h
··· 304 304 return unlikely(s2idle_state == S2IDLE_STATE_ENTER); 305 305 } 306 306 307 - extern bool pm_suspend_via_s2idle(void); 307 + extern bool pm_suspend_default_s2idle(void); 308 308 extern void __init pm_states_init(void); 309 309 extern void s2idle_set_ops(const struct platform_s2idle_ops *ops); 310 310 extern void s2idle_wake(void); ··· 336 336 static inline void pm_set_resume_via_firmware(void) {} 337 337 static inline bool pm_suspend_via_firmware(void) { return false; } 338 338 static inline bool pm_resume_via_firmware(void) { return false; } 339 - static inline bool pm_suspend_via_s2idle(void) { return false; } 339 + static inline bool pm_suspend_default_s2idle(void) { return false; } 340 340 341 341 static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {} 342 342 static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; } ··· 448 448 extern bool hibernation_available(void); 449 449 asmlinkage int swsusp_save(void); 450 450 extern struct pbe *restore_pblist; 451 + int pfn_is_nosave(unsigned long pfn); 451 452 #else /* CONFIG_HIBERNATION */ 452 453 static inline void register_nosave_region(unsigned long b, unsigned long e) {} 453 454 static inline void register_nosave_region_late(unsigned long b, unsigned long e) {}
-2
kernel/power/power.h
··· 75 75 static inline void hibernate_image_size_init(void) {} 76 76 #endif /* !CONFIG_HIBERNATION */ 77 77 78 - extern int pfn_is_nosave(unsigned long); 79 - 80 78 #define power_attr(_name) \ 81 79 static struct kobj_attribute _name##_attr = { \ 82 80 .attr = { \
+3 -3
kernel/power/suspend.c
··· 62 62 static DEFINE_RAW_SPINLOCK(s2idle_lock); 63 63 64 64 /** 65 - * pm_suspend_via_s2idle - Check if suspend-to-idle is the default suspend. 65 + * pm_suspend_default_s2idle - Check if suspend-to-idle is the default suspend. 66 66 * 67 67 * Return 'true' if suspend-to-idle has been selected as the default system 68 68 * suspend method. 69 69 */ 70 - bool pm_suspend_via_s2idle(void) 70 + bool pm_suspend_default_s2idle(void) 71 71 { 72 72 return mem_sleep_current == PM_SUSPEND_TO_IDLE; 73 73 } 74 - EXPORT_SYMBOL_GPL(pm_suspend_via_s2idle); 74 + EXPORT_SYMBOL_GPL(pm_suspend_default_s2idle); 75 75 76 76 void s2idle_set_ops(const struct platform_s2idle_ops *ops) 77 77 {
+1 -2
kernel/power/swap.c
··· 974 974 last = handle->maps = NULL; 975 975 offset = swsusp_header->image; 976 976 while (offset) { 977 - tmp = kmalloc(sizeof(*handle->maps), GFP_KERNEL); 977 + tmp = kzalloc(sizeof(*handle->maps), GFP_KERNEL); 978 978 if (!tmp) { 979 979 release_swap_reader(handle); 980 980 return -ENOMEM; 981 981 } 982 - memset(tmp, 0, sizeof(*tmp)); 983 982 if (!handle->maps) 984 983 handle->maps = tmp; 985 984 if (last)
+1 -1
tools/power/cpupower/man/cpupower-monitor.1
··· 61 61 .PP 62 62 \-i seconds 63 63 .RS 4 64 - Measure intervall. 64 + Measure interval. 65 65 .RE 66 66 .PP 67 67 \-c
+1 -1
tools/power/cpupower/po/cs.po
··· 98 98 99 99 #: utils/idle_monitor/cpupower-monitor.c:74 100 100 #, c-format 101 - msgid "\t -i: time intervall to measure for in seconds (default 1)\n" 101 + msgid "\t -i: time interval to measure for in seconds (default 1)\n" 102 102 msgstr "" 103 103 104 104 #: utils/idle_monitor/cpupower-monitor.c:75
+1 -1
tools/power/cpupower/po/de.po
··· 95 95 96 96 #: utils/idle_monitor/cpupower-monitor.c:74 97 97 #, c-format 98 - msgid "\t -i: time intervall to measure for in seconds (default 1)\n" 98 + msgid "\t -i: time interval to measure for in seconds (default 1)\n" 99 99 msgstr "" 100 100 101 101 #: utils/idle_monitor/cpupower-monitor.c:75
+1 -1
tools/power/cpupower/po/fr.po
··· 95 95 96 96 #: utils/idle_monitor/cpupower-monitor.c:74 97 97 #, c-format 98 - msgid "\t -i: time intervall to measure for in seconds (default 1)\n" 98 + msgid "\t -i: time interval to measure for in seconds (default 1)\n" 99 99 msgstr "" 100 100 101 101 #: utils/idle_monitor/cpupower-monitor.c:75
+1 -1
tools/power/cpupower/po/it.po
··· 95 95 96 96 #: utils/idle_monitor/cpupower-monitor.c:74 97 97 #, c-format 98 - msgid "\t -i: time intervall to measure for in seconds (default 1)\n" 98 + msgid "\t -i: time interval to measure for in seconds (default 1)\n" 99 99 msgstr "" 100 100 101 101 #: utils/idle_monitor/cpupower-monitor.c:75
+1 -1
tools/power/cpupower/po/pt.po
··· 93 93 94 94 #: utils/idle_monitor/cpupower-monitor.c:74 95 95 #, c-format 96 - msgid "\t -i: time intervall to measure for in seconds (default 1)\n" 96 + msgid "\t -i: time interval to measure for in seconds (default 1)\n" 97 97 msgstr "" 98 98 99 99 #: utils/idle_monitor/cpupower-monitor.c:75
+2
tools/power/cpupower/utils/cpufreq-set.c
··· 305 305 bitmask_setbit(cpus_chosen, cpus->cpu); 306 306 cpus = cpus->next; 307 307 } 308 + /* Set the last cpu in related cpus list */ 309 + bitmask_setbit(cpus_chosen, cpus->cpu); 308 310 cpufreq_put_related_cpus(cpus); 309 311 } 310 312 }
+552
tools/power/pm-graph/README
··· 1 + p m - g r a p h 2 + 3 + pm-graph: suspend/resume/boot timing analysis tools 4 + Version: 5.4 5 + Author: Todd Brandt <todd.e.brandt@intel.com> 6 + Home Page: https://01.org/pm-graph 7 + 8 + Report bugs/issues at bugzilla.kernel.org Tools/pm-graph 9 + - https://bugzilla.kernel.org/buglist.cgi?component=pm-graph&product=Tools 10 + 11 + Full documentation available online & in man pages 12 + - Getting Started: 13 + https://01.org/pm-graph/documentation/getting-started 14 + 15 + - Config File Format: 16 + https://01.org/pm-graph/documentation/3-config-file-format 17 + 18 + - upstream version in git: 19 + https://github.com/intel/pm-graph/ 20 + 21 + Table of Contents 22 + - Overview 23 + - Setup 24 + - Usage 25 + - Basic Usage 26 + - Dev Mode Usage 27 + - Proc Mode Usage 28 + - Configuration Files 29 + - Usage Examples 30 + - Config File Options 31 + - Custom Timeline Entries 32 + - Adding/Editing Timeline Functions 33 + - Adding/Editing Dev Timeline Source Functions 34 + - Verifying your Custom Functions 35 + - Testing on consumer linux Operating Systems 36 + - Android 37 + 38 + ------------------------------------------------------------------ 39 + | OVERVIEW | 40 + ------------------------------------------------------------------ 41 + 42 + This tool suite is designed to assist kernel and OS developers in optimizing 43 + their linux stack's suspend/resume & boot time. Using a kernel image built 44 + with a few extra options enabled, the tools will execute a suspend or boot, 45 + and will capture dmesg and ftrace data. This data is transformed into a set of 46 + timelines and a callgraph to give a quick and detailed view of which devices 47 + and kernel processes are taking the most time in suspend/resume & boot. 48 + 49 + ------------------------------------------------------------------ 50 + | SETUP | 51 + ------------------------------------------------------------------ 52 + 53 + These packages are required to execute the scripts 54 + - python 55 + - python-requests 56 + 57 + Ubuntu: 58 + sudo apt-get install python python-requests 59 + 60 + Fedora: 61 + sudo dnf install python python-requests 62 + 63 + The tools can most easily be installed via git clone and make install 64 + 65 + $> git clone http://github.com/intel/pm-graph.git 66 + $> cd pm-graph 67 + $> sudo make install 68 + $> man sleepgraph ; man bootgraph 69 + 70 + Setup involves some minor kernel configuration 71 + 72 + The following kernel build options are required for all kernels: 73 + CONFIG_DEVMEM=y 74 + CONFIG_PM_DEBUG=y 75 + CONFIG_PM_SLEEP_DEBUG=y 76 + CONFIG_FTRACE=y 77 + CONFIG_FUNCTION_TRACER=y 78 + CONFIG_FUNCTION_GRAPH_TRACER=y 79 + CONFIG_KPROBES=y 80 + CONFIG_KPROBES_ON_FTRACE=y 81 + 82 + In kernel 3.15.0, two patches were upstreamed which enable the 83 + v3.0 behavior. These patches allow the tool to read all the 84 + data from trace events instead of from dmesg. You can enable 85 + this behavior on earlier kernels with these patches: 86 + 87 + (kernel/pre-3.15/enable_trace_events_suspend_resume.patch) 88 + (kernel/pre-3.15/enable_trace_events_device_pm_callback.patch) 89 + 90 + If you're using a kernel older than 3.15.0, the following 91 + additional kernel parameters are required: 92 + (e.g. in file /etc/default/grub) 93 + GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=32M ..." 94 + 95 + If you're using a kernel older than 3.11-rc2, the following simple 96 + patch must be applied to enable ftrace data: 97 + in file: kernel/power/suspend.c 98 + in function: int suspend_devices_and_enter(suspend_state_t state) 99 + remove call to "ftrace_stop();" 100 + remove call to "ftrace_start();" 101 + 102 + There is a patch which does this for kernel v3.8.0: 103 + (kernel/pre-3.11-rc2/enable_ftrace_in_suspendresume.patch) 104 + 105 + 106 + 107 + ------------------------------------------------------------------ 108 + | USAGE | 109 + ------------------------------------------------------------------ 110 + 111 + Basic Usage 112 + ___________ 113 + 114 + 1) First configure a kernel using the instructions from the previous sections. 115 + Then build, install, and boot with it. 116 + 2) Open up a terminal window and execute the mode list command: 117 + 118 + %> sudo ./sleepgraph.py -modes 119 + ['freeze', 'mem', 'disk'] 120 + 121 + Execute a test using one of the available power modes, e.g. mem (S3): 122 + 123 + %> sudo ./sleepgraph.py -m mem -rtcwake 15 124 + 125 + or with a config file 126 + 127 + %> sudo ./sleepgraph.py -config config/suspend.cfg 128 + 129 + When the system comes back you'll see the script finishing up and 130 + creating the output files in the test subdir. It generates output 131 + files in subdirectory: suspend-mmddyy-HHMMSS. The ftrace file can 132 + be used to regenerate the html timeline with different options 133 + 134 + HTML output: <hostname>_<mode>.html 135 + raw dmesg output: <hostname>_<mode>_dmesg.txt 136 + raw ftrace output: <hostname>_<mode>_ftrace.txt 137 + 138 + View the html in firefox or chrome. 139 + 140 + 141 + Dev Mode Usage 142 + ______________ 143 + 144 + Developer mode adds information on low level source calls to the timeline. 145 + The tool sets kprobes on all delay and mutex calls to see which devices 146 + are waiting for something and when. It also sets a suite of kprobes on 147 + subsystem dependent calls to better fill out the timeline. 148 + 149 + The tool will also expose kernel threads that don't normally show up in the 150 + timeline. This is useful in discovering dependent threads to get a better 151 + idea of what each device is waiting for. For instance, the scsi_eh thread, 152 + a.k.a. scsi resume error handler, is what each SATA disk device waits for 153 + before it can continue resume. 154 + 155 + The timeline will be much larger if run with dev mode, so it can be useful 156 + to set the -mindev option to clip out any device blocks that are too small 157 + to see easily. The following command will give a nice dev mode run: 158 + 159 + %> sudo ./sleepgraph.py -m mem -rtcwake 15 -mindev 1 -dev 160 + 161 + or with a config file 162 + 163 + %> sudo ./sleepgraph.py -config config/suspend-dev.cfg 164 + 165 + 166 + Proc Mode Usage 167 + _______________ 168 + 169 + Proc mode adds user process info to the timeline. This is done in a manner 170 + similar to the bootchart utility, which graphs init processes and their 171 + execution as the system boots. This tool option does the same thing but for 172 + the period before and after suspend/resume. 173 + 174 + In order to see any process info, there needs to be some delay before or 175 + after resume since processes are frozen in suspend_prepare and thawed in 176 + resume_complete. The predelay and postdelay args allow you to do this. It 177 + can also be useful to run in x2 mode with an x2 delay, this way you can 178 + see process activity before and after resume, and in between two 179 + successive suspend/resumes. 180 + 181 + The command can be run like this: 182 + 183 + %> sudo ./sleepgraph.py -m mem -rtcwake 15 -x2 -x2delay 1000 -predelay 1000 -postdelay 1000 -proc 184 + 185 + or with a config file 186 + 187 + %> sudo ./sleepgraph.py -config config/suspend-proc.cfg 188 + 189 + 190 + ------------------------------------------------------------------ 191 + | CONFIGURATION FILES | 192 + ------------------------------------------------------------------ 193 + 194 + Since 4.0 we've moved to using config files in lieu of command line options. 195 + The config folder contains a collection of typical use cases. 196 + There are corresponding configs for other power modes: 197 + 198 + Simple suspend/resume with basic timeline (mem/freeze/standby) 199 + config/suspend.cfg 200 + config/freeze.cfg 201 + config/standby.cfg 202 + 203 + Dev mode suspend/resume with dev timeline (mem/freeze/standby) 204 + config/suspend-dev.cfg 205 + config/freeze-dev.cfg 206 + config/standby-dev.cfg 207 + 208 + Simple suspend/resume with timeline and callgraph (mem/freeze/standby) 209 + config/suspend-callgraph.cfg 210 + config/freeze-callgraph.cfg 211 + config/standby-callgraph.cfg 212 + 213 + Sample proc mode x2 run using mem suspend 214 + config/suspend-x2-proc.cfg 215 + 216 + Sample for editing timeline funcs (moves internal functions into config) 217 + config/custom-timeline-functions.cfg 218 + 219 + Sample debug config for serio subsystem 220 + config/debug-serio-suspend.cfg 221 + 222 + 223 + Usage Examples 224 + ______________ 225 + 226 + Run a simple mem suspend: 227 + %> sudo ./sleepgraph.py -config config/suspend.cfg 228 + 229 + Run a mem suspend with callgraph data: 230 + %> sudo ./sleepgraph.py -config config/suspend-callgraph.cfg 231 + 232 + Run a mem suspend with dev mode detail: 233 + %> sudo ./sleepgraph.py -config config/suspend-dev.cfg 234 + 235 + 236 + Config File Options 237 + ___________________ 238 + 239 + [Settings] 240 + 241 + # Verbosity: print verbose messages (def: false) 242 + verbose: false 243 + 244 + # Suspend Mode: e.g. standby, mem, freeze, disk (def: mem) 245 + mode: mem 246 + 247 + # Output Directory Format: {hostname}, {date}, {time} give current values 248 + output-dir: suspend-{hostname}-{date}-{time} 249 + 250 + # Automatic Wakeup: use rtcwake to wakeup after X seconds (def: infinity) 251 + rtcwake: 15 252 + 253 + # Add Logs: add the dmesg and ftrace log to the html output (def: false) 254 + addlogs: false 255 + 256 + # Sus/Res Gap: insert a gap between sus & res in the timeline (def: false) 257 + srgap: false 258 + 259 + # Custom Command: Command to execute in lieu of suspend (def: "") 260 + command: echo mem > /sys/power/state 261 + 262 + # Proc mode: graph user processes and cpu usage in the timeline (def: false) 263 + proc: false 264 + 265 + # Dev mode: graph source functions in the timeline (def: false) 266 + dev: false 267 + 268 + # Suspend/Resume x2: run 2 suspend/resumes back to back (def: false) 269 + x2: false 270 + 271 + # x2 Suspend Delay: time delay between the two test runs in ms (def: 0 ms) 272 + x2delay: 0 273 + 274 + # Pre Suspend Delay: nclude an N ms delay before (1st) suspend (def: 0 ms) 275 + predelay: 0 276 + 277 + # Post Resume Delay: include an N ms delay after (last) resume (def: 0 ms) 278 + postdelay: 0 279 + 280 + # Min Device Length: graph only dev callbacks longer than min (def: 0.001 ms) 281 + mindev: 0.001 282 + 283 + # Callgraph: gather ftrace callgraph data on all timeline events (def: false) 284 + callgraph: false 285 + 286 + # Expand Callgraph: pre-expand the callgraph treeviews in html (def: false) 287 + expandcg: false 288 + 289 + # Min Callgraph Length: show callgraphs only if longer than min (def: 1 ms) 290 + mincg: 1 291 + 292 + # Timestamp Precision: number of sig digits in timestamps (0:S, [3:ms], 6:us) 293 + timeprec: 3 294 + 295 + # Device Filter: show only devs whose name/driver includes one of these strings 296 + devicefilter: _cpu_up,_cpu_down,i915,usb 297 + 298 + # Override default timeline entries: 299 + # Do not use the internal default functions for timeline entries (def: false) 300 + # Set this to true if you intend to only use the ones defined in the config 301 + override-timeline-functions: true 302 + 303 + # Override default dev timeline entries: 304 + # Do not use the internal default functions for dev timeline entries (def: false) 305 + # Set this to true if you intend to only use the ones defined in the config 306 + override-dev-timeline-functions: true 307 + 308 + # Call Loop Max Gap (dev mode only) 309 + # merge loops of the same call if each is less than maxgap apart (def: 100us) 310 + callloop-maxgap: 0.0001 311 + 312 + # Call Loop Max Length (dev mode only) 313 + # merge loops of the same call if each is less than maxlen in length (def: 5ms) 314 + callloop-maxlen: 0.005 315 + 316 + ------------------------------------------------------------------ 317 + | CUSTOM TIMELINE ENTRIES | 318 + ------------------------------------------------------------------ 319 + 320 + Adding or Editing Timeline Functions 321 + ____________________________________ 322 + 323 + The tool uses an array of function names to fill out empty spaces in the 324 + timeline where device callbacks don't appear. For instance, in suspend_prepare 325 + the tool adds the sys_sync and freeze_processes calls as virtual device blocks 326 + in the timeline to show you where the time is going. These calls should fill 327 + the timeline with contiguous data so that most kernel execution is covered. 328 + 329 + It is possible to add new function calls to the timeline by adding them to 330 + the config. It's also possible to copy the internal timeline functions into 331 + the config so that you can override and edit them. Place them in the 332 + timeline_functions_ARCH section with the name of your architecture appended. 333 + i.e. for x86_64: [timeline_functions_x86_64] 334 + 335 + Use the override-timeline-functions option if you only want to use your 336 + custom calls, or leave it false to append them to the internal ones. 337 + 338 + This section includes a list of functions (set using kprobes) which use both 339 + symbol data and function arg data. The args are pulled directly from the 340 + stack using this architecture's registers and stack formatting. Each entry 341 + can include up to four pieces of info: The function name, a format string, 342 + an argument list, and a color. But only a function name is required. 343 + 344 + For a full example config, see config/custom-timeline-functions.cfg. It pulls 345 + all the internal timeline functions into the config and allows you to edit 346 + them. 347 + 348 + Entry format: 349 + 350 + function: format{fn_arg1}_{fn_arg2} fn_arg1 fn_arg2 ... [color=purple] 351 + 352 + Required Arguments: 353 + 354 + function: The symbol name for the function you want probed, this is the 355 + minimum required for an entry, it will show up as the function 356 + name with no arguments. 357 + 358 + example: _cpu_up: 359 + 360 + Optional Arguments: 361 + 362 + format: The format to display the data on the timeline in. Use braces to 363 + enclose the arg names. 364 + 365 + example: CPU_ON[{cpu}] 366 + 367 + color: The color of the entry block in the timeline. The default color is 368 + transparent, so the entry shares the phase color. The color is an 369 + html color string, either a word, or an RGB. 370 + 371 + example: [color=#CC00CC] 372 + 373 + arglist: A list of arguments from registers/stack addresses. See URL: 374 + https://www.kernel.org/doc/Documentation/trace/kprobetrace.txt 375 + 376 + example: cpu=%di:s32 377 + 378 + Here is a full example entry. It displays cpu resume calls in the timeline 379 + in orange. They will appear as CPU_ON[0], CPU_ON[1], etc. 380 + 381 + [timeline_functions_x86_64] 382 + _cpu_up: CPU_ON[{cpu}] cpu=%di:s32 [color=orange] 383 + 384 + 385 + Adding or Editing Dev Mode Timeline Source Functions 386 + ____________________________________________________ 387 + 388 + In dev mode, the tool uses an array of function names to monitor source 389 + execution within the timeline entries. 390 + 391 + The function calls are displayed inside the main device/call blocks in the 392 + timeline. However, if a function call is not within a main timeline event, 393 + it will spawn an entirely new event named after the caller's kernel thread. 394 + These asynchronous kernel threads will populate in a separate section 395 + beneath the main device/call section. 396 + 397 + The tool has a set of hard coded calls which focus on the most common use 398 + cases: msleep, udelay, schedule_timeout, mutex_lock_slowpath, etc. These are 399 + the functions that add a hardcoded time delay to the suspend/resume path. 400 + The tool also includes some common functions native to important 401 + subsystems: ata, i915, and ACPI, etc. 402 + 403 + It is possible to add new function calls to the dev timeline by adding them 404 + to the config. It's also possible to copy the internal dev timeline 405 + functions into the config so that you can override and edit them. Place them 406 + in the dev_timeline_functions_ARCH section with the name of your architecture 407 + appended. i.e. for x86_64: [dev_timeline_functions_x86_64] 408 + 409 + Use the override-dev-timeline-functions option if you only want to use your 410 + custom calls, or leave it false to append them to the internal ones. 411 + 412 + The format is the same as the timeline_functions_x86_64 section. It's a 413 + list of functions (set using kprobes) which use both symbol data and function 414 + arg data. The args are pulled directly from the stack using this 415 + architecture's registers and stack formatting. Each entry can include up 416 + to four pieces of info: The function name, a format string, an argument list, 417 + and a color. But only the function name is required. 418 + 419 + For a full example config, see config/custom-timeline-functions.cfg. It pulls 420 + all the internal dev timeline functions into the config and allows you to edit 421 + them. 422 + 423 + Here is a full example entry. It displays the ATA port reset calls as 424 + ataN_port_reset in the timeline. This is where most of the SATA disk resume 425 + time goes, so it can be helpful to see the low level call. 426 + 427 + [dev_timeline_functions_x86_64] 428 + ata_eh_recover: ata{port}_port_reset port=+36(%di):s32 [color=#CC00CC] 429 + 430 + 431 + Verifying your custom functions 432 + _______________________________ 433 + 434 + Once you have a set of functions (kprobes) defined, it can be useful to 435 + perform a quick check to see if you formatted them correctly and if the system 436 + actually supports them. To do this, run the tool with your config file 437 + and the -status option. The tool will go through all the kprobes (both 438 + custom and internal if you haven't overridden them) and actually attempts 439 + to set them in ftrace. It will then print out success or fail for you. 440 + 441 + Note that kprobes which don't actually exist in the kernel won't stop the 442 + tool, they just wont show up. 443 + 444 + For example: 445 + 446 + sudo ./sleepgraph.py -config config/custom-timeline-functions.cfg -status 447 + Checking this system (myhostname)... 448 + have root access: YES 449 + is sysfs mounted: YES 450 + is "mem" a valid power mode: YES 451 + is ftrace supported: YES 452 + are kprobes supported: YES 453 + timeline data source: FTRACE (all trace events found) 454 + is rtcwake supported: YES 455 + verifying timeline kprobes work: 456 + _cpu_down: YES 457 + _cpu_up: YES 458 + acpi_pm_finish: YES 459 + acpi_pm_prepare: YES 460 + freeze_kernel_threads: YES 461 + freeze_processes: YES 462 + sys_sync: YES 463 + thaw_processes: YES 464 + verifying dev kprobes work: 465 + __const_udelay: YES 466 + __mutex_lock_slowpath: YES 467 + acpi_os_stall: YES 468 + acpi_ps_parse_aml: YES 469 + intel_opregion_init: NO 470 + intel_opregion_register: NO 471 + intel_opregion_setup: NO 472 + msleep: YES 473 + schedule_timeout: YES 474 + schedule_timeout_uninterruptible: YES 475 + usleep_range: YES 476 + 477 + 478 + ------------------------------------------------------------------ 479 + | TESTING ON CONSUMER LINUX OPERATING SYSTEMS | 480 + ------------------------------------------------------------------ 481 + 482 + Android 483 + _______ 484 + 485 + The easiest way to execute on an android device is to run the android.sh 486 + script on the device, then pull the ftrace log back to the host and run 487 + sleepgraph.py on it. 488 + 489 + Here are the steps: 490 + 491 + [download and install the tool on the device] 492 + 493 + host%> wget https://raw.githubusercontent.com/intel/pm-graph/master/tools/android.sh 494 + host%> adb connect 192.168.1.6 495 + host%> adb root 496 + # push the script to a writeable location 497 + host%> adb push android.sh /sdcard/ 498 + 499 + [check whether the tool will run on your device] 500 + 501 + host%> adb shell 502 + dev%> cd /sdcard 503 + dev%> sh android.sh status 504 + host : asus_t100 505 + kernel : 3.14.0-i386-dirty 506 + modes : freeze mem 507 + rtcwake : supported 508 + ftrace : supported 509 + trace events { 510 + suspend_resume: found 511 + device_pm_callback_end: found 512 + device_pm_callback_start: found 513 + } 514 + # the above is what you see on a system that's properly patched 515 + 516 + [execute the suspend] 517 + 518 + # NOTE: The suspend will only work if the screen isn't timed out, 519 + # so you have to press some keys first to wake it up b4 suspend) 520 + dev%> sh android.sh suspend mem 521 + ------------------------------------ 522 + Suspend/Resume timing test initiated 523 + ------------------------------------ 524 + hostname : asus_t100 525 + kernel : 3.14.0-i386-dirty 526 + mode : mem 527 + ftrace out : /mnt/shell/emulated/0/ftrace.txt 528 + dmesg out : /mnt/shell/emulated/0/dmesg.txt 529 + log file : /mnt/shell/emulated/0/log.txt 530 + ------------------------------------ 531 + INITIALIZING FTRACE........DONE 532 + STARTING FTRACE 533 + SUSPEND START @ 21:24:02 (rtcwake in 10 seconds) 534 + <adb connection will now terminate> 535 + 536 + [retrieve the data from the device] 537 + 538 + # I find that you have to actually kill the adb process and 539 + # reconnect sometimes in order for the connection to work post-suspend 540 + host%> adb connect 192.168.1.6 541 + # (required) get the ftrace data, this is the most important piece 542 + host%> adb pull /sdcard/ftrace.txt 543 + # (optional) get the dmesg data, this is for debugging 544 + host%> adb pull /sdcard/dmesg.txt 545 + # (optional) get the log, which just lists some test times for comparison 546 + host%> adb pull /sdcard/log.txt 547 + 548 + [create an output html file using sleepgraph.py] 549 + 550 + host%> sleepgraph.py -ftrace ftrace.txt 551 + 552 + You should now have an output.html with the android data, enjoy!
+4 -4
tools/power/pm-graph/bootgraph.py
··· 325 325 if(not sysvals.stamp['kernel']): 326 326 sysvals.stamp['kernel'] = sysvals.kernelVersion(msg) 327 327 continue 328 - m = re.match('.* setting system clock to (?P<t>.*) UTC.*', msg) 328 + m = re.match('.* setting system clock to (?P<d>[0-9\-]*)[ A-Z](?P<t>[0-9:]*) UTC.*', msg) 329 329 if(m): 330 - bt = datetime.strptime(m.group('t'), '%Y-%m-%d %H:%M:%S') 330 + bt = datetime.strptime(m.group('d')+' '+m.group('t'), '%Y-%m-%d %H:%M:%S') 331 331 bt = bt - timedelta(seconds=int(ktime)) 332 332 data.boottime = bt.strftime('%Y-%m-%d_%H:%M:%S') 333 333 sysvals.stamp['time'] = bt.strftime('%B %d %Y, %I:%M:%S %p') ··· 348 348 data.newAction(phase, f, pid, start, ktime, int(r), int(t)) 349 349 del devtemp[f] 350 350 continue 351 - if(re.match('^Freeing unused kernel memory.*', msg)): 351 + if(re.match('^Freeing unused kernel .*', msg)): 352 352 data.tUserMode = ktime 353 353 data.dmesg['kernel']['end'] = ktime 354 354 data.dmesg['user']['start'] = ktime ··· 1008 1008 updateKernelParams() 1009 1009 elif cmd == 'flistall': 1010 1010 for f in sysvals.getBootFtraceFilterFunctions(): 1011 - print f 1011 + print(f) 1012 1012 elif cmd == 'checkbl': 1013 1013 sysvals.getBootLoader() 1014 1014 pprint('Boot Loader: %s\n%s' % (sysvals.bootloader, sysvals.blexec))
+26
tools/power/pm-graph/config/example.cfg
··· 98 98 # graph only devices longer than min in the timeline (default: 0.001 ms) 99 99 mindev: 0.001 100 100 101 + # Call Loop Max Gap (dev mode only) 102 + # merge loops of the same call if each is less than maxgap apart (def: 100us) 103 + callloop-maxgap: 0.0001 104 + 105 + # Call Loop Max Length (dev mode only) 106 + # merge loops of the same call if each is less than maxlen in length (def: 5ms) 107 + callloop-maxlen: 0.005 108 + 109 + # Override default timeline entries: 110 + # Do not use the internal default functions for timeline entries (def: false) 111 + # Set this to true if you intend to only use the ones defined in the config 112 + override-timeline-functions: true 113 + 114 + # Override default dev timeline entries: 115 + # Do not use the internal default functions for dev timeline entries (def: false) 116 + # Set this to true if you intend to only use the ones defined in the config 117 + override-dev-timeline-functions: true 118 + 101 119 # ---- Debug Options ---- 102 120 103 121 # Callgraph 104 122 # gather detailed ftrace callgraph data on all timeline events (default: false) 105 123 callgraph: false 124 + 125 + # Max graph depth 126 + # limit the callgraph trace to this depth (default: 0 = all) 127 + maxdepth: 2 106 128 107 129 # Callgraph phase filter 108 130 # Only enable callgraphs for one phase, i.e. resume_noirq (default: all) ··· 153 131 # Add kprobe functions to the timeline 154 132 # Add functions to the timeline from a text file (default: no-action) 155 133 # fadd: file.txt 134 + 135 + # Ftrace buffer size 136 + # Set trace buffer size to N kilo-bytes (default: all of free memory up to 3GB) 137 + # bufsize: 1000
+14 -2
tools/power/pm-graph/sleepgraph.8
··· 53 53 Add the dmesg and ftrace logs to the html output. They will be viewable by 54 54 clicking buttons in the timeline. 55 55 .TP 56 + \fB-turbostat\fR 57 + Use turbostat to execute the command in freeze mode (default: disabled). This 58 + will provide turbostat output in the log which will tell you which actual 59 + power modes were entered. 60 + .TP 56 61 \fB-result \fIfile\fR 57 62 Export a results table to a text file for parsing. 58 63 .TP ··· 126 121 Use ftrace to create device callgraphs (default: disabled). This can produce 127 122 very large outputs, i.e. 10MB - 100MB. 128 123 .TP 124 + \fB-ftop\fR 125 + Use ftrace on the top level call: "suspend_devices_and_enter" only (default: disabled). 126 + This option implies -f and creates a single callgraph covering all of suspend/resume. 127 + .TP 129 128 \fB-maxdepth \fIlevel\fR 130 129 limit the callgraph trace depth to \fIlevel\fR (default: 0=all). This is 131 130 the best way to limit the output size when using callgraphs via -f. ··· 147 138 The value is a float: e.g. 0.001 represents 1 us. 148 139 .TP 149 140 \fB-cgfilter \fI"func1,func2,..."\fR 150 - Reduce callgraph output in the timeline by limiting it to a list of calls. The 151 - argument can be a single function name or a comma delimited list. 141 + Reduce callgraph output in the timeline by limiting it certain devices. The 142 + argument can be a single device name or a comma delimited list. 152 143 (default: none) 153 144 .TP 154 145 \fB-cgskip \fIfile\fR ··· 191 182 .TP 192 183 \fB-battery\fR 193 184 Print out battery status and current charge. 185 + .TP 186 + \fB-wifi\fR 187 + Print out wifi status and connection details. 194 188 .TP 195 189 \fB-xon/-xoff/-xstandby/-xsuspend\fR 196 190 Test xset by attempting to switch the display to the given mode. This
+657 -200
tools/power/pm-graph/sleepgraph.py
··· 9 9 # 10 10 # Links: 11 11 # Home Page 12 - # https://01.org/suspendresume 12 + # https://01.org/pm-graph 13 13 # Source repo 14 - # git@github.com:01org/pm-graph 14 + # git@github.com:intel/pm-graph 15 15 # 16 16 # Description: 17 17 # This tool is designed to assist kernel and OS developers in optimizing ··· 24 24 # viewed in firefox or chrome. 25 25 # 26 26 # The following kernel build options are required: 27 + # CONFIG_DEVMEM=y 27 28 # CONFIG_PM_DEBUG=y 28 29 # CONFIG_PM_SLEEP_DEBUG=y 29 30 # CONFIG_FTRACE=y ··· 54 53 import gzip 55 54 from threading import Thread 56 55 from subprocess import call, Popen, PIPE 56 + import base64 57 57 58 58 def pprint(msg): 59 59 print(msg) ··· 68 66 # store system values and test parameters 69 67 class SystemValues: 70 68 title = 'SleepGraph' 71 - version = '5.2' 69 + version = '5.4' 72 70 ansi = False 73 71 rs = 0 74 72 display = '' ··· 76 74 sync = False 77 75 verbose = False 78 76 testlog = True 79 - dmesglog = False 77 + dmesglog = True 80 78 ftracelog = False 79 + tstat = False 81 80 mindevlen = 0.0 82 81 mincglen = 0.0 83 82 cgphase = '' ··· 102 99 pmdpath = '/sys/power/pm_debug_messages' 103 100 traceevents = [ 104 101 'suspend_resume', 102 + 'wakeup_source_activate', 103 + 'wakeup_source_deactivate', 105 104 'device_pm_callback_end', 106 105 'device_pm_callback_start' 107 106 ] ··· 135 130 x2delay = 0 136 131 skiphtml = False 137 132 usecallgraph = False 133 + ftopfunc = 'suspend_devices_and_enter' 134 + ftop = False 138 135 usetraceevents = False 139 136 usetracemarkers = True 140 137 usekprobes = True ··· 165 158 'acpi_hibernation_leave': {}, 166 159 'acpi_pm_freeze': {}, 167 160 'acpi_pm_thaw': {}, 161 + 'acpi_s2idle_end': {}, 162 + 'acpi_s2idle_sync': {}, 163 + 'acpi_s2idle_begin': {}, 164 + 'acpi_s2idle_prepare': {}, 165 + 'acpi_s2idle_wake': {}, 166 + 'acpi_s2idle_wakeup': {}, 167 + 'acpi_s2idle_restore': {}, 168 168 'hibernate_preallocate_memory': {}, 169 169 'create_basic_memory_bitmaps': {}, 170 170 'swsusp_write': {}, ··· 205 191 'usleep_range': { 'args_x86_64': {'min':'%di:s32', 'max':'%si:s32'}, 'ub': 1 }, 206 192 'mutex_lock_slowpath': { 'func':'__mutex_lock_slowpath', 'ub': 1 }, 207 193 'acpi_os_stall': {'ub': 1}, 194 + 'rt_mutex_slowlock': {'ub': 1}, 208 195 # ACPI 209 196 'acpi_resume_power_resources': {}, 210 - 'acpi_ps_parse_aml': {}, 197 + 'acpi_ps_execute_method': { 'args_x86_64': { 198 + 'fullpath':'+0(+40(%di)):string', 199 + }}, 200 + # mei_me 201 + 'mei_reset': {}, 211 202 # filesystem 212 203 'ext4_sync_fs': {}, 213 204 # 80211 ··· 261 242 timeformat = '%.3f' 262 243 cmdline = '%s %s' % \ 263 244 (os.path.basename(sys.argv[0]), ' '.join(sys.argv[1:])) 245 + kparams = '' 264 246 sudouser = '' 265 247 def __init__(self): 266 248 self.archargs = 'args_'+platform.machine() ··· 340 320 args['date'] = n.strftime('%y%m%d') 341 321 args['time'] = n.strftime('%H%M%S') 342 322 args['hostname'] = args['host'] = self.hostname 323 + args['mode'] = self.suspendmode 343 324 return value.format(**args) 344 325 def setOutputFile(self): 345 326 if self.dmesgfile != '': ··· 352 331 if(m): 353 332 self.htmlfile = m.group('name')+'.html' 354 333 def systemInfo(self, info): 355 - p = c = m = b = '' 334 + p = m = '' 356 335 if 'baseboard-manufacturer' in info: 357 336 m = info['baseboard-manufacturer'] 358 337 elif 'system-manufacturer' in info: 359 338 m = info['system-manufacturer'] 360 - if 'baseboard-product-name' in info: 361 - p = info['baseboard-product-name'] 362 - elif 'system-product-name' in info: 339 + if 'system-product-name' in info: 363 340 p = info['system-product-name'] 364 - if 'processor-version' in info: 365 - c = info['processor-version'] 366 - if 'bios-version' in info: 367 - b = info['bios-version'] 368 - self.sysstamp = '# sysinfo | man:%s | plat:%s | cpu:%s | bios:%s | numcpu:%d | memsz:%d | memfr:%d' % \ 369 - (m, p, c, b, self.cpucount, self.memtotal, self.memfree) 341 + elif 'baseboard-product-name' in info: 342 + p = info['baseboard-product-name'] 343 + if m[:5].lower() == 'intel' and 'baseboard-product-name' in info: 344 + p = info['baseboard-product-name'] 345 + c = info['processor-version'] if 'processor-version' in info else '' 346 + b = info['bios-version'] if 'bios-version' in info else '' 347 + r = info['bios-release-date'] if 'bios-release-date' in info else '' 348 + self.sysstamp = '# sysinfo | man:%s | plat:%s | cpu:%s | bios:%s | biosdate:%s | numcpu:%d | memsz:%d | memfr:%d' % \ 349 + (m, p, c, b, r, self.cpucount, self.memtotal, self.memfree) 350 + try: 351 + kcmd = open('/proc/cmdline', 'r').read().strip() 352 + except: 353 + kcmd = '' 354 + if kcmd: 355 + self.sysstamp += '\n# kparams | %s' % kcmd 370 356 def printSystemInfo(self, fatal=False): 371 357 self.rootCheck(True) 372 358 out = dmidecode(self.mempath, fatal) ··· 381 353 return 382 354 fmt = '%-24s: %s' 383 355 for name in sorted(out): 384 - print fmt % (name, out[name]) 385 - print fmt % ('cpucount', ('%d' % self.cpucount)) 386 - print fmt % ('memtotal', ('%d kB' % self.memtotal)) 387 - print fmt % ('memfree', ('%d kB' % self.memfree)) 356 + print(fmt % (name, out[name])) 357 + print(fmt % ('cpucount', ('%d' % self.cpucount))) 358 + print(fmt % ('memtotal', ('%d kB' % self.memtotal))) 359 + print(fmt % ('memfree', ('%d kB' % self.memfree))) 388 360 def cpuInfo(self): 389 361 self.cpucount = 0 390 362 fp = open('/proc/cpuinfo', 'r') ··· 404 376 def initTestOutput(self, name): 405 377 self.prefix = self.hostname 406 378 v = open('/proc/version', 'r').read().strip() 407 - kver = string.split(v)[2] 379 + kver = v.split()[2] 408 380 fmt = name+'-%m%d%y-%H%M%S' 409 381 testtime = datetime.now().strftime(fmt) 410 382 self.teststamp = \ ··· 419 391 self.htmlfile = \ 420 392 self.testdir+'/'+self.prefix+'_'+self.suspendmode+'.html' 421 393 if not os.path.isdir(self.testdir): 422 - os.mkdir(self.testdir) 394 + os.makedirs(self.testdir) 423 395 def getValueList(self, value): 424 396 out = [] 425 397 for i in value.split(','): ··· 430 402 self.devicefilter = self.getValueList(value) 431 403 def setCallgraphFilter(self, value): 432 404 self.cgfilter = self.getValueList(value) 405 + def skipKprobes(self, value): 406 + for k in self.getValueList(value): 407 + if k in self.tracefuncs: 408 + del self.tracefuncs[k] 409 + if k in self.dev_tracefuncs: 410 + del self.dev_tracefuncs[k] 433 411 def setCallgraphBlacklist(self, file): 434 412 self.cgblacklist = self.listFromFile(file) 435 413 def rtcWakeAlarmOn(self): ··· 505 471 if 'func' in self.tracefuncs[i]: 506 472 i = self.tracefuncs[i]['func'] 507 473 if i in master: 508 - print i 474 + print(i) 509 475 else: 510 - print self.colorText(i) 476 + print(self.colorText(i)) 511 477 def setFtraceFilterFunctions(self, list): 512 478 master = self.listFromFile(self.tpath+'available_filter_functions') 513 479 flist = '' ··· 714 680 if self.bufsize > 0: 715 681 tgtsize = self.bufsize 716 682 elif self.usecallgraph or self.usedevsrc: 717 - bmax = (1*1024*1024) if self.suspendmode == 'disk' else (3*1024*1024) 683 + bmax = (1*1024*1024) if self.suspendmode in ['disk', 'command'] \ 684 + else (3*1024*1024) 718 685 tgtsize = min(self.memfree, bmax) 719 686 else: 720 687 tgtsize = 65536 ··· 750 715 cf.append(self.tracefuncs[fn]['func']) 751 716 else: 752 717 cf.append(fn) 753 - self.setFtraceFilterFunctions(cf) 718 + if self.ftop: 719 + self.setFtraceFilterFunctions([self.ftopfunc]) 720 + else: 721 + self.setFtraceFilterFunctions(cf) 754 722 # initialize the kprobe trace 755 723 elif self.usekprobes: 756 724 for name in self.tracefuncs: ··· 806 768 fw = test['fw'] 807 769 if(fw): 808 770 fp.write('# fwsuspend %u fwresume %u\n' % (fw[0], fw[1])) 771 + if 'mcelog' in test: 772 + fp.write('# mcelog %s\n' % test['mcelog']) 773 + if 'turbo' in test: 774 + fp.write('# turbostat %s\n' % test['turbo']) 809 775 if 'bat' in test: 810 776 (a1, c1), (a2, c2) = test['bat'] 811 777 fp.write('# battery %s %d %s %d\n' % (a1, c1, a2, c2)) 778 + if 'wifi' in test: 779 + wstr = [] 780 + for wifi in test['wifi']: 781 + tmp = [] 782 + for key in sorted(wifi): 783 + tmp.append('%s:%s' % (key, wifi[key])) 784 + wstr.append('|'.join(tmp)) 785 + fp.write('# wifi %s\n' % (','.join(wstr))) 812 786 if test['error'] or len(testdata) > 1: 813 787 fp.write('# enter_sleep_error %s\n' % test['error']) 814 788 return fp ··· 871 821 if isgz: 872 822 return gzip.open(filename, mode+'b') 873 823 return open(filename, mode) 824 + def mcelog(self, clear=False): 825 + cmd = self.getExec('mcelog') 826 + if not cmd: 827 + return '' 828 + if clear: 829 + call(cmd+' > /dev/null 2>&1', shell=True) 830 + return '' 831 + fp = Popen([cmd], stdout=PIPE, stderr=PIPE).stdout 832 + out = fp.read().strip() 833 + fp.close() 834 + if not out: 835 + return '' 836 + return base64.b64encode(out.encode('zlib')) 837 + def haveTurbostat(self): 838 + if not self.tstat: 839 + return False 840 + cmd = self.getExec('turbostat') 841 + if not cmd: 842 + return False 843 + fp = Popen([cmd, '-v'], stdout=PIPE, stderr=PIPE).stderr 844 + out = fp.read().strip() 845 + fp.close() 846 + return re.match('turbostat version [0-9\.]* .*', out) 847 + def turbostat(self): 848 + cmd = self.getExec('turbostat') 849 + if not cmd: 850 + return 'missing turbostat executable' 851 + text = [] 852 + fullcmd = '%s -q -S echo freeze > %s' % (cmd, self.powerfile) 853 + fp = Popen(['sh', '-c', fullcmd], stdout=PIPE, stderr=PIPE).stderr 854 + for line in fp: 855 + if re.match('[0-9.]* sec', line): 856 + continue 857 + text.append(line.split()) 858 + fp.close() 859 + if len(text) < 2: 860 + return 'turbostat output format error' 861 + out = [] 862 + for key in text[0]: 863 + values = [] 864 + idx = text[0].index(key) 865 + for line in text[1:]: 866 + if len(line) > idx: 867 + values.append(line[idx]) 868 + out.append('%s=%s' % (key, ','.join(values))) 869 + return '|'.join(out) 870 + def checkWifi(self): 871 + out = dict() 872 + iwcmd, ifcmd = self.getExec('iwconfig'), self.getExec('ifconfig') 873 + if not iwcmd or not ifcmd: 874 + return out 875 + fp = Popen(iwcmd, stdout=PIPE, stderr=PIPE).stdout 876 + for line in fp: 877 + m = re.match('(?P<dev>\S*) .* ESSID:(?P<ess>\S*)', line) 878 + if not m: 879 + continue 880 + out['device'] = m.group('dev') 881 + if '"' in m.group('ess'): 882 + out['essid'] = m.group('ess').strip('"') 883 + break 884 + fp.close() 885 + if 'device' in out: 886 + fp = Popen([ifcmd, out['device']], stdout=PIPE, stderr=PIPE).stdout 887 + for line in fp: 888 + m = re.match('.* inet (?P<ip>[0-9\.]*)', line) 889 + if m: 890 + out['ip'] = m.group('ip') 891 + break 892 + fp.close() 893 + return out 894 + def errorSummary(self, errinfo, msg): 895 + found = False 896 + for entry in errinfo: 897 + if re.match(entry['match'], msg): 898 + entry['count'] += 1 899 + if self.hostname not in entry['urls']: 900 + entry['urls'][self.hostname] = [self.htmlfile] 901 + elif self.htmlfile not in entry['urls'][self.hostname]: 902 + entry['urls'][self.hostname].append(self.htmlfile) 903 + found = True 904 + break 905 + if found: 906 + return 907 + arr = msg.split() 908 + for j in range(len(arr)): 909 + if re.match('^[0-9,\-\.]*$', arr[j]): 910 + arr[j] = '[0-9,\-\.]*' 911 + else: 912 + arr[j] = arr[j]\ 913 + .replace('\\', '\\\\').replace(']', '\]').replace('[', '\[')\ 914 + .replace('.', '\.').replace('+', '\+').replace('*', '\*')\ 915 + .replace('(', '\(').replace(')', '\)') 916 + mstr = ' '.join(arr) 917 + entry = { 918 + 'line': msg, 919 + 'match': mstr, 920 + 'count': 1, 921 + 'urls': {self.hostname: [self.htmlfile]} 922 + } 923 + errinfo.append(entry) 874 924 875 925 sysvals = SystemValues() 876 926 switchvalues = ['enable', 'disable', 'on', 'off', 'true', 'false', '1', '0'] ··· 1065 915 'ERROR' : '.*ERROR.*', 1066 916 'WARNING' : '.*WARNING.*', 1067 917 'IRQ' : '.*genirq: .*', 1068 - 'TASKFAIL': '.*Freezing of tasks failed.*', 918 + 'TASKFAIL': '.*Freezing of tasks *.*', 919 + 'ACPI' : '.*ACPI *(?P<b>[A-Za-z]*) *Error[: ].*', 920 + 'DEVFAIL' : '.* failed to (?P<b>[a-z]*) async: .*', 921 + 'DISKFULL': '.*No space left on device.*', 922 + 'USBERR' : '.*usb .*device .*, error [0-9-]*', 923 + 'ATAERR' : ' *ata[0-9\.]*: .*failed.*', 924 + 'MEIERR' : ' *mei.*: .*failed.*', 925 + 'TPMERR' : '(?i) *tpm *tpm[0-9]*: .*error.*', 1069 926 } 1070 927 def __init__(self, num): 1071 928 idchar = 'abcdefghij' ··· 1090 933 self.outfile = '' 1091 934 self.kerror = False 1092 935 self.battery = 0 936 + self.wifi = 0 937 + self.turbostat = 0 938 + self.mcelog = 0 1093 939 self.enterfail = '' 1094 940 self.currphase = '' 1095 941 self.pstl = dict() # process timeline ··· 1127 967 if len(plist) < 1: 1128 968 return '' 1129 969 return plist[-1] 970 + def turbostatInfo(self): 971 + tp = TestProps() 972 + out = {'syslpi':'N/A','pkgpc10':'N/A'} 973 + for line in self.dmesgtext: 974 + m = re.match(tp.tstatfmt, line) 975 + if not m: 976 + continue 977 + for i in m.group('t').split('|'): 978 + if 'SYS%LPI' in i: 979 + out['syslpi'] = i.split('=')[-1]+'%' 980 + elif 'pc10' in i: 981 + out['pkgpc10'] = i.split('=')[-1]+'%' 982 + break 983 + return out 1130 984 def extractErrorInfo(self): 1131 - lf = sysvals.openlog(sysvals.dmesgfile, 'r') 985 + lf = self.dmesgtext 986 + if len(self.dmesgtext) < 1 and sysvals.dmesgfile: 987 + lf = sysvals.openlog(sysvals.dmesgfile, 'r') 1132 988 i = 0 1133 989 list = [] 1134 990 for line in lf: ··· 1159 983 msg = m.group('msg') 1160 984 for err in self.errlist: 1161 985 if re.match(self.errlist[err], msg): 1162 - list.append((err, dir, t, i, i)) 986 + list.append((msg, err, dir, t, i, i)) 1163 987 self.kerror = True 1164 988 break 1165 - for e in list: 1166 - type, dir, t, idx1, idx2 = e 989 + msglist = [] 990 + for msg, type, dir, t, idx1, idx2 in list: 991 + msglist.append(msg) 1167 992 sysvals.vprint('kernel %s found in %s at %f' % (type, dir, t)) 1168 993 self.errorinfo[dir].append((type, t, idx1, idx2)) 1169 994 if self.kerror: 1170 995 sysvals.dmesglog = True 1171 - lf.close() 996 + if len(self.dmesgtext) < 1 and sysvals.dmesgfile: 997 + lf.close() 998 + return msglist 1172 999 def setStart(self, time): 1173 1000 self.start = time 1174 1001 def setEnd(self, time): ··· 2224 2045 if(data.dmesg[p]['start'] <= self.start and 2225 2046 self.start <= data.dmesg[p]['end']): 2226 2047 list = data.dmesg[p]['list'] 2227 - for devname in list: 2048 + for devname in sorted(list, key=lambda k:list[k]['start']): 2228 2049 dev = list[devname] 2229 2050 if(pid == dev['pid'] and 2230 2051 self.start <= dev['start'] and ··· 2529 2350 '(?P<H>[0-9]{2})(?P<M>[0-9]{2})(?P<S>[0-9]{2})'+\ 2530 2351 ' (?P<host>.*) (?P<mode>.*) (?P<kernel>.*)$' 2531 2352 batteryfmt = '^# battery (?P<a1>\w*) (?P<c1>\d*) (?P<a2>\w*) (?P<c2>\d*)' 2353 + wififmt = '^# wifi (?P<w>.*)' 2354 + tstatfmt = '^# turbostat (?P<t>\S*)' 2355 + mcelogfmt = '^# mcelog (?P<m>\S*)' 2532 2356 testerrfmt = '^# enter_sleep_error (?P<e>.*)' 2533 2357 sysinfofmt = '^# sysinfo .*' 2534 2358 cmdlinefmt = '^# command \| (?P<cmd>.*)' ··· 2554 2372 self.cmdline = '' 2555 2373 self.kparams = '' 2556 2374 self.testerror = [] 2375 + self.mcelog = [] 2376 + self.turbostat = [] 2557 2377 self.battery = [] 2378 + self.wifi = [] 2558 2379 self.fwdata = [] 2559 2380 self.ftrace_line_fmt = self.ftrace_line_fmt_nop 2560 2381 self.cgformat = False ··· 2571 2386 self.ftrace_line_fmt = self.ftrace_line_fmt_nop 2572 2387 else: 2573 2388 doError('Invalid tracer format: [%s]' % tracer) 2389 + def decode(self, data): 2390 + try: 2391 + out = base64.b64decode(data).decode('zlib') 2392 + except: 2393 + out = data 2394 + return out 2395 + def stampInfo(self, line): 2396 + if re.match(self.stampfmt, line): 2397 + self.stamp = line 2398 + return True 2399 + elif re.match(self.sysinfofmt, line): 2400 + self.sysinfo = line 2401 + return True 2402 + elif re.match(self.kparamsfmt, line): 2403 + self.kparams = line 2404 + return True 2405 + elif re.match(self.cmdlinefmt, line): 2406 + self.cmdline = line 2407 + return True 2408 + elif re.match(self.mcelogfmt, line): 2409 + self.mcelog.append(line) 2410 + return True 2411 + elif re.match(self.tstatfmt, line): 2412 + self.turbostat.append(line) 2413 + return True 2414 + elif re.match(self.batteryfmt, line): 2415 + self.battery.append(line) 2416 + return True 2417 + elif re.match(self.wififmt, line): 2418 + self.wifi.append(line) 2419 + return True 2420 + elif re.match(self.testerrfmt, line): 2421 + self.testerror.append(line) 2422 + return True 2423 + elif re.match(self.firmwarefmt, line): 2424 + self.fwdata.append(line) 2425 + return True 2426 + return False 2574 2427 def parseStamp(self, data, sv): 2575 2428 # global test data 2576 2429 m = re.match(self.stampfmt, self.stamp) ··· 2651 2428 sv.stamp = data.stamp 2652 2429 # firmware data 2653 2430 if sv.suspendmode == 'mem' and len(self.fwdata) > data.testnumber: 2654 - data.fwSuspend, data.fwResume = self.fwdata[data.testnumber] 2655 - if(data.fwSuspend > 0 or data.fwResume > 0): 2656 - data.fwValid = True 2431 + m = re.match(self.firmwarefmt, self.fwdata[data.testnumber]) 2432 + if m: 2433 + data.fwSuspend, data.fwResume = int(m.group('s')), int(m.group('r')) 2434 + if(data.fwSuspend > 0 or data.fwResume > 0): 2435 + data.fwValid = True 2436 + # mcelog data 2437 + if len(self.mcelog) > data.testnumber: 2438 + m = re.match(self.mcelogfmt, self.mcelog[data.testnumber]) 2439 + if m: 2440 + data.mcelog = self.decode(m.group('m')) 2441 + # turbostat data 2442 + if len(self.turbostat) > data.testnumber: 2443 + m = re.match(self.tstatfmt, self.turbostat[data.testnumber]) 2444 + if m: 2445 + data.turbostat = m.group('t') 2657 2446 # battery data 2658 2447 if len(self.battery) > data.testnumber: 2659 2448 m = re.match(self.batteryfmt, self.battery[data.testnumber]) 2660 2449 if m: 2661 2450 data.battery = m.groups() 2451 + # wifi data 2452 + if len(self.wifi) > data.testnumber: 2453 + m = re.match(self.wififmt, self.wifi[data.testnumber]) 2454 + if m: 2455 + data.wifi = m.group('w') 2662 2456 # sleep mode enter errors 2663 2457 if len(self.testerror) > data.testnumber: 2664 2458 m = re.match(self.testerrfmt, self.testerror[data.testnumber]) ··· 2745 2505 # Quickly determine if the ftrace log has all of the trace events, 2746 2506 # markers, and/or kprobes required for primary parsing. 2747 2507 def doesTraceLogHaveTraceEvents(): 2748 - kpcheck = ['_cal: (', '_cpu_down()'] 2508 + kpcheck = ['_cal: (', '_ret: ('] 2749 2509 techeck = ['suspend_resume', 'device_pm_callback'] 2750 - tmcheck = ['tracing_mark_write'] 2510 + tmcheck = ['SUSPEND START', 'RESUME COMPLETE'] 2751 2511 sysvals.usekprobes = False 2752 2512 fp = sysvals.openlog(sysvals.ftracefile, 'r') 2753 2513 for line in fp: ··· 2796 2556 for line in tf: 2797 2557 # remove any latent carriage returns 2798 2558 line = line.replace('\r\n', '') 2799 - # grab the stamp and sysinfo 2800 - if re.match(tp.stampfmt, line): 2801 - tp.stamp = line 2802 - continue 2803 - elif re.match(tp.sysinfofmt, line): 2804 - tp.sysinfo = line 2805 - continue 2806 - elif re.match(tp.cmdlinefmt, line): 2807 - tp.cmdline = line 2808 - continue 2809 - elif re.match(tp.batteryfmt, line): 2810 - tp.battery.append(line) 2811 - continue 2812 - elif re.match(tp.testerrfmt, line): 2813 - tp.testerror.append(line) 2559 + if tp.stampInfo(line): 2814 2560 continue 2815 2561 # determine the trace data type (required for further parsing) 2816 2562 m = re.match(tp.tracertypefmt, line) ··· 2919 2693 for line in tf: 2920 2694 # remove any latent carriage returns 2921 2695 line = line.replace('\r\n', '') 2922 - # stamp and sysinfo lines 2923 - if re.match(tp.stampfmt, line): 2924 - tp.stamp = line 2925 - continue 2926 - elif re.match(tp.sysinfofmt, line): 2927 - tp.sysinfo = line 2928 - continue 2929 - elif re.match(tp.cmdlinefmt, line): 2930 - tp.cmdline = line 2931 - continue 2932 - elif re.match(tp.batteryfmt, line): 2933 - tp.battery.append(line) 2934 - continue 2935 - elif re.match(tp.testerrfmt, line): 2936 - tp.testerror.append(line) 2937 - continue 2938 - # firmware line: pull out any firmware data 2939 - m = re.match(tp.firmwarefmt, line) 2940 - if(m): 2941 - tp.fwdata.append((int(m.group('s')), int(m.group('r')))) 2696 + if tp.stampInfo(line): 2942 2697 continue 2943 2698 # tracer type line: determine the trace data type 2944 2699 m = re.match(tp.tracertypefmt, line) ··· 3132 2925 tp.ktemp[key].append({ 3133 2926 'pid': pid, 3134 2927 'begin': t.time, 3135 - 'end': t.time, 2928 + 'end': -1, 3136 2929 'name': displayname, 3137 2930 'cdata': kprobedata, 3138 2931 'proc': m_proc, ··· 3143 2936 elif(t.freturn): 3144 2937 if(key not in tp.ktemp) or len(tp.ktemp[key]) < 1: 3145 2938 continue 3146 - e = tp.ktemp[key][-1] 3147 - if e['begin'] < 0.0 or t.time - e['begin'] < 0.000001: 3148 - tp.ktemp[key].pop() 3149 - else: 3150 - e['end'] = t.time 3151 - e['rdata'] = kprobedata 2939 + e = next((x for x in reversed(tp.ktemp[key]) if x['end'] < 0), 0) 2940 + if not e: 2941 + continue 2942 + e['end'] = t.time 2943 + e['rdata'] = kprobedata 3152 2944 # end of kernel resume 3153 2945 if(phase != 'suspend_prepare' and kprobename in krescalls): 3154 2946 if phase in data.dmesg: ··· 3169 2963 if(res == -1): 3170 2964 testrun.ftemp[key][-1].addLine(t) 3171 2965 tf.close() 2966 + if len(testdata) < 1: 2967 + sysvals.vprint('WARNING: ftrace start marker is missing') 3172 2968 if data and not data.devicegroups: 3173 - sysvals.vprint('WARNING: end marker is missing') 2969 + sysvals.vprint('WARNING: ftrace end marker is missing') 3174 2970 data.handleEndMarker(t.time) 3175 2971 3176 2972 if sysvals.suspendmode == 'command': ··· 3221 3013 name, pid = key 3222 3014 if name not in sysvals.tracefuncs: 3223 3015 continue 3016 + if pid not in data.devpids: 3017 + data.devpids.append(pid) 3224 3018 for e in tp.ktemp[key]: 3225 3019 kb, ke = e['begin'], e['end'] 3226 - if kb == ke or tlb > kb or tle <= kb: 3020 + if ke - kb < 0.000001 or tlb > kb or tle <= kb: 3227 3021 continue 3228 3022 color = sysvals.kprobeColor(name) 3229 3023 data.newActionGlobal(e['name'], kb, ke, pid, color) ··· 3237 3027 continue 3238 3028 for e in tp.ktemp[key]: 3239 3029 kb, ke = e['begin'], e['end'] 3240 - if kb == ke or tlb > kb or tle <= kb: 3030 + if ke - kb < 0.000001 or tlb > kb or tle <= kb: 3241 3031 continue 3242 3032 data.addDeviceFunctionCall(e['name'], name, e['proc'], pid, kb, 3243 3033 ke, e['cdata'], e['rdata']) ··· 3261 3051 if not devname: 3262 3052 sortkey = '%f%f%d' % (cg.start, cg.end, pid) 3263 3053 sortlist[sortkey] = cg 3264 - elif len(cg.list) > 1000000: 3054 + elif len(cg.list) > 1000000 and cg.name != sysvals.ftopfunc: 3265 3055 sysvals.vprint('WARNING: the callgraph for %s is massive (%d lines)' %\ 3266 3056 (devname, len(cg.list))) 3267 3057 # create blocks for orphan cg data ··· 3343 3133 idx = line.find('[') 3344 3134 if idx > 1: 3345 3135 line = line[idx:] 3346 - # grab the stamp and sysinfo 3347 - if re.match(tp.stampfmt, line): 3348 - tp.stamp = line 3349 - continue 3350 - elif re.match(tp.sysinfofmt, line): 3351 - tp.sysinfo = line 3352 - continue 3353 - elif re.match(tp.cmdlinefmt, line): 3354 - tp.cmdline = line 3355 - continue 3356 - elif re.match(tp.batteryfmt, line): 3357 - tp.battery.append(line) 3358 - continue 3359 - elif re.match(tp.testerrfmt, line): 3360 - tp.testerror.append(line) 3361 - continue 3362 - m = re.match(tp.firmwarefmt, line) 3363 - if(m): 3364 - tp.fwdata.append((int(m.group('s')), int(m.group('r')))) 3136 + if tp.stampInfo(line): 3365 3137 continue 3366 3138 m = re.match('[ \t]*(\[ *)(?P<ktime>[0-9\.]*)(\]) (?P<msg>.*)', line) 3367 3139 if(not m): ··· 3368 3176 if data: 3369 3177 testruns.append(data) 3370 3178 if len(testruns) < 1: 3371 - pprint('ERROR: dmesg log has no suspend/resume data: %s' \ 3179 + doError('dmesg log has no suspend/resume data: %s' \ 3372 3180 % sysvals.dmesgfile) 3373 3181 3374 3182 # fix lines with same timestamp/function with the call and return swapped ··· 3707 3515 name += ' '+p 3708 3516 if('ftrace' in dev): 3709 3517 cg = dev['ftrace'] 3518 + if cg.name == sv.ftopfunc: 3519 + name = 'top level suspend/resume call' 3710 3520 num = callgraphHTML(sv, hf, num, cg, 3711 3521 name, color, dev['id']) 3712 3522 if('ftraces' in dev): ··· 3717 3523 name+' &rarr; '+cg.name, color, dev['id']) 3718 3524 hf.write('\n\n </section>\n') 3719 3525 3720 - # Function: createHTMLSummarySimple 3721 - # Description: 3722 - # Create summary html file for a series of tests 3723 - # Arguments: 3724 - # testruns: array of Data objects from parseTraceLog 3725 - def createHTMLSummarySimple(testruns, htmlfile, title): 3726 - # write the html header first (html head, css code, up to body start) 3727 - html = '<!DOCTYPE html>\n<html>\n<head>\n\ 3526 + def summaryCSS(title, center=True): 3527 + tdcenter = 'text-align:center;' if center else '' 3528 + out = '<!DOCTYPE html>\n<html>\n<head>\n\ 3728 3529 <meta http-equiv="content-type" content="text/html; charset=UTF-8">\n\ 3729 - <title>SleepGraph Summary</title>\n\ 3530 + <title>'+title+'</title>\n\ 3730 3531 <style type=\'text/css\'>\n\ 3731 3532 .stamp {width: 100%;text-align:center;background:#888;line-height:30px;color:white;font: 25px Arial;}\n\ 3732 - table {width:100%;border-collapse: collapse;}\n\ 3733 - .summary {border:1px solid;}\n\ 3533 + table {width:100%;border-collapse: collapse;border:1px solid;}\n\ 3734 3534 th {border: 1px solid black;background:#222;color:white;}\n\ 3735 - td {font: 14px "Times New Roman";text-align: center;}\n\ 3535 + td {font: 14px "Times New Roman";'+tdcenter+'}\n\ 3736 3536 tr.head td {border: 1px solid black;background:#aaa;}\n\ 3737 3537 tr.alt {background-color:#ddd;}\n\ 3738 3538 tr.notice {color:red;}\n\ ··· 3735 3547 .maxval {background-color:#FFBBBB;}\n\ 3736 3548 .head a {color:#000;text-decoration: none;}\n\ 3737 3549 </style>\n</head>\n<body>\n' 3550 + return out 3551 + 3552 + # Function: createHTMLSummarySimple 3553 + # Description: 3554 + # Create summary html file for a series of tests 3555 + # Arguments: 3556 + # testruns: array of Data objects from parseTraceLog 3557 + def createHTMLSummarySimple(testruns, htmlfile, title): 3558 + # write the html header first (html head, css code, up to body start) 3559 + html = summaryCSS('Summary - SleepGraph') 3738 3560 3739 3561 # extract the test data into list 3740 3562 list = dict() 3741 - tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [[], []] 3563 + tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()] 3742 3564 iMin, iMed, iMax = [0, 0], [0, 0], [0, 0] 3743 3565 num = 0 3566 + useturbo = False 3744 3567 lastmode = '' 3745 3568 cnt = dict() 3746 3569 for data in sorted(testruns, key=lambda v:(v['mode'], v['host'], v['kernel'], v['time'])): ··· 3762 3563 for i in range(2): 3763 3564 s = sorted(tMed[i]) 3764 3565 list[lastmode]['med'][i] = s[int(len(s)/2)] 3765 - iMed[i] = tMed[i].index(list[lastmode]['med'][i]) 3566 + iMed[i] = tMed[i][list[lastmode]['med'][i]] 3766 3567 list[lastmode]['avg'] = [tAvg[0] / num, tAvg[1] / num] 3767 3568 list[lastmode]['min'] = tMin 3768 3569 list[lastmode]['max'] = tMax 3769 3570 list[lastmode]['idx'] = (iMin, iMed, iMax) 3770 - tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [[], []] 3571 + tAvg, tMin, tMax, tMed = [0.0, 0.0], [0.0, 0.0], [0.0, 0.0], [dict(), dict()] 3771 3572 iMin, iMed, iMax = [0, 0], [0, 0], [0, 0] 3772 3573 num = 0 3574 + pkgpc10 = syslpi = '' 3575 + if 'pkgpc10' in data and 'syslpi' in data: 3576 + pkgpc10 = data['pkgpc10'] 3577 + syslpi = data['syslpi'] 3578 + useturbo = True 3579 + res = data['result'] 3773 3580 tVal = [float(data['suspend']), float(data['resume'])] 3774 3581 list[mode]['data'].append([data['host'], data['kernel'], 3775 - data['time'], tVal[0], tVal[1], data['url'], data['result'], 3582 + data['time'], tVal[0], tVal[1], data['url'], res, 3776 3583 data['issues'], data['sus_worst'], data['sus_worsttime'], 3777 - data['res_worst'], data['res_worsttime']]) 3584 + data['res_worst'], data['res_worsttime'], pkgpc10, syslpi]) 3778 3585 idx = len(list[mode]['data']) - 1 3779 - if data['result'] not in cnt: 3780 - cnt[data['result']] = 1 3586 + if res.startswith('fail in'): 3587 + res = 'fail' 3588 + if res not in cnt: 3589 + cnt[res] = 1 3781 3590 else: 3782 - cnt[data['result']] += 1 3783 - if data['result'] == 'pass': 3591 + cnt[res] += 1 3592 + if res == 'pass': 3784 3593 for i in range(2): 3785 - tMed[i].append(tVal[i]) 3594 + tMed[i][tVal[i]] = idx 3786 3595 tAvg[i] += tVal[i] 3787 3596 if tMin[i] == 0 or tVal[i] < tMin[i]: 3788 3597 iMin[i] = idx ··· 3804 3597 for i in range(2): 3805 3598 s = sorted(tMed[i]) 3806 3599 list[lastmode]['med'][i] = s[int(len(s)/2)] 3807 - iMed[i] = tMed[i].index(list[lastmode]['med'][i]) 3600 + iMed[i] = tMed[i][list[lastmode]['med'][i]] 3808 3601 list[lastmode]['avg'] = [tAvg[0] / num, tAvg[1] / num] 3809 3602 list[lastmode]['min'] = tMin 3810 3603 list[lastmode]['max'] = tMax ··· 3820 3613 td = '\t<td>{0}</td>\n' 3821 3614 tdh = '\t<td{1}>{0}</td>\n' 3822 3615 tdlink = '\t<td><a href="{0}">html</a></td>\n' 3616 + colspan = '14' if useturbo else '12' 3823 3617 3824 3618 # table header 3825 - html += '<table class="summary">\n<tr>\n' + th.format('#') +\ 3619 + html += '<table>\n<tr>\n' + th.format('#') +\ 3826 3620 th.format('Mode') + th.format('Host') + th.format('Kernel') +\ 3827 3621 th.format('Test Time') + th.format('Result') + th.format('Issues') +\ 3828 3622 th.format('Suspend') + th.format('Resume') +\ 3829 3623 th.format('Worst Suspend Device') + th.format('SD Time') +\ 3830 - th.format('Worst Resume Device') + th.format('RD Time') +\ 3831 - th.format('Detail') + '</tr>\n' 3832 - 3624 + th.format('Worst Resume Device') + th.format('RD Time') 3625 + if useturbo: 3626 + html += th.format('PkgPC10') + th.format('SysLPI') 3627 + html += th.format('Detail')+'</tr>\n' 3833 3628 # export list into html 3834 3629 head = '<tr class="head"><td>{0}</td><td>{1}</td>'+\ 3835 - '<td colspan=12 class="sus">Suspend Avg={2} '+\ 3630 + '<td colspan='+colspan+' class="sus">Suspend Avg={2} '+\ 3836 3631 '<span class=minval><a href="#s{10}min">Min={3}</a></span> '+\ 3837 3632 '<span class=medval><a href="#s{10}med">Med={4}</a></span> '+\ 3838 3633 '<span class=maxval><a href="#s{10}max">Max={5}</a></span> '+\ ··· 3843 3634 '<span class=medval><a href="#r{10}med">Med={8}</a></span> '+\ 3844 3635 '<span class=maxval><a href="#r{10}max">Max={9}</a></span></td>'+\ 3845 3636 '</tr>\n' 3846 - headnone = '<tr class="head"><td>{0}</td><td>{1}</td><td colspan=12></td></tr>\n' 3637 + headnone = '<tr class="head"><td>{0}</td><td>{1}</td><td colspan='+\ 3638 + colspan+'></td></tr>\n' 3847 3639 for mode in list: 3848 3640 # header line for each suspend mode 3849 3641 num = 0 ··· 3891 3681 html += td.format('%.3f ms' % d[9]) if d[9] else td.format('') # sus_worst time 3892 3682 html += td.format(d[10]) # res_worst 3893 3683 html += td.format('%.3f ms' % d[11]) if d[11] else td.format('') # res_worst time 3684 + if useturbo: 3685 + html += td.format(d[12]) # pkg_pc10 3686 + html += td.format(d[13]) # syslpi 3894 3687 html += tdlink.format(d[5]) if d[5] else td.format('') # url 3895 3688 html += '</tr>\n' 3896 3689 num += 1 ··· 3902 3689 hf = open(htmlfile, 'w') 3903 3690 hf.write(html+'</table>\n</body>\n</html>\n') 3904 3691 hf.close() 3692 + 3693 + def createHTMLDeviceSummary(testruns, htmlfile, title): 3694 + html = summaryCSS('Device Summary - SleepGraph', False) 3695 + 3696 + # create global device list from all tests 3697 + devall = dict() 3698 + for data in testruns: 3699 + host, url, devlist = data['host'], data['url'], data['devlist'] 3700 + for type in devlist: 3701 + if type not in devall: 3702 + devall[type] = dict() 3703 + mdevlist, devlist = devall[type], data['devlist'][type] 3704 + for name in devlist: 3705 + length = devlist[name] 3706 + if name not in mdevlist: 3707 + mdevlist[name] = {'name': name, 'host': host, 3708 + 'worst': length, 'total': length, 'count': 1, 3709 + 'url': url} 3710 + else: 3711 + if length > mdevlist[name]['worst']: 3712 + mdevlist[name]['worst'] = length 3713 + mdevlist[name]['url'] = url 3714 + mdevlist[name]['host'] = host 3715 + mdevlist[name]['total'] += length 3716 + mdevlist[name]['count'] += 1 3717 + 3718 + # generate the html 3719 + th = '\t<th>{0}</th>\n' 3720 + td = '\t<td align=center>{0}</td>\n' 3721 + tdr = '\t<td align=right>{0}</td>\n' 3722 + tdlink = '\t<td align=center><a href="{0}">html</a></td>\n' 3723 + limit = 1 3724 + for type in sorted(devall, reverse=True): 3725 + num = 0 3726 + devlist = devall[type] 3727 + # table header 3728 + html += '<div class="stamp">%s (%s devices > %d ms)</div><table>\n' % \ 3729 + (title, type.upper(), limit) 3730 + html += '<tr>\n' + '<th align=right>Device Name</th>' +\ 3731 + th.format('Average Time') + th.format('Count') +\ 3732 + th.format('Worst Time') + th.format('Host (worst time)') +\ 3733 + th.format('Link (worst time)') + '</tr>\n' 3734 + for name in sorted(devlist, key=lambda k:devlist[k]['worst'], reverse=True): 3735 + data = devall[type][name] 3736 + data['average'] = data['total'] / data['count'] 3737 + if data['average'] < limit: 3738 + continue 3739 + # row classes - alternate row color 3740 + rcls = ['alt'] if num % 2 == 1 else [] 3741 + html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 3742 + html += tdr.format(data['name']) # name 3743 + html += td.format('%.3f ms' % data['average']) # average 3744 + html += td.format(data['count']) # count 3745 + html += td.format('%.3f ms' % data['worst']) # worst 3746 + html += td.format(data['host']) # host 3747 + html += tdlink.format(data['url']) # url 3748 + html += '</tr>\n' 3749 + num += 1 3750 + html += '</table>\n' 3751 + 3752 + # flush the data to file 3753 + hf = open(htmlfile, 'w') 3754 + hf.write(html+'</body>\n</html>\n') 3755 + hf.close() 3756 + return devall 3757 + 3758 + def createHTMLIssuesSummary(testruns, issues, htmlfile, title, extra=''): 3759 + multihost = len([e for e in issues if len(e['urls']) > 1]) > 0 3760 + html = summaryCSS('Issues Summary - SleepGraph', False) 3761 + total = len(testruns) 3762 + 3763 + # generate the html 3764 + th = '\t<th>{0}</th>\n' 3765 + td = '\t<td align={0}>{1}</td>\n' 3766 + tdlink = '<a href="{1}">{0}</a>' 3767 + subtitle = '%d issues' % len(issues) if len(issues) > 0 else 'no issues' 3768 + html += '<div class="stamp">%s (%s)</div><table>\n' % (title, subtitle) 3769 + html += '<tr>\n' + th.format('Issue') + th.format('Count') 3770 + if multihost: 3771 + html += th.format('Hosts') 3772 + html += th.format('Tests') + th.format('Fail Rate') +\ 3773 + th.format('First Instance') + '</tr>\n' 3774 + 3775 + num = 0 3776 + for e in sorted(issues, key=lambda v:v['count'], reverse=True): 3777 + testtotal = 0 3778 + links = [] 3779 + for host in sorted(e['urls']): 3780 + links.append(tdlink.format(host, e['urls'][host][0])) 3781 + testtotal += len(e['urls'][host]) 3782 + rate = '%d/%d (%.2f%%)' % (testtotal, total, 100*float(testtotal)/float(total)) 3783 + # row classes - alternate row color 3784 + rcls = ['alt'] if num % 2 == 1 else [] 3785 + html += '<tr class="'+(' '.join(rcls))+'">\n' if len(rcls) > 0 else '<tr>\n' 3786 + html += td.format('left', e['line']) # issue 3787 + html += td.format('center', e['count']) # count 3788 + if multihost: 3789 + html += td.format('center', len(e['urls'])) # hosts 3790 + html += td.format('center', testtotal) # test count 3791 + html += td.format('center', rate) # test rate 3792 + html += td.format('center nowrap', '<br>'.join(links)) # links 3793 + html += '</tr>\n' 3794 + num += 1 3795 + 3796 + # flush the data to file 3797 + hf = open(htmlfile, 'w') 3798 + hf.write(html+'</table>\n'+extra+'</body>\n</html>\n') 3799 + hf.close() 3800 + return issues 3905 3801 3906 3802 def ordinal(value): 3907 3803 suffix = 'th' ··· 4313 3991 for word in phase.split('_'): 4314 3992 id += word[0] 4315 3993 order = '%.2f' % ((p['order'] * pdelta) + pmargin) 4316 - name = string.replace(phase, '_', ' &nbsp;') 3994 + name = phase.replace('_', ' &nbsp;') 4317 3995 devtl.html += devtl.html_legend.format(order, p['color'], name, id) 4318 3996 devtl.html += '</div>\n' 4319 3997 ··· 4902 4580 def executeSuspend(): 4903 4581 pm = ProcessMonitor() 4904 4582 tp = sysvals.tpath 4583 + wifi = sysvals.checkWifi() 4905 4584 testdata = [] 4906 4585 battery = True if getBattery() else False 4907 4586 # run these commands to prepare the system for suspend ··· 4936 4613 pprint('SUSPEND START') 4937 4614 else: 4938 4615 pprint('SUSPEND START (press a key to resume)') 4616 + sysvals.mcelog(True) 4939 4617 bat1 = getBattery() if battery else False 4940 4618 # set rtcwake 4941 4619 if(sysvals.rtcwake): ··· 4968 4644 pf = open(sysvals.diskpowerfile, 'w') 4969 4645 pf.write(sysvals.diskmode) 4970 4646 pf.close() 4971 - pf = open(sysvals.powerfile, 'w') 4972 - pf.write(mode) 4973 - # execution will pause here 4974 - try: 4975 - pf.close() 4976 - except Exception as e: 4977 - tdata['error'] = str(e) 4647 + if mode == 'freeze' and sysvals.haveTurbostat(): 4648 + # execution will pause here 4649 + turbo = sysvals.turbostat() 4650 + if '|' in turbo: 4651 + tdata['turbo'] = turbo 4652 + else: 4653 + tdata['error'] = turbo 4654 + else: 4655 + if sysvals.haveTurbostat(): 4656 + sysvals.vprint('WARNING: ignoring turbostat in mode "%s"' % mode) 4657 + pf = open(sysvals.powerfile, 'w') 4658 + pf.write(mode) 4659 + # execution will pause here 4660 + try: 4661 + pf.close() 4662 + except Exception as e: 4663 + tdata['error'] = str(e) 4978 4664 if(sysvals.rtcwake): 4979 4665 sysvals.rtcWakeAlarmOff() 4980 4666 # postdelay delay ··· 4998 4664 sysvals.fsetVal('RESUME COMPLETE', 'trace_marker') 4999 4665 if(sysvals.suspendmode == 'mem' or sysvals.suspendmode == 'command'): 5000 4666 tdata['fw'] = getFPDT(False) 4667 + mcelog = sysvals.mcelog() 4668 + if mcelog: 4669 + tdata['mcelog'] = mcelog 5001 4670 bat2 = getBattery() if battery else False 5002 4671 if battery and bat1 and bat2: 5003 4672 tdata['bat'] = (bat1, bat2) 4673 + if 'device' in wifi and 'ip' in wifi: 4674 + tdata['wifi'] = (wifi, sysvals.checkWifi()) 5004 4675 testdata.append(tdata) 5005 4676 # stop ftrace 5006 4677 if(sysvals.usecallgraph or sysvals.usetraceevents): ··· 5025 4686 op.close() 5026 4687 sysvals.fsetVal('', 'trace') 5027 4688 devProps() 4689 + return testdata 5028 4690 5029 4691 def readFile(file): 5030 4692 if os.path.islink(file): ··· 5112 4772 ms2nice(power['runtime_active_time']), \ 5113 4773 ms2nice(power['runtime_suspended_time'])) 5114 4774 for i in sorted(lines): 5115 - print lines[i] 4775 + print(lines[i]) 5116 4776 return res 5117 4777 5118 4778 # Function: devProps ··· 5245 4905 modes = [] 5246 4906 if(os.path.exists(sysvals.powerfile)): 5247 4907 fp = open(sysvals.powerfile, 'r') 5248 - modes = string.split(fp.read()) 4908 + modes = fp.read().split() 5249 4909 fp.close() 5250 4910 if(os.path.exists(sysvals.mempowerfile)): 5251 4911 deep = False 5252 4912 fp = open(sysvals.mempowerfile, 'r') 5253 - for m in string.split(fp.read()): 4913 + for m in fp.read().split(): 5254 4914 memmode = m.strip('[]') 5255 4915 if memmode == 'deep': 5256 4916 deep = True ··· 5261 4921 modes.remove('mem') 5262 4922 if('disk' in modes and os.path.exists(sysvals.diskpowerfile)): 5263 4923 fp = open(sysvals.diskpowerfile, 'r') 5264 - for m in string.split(fp.read()): 4924 + for m in fp.read().split(): 5265 4925 modes.append('disk-%s' % m.strip('[]')) 5266 4926 fp.close() 5267 4927 return modes ··· 5324 4984 continue 5325 4985 5326 4986 # read in the memory for scanning 5327 - fp = open(mempath, 'rb') 5328 4987 try: 4988 + fp = open(mempath, 'rb') 5329 4989 fp.seek(memaddr) 5330 4990 buf = fp.read(memsize) 5331 4991 except: 5332 4992 if(fatal): 5333 4993 doError('DMI table is unreachable, sorry') 5334 4994 else: 4995 + pprint('WARNING: /dev/mem is not readable, ignoring DMI data') 5335 4996 return out 5336 4997 fp.close() 5337 4998 ··· 5355 5014 return out 5356 5015 5357 5016 # read in the SM or DMI table 5358 - fp = open(mempath, 'rb') 5359 5017 try: 5018 + fp = open(mempath, 'rb') 5360 5019 fp.seek(base) 5361 5020 buf = fp.read(length) 5362 5021 except: 5363 5022 if(fatal): 5364 5023 doError('DMI table is unreachable, sorry') 5365 5024 else: 5025 + pprint('WARNING: /dev/mem is not readable, ignoring DMI data') 5366 5026 return out 5367 5027 fp.close() 5368 5028 ··· 5507 5165 i = 0 5508 5166 fwData = [0, 0] 5509 5167 records = buf[36:] 5510 - fp = open(sysvals.mempath, 'rb') 5168 + try: 5169 + fp = open(sysvals.mempath, 'rb') 5170 + except: 5171 + pprint('WARNING: /dev/mem is not readable, ignoring the FPDT data') 5172 + return False 5511 5173 while(i < len(records)): 5512 5174 header = struct.unpack('HBB', records[i:i+4]) 5513 5175 if(header[0] not in rectype): ··· 5628 5282 pprint(' is ftrace supported: %s' % res) 5629 5283 5630 5284 # check if kprobes are available 5631 - res = sysvals.colorText('NO') 5632 - sysvals.usekprobes = sysvals.verifyKprobes() 5633 - if(sysvals.usekprobes): 5634 - res = 'YES' 5635 - else: 5636 - sysvals.usedevsrc = False 5637 - pprint(' are kprobes supported: %s' % res) 5285 + if sysvals.usekprobes: 5286 + res = sysvals.colorText('NO') 5287 + sysvals.usekprobes = sysvals.verifyKprobes() 5288 + if(sysvals.usekprobes): 5289 + res = 'YES' 5290 + else: 5291 + sysvals.usedevsrc = False 5292 + pprint(' are kprobes supported: %s' % res) 5638 5293 5639 5294 # what data source are we using 5640 5295 res = 'DMESG' ··· 5723 5376 5724 5377 def processData(live=False): 5725 5378 pprint('PROCESSING DATA') 5379 + sysvals.vprint('usetraceevents=%s, usetracemarkers=%s, usekprobes=%s' % \ 5380 + (sysvals.usetraceevents, sysvals.usetracemarkers, sysvals.usekprobes)) 5726 5381 error = '' 5727 5382 if(sysvals.usetraceevents): 5728 5383 testruns, error = parseTraceLog(live) ··· 5737 5388 parseKernelLog(data) 5738 5389 if(sysvals.ftracefile and (sysvals.usecallgraph or sysvals.usetraceevents)): 5739 5390 appendIncompleteTraceLog(testruns) 5391 + sysvals.vprint('System Info:') 5392 + for key in sorted(sysvals.stamp): 5393 + sysvals.vprint(' %-8s : %s' % (key.upper(), sysvals.stamp[key])) 5394 + if sysvals.kparams: 5395 + sysvals.vprint('Kparams:\n %s' % sysvals.kparams) 5740 5396 sysvals.vprint('Command:\n %s' % sysvals.cmdline) 5741 5397 for data in testruns: 5398 + if data.mcelog: 5399 + sysvals.vprint('MCELOG Data:') 5400 + for line in data.mcelog.split('\n'): 5401 + sysvals.vprint(' %s' % line) 5402 + if data.turbostat: 5403 + idx, s = 0, 'Turbostat:\n ' 5404 + for val in data.turbostat.split('|'): 5405 + idx += len(val) + 1 5406 + if idx >= 80: 5407 + idx = 0 5408 + s += '\n ' 5409 + s += val + ' ' 5410 + sysvals.vprint(s) 5742 5411 if data.battery: 5743 5412 a1, c1, a2, c2 = data.battery 5744 5413 s = 'Battery:\n Before - AC: %s, Charge: %d\n After - AC: %s, Charge: %d' % \ 5745 5414 (a1, int(c1), a2, int(c2)) 5415 + sysvals.vprint(s) 5416 + if data.wifi: 5417 + w = data.wifi.replace('|', ' ').split(',') 5418 + s = 'Wifi:\n Before %s\n After %s' % \ 5419 + (w[0], w[1]) 5746 5420 sysvals.vprint(s) 5747 5421 data.printDetails() 5748 5422 if sysvals.cgdump: ··· 5790 5418 # Function: rerunTest 5791 5419 # Description: 5792 5420 # generate an output from an existing set of ftrace/dmesg logs 5793 - def rerunTest(): 5421 + def rerunTest(htmlfile=''): 5794 5422 if sysvals.ftracefile: 5795 5423 doesTraceLogHaveTraceEvents() 5796 5424 if not sysvals.dmesgfile and not sysvals.usetraceevents: 5797 5425 doError('recreating this html output requires a dmesg file') 5798 - sysvals.setOutputFile() 5426 + if htmlfile: 5427 + sysvals.htmlfile = htmlfile 5428 + else: 5429 + sysvals.setOutputFile() 5799 5430 if os.path.exists(sysvals.htmlfile): 5800 5431 if not os.path.isfile(sysvals.htmlfile): 5801 5432 doError('a directory already exists with this name: %s' % sysvals.htmlfile) ··· 5817 5442 sysvals.initTestOutput('suspend') 5818 5443 5819 5444 # execute the test 5820 - executeSuspend() 5445 + testdata = executeSuspend() 5821 5446 sysvals.cleanupFtrace() 5822 5447 if sysvals.skiphtml: 5823 5448 sysvals.sudoUserchown(sysvals.testdir) 5824 5449 return 5825 - testruns, stamp = processData(True) 5826 - for data in testruns: 5827 - del data 5450 + if not testdata[0]['error']: 5451 + testruns, stamp = processData(True) 5452 + for data in testruns: 5453 + del data 5454 + else: 5455 + stamp = testdata[0] 5456 + 5828 5457 sysvals.sudoUserchown(sysvals.testdir) 5829 5458 sysvals.outputResult(stamp, n) 5830 5459 if 'error' in stamp: ··· 5858 5479 return '' 5859 5480 return out 5860 5481 5861 - def data_from_html(file, outpath, devlist=False): 5482 + def data_from_html(file, outpath, issues, fulldetail=False): 5862 5483 html = open(file, 'r').read() 5484 + sysvals.htmlfile = os.path.relpath(file, outpath) 5485 + # extract general info 5863 5486 suspend = find_in_html(html, 'Kernel Suspend', 'ms') 5864 5487 resume = find_in_html(html, 'Kernel Resume', 'ms') 5488 + sysinfo = find_in_html(html, '<div class="stamp sysinfo">', '</div>') 5865 5489 line = find_in_html(html, '<div class="stamp">', '</div>') 5866 5490 stmp = line.split() 5867 5491 if not suspend or not resume or len(stmp) != 8: ··· 5873 5491 dt = datetime.strptime(' '.join(stmp[3:]), '%B %d %Y, %I:%M:%S %p') 5874 5492 except: 5875 5493 return False 5494 + sysvals.hostname = stmp[0] 5876 5495 tstr = dt.strftime('%Y/%m/%d %H:%M:%S') 5877 5496 error = find_in_html(html, '<table class="testfail"><tr><td>', '</td>') 5878 5497 if error: ··· 5884 5501 result = 'fail' 5885 5502 else: 5886 5503 result = 'pass' 5504 + # extract error info 5887 5505 ilist = [] 5888 - e = find_in_html(html, 'class="err"[\w=":;\.%\- ]*>', '&rarr;</div>', False) 5889 - for i in list(set(e)): 5890 - ilist.append('%sx%d' % (i, e.count(i)) if e.count(i) > 1 else i) 5506 + extra = dict() 5507 + log = find_in_html(html, '<div id="dmesglog" style="display:none;">', 5508 + '</div>').strip() 5509 + if log: 5510 + d = Data(0) 5511 + d.end = 999999999 5512 + d.dmesgtext = log.split('\n') 5513 + msglist = d.extractErrorInfo() 5514 + for msg in msglist: 5515 + sysvals.errorSummary(issues, msg) 5516 + if stmp[2] == 'freeze': 5517 + extra = d.turbostatInfo() 5518 + elist = dict() 5519 + for dir in d.errorinfo: 5520 + for err in d.errorinfo[dir]: 5521 + if err[0] not in elist: 5522 + elist[err[0]] = 0 5523 + elist[err[0]] += 1 5524 + for i in elist: 5525 + ilist.append('%sx%d' % (i, elist[i]) if elist[i] > 1 else i) 5891 5526 low = find_in_html(html, 'freeze time: <b>', ' ms</b>') 5892 5527 if low and '|' in low: 5893 - ilist.append('FREEZEx%d' % len(low.split('|'))) 5528 + issue = 'FREEZEx%d' % len(low.split('|')) 5529 + match = [i for i in issues if i['match'] == issue] 5530 + if len(match) > 0: 5531 + match[0]['count'] += 1 5532 + if sysvals.hostname not in match[0]['urls']: 5533 + match[0]['urls'][sysvals.hostname] = [sysvals.htmlfile] 5534 + elif sysvals.htmlfile not in match[0]['urls'][sysvals.hostname]: 5535 + match[0]['urls'][sysvals.hostname].append(sysvals.htmlfile) 5536 + else: 5537 + issues.append({ 5538 + 'match': issue, 'count': 1, 'line': issue, 5539 + 'urls': {sysvals.hostname: [sysvals.htmlfile]}, 5540 + }) 5541 + ilist.append(issue) 5542 + # extract device info 5894 5543 devices = dict() 5895 5544 for line in html.split('\n'): 5896 5545 m = re.match(' *<div id=\"[a,0-9]*\" *title=\"(?P<title>.*)\" class=\"thread.*', line) ··· 5934 5519 name, time, phase = m.group('n'), m.group('t'), m.group('p') 5935 5520 if ' async' in name or ' sync' in name: 5936 5521 name = ' '.join(name.split(' ')[:-1]) 5937 - d = phase.split('_')[0] 5522 + if phase.startswith('suspend'): 5523 + d = 'suspend' 5524 + elif phase.startswith('resume'): 5525 + d = 'resume' 5526 + else: 5527 + continue 5938 5528 if d not in devices: 5939 5529 devices[d] = dict() 5940 5530 if name not in devices[d]: 5941 5531 devices[d][name] = 0.0 5942 5532 devices[d][name] += float(time) 5943 - worst = {'suspend': {'name':'', 'time': 0.0}, 5944 - 'resume': {'name':'', 'time': 0.0}} 5945 - for d in devices: 5946 - if d not in worst: 5947 - worst[d] = dict() 5948 - dev = devices[d] 5949 - if len(dev.keys()) > 0: 5533 + # create worst device info 5534 + worst = dict() 5535 + for d in ['suspend', 'resume']: 5536 + worst[d] = {'name':'', 'time': 0.0} 5537 + dev = devices[d] if d in devices else 0 5538 + if dev and len(dev.keys()) > 0: 5950 5539 n = sorted(dev, key=dev.get, reverse=True)[0] 5951 5540 worst[d]['name'], worst[d]['time'] = n, dev[n] 5952 5541 data = { 5953 5542 'mode': stmp[2], 5954 5543 'host': stmp[0], 5955 5544 'kernel': stmp[1], 5545 + 'sysinfo': sysinfo, 5956 5546 'time': tstr, 5957 5547 'result': result, 5958 5548 'issues': ' '.join(ilist), 5959 5549 'suspend': suspend, 5960 5550 'resume': resume, 5551 + 'devlist': devices, 5961 5552 'sus_worst': worst['suspend']['name'], 5962 5553 'sus_worsttime': worst['suspend']['time'], 5963 5554 'res_worst': worst['resume']['name'], 5964 5555 'res_worsttime': worst['resume']['time'], 5965 - 'url': os.path.relpath(file, outpath), 5556 + 'url': sysvals.htmlfile, 5966 5557 } 5967 - if devlist: 5968 - data['devlist'] = devices 5558 + for key in extra: 5559 + data[key] = extra[key] 5560 + if fulldetail: 5561 + data['funclist'] = find_in_html(html, '<div title="', '" class="traceevent"', False) 5969 5562 return data 5563 + 5564 + def genHtml(subdir): 5565 + for dirname, dirnames, filenames in os.walk(subdir): 5566 + sysvals.dmesgfile = sysvals.ftracefile = sysvals.htmlfile = '' 5567 + for filename in filenames: 5568 + if(re.match('.*_dmesg.txt', filename)): 5569 + sysvals.dmesgfile = os.path.join(dirname, filename) 5570 + elif(re.match('.*_ftrace.txt', filename)): 5571 + sysvals.ftracefile = os.path.join(dirname, filename) 5572 + sysvals.setOutputFile() 5573 + if sysvals.ftracefile and sysvals.htmlfile and \ 5574 + not os.path.exists(sysvals.htmlfile): 5575 + pprint('FTRACE: %s' % sysvals.ftracefile) 5576 + if sysvals.dmesgfile: 5577 + pprint('DMESG : %s' % sysvals.dmesgfile) 5578 + rerunTest() 5970 5579 5971 5580 # Function: runSummary 5972 5581 # Description: ··· 5998 5559 def runSummary(subdir, local=True, genhtml=False): 5999 5560 inpath = os.path.abspath(subdir) 6000 5561 outpath = os.path.abspath('.') if local else inpath 6001 - pprint('Generating a summary of folder "%s"' % inpath) 5562 + pprint('Generating a summary of folder:\n %s' % inpath) 6002 5563 if genhtml: 6003 - for dirname, dirnames, filenames in os.walk(subdir): 6004 - sysvals.dmesgfile = sysvals.ftracefile = sysvals.htmlfile = '' 6005 - for filename in filenames: 6006 - if(re.match('.*_dmesg.txt', filename)): 6007 - sysvals.dmesgfile = os.path.join(dirname, filename) 6008 - elif(re.match('.*_ftrace.txt', filename)): 6009 - sysvals.ftracefile = os.path.join(dirname, filename) 6010 - sysvals.setOutputFile() 6011 - if sysvals.ftracefile and sysvals.htmlfile and \ 6012 - not os.path.exists(sysvals.htmlfile): 6013 - pprint('FTRACE: %s' % sysvals.ftracefile) 6014 - if sysvals.dmesgfile: 6015 - pprint('DMESG : %s' % sysvals.dmesgfile) 6016 - rerunTest() 5564 + genHtml(subdir) 5565 + issues = [] 6017 5566 testruns = [] 6018 5567 desc = {'host':[],'mode':[],'kernel':[]} 6019 5568 for dirname, dirnames, filenames in os.walk(subdir): 6020 5569 for filename in filenames: 6021 5570 if(not re.match('.*.html', filename)): 6022 5571 continue 6023 - data = data_from_html(os.path.join(dirname, filename), outpath) 5572 + data = data_from_html(os.path.join(dirname, filename), outpath, issues) 6024 5573 if(not data): 6025 5574 continue 6026 5575 testruns.append(data) 6027 5576 for key in desc: 6028 5577 if data[key] not in desc[key]: 6029 5578 desc[key].append(data[key]) 6030 - outfile = os.path.join(outpath, 'summary.html') 6031 - pprint('Summary file: %s' % outfile) 5579 + pprint('Summary files:') 6032 5580 if len(desc['host']) == len(desc['mode']) == len(desc['kernel']) == 1: 6033 5581 title = '%s %s %s' % (desc['host'][0], desc['kernel'][0], desc['mode'][0]) 6034 5582 else: 6035 5583 title = inpath 6036 - createHTMLSummarySimple(testruns, outfile, title) 5584 + createHTMLSummarySimple(testruns, os.path.join(outpath, 'summary.html'), title) 5585 + pprint(' summary.html - tabular list of test data found') 5586 + createHTMLDeviceSummary(testruns, os.path.join(outpath, 'summary-devices.html'), title) 5587 + pprint(' summary-devices.html - kernel device list sorted by total execution time') 5588 + createHTMLIssuesSummary(testruns, issues, os.path.join(outpath, 'summary-issues.html'), title) 5589 + pprint(' summary-issues.html - kernel issues found sorted by frequency') 6037 5590 6038 5591 # Function: checkArgBool 6039 5592 # Description: ··· 6270 5839 ' default: suspend-{date}-{time}\n'\ 6271 5840 ' -rtcwake t Wakeup t seconds after suspend, set t to "off" to disable (default: 15)\n'\ 6272 5841 ' -addlogs Add the dmesg and ftrace logs to the html output\n'\ 5842 + ' -turbostat Use turbostat to execute the command in freeze mode (default: disabled)\n'\ 6273 5843 ' -srgap Add a visible gap in the timeline between sus/res (default: disabled)\n'\ 6274 5844 ' -skiphtml Run the test and capture the trace logs, but skip the timeline (default: disabled)\n'\ 6275 5845 ' -result fn Export a results table to a text file for parsing.\n'\ ··· 6292 5860 ' be created in a new subdirectory with a summary page.\n'\ 6293 5861 ' [debug]\n'\ 6294 5862 ' -f Use ftrace to create device callgraphs (default: disabled)\n'\ 5863 + ' -ftop Use ftrace on the top level call: "%s" (default: disabled)\n'\ 6295 5864 ' -maxdepth N limit the callgraph data to N call levels (default: 0=all)\n'\ 6296 5865 ' -expandcg pre-expand the callgraph data in the html output (default: disabled)\n'\ 6297 5866 ' -fadd file Add functions to be graphed in the timeline from a list in a text file\n'\ ··· 6312 5879 ' -status Test to see if the system is enabled to run this tool\n'\ 6313 5880 ' -fpdt Print out the contents of the ACPI Firmware Performance Data Table\n'\ 6314 5881 ' -battery Print out battery info (if available)\n'\ 5882 + ' -wifi Print out wifi connection info (if wireless-tools and device exists)\n'\ 6315 5883 ' -x<mode> Test xset by toggling the given mode (on/off/standby/suspend)\n'\ 6316 5884 ' -sysinfo Print out system info extracted from BIOS\n'\ 6317 5885 ' -devinfo Print out the pm settings of all devices which support runtime suspend\n'\ ··· 6322 5888 ' [redo]\n'\ 6323 5889 ' -ftrace ftracefile Create HTML output using ftrace input (used with -dmesg)\n'\ 6324 5890 ' -dmesg dmesgfile Create HTML output using dmesg (used with -ftrace)\n'\ 6325 - '' % (sysvals.title, sysvals.version, sysvals.suspendmode)) 5891 + '' % (sysvals.title, sysvals.version, sysvals.suspendmode, sysvals.ftopfunc)) 6326 5892 return True 6327 5893 6328 5894 # ----------------- MAIN -------------------- ··· 6332 5898 cmd = '' 6333 5899 simplecmds = ['-sysinfo', '-modes', '-fpdt', '-flist', '-flistall', 6334 5900 '-devinfo', '-status', '-battery', '-xon', '-xoff', '-xstandby', 6335 - '-xsuspend', '-xinit', '-xreset', '-xstat'] 5901 + '-xsuspend', '-xinit', '-xreset', '-xstat', '-wifi'] 6336 5902 if '-f' in sys.argv: 6337 5903 sysvals.cgskip = sysvals.configFile('cgskip.txt') 6338 5904 # loop through the command line arguments ··· 6364 5930 sysvals.postdelay = getArgInt('-postdelay', args, 0, 60000) 6365 5931 elif(arg == '-f'): 6366 5932 sysvals.usecallgraph = True 5933 + elif(arg == '-ftop'): 5934 + sysvals.usecallgraph = True 5935 + sysvals.ftop = True 5936 + sysvals.usekprobes = False 6367 5937 elif(arg == '-skiphtml'): 6368 5938 sysvals.skiphtml = True 6369 5939 elif(arg == '-cgdump'): ··· 6378 5940 genhtml = True 6379 5941 elif(arg == '-addlogs'): 6380 5942 sysvals.dmesglog = sysvals.ftracelog = True 5943 + elif(arg == '-nologs'): 5944 + sysvals.dmesglog = sysvals.ftracelog = False 6381 5945 elif(arg == '-addlogdmesg'): 6382 5946 sysvals.dmesglog = True 6383 5947 elif(arg == '-addlogftrace'): 6384 5948 sysvals.ftracelog = True 5949 + elif(arg == '-turbostat'): 5950 + sysvals.tstat = True 5951 + if not sysvals.haveTurbostat(): 5952 + doError('Turbostat command not found') 6385 5953 elif(arg == '-verbose'): 6386 5954 sysvals.verbose = True 6387 5955 elif(arg == '-proc'): ··· 6457 6013 except: 6458 6014 doError('No callgraph functions supplied', True) 6459 6015 sysvals.setCallgraphFilter(val) 6016 + elif(arg == '-skipkprobe'): 6017 + try: 6018 + val = args.next() 6019 + except: 6020 + doError('No kprobe functions supplied', True) 6021 + sysvals.skipKprobes(val) 6460 6022 elif(arg == '-cgskip'): 6461 6023 try: 6462 6024 val = args.next() ··· 6601 6151 elif(cmd == 'devinfo'): 6602 6152 deviceInfo() 6603 6153 elif(cmd == 'modes'): 6604 - print getModes() 6154 + pprint(getModes()) 6605 6155 elif(cmd == 'flist'): 6606 6156 sysvals.getFtraceFilterFunctions(True) 6607 6157 elif(cmd == 'flistall'): ··· 6613 6163 ret = displayControl(cmd[1:]) 6614 6164 elif(cmd == 'xstat'): 6615 6165 pprint('Display Status: %s' % displayControl('stat').upper()) 6166 + elif(cmd == 'wifi'): 6167 + out = sysvals.checkWifi() 6168 + if 'device' not in out: 6169 + pprint('WIFI interface not found') 6170 + else: 6171 + for key in sorted(out): 6172 + pprint('%6s: %s' % (key.upper(), out[key])) 6616 6173 sys.exit(ret) 6617 6174 6618 6175 # if instructed, re-analyze existing data files 6619 6176 if(sysvals.notestrun): 6620 - stamp = rerunTest() 6177 + stamp = rerunTest(sysvals.outdir) 6621 6178 sysvals.outputResult(stamp) 6622 6179 sys.exit(0) 6623 6180 ··· 6661 6204 s = 'suspend-x%d' % sysvals.multitest['count'] 6662 6205 sysvals.outdir = datetime.now().strftime(s+'-%y%m%d-%H%M%S') 6663 6206 if not os.path.isdir(sysvals.outdir): 6664 - os.mkdir(sysvals.outdir) 6207 + os.makedirs(sysvals.outdir) 6665 6208 for i in range(sysvals.multitest['count']): 6666 6209 if(i != 0): 6667 6210 pprint('Waiting %d seconds...' % (sysvals.multitest['delay']))