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

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

Pull power management updates from Rafael Wysocki:
"These are mostly minor improvements all over including new CPU IDs for
the Intel RAPL driver, an Energy Model rework to use micro-Watt as the
power unit, cpufreq fixes and cleanus, cpuidle updates, devfreq
updates, documentation cleanups and a new version of the pm-graph
suite of utilities.

Specifics:

- Make cpufreq_show_cpus() more straightforward (Viresh Kumar).

- Drop unnecessary CPU hotplug locking from store() used by cpufreq
sysfs attributes (Viresh Kumar).

- Make the ACPI cpufreq driver support the boost control interface on
Zhaoxin/Centaur processors (Tony W Wang-oc).

- Print a warning message on attempts to free an active cpufreq
policy which should never happen (Viresh Kumar).

- Fix grammar in the Kconfig help text for the loongson2 cpufreq
driver (Randy Dunlap).

- Use cpumask_var_t for an on-stack CPU mask in the ondemand cpufreq
governor (Zhao Liu).

- Add trace points for guest_halt_poll_ns grow/shrink to the haltpoll
cpuidle driver (Eiichi Tsukata).

- Modify intel_idle to treat C1 and C1E as independent idle states on
Sapphire Rapids (Artem Bityutskiy).

- Extend support for wakeirq to callback wrappers used during system
suspend and resume (Ulf Hansson).

- Defer waiting for device probe before loading a hibernation image
till the first actual device access to avoid possible deadlocks
reported by syzbot (Tetsuo Handa).

- Unify device_init_wakeup() for PM_SLEEP and !PM_SLEEP (Bjorn
Helgaas).

- Add Raptor Lake-P to the list of processors supported by the Intel
RAPL driver (George D Sworo).

- Add Alder Lake-N and Raptor Lake-P to the list of processors for
which Power Limit4 is supported in the Intel RAPL driver (Sumeet
Pawnikar).

- Make pm_genpd_remove() check genpd_debugfs_dir against NULL before
attempting to remove it (Hsin-Yi Wang).

- Change the Energy Model code to represent power in micro-Watts and
adjust its users accordingly (Lukasz Luba).

- Add new devfreq driver for Mediatek CCI (Cache Coherent
Interconnect) (Johnson Wang).

- Convert the Samsung Exynos SoC Bus bindings to DT schema of
exynos-bus.c (Krzysztof Kozlowski).

- Address kernel-doc warnings by adding the description for unused
function parameters in devfreq core (Mauro Carvalho Chehab).

- Use NULL to pass a null pointer rather than zero according to the
function propotype in imx-bus.c (Colin Ian King).

- Print error message instead of error interger value in
tegra30-devfreq.c (Dmitry Osipenko).

- Add checks to prevent setting negative frequency QoS limits for
CPUs (Shivnandan Kumar).

- Update the pm-graph suite of utilities to the latest revision 5.9
including multiple improvements (Todd Brandt).

- Drop pme_interrupt reference from the PCI power management
documentation (Mario Limonciello)"

* tag 'pm-5.20-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (27 commits)
powercap: RAPL: Add Power Limit4 support for Alder Lake-N and Raptor Lake-P
PM: QoS: Add check to make sure CPU freq is non-negative
PM: hibernate: defer device probing when resuming from hibernation
intel_idle: make SPR C1 and C1E be independent
cpufreq: ondemand: Use cpumask_var_t for on-stack cpu mask
cpufreq: loongson2: fix Kconfig "its" grammar
pm-graph v5.9
cpufreq: Warn users while freeing active policy
cpufreq: scmi: Support the power scale in micro-Watts in SCMI v3.1
firmware: arm_scmi: Get detailed power scale from perf
Documentation: EM: Switch to micro-Watts scale
PM: EM: convert power field to micro-Watts precision and align drivers
PM / devfreq: tegra30: Add error message for devm_devfreq_add_device()
PM / devfreq: imx-bus: use NULL to pass a null pointer rather than zero
PM / devfreq: shut up kernel-doc warnings
dt-bindings: interconnect: samsung,exynos-bus: convert to dtschema
PM / devfreq: mediatek: Introduce MediaTek CCI devfreq driver
dt-bindings: interconnect: Add MediaTek CCI dt-bindings
PM: domains: Ensure genpd_debugfs_dir exists before remove
PM: runtime: Extend support for wakeirq for force_suspend|resume
...

+1499 -828
-488
Documentation/devicetree/bindings/devfreq/exynos-bus.txt
··· 1 - * Generic Exynos Bus frequency device 2 - 3 - The Samsung Exynos SoC has many buses for data transfer between DRAM 4 - and sub-blocks in SoC. Most Exynos SoCs share the common architecture 5 - for buses. Generally, each bus of Exynos SoC includes a source clock 6 - and a power line, which are able to change the clock frequency 7 - of the bus in runtime. To monitor the usage of each bus in runtime, 8 - the driver uses the PPMU (Platform Performance Monitoring Unit), which 9 - is able to measure the current load of sub-blocks. 10 - 11 - The Exynos SoC includes the various sub-blocks which have the each AXI bus. 12 - The each AXI bus has the owned source clock but, has not the only owned 13 - power line. The power line might be shared among one more sub-blocks. 14 - So, we can divide into two type of device as the role of each sub-block. 15 - There are two type of bus devices as following: 16 - - parent bus device 17 - - passive bus device 18 - 19 - Basically, parent and passive bus device share the same power line. 20 - The parent bus device can only change the voltage of shared power line 21 - and the rest bus devices (passive bus device) depend on the decision of 22 - the parent bus device. If there are three blocks which share the VDD_xxx 23 - power line, Only one block should be parent device and then the rest blocks 24 - should depend on the parent device as passive device. 25 - 26 - VDD_xxx |--- A block (parent) 27 - |--- B block (passive) 28 - |--- C block (passive) 29 - 30 - There are a little different composition among Exynos SoC because each Exynos 31 - SoC has different sub-blocks. Therefore, such difference should be specified 32 - in devicetree file instead of each device driver. In result, this driver 33 - is able to support the bus frequency for all Exynos SoCs. 34 - 35 - Required properties for all bus devices: 36 - - compatible: Should be "samsung,exynos-bus". 37 - - clock-names : the name of clock used by the bus, "bus". 38 - - clocks : phandles for clock specified in "clock-names" property. 39 - - operating-points-v2: the OPP table including frequency/voltage information 40 - to support DVFS (Dynamic Voltage/Frequency Scaling) feature. 41 - 42 - Required properties only for parent bus device: 43 - - vdd-supply: the regulator to provide the buses with the voltage. 44 - - devfreq-events: the devfreq-event device to monitor the current utilization 45 - of buses. 46 - 47 - Required properties only for passive bus device: 48 - - devfreq: the parent bus device. 49 - 50 - Optional properties only for parent bus device: 51 - - exynos,saturation-ratio: the percentage value which is used to calibrate 52 - the performance count against total cycle count. 53 - 54 - Optional properties for the interconnect functionality (QoS frequency 55 - constraints): 56 - - #interconnect-cells: should be 0. 57 - - interconnects: as documented in ../interconnect.txt, describes a path at the 58 - higher level interconnects used by this interconnect provider. 59 - If this interconnect provider is directly linked to a top level interconnect 60 - provider the property contains only one phandle. The provider extends 61 - the interconnect graph by linking its node to a node registered by provider 62 - pointed to by first phandle in the 'interconnects' property. 63 - 64 - - samsung,data-clock-ratio: ratio of the data throughput in B/s to minimum data 65 - clock frequency in Hz, default value is 8 when this property is missing. 66 - 67 - Detailed correlation between sub-blocks and power line according to Exynos SoC: 68 - - In case of Exynos3250, there are two power line as following: 69 - VDD_MIF |--- DMC 70 - 71 - VDD_INT |--- LEFTBUS (parent device) 72 - |--- PERIL 73 - |--- MFC 74 - |--- G3D 75 - |--- RIGHTBUS 76 - |--- PERIR 77 - |--- FSYS 78 - |--- LCD0 79 - |--- PERIR 80 - |--- ISP 81 - |--- CAM 82 - 83 - - In case of Exynos4210, there is one power line as following: 84 - VDD_INT |--- DMC (parent device) 85 - |--- LEFTBUS 86 - |--- PERIL 87 - |--- MFC(L) 88 - |--- G3D 89 - |--- TV 90 - |--- LCD0 91 - |--- RIGHTBUS 92 - |--- PERIR 93 - |--- MFC(R) 94 - |--- CAM 95 - |--- FSYS 96 - |--- GPS 97 - |--- LCD0 98 - |--- LCD1 99 - 100 - - In case of Exynos4x12, there are two power line as following: 101 - VDD_MIF |--- DMC 102 - 103 - VDD_INT |--- LEFTBUS (parent device) 104 - |--- PERIL 105 - |--- MFC(L) 106 - |--- G3D 107 - |--- TV 108 - |--- IMAGE 109 - |--- RIGHTBUS 110 - |--- PERIR 111 - |--- MFC(R) 112 - |--- CAM 113 - |--- FSYS 114 - |--- GPS 115 - |--- LCD0 116 - |--- ISP 117 - 118 - - In case of Exynos5422, there are two power line as following: 119 - VDD_MIF |--- DREX 0 (parent device, DRAM EXpress controller) 120 - |--- DREX 1 121 - 122 - VDD_INT |--- NoC_Core (parent device) 123 - |--- G2D 124 - |--- G3D 125 - |--- DISP1 126 - |--- NoC_WCORE 127 - |--- GSCL 128 - |--- MSCL 129 - |--- ISP 130 - |--- MFC 131 - |--- GEN 132 - |--- PERIS 133 - |--- PERIC 134 - |--- FSYS 135 - |--- FSYS2 136 - 137 - - In case of Exynos5433, there is VDD_INT power line as following: 138 - VDD_INT |--- G2D (parent device) 139 - |--- MSCL 140 - |--- GSCL 141 - |--- JPEG 142 - |--- MFC 143 - |--- HEVC 144 - |--- BUS0 145 - |--- BUS1 146 - |--- BUS2 147 - |--- PERIS (Fixed clock rate) 148 - |--- PERIC (Fixed clock rate) 149 - |--- FSYS (Fixed clock rate) 150 - 151 - Example 1: 152 - Show the AXI buses of Exynos3250 SoC. Exynos3250 divides the buses to 153 - power line (regulator). The MIF (Memory Interface) AXI bus is used to 154 - transfer data between DRAM and CPU and uses the VDD_MIF regulator. 155 - 156 - - MIF (Memory Interface) block 157 - : VDD_MIF |--- DMC (Dynamic Memory Controller) 158 - 159 - - INT (Internal) block 160 - : VDD_INT |--- LEFTBUS (parent device) 161 - |--- PERIL 162 - |--- MFC 163 - |--- G3D 164 - |--- RIGHTBUS 165 - |--- FSYS 166 - |--- LCD0 167 - |--- PERIR 168 - |--- ISP 169 - |--- CAM 170 - 171 - - MIF bus's frequency/voltage table 172 - ----------------------- 173 - |Lv| Freq | Voltage | 174 - ----------------------- 175 - |L1| 50000 |800000 | 176 - |L2| 100000 |800000 | 177 - |L3| 134000 |800000 | 178 - |L4| 200000 |825000 | 179 - |L5| 400000 |875000 | 180 - ----------------------- 181 - 182 - - INT bus's frequency/voltage table 183 - ---------------------------------------------------------- 184 - |Block|LEFTBUS|RIGHTBUS|MCUISP |ISP |PERIL ||VDD_INT | 185 - | name| |LCD0 | | | || | 186 - | | |FSYS | | | || | 187 - | | |MFC | | | || | 188 - ---------------------------------------------------------- 189 - |Mode |*parent|passive |passive|passive|passive|| | 190 - ---------------------------------------------------------- 191 - |Lv |Frequency ||Voltage | 192 - ---------------------------------------------------------- 193 - |L1 |50000 |50000 |50000 |50000 |50000 ||900000 | 194 - |L2 |80000 |80000 |80000 |80000 |80000 ||900000 | 195 - |L3 |100000 |100000 |100000 |100000 |100000 ||1000000 | 196 - |L4 |134000 |134000 |200000 |200000 | ||1000000 | 197 - |L5 |200000 |200000 |400000 |300000 | ||1000000 | 198 - ---------------------------------------------------------- 199 - 200 - Example 2: 201 - The bus of DMC (Dynamic Memory Controller) block in exynos3250.dtsi 202 - is listed below: 203 - 204 - bus_dmc: bus_dmc { 205 - compatible = "samsung,exynos-bus"; 206 - clocks = <&cmu_dmc CLK_DIV_DMC>; 207 - clock-names = "bus"; 208 - operating-points-v2 = <&bus_dmc_opp_table>; 209 - status = "disabled"; 210 - }; 211 - 212 - bus_dmc_opp_table: opp_table1 { 213 - compatible = "operating-points-v2"; 214 - opp-shared; 215 - 216 - opp-50000000 { 217 - opp-hz = /bits/ 64 <50000000>; 218 - opp-microvolt = <800000>; 219 - }; 220 - opp-100000000 { 221 - opp-hz = /bits/ 64 <100000000>; 222 - opp-microvolt = <800000>; 223 - }; 224 - opp-134000000 { 225 - opp-hz = /bits/ 64 <134000000>; 226 - opp-microvolt = <800000>; 227 - }; 228 - opp-200000000 { 229 - opp-hz = /bits/ 64 <200000000>; 230 - opp-microvolt = <825000>; 231 - }; 232 - opp-400000000 { 233 - opp-hz = /bits/ 64 <400000000>; 234 - opp-microvolt = <875000>; 235 - }; 236 - }; 237 - 238 - bus_leftbus: bus_leftbus { 239 - compatible = "samsung,exynos-bus"; 240 - clocks = <&cmu CLK_DIV_GDL>; 241 - clock-names = "bus"; 242 - operating-points-v2 = <&bus_leftbus_opp_table>; 243 - status = "disabled"; 244 - }; 245 - 246 - bus_rightbus: bus_rightbus { 247 - compatible = "samsung,exynos-bus"; 248 - clocks = <&cmu CLK_DIV_GDR>; 249 - clock-names = "bus"; 250 - operating-points-v2 = <&bus_leftbus_opp_table>; 251 - status = "disabled"; 252 - }; 253 - 254 - bus_lcd0: bus_lcd0 { 255 - compatible = "samsung,exynos-bus"; 256 - clocks = <&cmu CLK_DIV_ACLK_160>; 257 - clock-names = "bus"; 258 - operating-points-v2 = <&bus_leftbus_opp_table>; 259 - status = "disabled"; 260 - }; 261 - 262 - bus_fsys: bus_fsys { 263 - compatible = "samsung,exynos-bus"; 264 - clocks = <&cmu CLK_DIV_ACLK_200>; 265 - clock-names = "bus"; 266 - operating-points-v2 = <&bus_leftbus_opp_table>; 267 - status = "disabled"; 268 - }; 269 - 270 - bus_mcuisp: bus_mcuisp { 271 - compatible = "samsung,exynos-bus"; 272 - clocks = <&cmu CLK_DIV_ACLK_400_MCUISP>; 273 - clock-names = "bus"; 274 - operating-points-v2 = <&bus_mcuisp_opp_table>; 275 - status = "disabled"; 276 - }; 277 - 278 - bus_isp: bus_isp { 279 - compatible = "samsung,exynos-bus"; 280 - clocks = <&cmu CLK_DIV_ACLK_266>; 281 - clock-names = "bus"; 282 - operating-points-v2 = <&bus_isp_opp_table>; 283 - status = "disabled"; 284 - }; 285 - 286 - bus_peril: bus_peril { 287 - compatible = "samsung,exynos-bus"; 288 - clocks = <&cmu CLK_DIV_ACLK_100>; 289 - clock-names = "bus"; 290 - operating-points-v2 = <&bus_peril_opp_table>; 291 - status = "disabled"; 292 - }; 293 - 294 - bus_mfc: bus_mfc { 295 - compatible = "samsung,exynos-bus"; 296 - clocks = <&cmu CLK_SCLK_MFC>; 297 - clock-names = "bus"; 298 - operating-points-v2 = <&bus_leftbus_opp_table>; 299 - status = "disabled"; 300 - }; 301 - 302 - bus_leftbus_opp_table: opp_table1 { 303 - compatible = "operating-points-v2"; 304 - opp-shared; 305 - 306 - opp-50000000 { 307 - opp-hz = /bits/ 64 <50000000>; 308 - opp-microvolt = <900000>; 309 - }; 310 - opp-80000000 { 311 - opp-hz = /bits/ 64 <80000000>; 312 - opp-microvolt = <900000>; 313 - }; 314 - opp-100000000 { 315 - opp-hz = /bits/ 64 <100000000>; 316 - opp-microvolt = <1000000>; 317 - }; 318 - opp-134000000 { 319 - opp-hz = /bits/ 64 <134000000>; 320 - opp-microvolt = <1000000>; 321 - }; 322 - opp-200000000 { 323 - opp-hz = /bits/ 64 <200000000>; 324 - opp-microvolt = <1000000>; 325 - }; 326 - }; 327 - 328 - bus_mcuisp_opp_table: opp_table2 { 329 - compatible = "operating-points-v2"; 330 - opp-shared; 331 - 332 - opp-50000000 { 333 - opp-hz = /bits/ 64 <50000000>; 334 - }; 335 - opp-80000000 { 336 - opp-hz = /bits/ 64 <80000000>; 337 - }; 338 - opp-100000000 { 339 - opp-hz = /bits/ 64 <100000000>; 340 - }; 341 - opp-200000000 { 342 - opp-hz = /bits/ 64 <200000000>; 343 - }; 344 - opp-400000000 { 345 - opp-hz = /bits/ 64 <400000000>; 346 - }; 347 - }; 348 - 349 - bus_isp_opp_table: opp_table3 { 350 - compatible = "operating-points-v2"; 351 - opp-shared; 352 - 353 - opp-50000000 { 354 - opp-hz = /bits/ 64 <50000000>; 355 - }; 356 - opp-80000000 { 357 - opp-hz = /bits/ 64 <80000000>; 358 - }; 359 - opp-100000000 { 360 - opp-hz = /bits/ 64 <100000000>; 361 - }; 362 - opp-200000000 { 363 - opp-hz = /bits/ 64 <200000000>; 364 - }; 365 - opp-300000000 { 366 - opp-hz = /bits/ 64 <300000000>; 367 - }; 368 - }; 369 - 370 - bus_peril_opp_table: opp_table4 { 371 - compatible = "operating-points-v2"; 372 - opp-shared; 373 - 374 - opp-50000000 { 375 - opp-hz = /bits/ 64 <50000000>; 376 - }; 377 - opp-80000000 { 378 - opp-hz = /bits/ 64 <80000000>; 379 - }; 380 - opp-100000000 { 381 - opp-hz = /bits/ 64 <100000000>; 382 - }; 383 - }; 384 - 385 - 386 - Usage case to handle the frequency and voltage of bus on runtime 387 - in exynos3250-rinato.dts is listed below: 388 - 389 - &bus_dmc { 390 - devfreq-events = <&ppmu_dmc0_3>, <&ppmu_dmc1_3>; 391 - vdd-supply = <&buck1_reg>; /* VDD_MIF */ 392 - status = "okay"; 393 - }; 394 - 395 - &bus_leftbus { 396 - devfreq-events = <&ppmu_leftbus_3>, <&ppmu_rightbus_3>; 397 - vdd-supply = <&buck3_reg>; 398 - status = "okay"; 399 - }; 400 - 401 - &bus_rightbus { 402 - devfreq = <&bus_leftbus>; 403 - status = "okay"; 404 - }; 405 - 406 - &bus_lcd0 { 407 - devfreq = <&bus_leftbus>; 408 - status = "okay"; 409 - }; 410 - 411 - &bus_fsys { 412 - devfreq = <&bus_leftbus>; 413 - status = "okay"; 414 - }; 415 - 416 - &bus_mcuisp { 417 - devfreq = <&bus_leftbus>; 418 - status = "okay"; 419 - }; 420 - 421 - &bus_isp { 422 - devfreq = <&bus_leftbus>; 423 - status = "okay"; 424 - }; 425 - 426 - &bus_peril { 427 - devfreq = <&bus_leftbus>; 428 - status = "okay"; 429 - }; 430 - 431 - &bus_mfc { 432 - devfreq = <&bus_leftbus>; 433 - status = "okay"; 434 - }; 435 - 436 - Example 3: 437 - An interconnect path "bus_display -- bus_leftbus -- bus_dmc" on 438 - Exynos4412 SoC with video mixer as an interconnect consumer device. 439 - 440 - soc { 441 - bus_dmc: bus_dmc { 442 - compatible = "samsung,exynos-bus"; 443 - clocks = <&clock CLK_DIV_DMC>; 444 - clock-names = "bus"; 445 - operating-points-v2 = <&bus_dmc_opp_table>; 446 - samsung,data-clock-ratio = <4>; 447 - #interconnect-cells = <0>; 448 - }; 449 - 450 - bus_leftbus: bus_leftbus { 451 - compatible = "samsung,exynos-bus"; 452 - clocks = <&clock CLK_DIV_GDL>; 453 - clock-names = "bus"; 454 - operating-points-v2 = <&bus_leftbus_opp_table>; 455 - #interconnect-cells = <0>; 456 - interconnects = <&bus_dmc>; 457 - }; 458 - 459 - bus_display: bus_display { 460 - compatible = "samsung,exynos-bus"; 461 - clocks = <&clock CLK_ACLK160>; 462 - clock-names = "bus"; 463 - operating-points-v2 = <&bus_display_opp_table>; 464 - #interconnect-cells = <0>; 465 - interconnects = <&bus_leftbus &bus_dmc>; 466 - }; 467 - 468 - bus_dmc_opp_table: opp_table1 { 469 - compatible = "operating-points-v2"; 470 - /* ... */ 471 - } 472 - 473 - bus_leftbus_opp_table: opp_table3 { 474 - compatible = "operating-points-v2"; 475 - /* ... */ 476 - }; 477 - 478 - bus_display_opp_table: opp_table4 { 479 - compatible = "operating-points-v2"; 480 - /* .. */ 481 - }; 482 - 483 - &mixer { 484 - compatible = "samsung,exynos4212-mixer"; 485 - interconnects = <&bus_display &bus_dmc>; 486 - /* ... */ 487 - }; 488 - };
+141
Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
··· 1 + # SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause) 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/interconnect/mediatek,cci.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: MediaTek Cache Coherent Interconnect (CCI) frequency and voltage scaling 8 + 9 + maintainers: 10 + - Jia-Wei Chang <jia-wei.chang@mediatek.com> 11 + - Johnson Wang <johnson.wang@mediatek.com> 12 + 13 + description: | 14 + MediaTek Cache Coherent Interconnect (CCI) is a hardware engine used by 15 + MT8183 and MT8186 SoCs to scale the frequency and adjust the voltage in 16 + hardware. It can also optimize the voltage to reduce the power consumption. 17 + 18 + properties: 19 + compatible: 20 + enum: 21 + - mediatek,mt8183-cci 22 + - mediatek,mt8186-cci 23 + 24 + clocks: 25 + items: 26 + - description: 27 + The multiplexer for clock input of the bus. 28 + - description: 29 + A parent of "bus" clock which is used as an intermediate clock source 30 + when the original clock source (PLL) is under transition and not 31 + stable yet. 32 + 33 + clock-names: 34 + items: 35 + - const: cci 36 + - const: intermediate 37 + 38 + operating-points-v2: true 39 + opp-table: true 40 + 41 + proc-supply: 42 + description: 43 + Phandle of the regulator for CCI that provides the supply voltage. 44 + 45 + sram-supply: 46 + description: 47 + Phandle of the regulator for sram of CCI that provides the supply 48 + voltage. When it is present, the implementation needs to do 49 + "voltage tracking" to step by step scale up/down Vproc and Vsram to fit 50 + SoC specific needs. When absent, the voltage scaling flow is handled by 51 + hardware, hence no software "voltage tracking" is needed. 52 + 53 + required: 54 + - compatible 55 + - clocks 56 + - clock-names 57 + - operating-points-v2 58 + - proc-supply 59 + 60 + additionalProperties: false 61 + 62 + examples: 63 + - | 64 + #include <dt-bindings/clock/mt8183-clk.h> 65 + cci: cci { 66 + compatible = "mediatek,mt8183-cci"; 67 + clocks = <&mcucfg CLK_MCU_BUS_SEL>, 68 + <&topckgen CLK_TOP_ARMPLL_DIV_PLL1>; 69 + clock-names = "cci", "intermediate"; 70 + operating-points-v2 = <&cci_opp>; 71 + proc-supply = <&mt6358_vproc12_reg>; 72 + }; 73 + 74 + cci_opp: opp-table-cci { 75 + compatible = "operating-points-v2"; 76 + opp-shared; 77 + opp2_00: opp-273000000 { 78 + opp-hz = /bits/ 64 <273000000>; 79 + opp-microvolt = <650000>; 80 + }; 81 + opp2_01: opp-338000000 { 82 + opp-hz = /bits/ 64 <338000000>; 83 + opp-microvolt = <687500>; 84 + }; 85 + opp2_02: opp-403000000 { 86 + opp-hz = /bits/ 64 <403000000>; 87 + opp-microvolt = <718750>; 88 + }; 89 + opp2_03: opp-463000000 { 90 + opp-hz = /bits/ 64 <463000000>; 91 + opp-microvolt = <756250>; 92 + }; 93 + opp2_04: opp-546000000 { 94 + opp-hz = /bits/ 64 <546000000>; 95 + opp-microvolt = <800000>; 96 + }; 97 + opp2_05: opp-624000000 { 98 + opp-hz = /bits/ 64 <624000000>; 99 + opp-microvolt = <818750>; 100 + }; 101 + opp2_06: opp-689000000 { 102 + opp-hz = /bits/ 64 <689000000>; 103 + opp-microvolt = <850000>; 104 + }; 105 + opp2_07: opp-767000000 { 106 + opp-hz = /bits/ 64 <767000000>; 107 + opp-microvolt = <868750>; 108 + }; 109 + opp2_08: opp-845000000 { 110 + opp-hz = /bits/ 64 <845000000>; 111 + opp-microvolt = <893750>; 112 + }; 113 + opp2_09: opp-871000000 { 114 + opp-hz = /bits/ 64 <871000000>; 115 + opp-microvolt = <906250>; 116 + }; 117 + opp2_10: opp-923000000 { 118 + opp-hz = /bits/ 64 <923000000>; 119 + opp-microvolt = <931250>; 120 + }; 121 + opp2_11: opp-962000000 { 122 + opp-hz = /bits/ 64 <962000000>; 123 + opp-microvolt = <943750>; 124 + }; 125 + opp2_12: opp-1027000000 { 126 + opp-hz = /bits/ 64 <1027000000>; 127 + opp-microvolt = <975000>; 128 + }; 129 + opp2_13: opp-1092000000 { 130 + opp-hz = /bits/ 64 <1092000000>; 131 + opp-microvolt = <1000000>; 132 + }; 133 + opp2_14: opp-1144000000 { 134 + opp-hz = /bits/ 64 <1144000000>; 135 + opp-microvolt = <1025000>; 136 + }; 137 + opp2_15: opp-1196000000 { 138 + opp-hz = /bits/ 64 <1196000000>; 139 + opp-microvolt = <1050000>; 140 + }; 141 + };
+290
Documentation/devicetree/bindings/interconnect/samsung,exynos-bus.yaml
··· 1 + # SPDX-License-Identifier: GPL-2.0 2 + %YAML 1.2 3 + --- 4 + $id: http://devicetree.org/schemas/interconnect/samsung,exynos-bus.yaml# 5 + $schema: http://devicetree.org/meta-schemas/core.yaml# 6 + 7 + title: Samsung Exynos SoC Bus and Interconnect 8 + 9 + maintainers: 10 + - Chanwoo Choi <cw00.choi@samsung.com> 11 + - Krzysztof Kozlowski <krzk@kernel.org> 12 + 13 + description: | 14 + The Samsung Exynos SoC has many buses for data transfer between DRAM and 15 + sub-blocks in SoC. Most Exynos SoCs share the common architecture for buses. 16 + Generally, each bus of Exynos SoC includes a source clock and a power line, 17 + which are able to change the clock frequency of the bus in runtime. To 18 + monitor the usage of each bus in runtime, the driver uses the PPMU (Platform 19 + Performance Monitoring Unit), which is able to measure the current load of 20 + sub-blocks. 21 + 22 + The Exynos SoC includes the various sub-blocks which have the each AXI bus. 23 + The each AXI bus has the owned source clock but, has not the only owned power 24 + line. The power line might be shared among one more sub-blocks. So, we can 25 + divide into two type of device as the role of each sub-block. There are two 26 + type of bus devices as following:: 27 + - parent bus device 28 + - passive bus device 29 + 30 + Basically, parent and passive bus device share the same power line. The 31 + parent bus device can only change the voltage of shared power line and the 32 + rest bus devices (passive bus device) depend on the decision of the parent 33 + bus device. If there are three blocks which share the VDD_xxx power line, 34 + Only one block should be parent device and then the rest blocks should depend 35 + on the parent device as passive device. 36 + 37 + VDD_xxx |--- A block (parent) 38 + |--- B block (passive) 39 + |--- C block (passive) 40 + 41 + There are a little different composition among Exynos SoC because each Exynos 42 + SoC has different sub-blocks. Therefore, such difference should be specified 43 + in devicetree file instead of each device driver. In result, this driver is 44 + able to support the bus frequency for all Exynos SoCs. 45 + 46 + Detailed correlation between sub-blocks and power line according 47 + to Exynos SoC:: 48 + - In case of Exynos3250, there are two power line as following:: 49 + VDD_MIF |--- DMC (Dynamic Memory Controller) 50 + 51 + VDD_INT |--- LEFTBUS (parent device) 52 + |--- PERIL 53 + |--- MFC 54 + |--- G3D 55 + |--- RIGHTBUS 56 + |--- PERIR 57 + |--- FSYS 58 + |--- LCD0 59 + |--- PERIR 60 + |--- ISP 61 + |--- CAM 62 + 63 + - MIF bus's frequency/voltage table 64 + ----------------------- 65 + |Lv| Freq | Voltage | 66 + ----------------------- 67 + |L1| 50000 |800000 | 68 + |L2| 100000 |800000 | 69 + |L3| 134000 |800000 | 70 + |L4| 200000 |825000 | 71 + |L5| 400000 |875000 | 72 + ----------------------- 73 + 74 + - INT bus's frequency/voltage table 75 + ---------------------------------------------------------- 76 + |Block|LEFTBUS|RIGHTBUS|MCUISP |ISP |PERIL ||VDD_INT | 77 + | name| |LCD0 | | | || | 78 + | | |FSYS | | | || | 79 + | | |MFC | | | || | 80 + ---------------------------------------------------------- 81 + |Mode |*parent|passive |passive|passive|passive|| | 82 + ---------------------------------------------------------- 83 + |Lv |Frequency ||Voltage | 84 + ---------------------------------------------------------- 85 + |L1 |50000 |50000 |50000 |50000 |50000 ||900000 | 86 + |L2 |80000 |80000 |80000 |80000 |80000 ||900000 | 87 + |L3 |100000 |100000 |100000 |100000 |100000 ||1000000 | 88 + |L4 |134000 |134000 |200000 |200000 | ||1000000 | 89 + |L5 |200000 |200000 |400000 |300000 | ||1000000 | 90 + ---------------------------------------------------------- 91 + 92 + - In case of Exynos4210, there is one power line as following:: 93 + VDD_INT |--- DMC (parent device, Dynamic Memory Controller) 94 + |--- LEFTBUS 95 + |--- PERIL 96 + |--- MFC(L) 97 + |--- G3D 98 + |--- TV 99 + |--- LCD0 100 + |--- RIGHTBUS 101 + |--- PERIR 102 + |--- MFC(R) 103 + |--- CAM 104 + |--- FSYS 105 + |--- GPS 106 + |--- LCD0 107 + |--- LCD1 108 + 109 + - In case of Exynos4x12, there are two power line as following:: 110 + VDD_MIF |--- DMC (Dynamic Memory Controller) 111 + 112 + VDD_INT |--- LEFTBUS (parent device) 113 + |--- PERIL 114 + |--- MFC(L) 115 + |--- G3D 116 + |--- TV 117 + |--- IMAGE 118 + |--- RIGHTBUS 119 + |--- PERIR 120 + |--- MFC(R) 121 + |--- CAM 122 + |--- FSYS 123 + |--- GPS 124 + |--- LCD0 125 + |--- ISP 126 + 127 + - In case of Exynos5422, there are two power line as following:: 128 + VDD_MIF |--- DREX 0 (parent device, DRAM EXpress controller) 129 + |--- DREX 1 130 + 131 + VDD_INT |--- NoC_Core (parent device) 132 + |--- G2D 133 + |--- G3D 134 + |--- DISP1 135 + |--- NoC_WCORE 136 + |--- GSCL 137 + |--- MSCL 138 + |--- ISP 139 + |--- MFC 140 + |--- GEN 141 + |--- PERIS 142 + |--- PERIC 143 + |--- FSYS 144 + |--- FSYS2 145 + 146 + - In case of Exynos5433, there is VDD_INT power line as following:: 147 + VDD_INT |--- G2D (parent device) 148 + |--- MSCL 149 + |--- GSCL 150 + |--- JPEG 151 + |--- MFC 152 + |--- HEVC 153 + |--- BUS0 154 + |--- BUS1 155 + |--- BUS2 156 + |--- PERIS (Fixed clock rate) 157 + |--- PERIC (Fixed clock rate) 158 + |--- FSYS (Fixed clock rate) 159 + 160 + properties: 161 + compatible: 162 + enum: 163 + - samsung,exynos-bus 164 + 165 + clocks: 166 + maxItems: 1 167 + 168 + clock-names: 169 + items: 170 + - const: bus 171 + 172 + devfreq: 173 + $ref: /schemas/types.yaml#/definitions/phandle 174 + description: 175 + Parent bus device. Valid and required only for the passive bus devices. 176 + 177 + devfreq-events: 178 + $ref: /schemas/types.yaml#/definitions/phandle-array 179 + minItems: 1 180 + maxItems: 4 181 + description: 182 + Devfreq-event device to monitor the current utilization of buses. Valid 183 + and required only for the parent bus devices. 184 + 185 + exynos,saturation-ratio: 186 + $ref: /schemas/types.yaml#/definitions/uint32 187 + description: 188 + Percentage value which is used to calibrate the performance count against 189 + total cycle count. Valid only for the parent bus devices. 190 + 191 + '#interconnect-cells': 192 + const: 0 193 + 194 + interconnects: 195 + minItems: 1 196 + maxItems: 2 197 + 198 + operating-points-v2: true 199 + 200 + samsung,data-clock-ratio: 201 + $ref: /schemas/types.yaml#/definitions/uint32 202 + default: 8 203 + description: 204 + Ratio of the data throughput in B/s to minimum data clock frequency in 205 + Hz. 206 + 207 + vdd-supply: 208 + description: 209 + Main bus power rail. Valid and required only for the parent bus devices. 210 + 211 + required: 212 + - compatible 213 + - clocks 214 + - clock-names 215 + - operating-points-v2 216 + 217 + additionalProperties: false 218 + 219 + examples: 220 + - | 221 + #include <dt-bindings/clock/exynos3250.h> 222 + 223 + bus-dmc { 224 + compatible = "samsung,exynos-bus"; 225 + clocks = <&cmu_dmc CLK_DIV_DMC>; 226 + clock-names = "bus"; 227 + operating-points-v2 = <&bus_dmc_opp_table>; 228 + devfreq-events = <&ppmu_dmc0_3>, <&ppmu_dmc1_3>; 229 + vdd-supply = <&buck1_reg>; 230 + }; 231 + 232 + ppmu_dmc0: ppmu@106a0000 { 233 + compatible = "samsung,exynos-ppmu"; 234 + reg = <0x106a0000 0x2000>; 235 + events { 236 + ppmu_dmc0_3: ppmu-event3-dmc0 { 237 + event-name = "ppmu-event3-dmc0"; 238 + }; 239 + }; 240 + }; 241 + 242 + bus_leftbus: bus-leftbus { 243 + compatible = "samsung,exynos-bus"; 244 + clocks = <&cmu CLK_DIV_GDL>; 245 + clock-names = "bus"; 246 + operating-points-v2 = <&bus_leftbus_opp_table>; 247 + devfreq-events = <&ppmu_leftbus_3>, <&ppmu_rightbus_3>; 248 + vdd-supply = <&buck3_reg>; 249 + }; 250 + 251 + bus-rightbus { 252 + compatible = "samsung,exynos-bus"; 253 + clocks = <&cmu CLK_DIV_GDR>; 254 + clock-names = "bus"; 255 + operating-points-v2 = <&bus_leftbus_opp_table>; 256 + devfreq = <&bus_leftbus>; 257 + }; 258 + 259 + - | 260 + dmc: bus-dmc { 261 + compatible = "samsung,exynos-bus"; 262 + clocks = <&clock CLK_DIV_DMC>; 263 + clock-names = "bus"; 264 + operating-points-v2 = <&bus_dmc_opp_table>; 265 + samsung,data-clock-ratio = <4>; 266 + #interconnect-cells = <0>; 267 + devfreq-events = <&ppmu_dmc0_3>, <&ppmu_dmc1_3>; 268 + vdd-supply = <&buck1_reg>; 269 + }; 270 + 271 + leftbus: bus-leftbus { 272 + compatible = "samsung,exynos-bus"; 273 + clocks = <&clock CLK_DIV_GDL>; 274 + clock-names = "bus"; 275 + operating-points-v2 = <&bus_leftbus_opp_table>; 276 + interconnects = <&dmc>; 277 + #interconnect-cells = <0>; 278 + devfreq-events = <&ppmu_leftbus_3>, <&ppmu_rightbus_3>; 279 + vdd-supply = <&buck3_reg>; 280 + }; 281 + 282 + display: bus-display { 283 + compatible = "samsung,exynos-bus"; 284 + clocks = <&clock CLK_DIV_ACLK_266>; 285 + clock-names = "bus"; 286 + operating-points-v2 = <&bus_display_opp_table>; 287 + interconnects = <&leftbus &dmc>; 288 + #interconnect-cells = <0>; 289 + devfreq = <&leftbus>; 290 + };
+7 -7
Documentation/power/energy-model.rst
··· 20 20 abstraction layer which standardizes the format of power cost tables in the 21 21 kernel, hence enabling to avoid redundant work. 22 22 23 - The power values might be expressed in milli-Watts or in an 'abstract scale'. 23 + The power values might be expressed in micro-Watts or in an 'abstract scale'. 24 24 Multiple subsystems might use the EM and it is up to the system integrator to 25 25 check that the requirements for the power value scale types are met. An example 26 26 can be found in the Energy-Aware Scheduler documentation 27 27 Documentation/scheduler/sched-energy.rst. For some subsystems like thermal or 28 28 powercap power values expressed in an 'abstract scale' might cause issues. 29 29 These subsystems are more interested in estimation of power used in the past, 30 - thus the real milli-Watts might be needed. An example of these requirements can 30 + thus the real micro-Watts might be needed. An example of these requirements can 31 31 be found in the Intelligent Power Allocation in 32 32 Documentation/driver-api/thermal/power_allocator.rst. 33 33 Kernel subsystems might implement automatic detection to check whether EM 34 34 registered devices have inconsistent scale (based on EM internal flag). 35 35 Important thing to keep in mind is that when the power values are expressed in 36 - an 'abstract scale' deriving real energy in milli-Joules would not be possible. 36 + an 'abstract scale' deriving real energy in micro-Joules would not be possible. 37 37 38 38 The figure below depicts an example of drivers (Arm-specific here, but the 39 39 approach is applicable to any architecture) providing power costs to the EM ··· 98 98 calling the following API:: 99 99 100 100 int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, 101 - struct em_data_callback *cb, cpumask_t *cpus, bool milliwatts); 101 + struct em_data_callback *cb, cpumask_t *cpus, bool microwatts); 102 102 103 103 Drivers must provide a callback function returning <frequency, power> tuples 104 104 for each performance state. The callback function provided by the driver is free ··· 106 106 deemed necessary. Only for CPU devices, drivers must specify the CPUs of the 107 107 performance domains using cpumask. For other devices than CPUs the last 108 108 argument must be set to NULL. 109 - The last argument 'milliwatts' is important to set with correct value. Kernel 109 + The last argument 'microwatts' is important to set with correct value. Kernel 110 110 subsystems which use EM might rely on this flag to check if all EM devices use 111 111 the same scale. If there are different scales, these subsystems might decide 112 - to: return warning/error, stop working or panic. 112 + to return warning/error, stop working or panic. 113 113 See Section 3. for an example of driver implementing this 114 114 callback, or Section 2.4 for further documentation on this API 115 115 ··· 137 137 efficiency of the CPUs. This would allow to provide EAS information which 138 138 has different relation than what would be forced by the EM internal 139 139 formulas calculating 'cost' values. To register an EM for such platform, the 140 - driver must set the flag 'milliwatts' to 0, provide .get_power() callback 140 + driver must set the flag 'microwatts' to 0, provide .get_power() callback 141 141 and provide .get_cost() callback. The EM framework would handle such platform 142 142 properly during registration. A flag EM_PERF_DOMAIN_ARTIFICIAL is set for such 143 143 platform. Special care should be taken by other frameworks which are using EM
+1 -1
Documentation/power/pci.rst
··· 315 315 configuration space */ 316 316 unsigned int pme_support:5; /* Bitmask of states from which PME# 317 317 can be generated */ 318 - unsigned int pme_interrupt:1;/* Is native PCIe PME signaling used? */ 318 + unsigned int pme_poll:1; /* Poll device's PME status bit */ 319 319 unsigned int d1_support:1; /* Low power state D1 is supported */ 320 320 unsigned int d2_support:1; /* Low power state D2 is supported */ 321 321 unsigned int no_d1d2:1; /* D1 and D2 are forbidden */
+2 -1
MAINTAINERS
··· 4408 4408 L: linux-samsung-soc@vger.kernel.org 4409 4409 S: Maintained 4410 4410 T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git 4411 - F: Documentation/devicetree/bindings/devfreq/exynos-bus.txt 4411 + F: Documentation/devicetree/bindings/interconnect/samsung,exynos-bus.yaml 4412 4412 F: drivers/devfreq/exynos-bus.c 4413 4413 4414 4414 BUSLOGIC SCSI DRIVER ··· 5890 5890 S: Maintained 5891 5891 T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git 5892 5892 F: Documentation/devicetree/bindings/devfreq/ 5893 + F: Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml 5893 5894 F: drivers/devfreq/ 5894 5895 F: include/linux/devfreq.h 5895 5896 F: include/trace/events/devfreq.h
+3
drivers/base/power/domain.c
··· 222 222 { 223 223 struct dentry *d; 224 224 225 + if (!genpd_debugfs_dir) 226 + return; 227 + 225 228 d = debugfs_lookup(genpd->name, genpd_debugfs_dir); 226 229 debugfs_remove(d); 227 230 }
+6
drivers/base/power/runtime.c
··· 1862 1862 1863 1863 callback = RPM_GET_CALLBACK(dev, runtime_suspend); 1864 1864 1865 + dev_pm_enable_wake_irq_check(dev, true); 1865 1866 ret = callback ? callback(dev) : 0; 1866 1867 if (ret) 1867 1868 goto err; 1869 + 1870 + dev_pm_enable_wake_irq_complete(dev); 1868 1871 1869 1872 /* 1870 1873 * If the device can stay in suspend after the system-wide transition ··· 1885 1882 return 0; 1886 1883 1887 1884 err: 1885 + dev_pm_disable_wake_irq_check(dev, true); 1888 1886 pm_runtime_enable(dev); 1889 1887 return ret; 1890 1888 } ··· 1919 1915 1920 1916 callback = RPM_GET_CALLBACK(dev, runtime_resume); 1921 1917 1918 + dev_pm_disable_wake_irq_check(dev, false); 1922 1919 ret = callback ? callback(dev) : 0; 1923 1920 if (ret) { 1924 1921 pm_runtime_set_suspended(dev); 1922 + dev_pm_enable_wake_irq_check(dev, false); 1925 1923 goto out; 1926 1924 } 1927 1925
-30
drivers/base/power/wakeup.c
··· 501 501 EXPORT_SYMBOL_GPL(device_set_wakeup_capable); 502 502 503 503 /** 504 - * device_init_wakeup - Device wakeup initialization. 505 - * @dev: Device to handle. 506 - * @enable: Whether or not to enable @dev as a wakeup device. 507 - * 508 - * By default, most devices should leave wakeup disabled. The exceptions are 509 - * devices that everyone expects to be wakeup sources: keyboards, power buttons, 510 - * possibly network interfaces, etc. Also, devices that don't generate their 511 - * own wakeup requests but merely forward requests from one bus to another 512 - * (like PCI bridges) should have wakeup enabled by default. 513 - */ 514 - int device_init_wakeup(struct device *dev, bool enable) 515 - { 516 - int ret = 0; 517 - 518 - if (!dev) 519 - return -EINVAL; 520 - 521 - if (enable) { 522 - device_set_wakeup_capable(dev, true); 523 - ret = device_wakeup_enable(dev); 524 - } else { 525 - device_wakeup_disable(dev); 526 - device_set_wakeup_capable(dev, false); 527 - } 528 - 529 - return ret; 530 - } 531 - EXPORT_SYMBOL_GPL(device_init_wakeup); 532 - 533 - /** 534 504 * device_set_wakeup_enable - Enable or disable a device to wake up the system. 535 505 * @dev: Device to handle. 536 506 * @enable: enable/disable flag
+1 -1
drivers/cpufreq/Kconfig
··· 268 268 This option adds a CPUFreq driver for loongson processors which 269 269 support software configurable cpu frequency. 270 270 271 - Loongson2F and it's successors support this feature. 271 + Loongson2F and its successors support this feature. 272 272 273 273 If in doubt, say N. 274 274
+4
drivers/cpufreq/acpi-cpufreq.c
··· 78 78 79 79 switch (boot_cpu_data.x86_vendor) { 80 80 case X86_VENDOR_INTEL: 81 + case X86_VENDOR_CENTAUR: 82 + case X86_VENDOR_ZHAOXIN: 81 83 rdmsr_on_cpu(cpu, MSR_IA32_MISC_ENABLE, &lo, &hi); 82 84 msr = lo | ((u64)hi << 32); 83 85 return !(msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE); ··· 99 97 100 98 switch (boot_cpu_data.x86_vendor) { 101 99 case X86_VENDOR_INTEL: 100 + case X86_VENDOR_CENTAUR: 101 + case X86_VENDOR_ZHAOXIN: 102 102 msr_addr = MSR_IA32_MISC_ENABLE; 103 103 msr_mask = MSR_IA32_MISC_ENABLE_TURBO_DISABLE; 104 104 break;
+17 -20
drivers/cpufreq/cpufreq.c
··· 843 843 unsigned int cpu; 844 844 845 845 for_each_cpu(cpu, mask) { 846 - if (i) 847 - i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " "); 848 - i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu); 846 + i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u ", cpu); 849 847 if (i >= (PAGE_SIZE - 5)) 850 848 break; 851 849 } 850 + 851 + /* Remove the extra space at the end */ 852 + i--; 853 + 852 854 i += sprintf(&buf[i], "\n"); 853 855 return i; 854 856 } ··· 973 971 if (!fattr->store) 974 972 return -EIO; 975 973 976 - /* 977 - * cpus_read_trylock() is used here to work around a circular lock 978 - * dependency problem with respect to the cpufreq_register_driver(). 979 - */ 980 - if (!cpus_read_trylock()) 981 - return -EBUSY; 982 - 983 - if (cpu_online(policy->cpu)) { 984 - down_write(&policy->rwsem); 985 - if (likely(!policy_is_inactive(policy))) 986 - ret = fattr->store(policy, buf, count); 987 - up_write(&policy->rwsem); 988 - } 989 - 990 - cpus_read_unlock(); 974 + down_write(&policy->rwsem); 975 + if (likely(!policy_is_inactive(policy))) 976 + ret = fattr->store(policy, buf, count); 977 + up_write(&policy->rwsem); 991 978 992 979 return ret; 993 980 } ··· 1273 1282 unsigned long flags; 1274 1283 int cpu; 1275 1284 1285 + /* 1286 + * The callers must ensure the policy is inactive by now, to avoid any 1287 + * races with show()/store() callbacks. 1288 + */ 1289 + if (unlikely(!policy_is_inactive(policy))) 1290 + pr_warn("%s: Freeing active policy\n", __func__); 1291 + 1276 1292 /* Remove policy from list */ 1277 1293 write_lock_irqsave(&cpufreq_driver_lock, flags); 1278 1294 list_del(&policy->policy_list); ··· 1534 1536 for_each_cpu(j, policy->real_cpus) 1535 1537 remove_cpu_dev_symlink(policy, j, get_cpu_device(j)); 1536 1538 1537 - cpumask_clear(policy->cpus); 1538 - 1539 1539 out_offline_policy: 1540 1540 if (cpufreq_driver->offline) 1541 1541 cpufreq_driver->offline(policy); ··· 1543 1547 cpufreq_driver->exit(policy); 1544 1548 1545 1549 out_free_policy: 1550 + cpumask_clear(policy->cpus); 1546 1551 up_write(&policy->rwsem); 1547 1552 1548 1553 cpufreq_policy_free(policy);
+9 -4
drivers/cpufreq/cpufreq_ondemand.c
··· 416 416 static void od_set_powersave_bias(unsigned int powersave_bias) 417 417 { 418 418 unsigned int cpu; 419 - cpumask_t done; 419 + cpumask_var_t done; 420 + 421 + if (!alloc_cpumask_var(&done, GFP_KERNEL)) 422 + return; 420 423 421 424 default_powersave_bias = powersave_bias; 422 - cpumask_clear(&done); 425 + cpumask_clear(done); 423 426 424 427 cpus_read_lock(); 425 428 for_each_online_cpu(cpu) { ··· 431 428 struct dbs_data *dbs_data; 432 429 struct od_dbs_tuners *od_tuners; 433 430 434 - if (cpumask_test_cpu(cpu, &done)) 431 + if (cpumask_test_cpu(cpu, done)) 435 432 continue; 436 433 437 434 policy = cpufreq_cpu_get_raw(cpu); ··· 442 439 if (!policy_dbs) 443 440 continue; 444 441 445 - cpumask_or(&done, &done, policy->cpus); 442 + cpumask_or(done, done, policy->cpus); 446 443 447 444 dbs_data = policy_dbs->dbs_data; 448 445 od_tuners = dbs_data->tuners; 449 446 od_tuners->powersave_bias = default_powersave_bias; 450 447 } 451 448 cpus_read_unlock(); 449 + 450 + free_cpumask_var(done); 452 451 } 453 452 454 453 void od_register_powersave_bias_handler(unsigned int (*f)
+4 -3
drivers/cpufreq/mediatek-cpufreq-hw.c
··· 51 51 }; 52 52 53 53 static int __maybe_unused 54 - mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *mW, 54 + mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *uW, 55 55 unsigned long *KHz) 56 56 { 57 57 struct mtk_cpufreq_data *data; ··· 71 71 i--; 72 72 73 73 *KHz = data->table[i].frequency; 74 - *mW = readl_relaxed(data->reg_bases[REG_EM_POWER_TBL] + 75 - i * LUT_ROW_SIZE) / 1000; 74 + /* Provide micro-Watts value to the Energy Model */ 75 + *uW = readl_relaxed(data->reg_bases[REG_EM_POWER_TBL] + 76 + i * LUT_ROW_SIZE); 76 77 77 78 return 0; 78 79 }
+13 -2
drivers/cpufreq/scmi-cpufreq.c
··· 19 19 #include <linux/slab.h> 20 20 #include <linux/scmi_protocol.h> 21 21 #include <linux/types.h> 22 + #include <linux/units.h> 22 23 23 24 struct scmi_data { 24 25 int domain_id; ··· 100 99 scmi_get_cpu_power(struct device *cpu_dev, unsigned long *power, 101 100 unsigned long *KHz) 102 101 { 102 + enum scmi_power_scale power_scale = perf_ops->power_scale_get(ph); 103 103 unsigned long Hz; 104 104 int ret, domain; 105 105 ··· 113 111 ret = perf_ops->est_power_get(ph, domain, &Hz, power); 114 112 if (ret) 115 113 return ret; 114 + 115 + /* Convert the power to uW if it is mW (ignore bogoW) */ 116 + if (power_scale == SCMI_POWER_MILLIWATTS) 117 + *power *= MICROWATT_PER_MILLIWATT; 116 118 117 119 /* The EM framework specifies the frequency in KHz. */ 118 120 *KHz = Hz / 1000; ··· 255 249 static void scmi_cpufreq_register_em(struct cpufreq_policy *policy) 256 250 { 257 251 struct em_data_callback em_cb = EM_DATA_CB(scmi_get_cpu_power); 258 - bool power_scale_mw = perf_ops->power_scale_mw_get(ph); 252 + enum scmi_power_scale power_scale = perf_ops->power_scale_get(ph); 259 253 struct scmi_data *priv = policy->driver_data; 254 + bool em_power_scale = false; 260 255 261 256 /* 262 257 * This callback will be called for each policy, but we don't need to ··· 269 262 if (!priv->nr_opp) 270 263 return; 271 264 265 + if (power_scale == SCMI_POWER_MILLIWATTS 266 + || power_scale == SCMI_POWER_MICROWATTS) 267 + em_power_scale = true; 268 + 272 269 em_dev_register_perf_domain(get_cpu_device(policy->cpu), priv->nr_opp, 273 270 &em_cb, priv->opp_shared_cpus, 274 - power_scale_mw); 271 + em_power_scale); 275 272 } 276 273 277 274 static struct cpufreq_driver scmi_cpufreq_driver = {
+3
drivers/cpuidle/governors/haltpoll.c
··· 19 19 #include <linux/sched.h> 20 20 #include <linux/module.h> 21 21 #include <linux/kvm_para.h> 22 + #include <trace/events/power.h> 22 23 23 24 static unsigned int guest_halt_poll_ns __read_mostly = 200000; 24 25 module_param(guest_halt_poll_ns, uint, 0644); ··· 91 90 if (val > guest_halt_poll_ns) 92 91 val = guest_halt_poll_ns; 93 92 93 + trace_guest_halt_poll_ns_grow(val, dev->poll_limit_ns); 94 94 dev->poll_limit_ns = val; 95 95 } else if (block_ns > guest_halt_poll_ns && 96 96 guest_halt_poll_allow_shrink) { ··· 102 100 val = 0; 103 101 else 104 102 val /= shrink; 103 + trace_guest_halt_poll_ns_shrink(val, dev->poll_limit_ns); 105 104 dev->poll_limit_ns = val; 106 105 } 107 106 }
+10
drivers/devfreq/Kconfig
··· 120 120 It reads ACTMON counters of memory controllers and adjusts the 121 121 operating frequencies and voltages with OPP support. 122 122 123 + config ARM_MEDIATEK_CCI_DEVFREQ 124 + tristate "MEDIATEK CCI DEVFREQ Driver" 125 + depends on ARM_MEDIATEK_CPUFREQ || COMPILE_TEST 126 + select DEVFREQ_GOV_PASSIVE 127 + help 128 + This adds a devfreq driver for MediaTek Cache Coherent Interconnect 129 + which is shared the same regulators with the cpu cluster. It can track 130 + buck voltages and update a proper CCI frequency. Use the notification 131 + to get the regulator status. 132 + 123 133 config ARM_RK3399_DMC_DEVFREQ 124 134 tristate "ARM RK3399 DMC DEVFREQ Driver" 125 135 depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \
+1
drivers/devfreq/Makefile
··· 11 11 obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o 12 12 obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ) += imx-bus.o 13 13 obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ) += imx8m-ddrc.o 14 + obj-$(CONFIG_ARM_MEDIATEK_CCI_DEVFREQ) += mtk-cci-devfreq.o 14 15 obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o 15 16 obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ) += sun8i-a33-mbus.o 16 17 obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o
+4
drivers/devfreq/devfreq.c
··· 696 696 /** 697 697 * qos_min_notifier_call() - Callback for QoS min_freq changes. 698 698 * @nb: Should be devfreq->nb_min 699 + * @val: not used 700 + * @ptr: not used 699 701 */ 700 702 static int qos_min_notifier_call(struct notifier_block *nb, 701 703 unsigned long val, void *ptr) ··· 708 706 /** 709 707 * qos_max_notifier_call() - Callback for QoS max_freq changes. 710 708 * @nb: Should be devfreq->nb_max 709 + * @val: not used 710 + * @ptr: not used 711 711 */ 712 712 static int qos_max_notifier_call(struct notifier_block *nb, 713 713 unsigned long val, void *ptr)
+1 -1
drivers/devfreq/imx-bus.c
··· 59 59 struct imx_bus *priv = dev_get_drvdata(dev); 60 60 const char *icc_driver_name; 61 61 62 - if (!of_get_property(dev->of_node, "#interconnect-cells", 0)) 62 + if (!of_get_property(dev->of_node, "#interconnect-cells", NULL)) 63 63 return 0; 64 64 if (!IS_ENABLED(CONFIG_INTERCONNECT_IMX)) { 65 65 dev_warn(dev, "imx interconnect drivers disabled\n");
+440
drivers/devfreq/mtk-cci-devfreq.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (C) 2022 MediaTek Inc. 4 + */ 5 + 6 + #include <linux/clk.h> 7 + #include <linux/devfreq.h> 8 + #include <linux/minmax.h> 9 + #include <linux/module.h> 10 + #include <linux/of.h> 11 + #include <linux/of_device.h> 12 + #include <linux/platform_device.h> 13 + #include <linux/pm_opp.h> 14 + #include <linux/regulator/consumer.h> 15 + 16 + struct mtk_ccifreq_platform_data { 17 + int min_volt_shift; 18 + int max_volt_shift; 19 + int proc_max_volt; 20 + int sram_min_volt; 21 + int sram_max_volt; 22 + }; 23 + 24 + struct mtk_ccifreq_drv { 25 + struct device *dev; 26 + struct devfreq *devfreq; 27 + struct regulator *proc_reg; 28 + struct regulator *sram_reg; 29 + struct clk *cci_clk; 30 + struct clk *inter_clk; 31 + int inter_voltage; 32 + unsigned long pre_freq; 33 + /* Avoid race condition for regulators between notify and policy */ 34 + struct mutex reg_lock; 35 + struct notifier_block opp_nb; 36 + const struct mtk_ccifreq_platform_data *soc_data; 37 + int vtrack_max; 38 + }; 39 + 40 + static int mtk_ccifreq_set_voltage(struct mtk_ccifreq_drv *drv, int new_voltage) 41 + { 42 + const struct mtk_ccifreq_platform_data *soc_data = drv->soc_data; 43 + struct device *dev = drv->dev; 44 + int pre_voltage, pre_vsram, new_vsram, vsram, voltage, ret; 45 + int retry_max = drv->vtrack_max; 46 + 47 + if (!drv->sram_reg) { 48 + ret = regulator_set_voltage(drv->proc_reg, new_voltage, 49 + drv->soc_data->proc_max_volt); 50 + return ret; 51 + } 52 + 53 + pre_voltage = regulator_get_voltage(drv->proc_reg); 54 + if (pre_voltage < 0) { 55 + dev_err(dev, "invalid vproc value: %d\n", pre_voltage); 56 + return pre_voltage; 57 + } 58 + 59 + pre_vsram = regulator_get_voltage(drv->sram_reg); 60 + if (pre_vsram < 0) { 61 + dev_err(dev, "invalid vsram value: %d\n", pre_vsram); 62 + return pre_vsram; 63 + } 64 + 65 + new_vsram = clamp(new_voltage + soc_data->min_volt_shift, 66 + soc_data->sram_min_volt, soc_data->sram_max_volt); 67 + 68 + do { 69 + if (pre_voltage <= new_voltage) { 70 + vsram = clamp(pre_voltage + soc_data->max_volt_shift, 71 + soc_data->sram_min_volt, new_vsram); 72 + ret = regulator_set_voltage(drv->sram_reg, vsram, 73 + soc_data->sram_max_volt); 74 + if (ret) 75 + return ret; 76 + 77 + if (vsram == soc_data->sram_max_volt || 78 + new_vsram == soc_data->sram_min_volt) 79 + voltage = new_voltage; 80 + else 81 + voltage = vsram - soc_data->min_volt_shift; 82 + 83 + ret = regulator_set_voltage(drv->proc_reg, voltage, 84 + soc_data->proc_max_volt); 85 + if (ret) { 86 + regulator_set_voltage(drv->sram_reg, pre_vsram, 87 + soc_data->sram_max_volt); 88 + return ret; 89 + } 90 + } else if (pre_voltage > new_voltage) { 91 + voltage = max(new_voltage, 92 + pre_vsram - soc_data->max_volt_shift); 93 + ret = regulator_set_voltage(drv->proc_reg, voltage, 94 + soc_data->proc_max_volt); 95 + if (ret) 96 + return ret; 97 + 98 + if (voltage == new_voltage) 99 + vsram = new_vsram; 100 + else 101 + vsram = max(new_vsram, 102 + voltage + soc_data->min_volt_shift); 103 + 104 + ret = regulator_set_voltage(drv->sram_reg, vsram, 105 + soc_data->sram_max_volt); 106 + if (ret) { 107 + regulator_set_voltage(drv->proc_reg, pre_voltage, 108 + soc_data->proc_max_volt); 109 + return ret; 110 + } 111 + } 112 + 113 + pre_voltage = voltage; 114 + pre_vsram = vsram; 115 + 116 + if (--retry_max < 0) { 117 + dev_err(dev, 118 + "over loop count, failed to set voltage\n"); 119 + return -EINVAL; 120 + } 121 + } while (voltage != new_voltage || vsram != new_vsram); 122 + 123 + return 0; 124 + } 125 + 126 + static int mtk_ccifreq_target(struct device *dev, unsigned long *freq, 127 + u32 flags) 128 + { 129 + struct mtk_ccifreq_drv *drv = dev_get_drvdata(dev); 130 + struct clk *cci_pll = clk_get_parent(drv->cci_clk); 131 + struct dev_pm_opp *opp; 132 + unsigned long opp_rate; 133 + int voltage, pre_voltage, inter_voltage, target_voltage, ret; 134 + 135 + if (!drv) 136 + return -EINVAL; 137 + 138 + if (drv->pre_freq == *freq) 139 + return 0; 140 + 141 + inter_voltage = drv->inter_voltage; 142 + 143 + opp_rate = *freq; 144 + opp = devfreq_recommended_opp(dev, &opp_rate, 1); 145 + if (IS_ERR(opp)) { 146 + dev_err(dev, "failed to find opp for freq: %ld\n", opp_rate); 147 + return PTR_ERR(opp); 148 + } 149 + 150 + mutex_lock(&drv->reg_lock); 151 + 152 + voltage = dev_pm_opp_get_voltage(opp); 153 + dev_pm_opp_put(opp); 154 + 155 + pre_voltage = regulator_get_voltage(drv->proc_reg); 156 + if (pre_voltage < 0) { 157 + dev_err(dev, "invalid vproc value: %d\n", pre_voltage); 158 + ret = pre_voltage; 159 + goto out_unlock; 160 + } 161 + 162 + /* scale up: set voltage first then freq. */ 163 + target_voltage = max(inter_voltage, voltage); 164 + if (pre_voltage <= target_voltage) { 165 + ret = mtk_ccifreq_set_voltage(drv, target_voltage); 166 + if (ret) { 167 + dev_err(dev, "failed to scale up voltage\n"); 168 + goto out_restore_voltage; 169 + } 170 + } 171 + 172 + /* switch the cci clock to intermediate clock source. */ 173 + ret = clk_set_parent(drv->cci_clk, drv->inter_clk); 174 + if (ret) { 175 + dev_err(dev, "failed to re-parent cci clock\n"); 176 + goto out_restore_voltage; 177 + } 178 + 179 + /* set the original clock to target rate. */ 180 + ret = clk_set_rate(cci_pll, *freq); 181 + if (ret) { 182 + dev_err(dev, "failed to set cci pll rate: %d\n", ret); 183 + clk_set_parent(drv->cci_clk, cci_pll); 184 + goto out_restore_voltage; 185 + } 186 + 187 + /* switch the cci clock back to the original clock source. */ 188 + ret = clk_set_parent(drv->cci_clk, cci_pll); 189 + if (ret) { 190 + dev_err(dev, "failed to re-parent cci clock\n"); 191 + mtk_ccifreq_set_voltage(drv, inter_voltage); 192 + goto out_unlock; 193 + } 194 + 195 + /* 196 + * If the new voltage is lower than the intermediate voltage or the 197 + * original voltage, scale down to the new voltage. 198 + */ 199 + if (voltage < inter_voltage || voltage < pre_voltage) { 200 + ret = mtk_ccifreq_set_voltage(drv, voltage); 201 + if (ret) { 202 + dev_err(dev, "failed to scale down voltage\n"); 203 + goto out_unlock; 204 + } 205 + } 206 + 207 + drv->pre_freq = *freq; 208 + mutex_unlock(&drv->reg_lock); 209 + 210 + return 0; 211 + 212 + out_restore_voltage: 213 + mtk_ccifreq_set_voltage(drv, pre_voltage); 214 + 215 + out_unlock: 216 + mutex_unlock(&drv->reg_lock); 217 + return ret; 218 + } 219 + 220 + static int mtk_ccifreq_opp_notifier(struct notifier_block *nb, 221 + unsigned long event, void *data) 222 + { 223 + struct dev_pm_opp *opp = data; 224 + struct mtk_ccifreq_drv *drv; 225 + unsigned long freq, volt; 226 + 227 + drv = container_of(nb, struct mtk_ccifreq_drv, opp_nb); 228 + 229 + if (event == OPP_EVENT_ADJUST_VOLTAGE) { 230 + freq = dev_pm_opp_get_freq(opp); 231 + 232 + mutex_lock(&drv->reg_lock); 233 + /* current opp item is changed */ 234 + if (freq == drv->pre_freq) { 235 + volt = dev_pm_opp_get_voltage(opp); 236 + mtk_ccifreq_set_voltage(drv, volt); 237 + } 238 + mutex_unlock(&drv->reg_lock); 239 + } 240 + 241 + return 0; 242 + } 243 + 244 + static struct devfreq_dev_profile mtk_ccifreq_profile = { 245 + .target = mtk_ccifreq_target, 246 + }; 247 + 248 + static int mtk_ccifreq_probe(struct platform_device *pdev) 249 + { 250 + struct device *dev = &pdev->dev; 251 + struct mtk_ccifreq_drv *drv; 252 + struct devfreq_passive_data *passive_data; 253 + struct dev_pm_opp *opp; 254 + unsigned long rate, opp_volt; 255 + int ret; 256 + 257 + drv = devm_kzalloc(dev, sizeof(*drv), GFP_KERNEL); 258 + if (!drv) 259 + return -ENOMEM; 260 + 261 + drv->dev = dev; 262 + drv->soc_data = (const struct mtk_ccifreq_platform_data *) 263 + of_device_get_match_data(&pdev->dev); 264 + mutex_init(&drv->reg_lock); 265 + platform_set_drvdata(pdev, drv); 266 + 267 + drv->cci_clk = devm_clk_get(dev, "cci"); 268 + if (IS_ERR(drv->cci_clk)) { 269 + ret = PTR_ERR(drv->cci_clk); 270 + return dev_err_probe(dev, ret, "failed to get cci clk\n"); 271 + } 272 + 273 + drv->inter_clk = devm_clk_get(dev, "intermediate"); 274 + if (IS_ERR(drv->inter_clk)) { 275 + ret = PTR_ERR(drv->inter_clk); 276 + return dev_err_probe(dev, ret, 277 + "failed to get intermediate clk\n"); 278 + } 279 + 280 + drv->proc_reg = devm_regulator_get_optional(dev, "proc"); 281 + if (IS_ERR(drv->proc_reg)) { 282 + ret = PTR_ERR(drv->proc_reg); 283 + return dev_err_probe(dev, ret, 284 + "failed to get proc regulator\n"); 285 + } 286 + 287 + ret = regulator_enable(drv->proc_reg); 288 + if (ret) { 289 + dev_err(dev, "failed to enable proc regulator\n"); 290 + return ret; 291 + } 292 + 293 + drv->sram_reg = devm_regulator_get_optional(dev, "sram"); 294 + if (IS_ERR(drv->sram_reg)) 295 + drv->sram_reg = NULL; 296 + else { 297 + ret = regulator_enable(drv->sram_reg); 298 + if (ret) { 299 + dev_err(dev, "failed to enable sram regulator\n"); 300 + goto out_free_resources; 301 + } 302 + } 303 + 304 + /* 305 + * We assume min voltage is 0 and tracking target voltage using 306 + * min_volt_shift for each iteration. 307 + * The retry_max is 3 times of expected iteration count. 308 + */ 309 + drv->vtrack_max = 3 * DIV_ROUND_UP(max(drv->soc_data->sram_max_volt, 310 + drv->soc_data->proc_max_volt), 311 + drv->soc_data->min_volt_shift); 312 + 313 + ret = clk_prepare_enable(drv->cci_clk); 314 + if (ret) 315 + goto out_free_resources; 316 + 317 + ret = dev_pm_opp_of_add_table(dev); 318 + if (ret) { 319 + dev_err(dev, "failed to add opp table: %d\n", ret); 320 + goto out_disable_cci_clk; 321 + } 322 + 323 + rate = clk_get_rate(drv->inter_clk); 324 + opp = dev_pm_opp_find_freq_ceil(dev, &rate); 325 + if (IS_ERR(opp)) { 326 + ret = PTR_ERR(opp); 327 + dev_err(dev, "failed to get intermediate opp: %d\n", ret); 328 + goto out_remove_opp_table; 329 + } 330 + drv->inter_voltage = dev_pm_opp_get_voltage(opp); 331 + dev_pm_opp_put(opp); 332 + 333 + rate = U32_MAX; 334 + opp = dev_pm_opp_find_freq_floor(drv->dev, &rate); 335 + if (IS_ERR(opp)) { 336 + dev_err(dev, "failed to get opp\n"); 337 + ret = PTR_ERR(opp); 338 + goto out_remove_opp_table; 339 + } 340 + 341 + opp_volt = dev_pm_opp_get_voltage(opp); 342 + dev_pm_opp_put(opp); 343 + ret = mtk_ccifreq_set_voltage(drv, opp_volt); 344 + if (ret) { 345 + dev_err(dev, "failed to scale to highest voltage %lu in proc_reg\n", 346 + opp_volt); 347 + goto out_remove_opp_table; 348 + } 349 + 350 + passive_data = devm_kzalloc(dev, sizeof(*passive_data), GFP_KERNEL); 351 + if (!passive_data) { 352 + ret = -ENOMEM; 353 + goto out_remove_opp_table; 354 + } 355 + 356 + passive_data->parent_type = CPUFREQ_PARENT_DEV; 357 + drv->devfreq = devm_devfreq_add_device(dev, &mtk_ccifreq_profile, 358 + DEVFREQ_GOV_PASSIVE, 359 + passive_data); 360 + if (IS_ERR(drv->devfreq)) { 361 + ret = -EPROBE_DEFER; 362 + dev_err(dev, "failed to add devfreq device: %ld\n", 363 + PTR_ERR(drv->devfreq)); 364 + goto out_remove_opp_table; 365 + } 366 + 367 + drv->opp_nb.notifier_call = mtk_ccifreq_opp_notifier; 368 + ret = dev_pm_opp_register_notifier(dev, &drv->opp_nb); 369 + if (ret) { 370 + dev_err(dev, "failed to register opp notifier: %d\n", ret); 371 + goto out_remove_opp_table; 372 + } 373 + return 0; 374 + 375 + out_remove_opp_table: 376 + dev_pm_opp_of_remove_table(dev); 377 + 378 + out_disable_cci_clk: 379 + clk_disable_unprepare(drv->cci_clk); 380 + 381 + out_free_resources: 382 + if (regulator_is_enabled(drv->proc_reg)) 383 + regulator_disable(drv->proc_reg); 384 + if (drv->sram_reg && regulator_is_enabled(drv->sram_reg)) 385 + regulator_disable(drv->sram_reg); 386 + 387 + return ret; 388 + } 389 + 390 + static int mtk_ccifreq_remove(struct platform_device *pdev) 391 + { 392 + struct device *dev = &pdev->dev; 393 + struct mtk_ccifreq_drv *drv; 394 + 395 + drv = platform_get_drvdata(pdev); 396 + 397 + dev_pm_opp_unregister_notifier(dev, &drv->opp_nb); 398 + dev_pm_opp_of_remove_table(dev); 399 + clk_disable_unprepare(drv->cci_clk); 400 + regulator_disable(drv->proc_reg); 401 + if (drv->sram_reg) 402 + regulator_disable(drv->sram_reg); 403 + 404 + return 0; 405 + } 406 + 407 + static const struct mtk_ccifreq_platform_data mt8183_platform_data = { 408 + .min_volt_shift = 100000, 409 + .max_volt_shift = 200000, 410 + .proc_max_volt = 1150000, 411 + }; 412 + 413 + static const struct mtk_ccifreq_platform_data mt8186_platform_data = { 414 + .min_volt_shift = 100000, 415 + .max_volt_shift = 250000, 416 + .proc_max_volt = 1118750, 417 + .sram_min_volt = 850000, 418 + .sram_max_volt = 1118750, 419 + }; 420 + 421 + static const struct of_device_id mtk_ccifreq_machines[] = { 422 + { .compatible = "mediatek,mt8183-cci", .data = &mt8183_platform_data }, 423 + { .compatible = "mediatek,mt8186-cci", .data = &mt8186_platform_data }, 424 + { }, 425 + }; 426 + MODULE_DEVICE_TABLE(of, mtk_ccifreq_machines); 427 + 428 + static struct platform_driver mtk_ccifreq_platdrv = { 429 + .probe = mtk_ccifreq_probe, 430 + .remove = mtk_ccifreq_remove, 431 + .driver = { 432 + .name = "mtk-ccifreq", 433 + .of_match_table = mtk_ccifreq_machines, 434 + }, 435 + }; 436 + module_platform_driver(mtk_ccifreq_platdrv); 437 + 438 + MODULE_DESCRIPTION("MediaTek CCI devfreq driver"); 439 + MODULE_AUTHOR("Jia-Wei Chang <jia-wei.chang@mediatek.com>"); 440 + MODULE_LICENSE("GPL v2");
+3 -1
drivers/devfreq/tegra30-devfreq.c
··· 922 922 923 923 devfreq = devm_devfreq_add_device(&pdev->dev, &tegra_devfreq_profile, 924 924 "tegra_actmon", NULL); 925 - if (IS_ERR(devfreq)) 925 + if (IS_ERR(devfreq)) { 926 + dev_err(&pdev->dev, "Failed to add device: %pe\n", devfreq); 926 927 return PTR_ERR(devfreq); 928 + } 927 929 928 930 return 0; 929 931 }
+11 -7
drivers/firmware/arm_scmi/perf.c
··· 140 140 struct scmi_perf_info { 141 141 u32 version; 142 142 int num_domains; 143 - bool power_scale_mw; 144 - bool power_scale_uw; 143 + enum scmi_power_scale power_scale; 145 144 u64 stats_addr; 146 145 u32 stats_size; 147 146 struct perf_dom_info *dom_info; ··· 170 171 u16 flags = le16_to_cpu(attr->flags); 171 172 172 173 pi->num_domains = le16_to_cpu(attr->num_domains); 173 - pi->power_scale_mw = POWER_SCALE_IN_MILLIWATT(flags); 174 + 175 + if (POWER_SCALE_IN_MILLIWATT(flags)) 176 + pi->power_scale = SCMI_POWER_MILLIWATTS; 174 177 if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3) 175 - pi->power_scale_uw = POWER_SCALE_IN_MICROWATT(flags); 178 + if (POWER_SCALE_IN_MICROWATT(flags)) 179 + pi->power_scale = SCMI_POWER_MICROWATTS; 180 + 176 181 pi->stats_addr = le32_to_cpu(attr->stats_addr_low) | 177 182 (u64)le32_to_cpu(attr->stats_addr_high) << 32; 178 183 pi->stats_size = le32_to_cpu(attr->stats_size); ··· 678 675 return dom->fc_info && dom->fc_info[PERF_FC_LEVEL].set_addr; 679 676 } 680 677 681 - static bool scmi_power_scale_mw_get(const struct scmi_protocol_handle *ph) 678 + static enum scmi_power_scale 679 + scmi_power_scale_get(const struct scmi_protocol_handle *ph) 682 680 { 683 681 struct scmi_perf_info *pi = ph->get_priv(ph); 684 682 685 - return pi->power_scale_mw; 683 + return pi->power_scale; 686 684 } 687 685 688 686 static const struct scmi_perf_proto_ops perf_proto_ops = { ··· 698 694 .freq_get = scmi_dvfs_freq_get, 699 695 .est_power_get = scmi_dvfs_est_power_get, 700 696 .fast_switch_possible = scmi_fast_switch_possible, 701 - .power_scale_mw_get = scmi_power_scale_mw_get, 697 + .power_scale_get = scmi_power_scale_get, 702 698 }; 703 699 704 700 static int scmi_perf_set_notify_enabled(const struct scmi_protocol_handle *ph,
+1 -23
drivers/idle/intel_idle.c
··· 928 928 .enter = NULL } 929 929 }; 930 930 931 - /* 932 - * On Sapphire Rapids Xeon C1 has to be disabled if C1E is enabled, and vice 933 - * versa. On SPR C1E is enabled only if "C1E promotion" bit is set in 934 - * MSR_IA32_POWER_CTL. But in this case there effectively no C1, because C1 935 - * requests are promoted to C1E. If the "C1E promotion" bit is cleared, then 936 - * both C1 and C1E requests end up with C1, so there is effectively no C1E. 937 - * 938 - * By default we enable C1 and disable C1E by marking it with 939 - * 'CPUIDLE_FLAG_UNUSABLE'. 940 - */ 941 931 static struct cpuidle_state spr_cstates[] __initdata = { 942 932 { 943 933 .name = "C1", ··· 940 950 { 941 951 .name = "C1E", 942 952 .desc = "MWAIT 0x01", 943 - .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE | 944 - CPUIDLE_FLAG_UNUSABLE, 953 + .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE, 945 954 .exit_latency = 2, 946 955 .target_residency = 4, 947 956 .enter = &intel_idle, ··· 1762 1773 static void __init spr_idle_state_table_update(void) 1763 1774 { 1764 1775 unsigned long long msr; 1765 - 1766 - /* Check if user prefers C1E over C1. */ 1767 - if ((preferred_states_mask & BIT(2)) && 1768 - !(preferred_states_mask & BIT(1))) { 1769 - /* Disable C1 and enable C1E. */ 1770 - spr_cstates[0].flags |= CPUIDLE_FLAG_UNUSABLE; 1771 - spr_cstates[1].flags &= ~CPUIDLE_FLAG_UNUSABLE; 1772 - 1773 - /* Enable C1E using the "C1E promotion" bit. */ 1774 - c1e_promotion = C1E_PROMOTION_ENABLE; 1775 - } 1776 1776 1777 1777 /* 1778 1778 * By default, the C6 state assumes the worst-case scenario of package
+8 -7
drivers/opp/of.c
··· 1443 1443 * It provides the power used by @dev at @kHz if it is the frequency of an 1444 1444 * existing OPP, or at the frequency of the first OPP above @kHz otherwise 1445 1445 * (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled 1446 - * frequency and @mW to the associated power. 1446 + * frequency and @uW to the associated power. 1447 1447 * 1448 1448 * Returns 0 on success or a proper -EINVAL value in case of error. 1449 1449 */ 1450 1450 static int __maybe_unused 1451 - _get_dt_power(struct device *dev, unsigned long *mW, unsigned long *kHz) 1451 + _get_dt_power(struct device *dev, unsigned long *uW, unsigned long *kHz) 1452 1452 { 1453 1453 struct dev_pm_opp *opp; 1454 1454 unsigned long opp_freq, opp_power; ··· 1465 1465 return -EINVAL; 1466 1466 1467 1467 *kHz = opp_freq / 1000; 1468 - *mW = opp_power / 1000; 1468 + *uW = opp_power; 1469 1469 1470 1470 return 0; 1471 1471 } ··· 1475 1475 * This computes the power estimated by @dev at @kHz if it is the frequency 1476 1476 * of an existing OPP, or at the frequency of the first OPP above @kHz otherwise 1477 1477 * (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled 1478 - * frequency and @mW to the associated power. The power is estimated as 1478 + * frequency and @uW to the associated power. The power is estimated as 1479 1479 * P = C * V^2 * f with C being the device's capacitance and V and f 1480 1480 * respectively the voltage and frequency of the OPP. 1481 1481 * 1482 1482 * Returns -EINVAL if the power calculation failed because of missing 1483 1483 * parameters, 0 otherwise. 1484 1484 */ 1485 - static int __maybe_unused _get_power(struct device *dev, unsigned long *mW, 1485 + static int __maybe_unused _get_power(struct device *dev, unsigned long *uW, 1486 1486 unsigned long *kHz) 1487 1487 { 1488 1488 struct dev_pm_opp *opp; ··· 1512 1512 return -EINVAL; 1513 1513 1514 1514 tmp = (u64)cap * mV * mV * (Hz / 1000000); 1515 - do_div(tmp, 1000000000); 1515 + /* Provide power in micro-Watts */ 1516 + do_div(tmp, 1000000); 1516 1517 1517 - *mW = (unsigned long)tmp; 1518 + *uW = (unsigned long)tmp; 1518 1519 *kHz = Hz / 1000; 1519 1520 1520 1521 return 0;
+2 -3
drivers/powercap/dtpm_cpu.c
··· 53 53 54 54 for (i = 0; i < pd->nr_perf_states; i++) { 55 55 56 - power = pd->table[i].power * MICROWATT_PER_MILLIWATT * nr_cpus; 56 + power = pd->table[i].power * nr_cpus; 57 57 58 58 if (power > power_limit) 59 59 break; ··· 63 63 64 64 freq_qos_update_request(&dtpm_cpu->qos_req, freq); 65 65 66 - power_limit = pd->table[i - 1].power * 67 - MICROWATT_PER_MILLIWATT * nr_cpus; 66 + power_limit = pd->table[i - 1].power * nr_cpus; 68 67 69 68 return power_limit; 70 69 }
+1
drivers/powercap/intel_rapl_common.c
··· 1109 1109 X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, &rapl_defaults_core), 1110 1110 X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, &rapl_defaults_core), 1111 1111 X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, &rapl_defaults_core), 1112 + X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, &rapl_defaults_core), 1112 1113 X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, &rapl_defaults_spr_server), 1113 1114 X86_MATCH_INTEL_FAM6_MODEL(LAKEFIELD, &rapl_defaults_core), 1114 1115
+2
drivers/powercap/intel_rapl_msr.c
··· 140 140 { X86_VENDOR_INTEL, 6, INTEL_FAM6_TIGERLAKE_L, X86_FEATURE_ANY }, 141 141 { X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE, X86_FEATURE_ANY }, 142 142 { X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE_L, X86_FEATURE_ANY }, 143 + { X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE_N, X86_FEATURE_ANY }, 143 144 { X86_VENDOR_INTEL, 6, INTEL_FAM6_RAPTORLAKE, X86_FEATURE_ANY }, 145 + { X86_VENDOR_INTEL, 6, INTEL_FAM6_RAPTORLAKE_P, X86_FEATURE_ANY }, 144 146 {} 145 147 }; 146 148
+11 -2
drivers/thermal/cpufreq_cooling.c
··· 21 21 #include <linux/pm_qos.h> 22 22 #include <linux/slab.h> 23 23 #include <linux/thermal.h> 24 + #include <linux/units.h> 24 25 25 26 #include <trace/events/thermal.h> 26 27 ··· 102 101 static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_cdev, 103 102 u32 freq) 104 103 { 104 + unsigned long power_mw; 105 105 int i; 106 106 107 107 for (i = cpufreq_cdev->max_level - 1; i >= 0; i--) { ··· 110 108 break; 111 109 } 112 110 113 - return cpufreq_cdev->em->table[i + 1].power; 111 + power_mw = cpufreq_cdev->em->table[i + 1].power; 112 + power_mw /= MICROWATT_PER_MILLIWATT; 113 + 114 + return power_mw; 114 115 } 115 116 116 117 static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev, 117 118 u32 power) 118 119 { 120 + unsigned long em_power_mw; 119 121 int i; 120 122 121 123 for (i = cpufreq_cdev->max_level; i > 0; i--) { 122 - if (power >= cpufreq_cdev->em->table[i].power) 124 + /* Convert EM power to milli-Watts to make safe comparison */ 125 + em_power_mw = cpufreq_cdev->em->table[i].power; 126 + em_power_mw /= MICROWATT_PER_MILLIWATT; 127 + if (power >= em_power_mw) 123 128 break; 124 129 } 125 130
+15 -4
drivers/thermal/devfreq_cooling.c
··· 200 200 res = dfc->power_ops->get_real_power(df, power, freq, voltage); 201 201 if (!res) { 202 202 state = dfc->capped_state; 203 + 204 + /* Convert EM power into milli-Watts first */ 203 205 dfc->res_util = dfc->em_pd->table[state].power; 206 + dfc->res_util /= MICROWATT_PER_MILLIWATT; 207 + 204 208 dfc->res_util *= SCALE_ERROR_MITIGATION; 205 209 206 210 if (*power > 1) ··· 222 218 223 219 _normalize_load(&status); 224 220 225 - /* Scale power for utilization */ 221 + /* Convert EM power into milli-Watts first */ 226 222 *power = dfc->em_pd->table[perf_idx].power; 223 + *power /= MICROWATT_PER_MILLIWATT; 224 + /* Scale power for utilization */ 227 225 *power *= status.busy_time; 228 226 *power >>= 10; 229 227 } ··· 250 244 251 245 perf_idx = dfc->max_state - state; 252 246 *power = dfc->em_pd->table[perf_idx].power; 247 + *power /= MICROWATT_PER_MILLIWATT; 253 248 254 249 return 0; 255 250 } ··· 261 254 struct devfreq_cooling_device *dfc = cdev->devdata; 262 255 struct devfreq *df = dfc->devfreq; 263 256 struct devfreq_dev_status status; 264 - unsigned long freq; 257 + unsigned long freq, em_power_mw; 265 258 s32 est_power; 266 259 int i; 267 260 ··· 286 279 * Find the first cooling state that is within the power 287 280 * budget. The EM power table is sorted ascending. 288 281 */ 289 - for (i = dfc->max_state; i > 0; i--) 290 - if (est_power >= dfc->em_pd->table[i].power) 282 + for (i = dfc->max_state; i > 0; i--) { 283 + /* Convert EM power to milli-Watts to make safe comparison */ 284 + em_power_mw = dfc->em_pd->table[i].power; 285 + em_power_mw /= MICROWATT_PER_MILLIWATT; 286 + if (est_power >= em_power_mw) 291 287 break; 288 + } 292 289 293 290 *state = dfc->max_state - i; 294 291 dfc->capped_state = *state;
+39 -17
include/linux/energy_model.h
··· 62 62 /* 63 63 * em_perf_domain flags: 64 64 * 65 - * EM_PERF_DOMAIN_MILLIWATTS: The power values are in milli-Watts or some 65 + * EM_PERF_DOMAIN_MICROWATTS: The power values are in micro-Watts or some 66 66 * other scale. 67 67 * 68 68 * EM_PERF_DOMAIN_SKIP_INEFFICIENCIES: Skip inefficient states when estimating ··· 71 71 * EM_PERF_DOMAIN_ARTIFICIAL: The power values are artificial and might be 72 72 * created by platform missing real power information 73 73 */ 74 - #define EM_PERF_DOMAIN_MILLIWATTS BIT(0) 74 + #define EM_PERF_DOMAIN_MICROWATTS BIT(0) 75 75 #define EM_PERF_DOMAIN_SKIP_INEFFICIENCIES BIT(1) 76 76 #define EM_PERF_DOMAIN_ARTIFICIAL BIT(2) 77 77 ··· 79 79 #define em_is_artificial(em) ((em)->flags & EM_PERF_DOMAIN_ARTIFICIAL) 80 80 81 81 #ifdef CONFIG_ENERGY_MODEL 82 - #define EM_MAX_POWER 0xFFFF 82 + /* 83 + * The max power value in micro-Watts. The limit of 64 Watts is set as 84 + * a safety net to not overflow multiplications on 32bit platforms. The 85 + * 32bit value limit for total Perf Domain power implies a limit of 86 + * maximum CPUs in such domain to 64. 87 + */ 88 + #define EM_MAX_POWER (64000000) /* 64 Watts */ 83 89 84 90 /* 85 - * Increase resolution of energy estimation calculations for 64-bit 86 - * architectures. The extra resolution improves decision made by EAS for the 87 - * task placement when two Performance Domains might provide similar energy 88 - * estimation values (w/o better resolution the values could be equal). 89 - * 90 - * We increase resolution only if we have enough bits to allow this increased 91 - * resolution (i.e. 64-bit). The costs for increasing resolution when 32-bit 92 - * are pretty high and the returns do not justify the increased costs. 91 + * To avoid possible energy estimation overflow on 32bit machines add 92 + * limits to number of CPUs in the Perf. Domain. 93 + * We are safe on 64bit machine, thus some big number. 93 94 */ 94 95 #ifdef CONFIG_64BIT 95 - #define em_scale_power(p) ((p) * 1000) 96 + #define EM_MAX_NUM_CPUS 4096 96 97 #else 97 - #define em_scale_power(p) (p) 98 + #define EM_MAX_NUM_CPUS 16 99 + #endif 100 + 101 + /* 102 + * To avoid an overflow on 32bit machines while calculating the energy 103 + * use a different order in the operation. First divide by the 'cpu_scale' 104 + * which would reduce big value stored in the 'cost' field, then multiply by 105 + * the 'sum_util'. This would allow to handle existing platforms, which have 106 + * e.g. power ~1.3 Watt at max freq, so the 'cost' value > 1mln micro-Watts. 107 + * In such scenario, where there are 4 CPUs in the Perf. Domain the 'sum_util' 108 + * could be 4096, then multiplication: 'cost' * 'sum_util' would overflow. 109 + * This reordering of operations has some limitations, we lose small 110 + * precision in the estimation (comparing to 64bit platform w/o reordering). 111 + * 112 + * We are safe on 64bit machine. 113 + */ 114 + #ifdef CONFIG_64BIT 115 + #define em_estimate_energy(cost, sum_util, scale_cpu) \ 116 + (((cost) * (sum_util)) / (scale_cpu)) 117 + #else 118 + #define em_estimate_energy(cost, sum_util, scale_cpu) \ 119 + (((cost) / (scale_cpu)) * (sum_util)) 98 120 #endif 99 121 100 122 struct em_data_callback { ··· 134 112 * and frequency. 135 113 * 136 114 * In case of CPUs, the power is the one of a single CPU in the domain, 137 - * expressed in milli-Watts or an abstract scale. It is expected to 115 + * expressed in micro-Watts or an abstract scale. It is expected to 138 116 * fit in the [0, EM_MAX_POWER] range. 139 117 * 140 118 * Return 0 on success. ··· 170 148 struct em_perf_domain *em_pd_get(struct device *dev); 171 149 int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, 172 150 struct em_data_callback *cb, cpumask_t *span, 173 - bool milliwatts); 151 + bool microwatts); 174 152 void em_dev_unregister_perf_domain(struct device *dev); 175 153 176 154 /** ··· 295 273 * pd_nrg = ------------------------ (4) 296 274 * scale_cpu 297 275 */ 298 - return ps->cost * sum_util / scale_cpu; 276 + return em_estimate_energy(ps->cost, sum_util, scale_cpu); 299 277 } 300 278 301 279 /** ··· 319 297 static inline 320 298 int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, 321 299 struct em_data_callback *cb, cpumask_t *span, 322 - bool milliwatts) 300 + bool microwatts) 323 301 { 324 302 return -EINVAL; 325 303 }
+23 -8
include/linux/pm_wakeup.h
··· 109 109 extern int device_wakeup_enable(struct device *dev); 110 110 extern int device_wakeup_disable(struct device *dev); 111 111 extern void device_set_wakeup_capable(struct device *dev, bool capable); 112 - extern int device_init_wakeup(struct device *dev, bool val); 113 112 extern int device_set_wakeup_enable(struct device *dev, bool enable); 114 113 extern void __pm_stay_awake(struct wakeup_source *ws); 115 114 extern void pm_stay_awake(struct device *dev); ··· 166 167 return 0; 167 168 } 168 169 169 - static inline int device_init_wakeup(struct device *dev, bool val) 170 - { 171 - device_set_wakeup_capable(dev, val); 172 - device_set_wakeup_enable(dev, val); 173 - return 0; 174 - } 175 - 176 170 static inline bool device_may_wakeup(struct device *dev) 177 171 { 178 172 return dev->power.can_wakeup && dev->power.should_wakeup; ··· 207 215 static inline void pm_wakeup_hard_event(struct device *dev) 208 216 { 209 217 return pm_wakeup_dev_event(dev, 0, true); 218 + } 219 + 220 + /** 221 + * device_init_wakeup - Device wakeup initialization. 222 + * @dev: Device to handle. 223 + * @enable: Whether or not to enable @dev as a wakeup device. 224 + * 225 + * By default, most devices should leave wakeup disabled. The exceptions are 226 + * devices that everyone expects to be wakeup sources: keyboards, power buttons, 227 + * possibly network interfaces, etc. Also, devices that don't generate their 228 + * own wakeup requests but merely forward requests from one bus to another 229 + * (like PCI bridges) should have wakeup enabled by default. 230 + */ 231 + static inline int device_init_wakeup(struct device *dev, bool enable) 232 + { 233 + if (enable) { 234 + device_set_wakeup_capable(dev, true); 235 + return device_wakeup_enable(dev); 236 + } else { 237 + device_wakeup_disable(dev); 238 + device_set_wakeup_capable(dev, false); 239 + return 0; 240 + } 210 241 } 211 242 212 243 #endif /* _LINUX_PM_WAKEUP_H */
+7 -1
include/linux/scmi_protocol.h
··· 60 60 }; 61 61 }; 62 62 63 + enum scmi_power_scale { 64 + SCMI_POWER_BOGOWATTS, 65 + SCMI_POWER_MILLIWATTS, 66 + SCMI_POWER_MICROWATTS 67 + }; 68 + 63 69 struct scmi_handle; 64 70 struct scmi_device; 65 71 struct scmi_protocol_handle; ··· 141 135 unsigned long *rate, unsigned long *power); 142 136 bool (*fast_switch_possible)(const struct scmi_protocol_handle *ph, 143 137 struct device *dev); 144 - bool (*power_scale_mw_get)(const struct scmi_protocol_handle *ph); 138 + enum scmi_power_scale (*power_scale_get)(const struct scmi_protocol_handle *ph); 145 139 }; 146 140 147 141 /**
+29
include/trace/events/power.h
··· 500 500 501 501 TP_ARGS(name, type, new_value) 502 502 ); 503 + 504 + TRACE_EVENT(guest_halt_poll_ns, 505 + 506 + TP_PROTO(bool grow, unsigned int new, unsigned int old), 507 + 508 + TP_ARGS(grow, new, old), 509 + 510 + TP_STRUCT__entry( 511 + __field(bool, grow) 512 + __field(unsigned int, new) 513 + __field(unsigned int, old) 514 + ), 515 + 516 + TP_fast_assign( 517 + __entry->grow = grow; 518 + __entry->new = new; 519 + __entry->old = old; 520 + ), 521 + 522 + TP_printk("halt_poll_ns %u (%s %u)", 523 + __entry->new, 524 + __entry->grow ? "grow" : "shrink", 525 + __entry->old) 526 + ); 527 + 528 + #define trace_guest_halt_poll_ns_grow(new, old) \ 529 + trace_guest_halt_poll_ns(true, new, old) 530 + #define trace_guest_halt_poll_ns_shrink(new, old) \ 531 + trace_guest_halt_poll_ns(false, new, old) 503 532 #endif /* _TRACE_POWER_H */ 504 533 505 534 /* This part must be outside protection */
+16 -8
kernel/power/energy_model.c
··· 145 145 146 146 /* 147 147 * The power returned by active_state() is expected to be 148 - * positive and to fit into 16 bits. 148 + * positive and be in range. 149 149 */ 150 150 if (!power || power > EM_MAX_POWER) { 151 151 dev_err(dev, "EM: invalid power: %lu\n", ··· 170 170 goto free_ps_table; 171 171 } 172 172 } else { 173 - power_res = em_scale_power(table[i].power); 173 + power_res = table[i].power; 174 174 cost = div64_u64(fmax * power_res, table[i].frequency); 175 175 } 176 176 ··· 201 201 { 202 202 struct em_perf_domain *pd; 203 203 struct device *cpu_dev; 204 - int cpu, ret; 204 + int cpu, ret, num_cpus; 205 205 206 206 if (_is_cpu_device(dev)) { 207 + num_cpus = cpumask_weight(cpus); 208 + 209 + /* Prevent max possible energy calculation to not overflow */ 210 + if (num_cpus > EM_MAX_NUM_CPUS) { 211 + dev_err(dev, "EM: too many CPUs, overflow possible\n"); 212 + return -EINVAL; 213 + } 214 + 207 215 pd = kzalloc(sizeof(*pd) + cpumask_size(), GFP_KERNEL); 208 216 if (!pd) 209 217 return -ENOMEM; ··· 322 314 * @cpus : Pointer to cpumask_t, which in case of a CPU device is 323 315 * obligatory. It can be taken from i.e. 'policy->cpus'. For other 324 316 * type of devices this should be set to NULL. 325 - * @milliwatts : Flag indicating that the power values are in milliWatts or 317 + * @microwatts : Flag indicating that the power values are in micro-Watts or 326 318 * in some other scale. It must be set properly. 327 319 * 328 320 * Create Energy Model tables for a performance domain using the callbacks 329 321 * defined in cb. 330 322 * 331 - * The @milliwatts is important to set with correct value. Some kernel 323 + * The @microwatts is important to set with correct value. Some kernel 332 324 * sub-systems might rely on this flag and check if all devices in the EM are 333 325 * using the same scale. 334 326 * ··· 339 331 */ 340 332 int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, 341 333 struct em_data_callback *cb, cpumask_t *cpus, 342 - bool milliwatts) 334 + bool microwatts) 343 335 { 344 336 unsigned long cap, prev_cap = 0; 345 337 unsigned long flags = 0; ··· 389 381 } 390 382 } 391 383 392 - if (milliwatts) 393 - flags |= EM_PERF_DOMAIN_MILLIWATTS; 384 + if (microwatts) 385 + flags |= EM_PERF_DOMAIN_MICROWATTS; 394 386 else if (cb->get_cost) 395 387 flags |= EM_PERF_DOMAIN_ARTIFICIAL; 396 388
+2 -2
kernel/power/qos.c
··· 531 531 { 532 532 int ret; 533 533 534 - if (IS_ERR_OR_NULL(qos) || !req) 534 + if (IS_ERR_OR_NULL(qos) || !req || value < 0) 535 535 return -EINVAL; 536 536 537 537 if (WARN(freq_qos_request_active(req), ··· 563 563 */ 564 564 int freq_qos_update_request(struct freq_qos_request *req, s32 new_value) 565 565 { 566 - if (!req) 566 + if (!req || new_value < 0) 567 567 return -EINVAL; 568 568 569 569 if (WARN(!freq_qos_request_active(req),
+12 -1
kernel/power/user.c
··· 26 26 27 27 #include "power.h" 28 28 29 + static bool need_wait; 29 30 30 31 static struct snapshot_data { 31 32 struct snapshot_handle handle; ··· 79 78 * Resuming. We may need to wait for the image device to 80 79 * appear. 81 80 */ 82 - wait_for_device_probe(); 81 + need_wait = true; 83 82 84 83 data->swap = -1; 85 84 data->mode = O_WRONLY; ··· 169 168 ssize_t res; 170 169 loff_t pg_offp = *offp & ~PAGE_MASK; 171 170 171 + if (need_wait) { 172 + wait_for_device_probe(); 173 + need_wait = false; 174 + } 175 + 172 176 lock_system_sleep(); 173 177 174 178 data = filp->private_data; ··· 249 243 struct snapshot_data *data; 250 244 loff_t size; 251 245 sector_t offset; 246 + 247 + if (need_wait) { 248 + wait_for_device_probe(); 249 + need_wait = false; 250 + } 252 251 253 252 if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC) 254 253 return -ENOTTY;
+3 -3
tools/power/pm-graph/README
··· 6 6 |_| |___/ |_| 7 7 8 8 pm-graph: suspend/resume/boot timing analysis tools 9 - Version: 5.8 9 + Version: 5.9 10 10 Author: Todd Brandt <todd.e.brandt@intel.com> 11 11 Home Page: https://01.org/pm-graph 12 12 ··· 97 97 (kernel/pre-3.15/enable_trace_events_suspend_resume.patch) 98 98 (kernel/pre-3.15/enable_trace_events_device_pm_callback.patch) 99 99 100 - If you're using a kernel older than 3.15.0, the following 101 - additional kernel parameters are required: 100 + If you're using bootgraph, or sleepgraph with a kernel older than 3.15.0, 101 + the following additional kernel parameters are required: 102 102 (e.g. in file /etc/default/grub) 103 103 GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=32M ..." 104 104
+11 -9
tools/power/pm-graph/bootgraph.py
··· 69 69 bootloader = 'grub' 70 70 blexec = [] 71 71 def __init__(self): 72 - self.hostname = platform.node() 72 + self.kernel, self.hostname = 'unknown', platform.node() 73 73 self.testtime = datetime.now().strftime('%Y-%m-%d_%H:%M:%S') 74 74 if os.path.exists('/proc/version'): 75 75 fp = open('/proc/version', 'r') 76 - val = fp.read().strip() 76 + self.kernel = self.kernelVersion(fp.read().strip()) 77 77 fp.close() 78 - self.kernel = self.kernelVersion(val) 79 - else: 80 - self.kernel = 'unknown' 81 78 self.testdir = datetime.now().strftime('boot-%y%m%d-%H%M%S') 82 79 def kernelVersion(self, msg): 83 - return msg.split()[2] 80 + m = re.match('^[Ll]inux *[Vv]ersion *(?P<v>\S*) .*', msg) 81 + if m: 82 + return m.group('v') 83 + return 'unknown' 84 84 def checkFtraceKernelVersion(self): 85 - val = tuple(map(int, self.kernel.split('-')[0].split('.'))) 86 - if val >= (4, 10, 0): 87 - return True 85 + m = re.match('^(?P<x>[0-9]*)\.(?P<y>[0-9]*)\.(?P<z>[0-9]*).*', self.kernel) 86 + if m: 87 + val = tuple(map(int, m.groups())) 88 + if val >= (4, 10, 0): 89 + return True 88 90 return False 89 91 def kernelParams(self): 90 92 cmdline = 'initcall_debug log_buf_len=32M'
+1 -1
tools/power/pm-graph/config/custom-timeline-functions.cfg
··· 125 125 suspend_console: 126 126 acpi_pm_prepare: 127 127 syscore_suspend: 128 - arch_thaw_secondary_cpus_end: 128 + arch_enable_nonboot_cpus_end: 129 129 syscore_resume: 130 130 acpi_pm_finish: 131 131 resume_console:
+345 -173
tools/power/pm-graph/sleepgraph.py
··· 66 66 from subprocess import call, Popen, PIPE 67 67 import base64 68 68 69 + debugtiming = False 70 + mystarttime = time.time() 69 71 def pprint(msg): 70 - print(msg) 72 + if debugtiming: 73 + print('[%09.3f] %s' % (time.time()-mystarttime, msg)) 74 + else: 75 + print(msg) 71 76 sys.stdout.flush() 72 77 73 78 def ascii(text): ··· 86 81 # store system values and test parameters 87 82 class SystemValues: 88 83 title = 'SleepGraph' 89 - version = '5.8' 84 + version = '5.9' 90 85 ansi = False 91 86 rs = 0 92 87 display = '' 93 88 gzip = False 94 89 sync = False 95 90 wifi = False 91 + netfix = False 96 92 verbose = False 97 93 testlog = True 98 94 dmesglog = True ··· 114 108 cpucount = 0 115 109 memtotal = 204800 116 110 memfree = 204800 111 + osversion = '' 117 112 srgap = 0 118 113 cgexp = False 119 114 testdir = '' ··· 123 116 fpdtpath = '/sys/firmware/acpi/tables/FPDT' 124 117 epath = '/sys/kernel/debug/tracing/events/power/' 125 118 pmdpath = '/sys/power/pm_debug_messages' 119 + s0ixpath = '/sys/module/intel_pmc_core/parameters/warn_on_s0ix_failures' 126 120 acpipath='/sys/module/acpi/parameters/debug_level' 127 121 traceevents = [ 128 122 'suspend_resume', ··· 164 156 ftop = False 165 157 usetraceevents = False 166 158 usetracemarkers = True 159 + useftrace = True 167 160 usekprobes = True 168 161 usedevsrc = False 169 162 useprocmon = False ··· 288 279 'intel_fbdev_set_suspend': {}, 289 280 } 290 281 infocmds = [ 282 + [0, 'sysinfo', 'uname', '-a'], 283 + [0, 'cpuinfo', 'head', '-7', '/proc/cpuinfo'], 291 284 [0, 'kparams', 'cat', '/proc/cmdline'], 292 285 [0, 'mcelog', 'mcelog'], 293 286 [0, 'pcidevices', 'lspci', '-tv'], 294 - [0, 'usbdevices', 'lsusb', '-t'], 287 + [0, 'usbdevices', 'lsusb', '-tv'], 288 + [0, 'acpidevices', 'sh', '-c', 'ls -l /sys/bus/acpi/devices/*/physical_node'], 289 + [0, 's0ix_require', 'cat', '/sys/kernel/debug/pmc_core/substate_requirements'], 290 + [0, 's0ix_debug', 'cat', '/sys/kernel/debug/pmc_core/slp_s0_debug_status'], 291 + [1, 's0ix_residency', 'cat', '/sys/kernel/debug/pmc_core/slp_s0_residency_usec'], 295 292 [1, 'interrupts', 'cat', '/proc/interrupts'], 296 293 [1, 'wakeups', 'cat', '/sys/kernel/debug/wakeup_sources'], 297 294 [2, 'gpecounts', 'sh', '-c', 'grep -v invalid /sys/firmware/acpi/interrupts/*'], ··· 373 358 self.outputResult({'error':msg}) 374 359 sys.exit(1) 375 360 return False 376 - def usable(self, file): 377 - return (os.path.exists(file) and os.path.getsize(file) > 0) 361 + def usable(self, file, ishtml=False): 362 + if not os.path.exists(file) or os.path.getsize(file) < 1: 363 + return False 364 + if ishtml: 365 + try: 366 + fp = open(file, 'r') 367 + res = fp.read(1000) 368 + fp.close() 369 + except: 370 + return False 371 + if '<html>' not in res: 372 + return False 373 + return True 378 374 def getExec(self, cmd): 379 375 try: 380 376 fp = Popen(['which', cmd], stdout=PIPE, stderr=PIPE).stdout ··· 439 413 r = info['bios-release-date'] if 'bios-release-date' in info else '' 440 414 self.sysstamp = '# sysinfo | man:%s | plat:%s | cpu:%s | bios:%s | biosdate:%s | numcpu:%d | memsz:%d | memfr:%d' % \ 441 415 (m, p, c, b, r, self.cpucount, self.memtotal, self.memfree) 416 + if self.osversion: 417 + self.sysstamp += ' | os:%s' % self.osversion 442 418 def printSystemInfo(self, fatal=False): 443 419 self.rootCheck(True) 444 420 out = dmidecode(self.mempath, fatal) 445 421 if len(out) < 1: 446 422 return 447 423 fmt = '%-24s: %s' 424 + if self.osversion: 425 + print(fmt % ('os-version', self.osversion)) 448 426 for name in sorted(out): 449 427 print(fmt % (name, out[name])) 450 428 print(fmt % ('cpucount', ('%d' % self.cpucount))) ··· 456 426 print(fmt % ('memfree', ('%d kB' % self.memfree))) 457 427 def cpuInfo(self): 458 428 self.cpucount = 0 459 - fp = open('/proc/cpuinfo', 'r') 460 - for line in fp: 461 - if re.match('^processor[ \t]*:[ \t]*[0-9]*', line): 462 - self.cpucount += 1 463 - fp.close() 464 - fp = open('/proc/meminfo', 'r') 465 - for line in fp: 466 - m = re.match('^MemTotal:[ \t]*(?P<sz>[0-9]*) *kB', line) 467 - if m: 468 - self.memtotal = int(m.group('sz')) 469 - m = re.match('^MemFree:[ \t]*(?P<sz>[0-9]*) *kB', line) 470 - if m: 471 - self.memfree = int(m.group('sz')) 472 - fp.close() 429 + if os.path.exists('/proc/cpuinfo'): 430 + with open('/proc/cpuinfo', 'r') as fp: 431 + for line in fp: 432 + if re.match('^processor[ \t]*:[ \t]*[0-9]*', line): 433 + self.cpucount += 1 434 + if os.path.exists('/proc/meminfo'): 435 + with open('/proc/meminfo', 'r') as fp: 436 + for line in fp: 437 + m = re.match('^MemTotal:[ \t]*(?P<sz>[0-9]*) *kB', line) 438 + if m: 439 + self.memtotal = int(m.group('sz')) 440 + m = re.match('^MemFree:[ \t]*(?P<sz>[0-9]*) *kB', line) 441 + if m: 442 + self.memfree = int(m.group('sz')) 443 + if os.path.exists('/etc/os-release'): 444 + with open('/etc/os-release', 'r') as fp: 445 + for line in fp: 446 + if line.startswith('PRETTY_NAME='): 447 + self.osversion = line[12:].strip().replace('"', '') 473 448 def initTestOutput(self, name): 474 449 self.prefix = self.hostname 475 450 v = open('/proc/version', 'r').read().strip() ··· 733 698 return False 734 699 return True 735 700 def fsetVal(self, val, path): 701 + if not self.useftrace: 702 + return False 736 703 return self.setVal(val, self.tpath+path) 737 704 def getVal(self, file): 738 705 res = '' ··· 748 711 pass 749 712 return res 750 713 def fgetVal(self, path): 714 + if not self.useftrace: 715 + return '' 751 716 return self.getVal(self.tpath+path) 752 717 def cleanupFtrace(self): 753 - if(self.usecallgraph or self.usetraceevents or self.usedevsrc): 718 + if self.useftrace: 754 719 self.fsetVal('0', 'events/kprobes/enable') 755 720 self.fsetVal('', 'kprobe_events') 756 721 self.fsetVal('1024', 'buffer_size_kb') ··· 773 734 return True 774 735 return False 775 736 def initFtrace(self, quiet=False): 737 + if not self.useftrace: 738 + return 776 739 if not quiet: 777 740 sysvals.printSystemInfo(False) 778 741 pprint('INITIALIZING FTRACE...') 779 742 # turn trace off 780 743 self.fsetVal('0', 'tracing_on') 781 744 self.cleanupFtrace() 782 - self.testVal(self.pmdpath, 'basic', '1') 783 745 # set the trace clock to global 784 746 self.fsetVal('global', 'trace_clock') 785 747 self.fsetVal('nop', 'current_tracer') ··· 806 766 # set trace type 807 767 self.fsetVal('function_graph', 'current_tracer') 808 768 self.fsetVal('', 'set_ftrace_filter') 769 + # temporary hack to fix https://bugzilla.kernel.org/show_bug.cgi?id=212761 770 + fp = open(self.tpath+'set_ftrace_notrace', 'w') 771 + fp.write('native_queued_spin_lock_slowpath\ndev_driver_string') 772 + fp.close() 809 773 # set trace format options 810 774 self.fsetVal('print-parent', 'trace_options') 811 775 self.fsetVal('funcgraph-abstime', 'trace_options') ··· 890 846 fp.write('# turbostat %s\n' % test['turbo']) 891 847 if 'wifi' in test: 892 848 fp.write('# wifi %s\n' % test['wifi']) 849 + if 'netfix' in test: 850 + fp.write('# netfix %s\n' % test['netfix']) 893 851 if test['error'] or len(testdata) > 1: 894 852 fp.write('# enter_sleep_error %s\n' % test['error']) 895 853 return fp ··· 911 865 fp.write('error%s: %s\n' % (n, testdata['error'])) 912 866 else: 913 867 fp.write('result%s: pass\n' % n) 868 + if 'mode' in testdata: 869 + fp.write('mode%s: %s\n' % (n, testdata['mode'])) 914 870 for v in ['suspend', 'resume', 'boot', 'lastinit']: 915 871 if v in testdata: 916 872 fp.write('%s%s: %.3f\n' % (v, n, testdata[v])) ··· 949 901 fp.write(text) 950 902 fp.close() 951 903 def dlog(self, text): 904 + if not self.dmesgfile: 905 + return 952 906 self.putlog(self.dmesgfile, '# %s\n' % text) 953 907 def flog(self, text): 954 908 self.putlog(self.ftracefile, text) ··· 1004 954 dirname = props[dev].syspath 1005 955 if not dirname or not os.path.exists(dirname): 1006 956 continue 1007 - with open(dirname+'/power/async') as fp: 1008 - text = fp.read() 1009 - props[dev].isasync = False 1010 - if 'enabled' in text: 957 + props[dev].isasync = False 958 + if os.path.exists(dirname+'/power/async'): 959 + fp = open(dirname+'/power/async') 960 + if 'enabled' in fp.read(): 1011 961 props[dev].isasync = True 962 + fp.close() 1012 963 fields = os.listdir(dirname) 1013 - if 'product' in fields: 1014 - with open(dirname+'/product', 'rb') as fp: 1015 - props[dev].altname = ascii(fp.read()) 1016 - elif 'name' in fields: 1017 - with open(dirname+'/name', 'rb') as fp: 1018 - props[dev].altname = ascii(fp.read()) 1019 - elif 'model' in fields: 1020 - with open(dirname+'/model', 'rb') as fp: 1021 - props[dev].altname = ascii(fp.read()) 1022 - elif 'description' in fields: 1023 - with open(dirname+'/description', 'rb') as fp: 1024 - props[dev].altname = ascii(fp.read()) 1025 - elif 'id' in fields: 1026 - with open(dirname+'/id', 'rb') as fp: 1027 - props[dev].altname = ascii(fp.read()) 1028 - elif 'idVendor' in fields and 'idProduct' in fields: 1029 - idv, idp = '', '' 1030 - with open(dirname+'/idVendor', 'rb') as fp: 1031 - idv = ascii(fp.read()).strip() 1032 - with open(dirname+'/idProduct', 'rb') as fp: 1033 - idp = ascii(fp.read()).strip() 1034 - props[dev].altname = '%s:%s' % (idv, idp) 964 + for file in ['product', 'name', 'model', 'description', 'id', 'idVendor']: 965 + if file not in fields: 966 + continue 967 + try: 968 + with open(os.path.join(dirname, file), 'rb') as fp: 969 + props[dev].altname = ascii(fp.read()) 970 + except: 971 + continue 972 + if file == 'idVendor': 973 + idv, idp = props[dev].altname.strip(), '' 974 + try: 975 + with open(os.path.join(dirname, 'idProduct'), 'rb') as fp: 976 + idp = ascii(fp.read()).strip() 977 + except: 978 + props[dev].altname = '' 979 + break 980 + props[dev].altname = '%s:%s' % (idv, idp) 981 + break 1035 982 if props[dev].altname: 1036 983 out = props[dev].altname.strip().replace('\n', ' ')\ 1037 984 .replace(',', ' ').replace(';', ' ') ··· 1094 1047 self.cmd1[name] = self.dictify(info, delta) 1095 1048 elif not debug and delta and name in self.cmd1: 1096 1049 before, after = self.cmd1[name], self.dictify(info, delta) 1097 - dinfo = ('\t%s\n' % before['@']) if '@' in before else '' 1050 + dinfo = ('\t%s\n' % before['@']) if '@' in before and len(before) > 1 else '' 1098 1051 prefix = self.commonPrefix(list(before.keys())) 1099 1052 for key in sorted(before): 1100 1053 if key in after and before[key] != after[key]: ··· 1175 1128 val = valline[idx] 1176 1129 out.append('%s=%s' % (key, val)) 1177 1130 return '|'.join(out) 1131 + def netfixon(self, net='both'): 1132 + cmd = self.getExec('netfix') 1133 + if not cmd: 1134 + return '' 1135 + fp = Popen([cmd, '-s', net, 'on'], stdout=PIPE, stderr=PIPE).stdout 1136 + out = ascii(fp.read()).strip() 1137 + fp.close() 1138 + return out 1139 + def wifiRepair(self): 1140 + out = self.netfixon('wifi') 1141 + if not out or 'error' in out.lower(): 1142 + return '' 1143 + m = re.match('WIFI \S* ONLINE (?P<action>\S*)', out) 1144 + if not m: 1145 + return 'dead' 1146 + return m.group('action') 1178 1147 def wifiDetails(self, dev): 1179 1148 try: 1180 1149 info = open('/sys/class/net/%s/device/uevent' % dev, 'r').read().strip() ··· 1207 1144 except: 1208 1145 return '' 1209 1146 for line in reversed(w.split('\n')): 1210 - m = re.match(' *(?P<dev>.*): (?P<stat>[0-9a-f]*) .*', w.split('\n')[-1]) 1147 + m = re.match(' *(?P<dev>.*): (?P<stat>[0-9a-f]*) .*', line) 1211 1148 if not m or (dev and dev != m.group('dev')): 1212 1149 continue 1213 1150 return m.group('dev') 1214 1151 return '' 1215 - def pollWifi(self, dev, timeout=60): 1152 + def pollWifi(self, dev, timeout=10): 1216 1153 start = time.time() 1217 1154 while (time.time() - start) < timeout: 1218 1155 w = self.checkWifi(dev) ··· 1220 1157 return '%s reconnected %.2f' % \ 1221 1158 (self.wifiDetails(dev), max(0, time.time() - start)) 1222 1159 time.sleep(0.01) 1160 + if self.netfix: 1161 + res = self.wifiRepair() 1162 + if res: 1163 + timeout = max(0, time.time() - start) 1164 + return '%s %s %d' % (self.wifiDetails(dev), res, timeout) 1223 1165 return '%s timeout %d' % (self.wifiDetails(dev), timeout) 1224 1166 def errorSummary(self, errinfo, msg): 1225 1167 found = False ··· 1351 1283 switchvalues = ['enable', 'disable', 'on', 'off', 'true', 'false', '1', '0'] 1352 1284 switchoff = ['disable', 'off', 'false', '0'] 1353 1285 suspendmodename = { 1354 - 'freeze': 'Freeze (S0)', 1355 - 'standby': 'Standby (S1)', 1356 - 'mem': 'Suspend (S3)', 1357 - 'disk': 'Hibernate (S4)' 1286 + 'standby': 'standby (S1)', 1287 + 'freeze': 'freeze (S2idle)', 1288 + 'mem': 'suspend (S3)', 1289 + 'disk': 'hibernate (S4)' 1358 1290 } 1359 1291 1360 1292 # Class: DevProps ··· 1444 1376 'INVALID' : r'(?i).*\bINVALID\b.*', 1445 1377 'CRASH' : r'(?i).*\bCRASHED\b.*', 1446 1378 'TIMEOUT' : r'(?i).*\bTIMEOUT\b.*', 1379 + 'ABORT' : r'(?i).*\bABORT\b.*', 1447 1380 'IRQ' : r'.*\bgenirq: .*', 1448 1381 'TASKFAIL': r'.*Freezing of tasks *.*', 1449 1382 'ACPI' : r'.*\bACPI *(?P<b>[A-Za-z]*) *Error[: ].*', ··· 1793 1724 if 'waking' in self.dmesg[lp]: 1794 1725 tCnt = self.dmesg[lp]['waking'][0] 1795 1726 if self.dmesg[lp]['waking'][1] >= 0.001: 1796 - tTry = '-%.0f' % (round(self.dmesg[lp]['waking'][1] * 1000)) 1727 + tTry = '%.0f' % (round(self.dmesg[lp]['waking'][1] * 1000)) 1797 1728 else: 1798 - tTry = '-%.3f' % (self.dmesg[lp]['waking'][1] * 1000) 1729 + tTry = '%.3f' % (self.dmesg[lp]['waking'][1] * 1000) 1799 1730 text = '%.0f (%s ms waking %d times)' % (tL * 1000, tTry, tCnt) 1800 1731 else: 1801 1732 text = '%.0f' % (tL * 1000) ··· 2176 2107 # set resume complete to end at end marker 2177 2108 if 'resume_complete' in dm: 2178 2109 dm['resume_complete']['end'] = time 2110 + def initcall_debug_call(self, line, quick=False): 2111 + m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: '+\ 2112 + 'PM: *calling .* @ (?P<n>.*), parent: (?P<p>.*)', line) 2113 + if not m: 2114 + m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: '+\ 2115 + 'calling .* @ (?P<n>.*), parent: (?P<p>.*)', line) 2116 + if not m: 2117 + m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) calling '+\ 2118 + '(?P<f>.*)\+ @ (?P<n>.*), parent: (?P<p>.*)', line) 2119 + if m: 2120 + return True if quick else m.group('t', 'f', 'n', 'p') 2121 + return False if quick else ('', '', '', '') 2122 + def initcall_debug_return(self, line, quick=False): 2123 + m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: PM: '+\ 2124 + '.* returned (?P<r>[0-9]*) after (?P<dt>[0-9]*) usecs', line) 2125 + if not m: 2126 + m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) .* (?P<f>.*)\: '+\ 2127 + '.* returned (?P<r>[0-9]*) after (?P<dt>[0-9]*) usecs', line) 2128 + if not m: 2129 + m = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) call '+\ 2130 + '(?P<f>.*)\+ returned .* after (?P<dt>.*) usecs', line) 2131 + if m: 2132 + return True if quick else m.group('t', 'f', 'dt') 2133 + return False if quick else ('', '', '') 2179 2134 def debugPrint(self): 2180 2135 for p in self.sortedPhases(): 2181 2136 list = self.dmesg[p]['list'] ··· 2973 2880 cmdlinefmt = '^# command \| (?P<cmd>.*)' 2974 2881 kparamsfmt = '^# kparams \| (?P<kp>.*)' 2975 2882 devpropfmt = '# Device Properties: .*' 2976 - pinfofmt = '# platform-(?P<val>[a-z,A-Z,0-9]*): (?P<info>.*)' 2883 + pinfofmt = '# platform-(?P<val>[a-z,A-Z,0-9,_]*): (?P<info>.*)' 2977 2884 tracertypefmt = '# tracer: (?P<t>.*)' 2978 2885 firmwarefmt = '# fwsuspend (?P<s>[0-9]*) fwresume (?P<r>[0-9]*)$' 2979 2886 procexecfmt = 'ps - (?P<ps>.*)$' 2887 + procmultifmt = '@(?P<n>[0-9]*)\|(?P<ps>.*)$' 2980 2888 ftrace_line_fmt_fg = \ 2981 2889 '^ *(?P<time>[0-9\.]*) *\| *(?P<cpu>[0-9]*)\)'+\ 2982 2890 ' *(?P<proc>.*)-(?P<pid>[0-9]*) *\|'+\ ··· 2987 2893 '(?P<flags>\S*) *(?P<time>[0-9\.]*): *'+\ 2988 2894 '(?P<msg>.*)' 2989 2895 machinesuspend = 'machine_suspend\[.*' 2896 + multiproclist = dict() 2897 + multiproctime = 0.0 2898 + multiproccnt = 0 2990 2899 def __init__(self): 2991 2900 self.stamp = '' 2992 2901 self.sysinfo = '' ··· 3160 3063 self.ttemp = dict() 3161 3064 3162 3065 class ProcessMonitor: 3066 + maxchars = 512 3163 3067 def __init__(self): 3164 3068 self.proclist = dict() 3165 3069 self.running = False ··· 3186 3088 if ujiff > 0 or kjiff > 0: 3187 3089 running[pid] = ujiff + kjiff 3188 3090 process.wait() 3189 - out = '' 3091 + out = [''] 3190 3092 for pid in running: 3191 3093 jiffies = running[pid] 3192 3094 val = self.proclist[pid] 3193 - if out: 3194 - out += ',' 3195 - out += '%s-%s %d' % (val['name'], pid, jiffies) 3196 - return 'ps - '+out 3095 + if len(out[-1]) > self.maxchars: 3096 + out.append('') 3097 + elif len(out[-1]) > 0: 3098 + out[-1] += ',' 3099 + out[-1] += '%s-%s %d' % (val['name'], pid, jiffies) 3100 + if len(out) > 1: 3101 + for line in out: 3102 + sysvals.fsetVal('ps - @%d|%s' % (len(out), line), 'trace_marker') 3103 + else: 3104 + sysvals.fsetVal('ps - %s' % out[0], 'trace_marker') 3197 3105 def processMonitor(self, tid): 3198 3106 while self.running: 3199 - out = self.procstat() 3200 - if out: 3201 - sysvals.fsetVal(out, 'trace_marker') 3107 + self.procstat() 3202 3108 def start(self): 3203 3109 self.thread = Thread(target=self.processMonitor, args=(0,)) 3204 3110 self.running = True ··· 3246 3144 3247 3145 # Function: appendIncompleteTraceLog 3248 3146 # Description: 3249 - # [deprecated for kernel 3.15 or newer] 3250 3147 # Adds callgraph data which lacks trace event data. This is only 3251 3148 # for timelines generated from 3.15 or older 3252 3149 # Arguments: ··· 3347 3246 dev['ftrace'] = cg 3348 3247 break 3349 3248 3249 + # Function: loadTraceLog 3250 + # Description: 3251 + # load the ftrace file into memory and fix up any ordering issues 3252 + # Output: 3253 + # TestProps instance and an array of lines in proper order 3254 + def loadTraceLog(): 3255 + tp, data, lines, trace = TestProps(), dict(), [], [] 3256 + tf = sysvals.openlog(sysvals.ftracefile, 'r') 3257 + for line in tf: 3258 + # remove any latent carriage returns 3259 + line = line.replace('\r\n', '') 3260 + if tp.stampInfo(line, sysvals): 3261 + continue 3262 + # ignore all other commented lines 3263 + if line[0] == '#': 3264 + continue 3265 + # ftrace line: parse only valid lines 3266 + m = re.match(tp.ftrace_line_fmt, line) 3267 + if(not m): 3268 + continue 3269 + dur = m.group('dur') if tp.cgformat else 'traceevent' 3270 + info = (m.group('time'), m.group('proc'), m.group('pid'), 3271 + m.group('msg'), dur) 3272 + # group the data by timestamp 3273 + t = float(info[0]) 3274 + if t in data: 3275 + data[t].append(info) 3276 + else: 3277 + data[t] = [info] 3278 + # we only care about trace event ordering 3279 + if (info[3].startswith('suspend_resume:') or \ 3280 + info[3].startswith('tracing_mark_write:')) and t not in trace: 3281 + trace.append(t) 3282 + tf.close() 3283 + for t in sorted(data): 3284 + first, last, blk = [], [], data[t] 3285 + if len(blk) > 1 and t in trace: 3286 + # move certain lines to the start or end of a timestamp block 3287 + for i in range(len(blk)): 3288 + if 'SUSPEND START' in blk[i][3]: 3289 + first.append(i) 3290 + elif re.match('.* timekeeping_freeze.*begin', blk[i][3]): 3291 + last.append(i) 3292 + elif re.match('.* timekeeping_freeze.*end', blk[i][3]): 3293 + first.append(i) 3294 + elif 'RESUME COMPLETE' in blk[i][3]: 3295 + last.append(i) 3296 + if len(first) == 1 and len(last) == 0: 3297 + blk.insert(0, blk.pop(first[0])) 3298 + elif len(last) == 1 and len(first) == 0: 3299 + blk.append(blk.pop(last[0])) 3300 + for info in blk: 3301 + lines.append(info) 3302 + return (tp, lines) 3303 + 3350 3304 # Function: parseTraceLog 3351 3305 # Description: 3352 3306 # Analyze an ftrace log output file generated from this app during ··· 3427 3271 3428 3272 # extract the callgraph and traceevent data 3429 3273 s2idle_enter = hwsus = False 3430 - tp = TestProps() 3431 3274 testruns, testdata = [], [] 3432 3275 testrun, data, limbo = 0, 0, True 3433 - tf = sysvals.openlog(sysvals.ftracefile, 'r') 3434 3276 phase = 'suspend_prepare' 3435 - for line in tf: 3436 - # remove any latent carriage returns 3437 - line = line.replace('\r\n', '') 3438 - if tp.stampInfo(line, sysvals): 3439 - continue 3440 - # ignore all other commented lines 3441 - if line[0] == '#': 3442 - continue 3443 - # ftrace line: parse only valid lines 3444 - m = re.match(tp.ftrace_line_fmt, line) 3445 - if(not m): 3446 - continue 3277 + tp, tf = loadTraceLog() 3278 + for m_time, m_proc, m_pid, m_msg, m_param3 in tf: 3447 3279 # gather the basic message data from the line 3448 - m_time = m.group('time') 3449 - m_proc = m.group('proc') 3450 - m_pid = m.group('pid') 3451 - m_msg = m.group('msg') 3452 - if(tp.cgformat): 3453 - m_param3 = m.group('dur') 3454 - else: 3455 - m_param3 = 'traceevent' 3456 3280 if(m_time and m_pid and m_msg): 3457 3281 t = FTraceLine(m_time, m_msg, m_param3) 3458 3282 pid = int(m_pid) ··· 3458 3322 if t.type == 'tracing_mark_write': 3459 3323 m = re.match(tp.procexecfmt, t.name) 3460 3324 if(m): 3461 - proclist = dict() 3462 - for ps in m.group('ps').split(','): 3325 + parts, msg = 1, m.group('ps') 3326 + m = re.match(tp.procmultifmt, msg) 3327 + if(m): 3328 + parts, msg = int(m.group('n')), m.group('ps') 3329 + if tp.multiproccnt == 0: 3330 + tp.multiproctime = t.time 3331 + tp.multiproclist = dict() 3332 + proclist = tp.multiproclist 3333 + tp.multiproccnt += 1 3334 + else: 3335 + proclist = dict() 3336 + tp.multiproccnt = 0 3337 + for ps in msg.split(','): 3463 3338 val = ps.split() 3464 - if not val: 3339 + if not val or len(val) != 2: 3465 3340 continue 3466 3341 name = val[0].replace('--', '-') 3467 3342 proclist[name] = int(val[1]) 3468 - data.pstl[t.time] = proclist 3343 + if parts == 1: 3344 + data.pstl[t.time] = proclist 3345 + elif parts == tp.multiproccnt: 3346 + data.pstl[tp.multiproctime] = proclist 3347 + tp.multiproccnt = 0 3469 3348 continue 3470 3349 # find the end of resume 3471 3350 if(t.endMarker()): ··· 3696 3545 testrun.ftemp[key].append(FTraceCallGraph(pid, sysvals)) 3697 3546 if(res == -1): 3698 3547 testrun.ftemp[key][-1].addLine(t) 3699 - tf.close() 3700 3548 if len(testdata) < 1: 3701 3549 sysvals.vprint('WARNING: ftrace start marker is missing') 3702 3550 if data and not data.devicegroups: ··· 3817 3667 if p not in data.dmesg: 3818 3668 if not terr: 3819 3669 ph = p if 'machine' in p else lp 3820 - terr = '%s%s failed in %s phase' % (sysvals.suspendmode, tn, ph) 3670 + if p == 'suspend_machine': 3671 + sm = sysvals.suspendmode 3672 + if sm in suspendmodename: 3673 + sm = suspendmodename[sm] 3674 + terr = 'test%s did not enter %s power mode' % (tn, sm) 3675 + else: 3676 + terr = '%s%s failed in %s phase' % (sysvals.suspendmode, tn, ph) 3821 3677 pprint('TEST%s FAILED: %s' % (tn, terr)) 3822 3678 error.append(terr) 3823 3679 if data.tSuspended == 0: ··· 3864 3708 3865 3709 # Function: loadKernelLog 3866 3710 # Description: 3867 - # [deprecated for kernel 3.15.0 or newer] 3868 3711 # load the dmesg file into memory and fix up any ordering issues 3869 - # The dmesg filename is taken from sysvals 3870 3712 # Output: 3871 3713 # An array of empty Data objects with only their dmesgtext attributes set 3872 3714 def loadKernelLog(): ··· 3890 3736 if(not m): 3891 3737 continue 3892 3738 msg = m.group("msg") 3893 - if(re.match('PM: Syncing filesystems.*', msg)): 3739 + if re.match('PM: Syncing filesystems.*', msg) or \ 3740 + re.match('PM: suspend entry.*', msg): 3894 3741 if(data): 3895 3742 testruns.append(data) 3896 3743 data = Data(len(testruns)) ··· 3902 3747 if(m): 3903 3748 sysvals.stamp['kernel'] = m.group('k') 3904 3749 m = re.match('PM: Preparing system for (?P<m>.*) sleep', msg) 3905 - if(m): 3750 + if not m: 3751 + m = re.match('PM: Preparing system for sleep \((?P<m>.*)\)', msg) 3752 + if m: 3906 3753 sysvals.stamp['mode'] = sysvals.suspendmode = m.group('m') 3907 3754 data.dmesgtext.append(line) 3908 3755 lf.close() 3909 3756 3757 + if sysvals.suspendmode == 's2idle': 3758 + sysvals.suspendmode = 'freeze' 3759 + elif sysvals.suspendmode == 'deep': 3760 + sysvals.suspendmode = 'mem' 3910 3761 if data: 3911 3762 testruns.append(data) 3912 3763 if len(testruns) < 1: ··· 3923 3762 for data in testruns: 3924 3763 last = '' 3925 3764 for line in data.dmesgtext: 3926 - mc = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) calling '+\ 3927 - '(?P<f>.*)\+ @ .*, parent: .*', line) 3928 - mr = re.match('.*(\[ *)(?P<t>[0-9\.]*)(\]) call '+\ 3929 - '(?P<f>.*)\+ returned .* after (?P<dt>.*) usecs', last) 3930 - if(mc and mr and (mc.group('t') == mr.group('t')) and 3931 - (mc.group('f') == mr.group('f'))): 3765 + ct, cf, n, p = data.initcall_debug_call(line) 3766 + rt, rf, l = data.initcall_debug_return(last) 3767 + if ct and rt and ct == rt and cf == rf: 3932 3768 i = data.dmesgtext.index(last) 3933 3769 j = data.dmesgtext.index(line) 3934 3770 data.dmesgtext[i] = line ··· 3935 3777 3936 3778 # Function: parseKernelLog 3937 3779 # Description: 3938 - # [deprecated for kernel 3.15.0 or newer] 3939 3780 # Analyse a dmesg log output file generated from this app during 3940 3781 # the execution phase. Create a set of device structures in memory 3941 3782 # for subsequent formatting in the html output file ··· 3953 3796 3954 3797 # dmesg phase match table 3955 3798 dm = { 3956 - 'suspend_prepare': ['PM: Syncing filesystems.*'], 3957 - 'suspend': ['PM: Entering [a-z]* sleep.*', 'Suspending console.*'], 3958 - 'suspend_late': ['PM: suspend of devices complete after.*'], 3959 - 'suspend_noirq': ['PM: late suspend of devices complete after.*'], 3960 - 'suspend_machine': ['PM: noirq suspend of devices complete after.*'], 3961 - 'resume_machine': ['ACPI: Low-level resume complete.*'], 3962 - 'resume_noirq': ['ACPI: Waking up from system sleep state.*'], 3963 - 'resume_early': ['PM: noirq resume of devices complete after.*'], 3964 - 'resume': ['PM: early resume of devices complete after.*'], 3965 - 'resume_complete': ['PM: resume of devices complete after.*'], 3799 + 'suspend_prepare': ['PM: Syncing filesystems.*', 'PM: suspend entry.*'], 3800 + 'suspend': ['PM: Entering [a-z]* sleep.*', 'Suspending console.*', 3801 + 'PM: Suspending system .*'], 3802 + 'suspend_late': ['PM: suspend of devices complete after.*', 3803 + 'PM: freeze of devices complete after.*'], 3804 + 'suspend_noirq': ['PM: late suspend of devices complete after.*', 3805 + 'PM: late freeze of devices complete after.*'], 3806 + 'suspend_machine': ['PM: suspend-to-idle', 3807 + 'PM: noirq suspend of devices complete after.*', 3808 + 'PM: noirq freeze of devices complete after.*'], 3809 + 'resume_machine': ['PM: Timekeeping suspended for.*', 3810 + 'ACPI: Low-level resume complete.*', 3811 + 'ACPI: resume from mwait', 3812 + 'Suspended for [0-9\.]* seconds'], 3813 + 'resume_noirq': ['PM: resume from suspend-to-idle', 3814 + 'ACPI: Waking up from system sleep state.*'], 3815 + 'resume_early': ['PM: noirq resume of devices complete after.*', 3816 + 'PM: noirq restore of devices complete after.*'], 3817 + 'resume': ['PM: early resume of devices complete after.*', 3818 + 'PM: early restore of devices complete after.*'], 3819 + 'resume_complete': ['PM: resume of devices complete after.*', 3820 + 'PM: restore of devices complete after.*'], 3966 3821 'post_resume': ['.*Restarting tasks \.\.\..*'], 3967 3822 } 3968 - if(sysvals.suspendmode == 'standby'): 3969 - dm['resume_machine'] = ['PM: Restoring platform NVS memory'] 3970 - elif(sysvals.suspendmode == 'disk'): 3971 - dm['suspend_late'] = ['PM: freeze of devices complete after.*'] 3972 - dm['suspend_noirq'] = ['PM: late freeze of devices complete after.*'] 3973 - dm['suspend_machine'] = ['PM: noirq freeze of devices complete after.*'] 3974 - dm['resume_machine'] = ['PM: Restoring platform NVS memory'] 3975 - dm['resume_early'] = ['PM: noirq restore of devices complete after.*'] 3976 - dm['resume'] = ['PM: early restore of devices complete after.*'] 3977 - dm['resume_complete'] = ['PM: restore of devices complete after.*'] 3978 - elif(sysvals.suspendmode == 'freeze'): 3979 - dm['resume_machine'] = ['ACPI: resume from mwait'] 3980 3823 3981 3824 # action table (expected events that occur and show up in dmesg) 3982 3825 at = { ··· 4024 3867 for s in dm[p]: 4025 3868 if(re.match(s, msg)): 4026 3869 phasechange, phase = True, p 3870 + dm[p] = [s] 4027 3871 break 4028 3872 4029 3873 # hack for determining resume_machine end for freeze 4030 3874 if(not sysvals.usetraceevents and sysvals.suspendmode == 'freeze' \ 4031 3875 and phase == 'resume_machine' and \ 4032 - re.match('calling (?P<f>.*)\+ @ .*, parent: .*', msg)): 3876 + data.initcall_debug_call(line, True)): 4033 3877 data.setPhase(phase, ktime, False) 4034 3878 phase = 'resume_noirq' 4035 3879 data.setPhase(phase, ktime, True) ··· 4103 3945 # -- device callbacks -- 4104 3946 if(phase in data.sortedPhases()): 4105 3947 # device init call 4106 - if(re.match('calling (?P<f>.*)\+ @ .*, parent: .*', msg)): 4107 - sm = re.match('calling (?P<f>.*)\+ @ '+\ 4108 - '(?P<n>.*), parent: (?P<p>.*)', msg); 4109 - f = sm.group('f') 4110 - n = sm.group('n') 4111 - p = sm.group('p') 4112 - if(f and n and p): 4113 - data.newAction(phase, f, int(n), p, ktime, -1, '') 4114 - # device init return 4115 - elif(re.match('call (?P<f>.*)\+ returned .* after '+\ 4116 - '(?P<t>.*) usecs', msg)): 4117 - sm = re.match('call (?P<f>.*)\+ returned .* after '+\ 4118 - '(?P<t>.*) usecs(?P<a>.*)', msg); 4119 - f = sm.group('f') 4120 - t = sm.group('t') 4121 - list = data.dmesg[phase]['list'] 4122 - if(f in list): 4123 - dev = list[f] 4124 - dev['length'] = int(t) 4125 - dev['end'] = ktime 3948 + t, f, n, p = data.initcall_debug_call(line) 3949 + if t and f and n and p: 3950 + data.newAction(phase, f, int(n), p, ktime, -1, '') 3951 + else: 3952 + # device init return 3953 + t, f, l = data.initcall_debug_return(line) 3954 + if t and f and l: 3955 + list = data.dmesg[phase]['list'] 3956 + if(f in list): 3957 + dev = list[f] 3958 + dev['length'] = int(l) 3959 + dev['end'] = ktime 4126 3960 4127 3961 # if trace events are not available, these are better than nothing 4128 3962 if(not sysvals.usetraceevents): ··· 4156 4006 # fill in any missing phases 4157 4007 phasedef = data.phasedef 4158 4008 terr, lp = '', 'suspend_prepare' 4009 + if lp not in data.dmesg: 4010 + doError('dmesg log format has changed, could not find start of suspend') 4159 4011 for p in sorted(phasedef, key=lambda k:phasedef[k]['order']): 4160 4012 if p not in data.dmesg: 4161 4013 if not terr: ··· 5454 5302 sv.dlog('read dmesg') 5455 5303 sv.initdmesg() 5456 5304 # start ftrace 5457 - if(sv.usecallgraph or sv.usetraceevents): 5305 + if sv.useftrace: 5458 5306 if not quiet: 5459 5307 pprint('START TRACING') 5460 5308 sv.dlog('start ftrace tracing') ··· 5486 5334 sv.dlog('enable RTC wake alarm') 5487 5335 sv.rtcWakeAlarmOn() 5488 5336 # start of suspend trace marker 5489 - if(sv.usecallgraph or sv.usetraceevents): 5490 - sv.fsetVal(datetime.now().strftime(sv.tmstart), 'trace_marker') 5337 + sv.fsetVal(datetime.now().strftime(sv.tmstart), 'trace_marker') 5491 5338 # predelay delay 5492 5339 if(count == 1 and sv.predelay > 0): 5493 5340 sv.fsetVal('WAIT %d' % sv.predelay, 'trace_marker') ··· 5535 5384 sv.fsetVal('WAIT END', 'trace_marker') 5536 5385 # return from suspend 5537 5386 pprint('RESUME COMPLETE') 5538 - if(sv.usecallgraph or sv.usetraceevents): 5539 - sv.fsetVal(datetime.now().strftime(sv.tmend), 'trace_marker') 5387 + sv.fsetVal(datetime.now().strftime(sv.tmend), 'trace_marker') 5540 5388 if sv.wifi and wifi: 5541 5389 tdata['wifi'] = sv.pollWifi(wifi) 5542 5390 sv.dlog('wifi check, %s' % tdata['wifi']) 5391 + if sv.netfix: 5392 + netfixout = sv.netfixon('wired') 5393 + elif sv.netfix: 5394 + netfixout = sv.netfixon() 5395 + if sv.netfix and netfixout: 5396 + tdata['netfix'] = netfixout 5397 + sv.dlog('netfix, %s' % tdata['netfix']) 5543 5398 if(sv.suspendmode == 'mem' or sv.suspendmode == 'command'): 5544 5399 sv.dlog('read the ACPI FPDT') 5545 5400 tdata['fw'] = getFPDT(False) ··· 5553 5396 sv.dlog('run the cmdinfo list after') 5554 5397 cmdafter = sv.cmdinfo(False) 5555 5398 # stop ftrace 5556 - if(sv.usecallgraph or sv.usetraceevents): 5399 + if sv.useftrace: 5557 5400 if sv.useprocmon: 5558 5401 sv.dlog('stop the process monitor') 5559 5402 pm.stop() ··· 5564 5407 sysvals.dlog('EXECUTION TRACE END') 5565 5408 sv.getdmesg(testdata) 5566 5409 # grab a copy of the ftrace output 5567 - if(sv.usecallgraph or sv.usetraceevents): 5410 + if sv.useftrace: 5568 5411 if not quiet: 5569 5412 pprint('CAPTURING TRACE') 5570 5413 op = sv.writeDatafileHeader(sv.ftracefile, testdata) ··· 5995 5838 pprint(' please choose one with -m') 5996 5839 5997 5840 # check if ftrace is available 5998 - res = sysvals.colorText('NO') 5999 - ftgood = sysvals.verifyFtrace() 6000 - if(ftgood): 6001 - res = 'YES' 6002 - elif(sysvals.usecallgraph): 6003 - status = 'ftrace is not properly supported' 6004 - pprint(' is ftrace supported: %s' % res) 5841 + if sysvals.useftrace: 5842 + res = sysvals.colorText('NO') 5843 + sysvals.useftrace = sysvals.verifyFtrace() 5844 + efmt = '"{0}" uses ftrace, and it is not properly supported' 5845 + if sysvals.useftrace: 5846 + res = 'YES' 5847 + elif sysvals.usecallgraph: 5848 + status = efmt.format('-f') 5849 + elif sysvals.usedevsrc: 5850 + status = efmt.format('-dev') 5851 + elif sysvals.useprocmon: 5852 + status = efmt.format('-proc') 5853 + pprint(' is ftrace supported: %s' % res) 6005 5854 6006 5855 # check if kprobes are available 6007 5856 if sysvals.usekprobes: ··· 6020 5857 pprint(' are kprobes supported: %s' % res) 6021 5858 6022 5859 # what data source are we using 6023 - res = 'DMESG' 6024 - if(ftgood): 5860 + res = 'DMESG (very limited, ftrace is preferred)' 5861 + if sysvals.useftrace: 6025 5862 sysvals.usetraceevents = True 6026 5863 for e in sysvals.traceevents: 6027 5864 if not os.path.exists(sysvals.epath+e): ··· 6042 5879 pprint(' optional commands this tool may use for info:') 6043 5880 no = sysvals.colorText('MISSING') 6044 5881 yes = sysvals.colorText('FOUND', 32) 6045 - for c in ['turbostat', 'mcelog', 'lspci', 'lsusb']: 5882 + for c in ['turbostat', 'mcelog', 'lspci', 'lsusb', 'netfix']: 6046 5883 if c == 'turbostat': 6047 5884 res = yes if sysvals.haveTurbostat() else no 6048 5885 else: ··· 6134 5971 if not sysvals.stamp: 6135 5972 pprint('ERROR: data does not include the expected stamp') 6136 5973 return (testruns, {'error': 'timeline generation failed'}) 6137 - shown = ['bios', 'biosdate', 'cpu', 'host', 'kernel', 'man', 'memfr', 5974 + shown = ['os', 'bios', 'biosdate', 'cpu', 'host', 'kernel', 'man', 'memfr', 6138 5975 'memsz', 'mode', 'numcpu', 'plat', 'time', 'wifi'] 6139 5976 sysvals.vprint('System Info:') 6140 5977 for key in sorted(sysvals.stamp): ··· 6215 6052 if sysvals.display: 6216 6053 ret = sysvals.displayControl('init') 6217 6054 sysvals.dlog('xset display init, ret = %d' % ret) 6055 + sysvals.testVal(sysvals.pmdpath, 'basic', '1') 6056 + sysvals.testVal(sysvals.s0ixpath, 'basic', 'Y') 6218 6057 sysvals.dlog('initialize ftrace') 6219 6058 sysvals.initFtrace(quiet) 6220 6059 ··· 6310 6145 elist[err[0]] += 1 6311 6146 for i in elist: 6312 6147 ilist.append('%sx%d' % (i, elist[i]) if elist[i] > 1 else i) 6313 - wifi = find_in_html(html, 'Wifi Resume: ', '</td>') 6314 - if wifi: 6315 - extra['wifi'] = wifi 6148 + line = find_in_html(log, '# wifi ', '\n') 6149 + if line: 6150 + extra['wifi'] = line 6151 + line = find_in_html(log, '# netfix ', '\n') 6152 + if line: 6153 + extra['netfix'] = line 6316 6154 low = find_in_html(html, 'freeze time: <b>', ' ms</b>') 6317 6155 for lowstr in ['waking', '+']: 6318 6156 if not low: ··· 6411 6243 sysvals.ftracefile = file 6412 6244 sysvals.setOutputFile() 6413 6245 if (sysvals.dmesgfile or sysvals.ftracefile) and sysvals.htmlfile and \ 6414 - (force or not sysvals.usable(sysvals.htmlfile)): 6246 + (force or not sysvals.usable(sysvals.htmlfile, True)): 6415 6247 pprint('FTRACE: %s' % sysvals.ftracefile) 6416 6248 if sysvals.dmesgfile: 6417 6249 pprint('DMESG : %s' % sysvals.dmesgfile) ··· 6701 6533 ' -skiphtml Run the test and capture the trace logs, but skip the timeline (default: disabled)\n'\ 6702 6534 ' -result fn Export a results table to a text file for parsing.\n'\ 6703 6535 ' -wifi If a wifi connection is available, check that it reconnects after resume.\n'\ 6536 + ' -netfix Use netfix to reset the network in the event it fails to resume.\n'\ 6704 6537 ' [testprep]\n'\ 6705 6538 ' -sync Sync the filesystems before starting the test\n'\ 6706 6539 ' -rs on/off Enable/disable runtime suspend for all devices, restore all after test\n'\ ··· 6784 6615 elif(arg == '-v'): 6785 6616 pprint("Version %s" % sysvals.version) 6786 6617 sys.exit(0) 6618 + elif(arg == '-debugtiming'): 6619 + debugtiming = True 6787 6620 elif(arg == '-x2'): 6788 6621 sysvals.execcount = 2 6789 6622 elif(arg == '-x2delay'): ··· 6828 6657 sysvals.sync = True 6829 6658 elif(arg == '-wifi'): 6830 6659 sysvals.wifi = True 6660 + elif(arg == '-netfix'): 6661 + sysvals.netfix = True 6831 6662 elif(arg == '-gzip'): 6832 6663 sysvals.gzip = True 6833 6664 elif(arg == '-info'): ··· 6992 6819 sysvals.outdir = val 6993 6820 sysvals.notestrun = True 6994 6821 if(os.path.isdir(val) == False): 6995 - doError('%s is not accessible' % val) 6822 + doError('%s is not accesible' % val) 6996 6823 elif(arg == '-filter'): 6997 6824 try: 6998 6825 val = next(args) ··· 7115 6942 time.sleep(sysvals.multitest['delay']) 7116 6943 fmt = 'suspend-%y%m%d-%H%M%S' 7117 6944 sysvals.testdir = os.path.join(sysvals.outdir, datetime.now().strftime(fmt)) 7118 - ret = runTest(i+1, True) 6945 + ret = runTest(i+1, not sysvals.verbose) 7119 6946 failcnt = 0 if not ret else failcnt + 1 7120 6947 if sysvals.maxfail > 0 and failcnt >= sysvals.maxfail: 7121 6948 pprint('Maximum fail count of %d reached, aborting multitest' % (sysvals.maxfail)) 7122 6949 break 7123 - time.sleep(5) 7124 6950 sysvals.resetlog() 7125 6951 sysvals.multistat(False, i, finish) 7126 6952 if 'time' in sysvals.multitest and datetime.now() >= finish: