Commit a771ea64 authored by Linus Torvalds's avatar Linus Torvalds

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
  ...
parents 8fa0db3a aa727b7b
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/interconnect/mediatek,cci.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Cache Coherent Interconnect (CCI) frequency and voltage scaling
maintainers:
- Jia-Wei Chang <jia-wei.chang@mediatek.com>
- Johnson Wang <johnson.wang@mediatek.com>
description: |
MediaTek Cache Coherent Interconnect (CCI) is a hardware engine used by
MT8183 and MT8186 SoCs to scale the frequency and adjust the voltage in
hardware. It can also optimize the voltage to reduce the power consumption.
properties:
compatible:
enum:
- mediatek,mt8183-cci
- mediatek,mt8186-cci
clocks:
items:
- description:
The multiplexer for clock input of the bus.
- description:
A parent of "bus" clock which is used as an intermediate clock source
when the original clock source (PLL) is under transition and not
stable yet.
clock-names:
items:
- const: cci
- const: intermediate
operating-points-v2: true
opp-table: true
proc-supply:
description:
Phandle of the regulator for CCI that provides the supply voltage.
sram-supply:
description:
Phandle of the regulator for sram of CCI that provides the supply
voltage. When it is present, the implementation needs to do
"voltage tracking" to step by step scale up/down Vproc and Vsram to fit
SoC specific needs. When absent, the voltage scaling flow is handled by
hardware, hence no software "voltage tracking" is needed.
required:
- compatible
- clocks
- clock-names
- operating-points-v2
- proc-supply
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mt8183-clk.h>
cci: cci {
compatible = "mediatek,mt8183-cci";
clocks = <&mcucfg CLK_MCU_BUS_SEL>,
<&topckgen CLK_TOP_ARMPLL_DIV_PLL1>;
clock-names = "cci", "intermediate";
operating-points-v2 = <&cci_opp>;
proc-supply = <&mt6358_vproc12_reg>;
};
cci_opp: opp-table-cci {
compatible = "operating-points-v2";
opp-shared;
opp2_00: opp-273000000 {
opp-hz = /bits/ 64 <273000000>;
opp-microvolt = <650000>;
};
opp2_01: opp-338000000 {
opp-hz = /bits/ 64 <338000000>;
opp-microvolt = <687500>;
};
opp2_02: opp-403000000 {
opp-hz = /bits/ 64 <403000000>;
opp-microvolt = <718750>;
};
opp2_03: opp-463000000 {
opp-hz = /bits/ 64 <463000000>;
opp-microvolt = <756250>;
};
opp2_04: opp-546000000 {
opp-hz = /bits/ 64 <546000000>;
opp-microvolt = <800000>;
};
opp2_05: opp-624000000 {
opp-hz = /bits/ 64 <624000000>;
opp-microvolt = <818750>;
};
opp2_06: opp-689000000 {
opp-hz = /bits/ 64 <689000000>;
opp-microvolt = <850000>;
};
opp2_07: opp-767000000 {
opp-hz = /bits/ 64 <767000000>;
opp-microvolt = <868750>;
};
opp2_08: opp-845000000 {
opp-hz = /bits/ 64 <845000000>;
opp-microvolt = <893750>;
};
opp2_09: opp-871000000 {
opp-hz = /bits/ 64 <871000000>;
opp-microvolt = <906250>;
};
opp2_10: opp-923000000 {
opp-hz = /bits/ 64 <923000000>;
opp-microvolt = <931250>;
};
opp2_11: opp-962000000 {
opp-hz = /bits/ 64 <962000000>;
opp-microvolt = <943750>;
};
opp2_12: opp-1027000000 {
opp-hz = /bits/ 64 <1027000000>;
opp-microvolt = <975000>;
};
opp2_13: opp-1092000000 {
opp-hz = /bits/ 64 <1092000000>;
opp-microvolt = <1000000>;
};
opp2_14: opp-1144000000 {
opp-hz = /bits/ 64 <1144000000>;
opp-microvolt = <1025000>;
};
opp2_15: opp-1196000000 {
opp-hz = /bits/ 64 <1196000000>;
opp-microvolt = <1050000>;
};
};
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/interconnect/samsung,exynos-bus.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Samsung Exynos SoC Bus and Interconnect
maintainers:
- Chanwoo Choi <cw00.choi@samsung.com>
- Krzysztof Kozlowski <krzk@kernel.org>
description: |
The Samsung Exynos SoC has many buses for data transfer between DRAM and
sub-blocks in SoC. Most Exynos SoCs share the common architecture for buses.
Generally, each bus of Exynos SoC includes a source clock and a power line,
which are able to change the clock frequency of the bus in runtime. To
monitor the usage of each bus in runtime, the driver uses the PPMU (Platform
Performance Monitoring Unit), which is able to measure the current load of
sub-blocks.
The Exynos SoC includes the various sub-blocks which have the each AXI bus.
The each AXI bus has the owned source clock but, has not the only owned power
line. The power line might be shared among one more sub-blocks. So, we can
divide into two type of device as the role of each sub-block. There are two
type of bus devices as following::
- parent bus device
- passive bus device
Basically, parent and passive bus device share the same power line. The
parent bus device can only change the voltage of shared power line and the
rest bus devices (passive bus device) depend on the decision of the parent
bus device. If there are three blocks which share the VDD_xxx power line,
Only one block should be parent device and then the rest blocks should depend
on the parent device as passive device.
VDD_xxx |--- A block (parent)
|--- B block (passive)
|--- C block (passive)
There are a little different composition among Exynos SoC because each Exynos
SoC has different sub-blocks. Therefore, such difference should be specified
in devicetree file instead of each device driver. In result, this driver is
able to support the bus frequency for all Exynos SoCs.
Detailed correlation between sub-blocks and power line according
to Exynos SoC::
- In case of Exynos3250, there are two power line as following::
VDD_MIF |--- DMC (Dynamic Memory Controller)
VDD_INT |--- LEFTBUS (parent device)
|--- PERIL
|--- MFC
|--- G3D
|--- RIGHTBUS
|--- PERIR
|--- FSYS
|--- LCD0
|--- PERIR
|--- ISP
|--- CAM
- MIF bus's frequency/voltage table
-----------------------
|Lv| Freq | Voltage |
-----------------------
|L1| 50000 |800000 |
|L2| 100000 |800000 |
|L3| 134000 |800000 |
|L4| 200000 |825000 |
|L5| 400000 |875000 |
-----------------------
- INT bus's frequency/voltage table
----------------------------------------------------------
|Block|LEFTBUS|RIGHTBUS|MCUISP |ISP |PERIL ||VDD_INT |
| name| |LCD0 | | | || |
| | |FSYS | | | || |
| | |MFC | | | || |
----------------------------------------------------------
|Mode |*parent|passive |passive|passive|passive|| |
----------------------------------------------------------
|Lv |Frequency ||Voltage |
----------------------------------------------------------
|L1 |50000 |50000 |50000 |50000 |50000 ||900000 |
|L2 |80000 |80000 |80000 |80000 |80000 ||900000 |
|L3 |100000 |100000 |100000 |100000 |100000 ||1000000 |
|L4 |134000 |134000 |200000 |200000 | ||1000000 |
|L5 |200000 |200000 |400000 |300000 | ||1000000 |
----------------------------------------------------------
- In case of Exynos4210, there is one power line as following::
VDD_INT |--- DMC (parent device, Dynamic Memory Controller)
|--- LEFTBUS
|--- PERIL
|--- MFC(L)
|--- G3D
|--- TV
|--- LCD0
|--- RIGHTBUS
|--- PERIR
|--- MFC(R)
|--- CAM
|--- FSYS
|--- GPS
|--- LCD0
|--- LCD1
- In case of Exynos4x12, there are two power line as following::
VDD_MIF |--- DMC (Dynamic Memory Controller)
VDD_INT |--- LEFTBUS (parent device)
|--- PERIL
|--- MFC(L)
|--- G3D
|--- TV
|--- IMAGE
|--- RIGHTBUS
|--- PERIR
|--- MFC(R)
|--- CAM
|--- FSYS
|--- GPS
|--- LCD0
|--- ISP
- In case of Exynos5422, there are two power line as following::
VDD_MIF |--- DREX 0 (parent device, DRAM EXpress controller)
|--- DREX 1
VDD_INT |--- NoC_Core (parent device)
|--- G2D
|--- G3D
|--- DISP1
|--- NoC_WCORE
|--- GSCL
|--- MSCL
|--- ISP
|--- MFC
|--- GEN
|--- PERIS
|--- PERIC
|--- FSYS
|--- FSYS2
- In case of Exynos5433, there is VDD_INT power line as following::
VDD_INT |--- G2D (parent device)
|--- MSCL
|--- GSCL
|--- JPEG
|--- MFC
|--- HEVC
|--- BUS0
|--- BUS1
|--- BUS2
|--- PERIS (Fixed clock rate)
|--- PERIC (Fixed clock rate)
|--- FSYS (Fixed clock rate)
properties:
compatible:
enum:
- samsung,exynos-bus
clocks:
maxItems: 1
clock-names:
items:
- const: bus
devfreq:
$ref: /schemas/types.yaml#/definitions/phandle
description:
Parent bus device. Valid and required only for the passive bus devices.
devfreq-events:
$ref: /schemas/types.yaml#/definitions/phandle-array
minItems: 1
maxItems: 4
description:
Devfreq-event device to monitor the current utilization of buses. Valid
and required only for the parent bus devices.
exynos,saturation-ratio:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Percentage value which is used to calibrate the performance count against
total cycle count. Valid only for the parent bus devices.
'#interconnect-cells':
const: 0
interconnects:
minItems: 1
maxItems: 2
operating-points-v2: true
samsung,data-clock-ratio:
$ref: /schemas/types.yaml#/definitions/uint32
default: 8
description:
Ratio of the data throughput in B/s to minimum data clock frequency in
Hz.
vdd-supply:
description:
Main bus power rail. Valid and required only for the parent bus devices.
required:
- compatible
- clocks
- clock-names
- operating-points-v2
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/exynos3250.h>
bus-dmc {
compatible = "samsung,exynos-bus";
clocks = <&cmu_dmc CLK_DIV_DMC>;
clock-names = "bus";
operating-points-v2 = <&bus_dmc_opp_table>;
devfreq-events = <&ppmu_dmc0_3>, <&ppmu_dmc1_3>;
vdd-supply = <&buck1_reg>;
};
ppmu_dmc0: ppmu@106a0000 {
compatible = "samsung,exynos-ppmu";
reg = <0x106a0000 0x2000>;
events {
ppmu_dmc0_3: ppmu-event3-dmc0 {
event-name = "ppmu-event3-dmc0";
};
};
};
bus_leftbus: bus-leftbus {
compatible = "samsung,exynos-bus";
clocks = <&cmu CLK_DIV_GDL>;
clock-names = "bus";
operating-points-v2 = <&bus_leftbus_opp_table>;
devfreq-events = <&ppmu_leftbus_3>, <&ppmu_rightbus_3>;
vdd-supply = <&buck3_reg>;
};
bus-rightbus {
compatible = "samsung,exynos-bus";
clocks = <&cmu CLK_DIV_GDR>;
clock-names = "bus";
operating-points-v2 = <&bus_leftbus_opp_table>;
devfreq = <&bus_leftbus>;
};
- |
dmc: bus-dmc {
compatible = "samsung,exynos-bus";
clocks = <&clock CLK_DIV_DMC>;
clock-names = "bus";
operating-points-v2 = <&bus_dmc_opp_table>;
samsung,data-clock-ratio = <4>;
#interconnect-cells = <0>;
devfreq-events = <&ppmu_dmc0_3>, <&ppmu_dmc1_3>;
vdd-supply = <&buck1_reg>;
};
leftbus: bus-leftbus {
compatible = "samsung,exynos-bus";
clocks = <&clock CLK_DIV_GDL>;
clock-names = "bus";
operating-points-v2 = <&bus_leftbus_opp_table>;
interconnects = <&dmc>;
#interconnect-cells = <0>;
devfreq-events = <&ppmu_leftbus_3>, <&ppmu_rightbus_3>;
vdd-supply = <&buck3_reg>;
};
display: bus-display {
compatible = "samsung,exynos-bus";
clocks = <&clock CLK_DIV_ACLK_266>;
clock-names = "bus";
operating-points-v2 = <&bus_display_opp_table>;
interconnects = <&leftbus &dmc>;
#interconnect-cells = <0>;
devfreq = <&leftbus>;
};
...@@ -20,20 +20,20 @@ possible source of information on its own, the EM framework intervenes as an ...@@ -20,20 +20,20 @@ possible source of information on its own, the EM framework intervenes as an
abstraction layer which standardizes the format of power cost tables in the abstraction layer which standardizes the format of power cost tables in the
kernel, hence enabling to avoid redundant work. kernel, hence enabling to avoid redundant work.
The power values might be expressed in milli-Watts or in an 'abstract scale'. The power values might be expressed in micro-Watts or in an 'abstract scale'.
Multiple subsystems might use the EM and it is up to the system integrator to Multiple subsystems might use the EM and it is up to the system integrator to
check that the requirements for the power value scale types are met. An example check that the requirements for the power value scale types are met. An example
can be found in the Energy-Aware Scheduler documentation can be found in the Energy-Aware Scheduler documentation
Documentation/scheduler/sched-energy.rst. For some subsystems like thermal or Documentation/scheduler/sched-energy.rst. For some subsystems like thermal or
powercap power values expressed in an 'abstract scale' might cause issues. powercap power values expressed in an 'abstract scale' might cause issues.
These subsystems are more interested in estimation of power used in the past, These subsystems are more interested in estimation of power used in the past,
thus the real milli-Watts might be needed. An example of these requirements can thus the real micro-Watts might be needed. An example of these requirements can
be found in the Intelligent Power Allocation in be found in the Intelligent Power Allocation in
Documentation/driver-api/thermal/power_allocator.rst. Documentation/driver-api/thermal/power_allocator.rst.
Kernel subsystems might implement automatic detection to check whether EM Kernel subsystems might implement automatic detection to check whether EM
registered devices have inconsistent scale (based on EM internal flag). registered devices have inconsistent scale (based on EM internal flag).
Important thing to keep in mind is that when the power values are expressed in Important thing to keep in mind is that when the power values are expressed in
an 'abstract scale' deriving real energy in milli-Joules would not be possible. an 'abstract scale' deriving real energy in micro-Joules would not be possible.
The figure below depicts an example of drivers (Arm-specific here, but the The figure below depicts an example of drivers (Arm-specific here, but the
approach is applicable to any architecture) providing power costs to the EM approach is applicable to any architecture) providing power costs to the EM
...@@ -98,7 +98,7 @@ Drivers are expected to register performance domains into the EM framework by ...@@ -98,7 +98,7 @@ Drivers are expected to register performance domains into the EM framework by
calling the following API:: calling the following API::
int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
struct em_data_callback *cb, cpumask_t *cpus, bool milliwatts); struct em_data_callback *cb, cpumask_t *cpus, bool microwatts);
Drivers must provide a callback function returning <frequency, power> tuples Drivers must provide a callback function returning <frequency, power> tuples
for each performance state. The callback function provided by the driver is free for each performance state. The callback function provided by the driver is free
...@@ -106,10 +106,10 @@ to fetch data from any relevant location (DT, firmware, ...), and by any mean ...@@ -106,10 +106,10 @@ to fetch data from any relevant location (DT, firmware, ...), and by any mean
deemed necessary. Only for CPU devices, drivers must specify the CPUs of the deemed necessary. Only for CPU devices, drivers must specify the CPUs of the
performance domains using cpumask. For other devices than CPUs the last performance domains using cpumask. For other devices than CPUs the last
argument must be set to NULL. argument must be set to NULL.
The last argument 'milliwatts' is important to set with correct value. Kernel The last argument 'microwatts' is important to set with correct value. Kernel
subsystems which use EM might rely on this flag to check if all EM devices use subsystems which use EM might rely on this flag to check if all EM devices use
the same scale. If there are different scales, these subsystems might decide the same scale. If there are different scales, these subsystems might decide
to: return warning/error, stop working or panic. to return warning/error, stop working or panic.
See Section 3. for an example of driver implementing this See Section 3. for an example of driver implementing this
callback, or Section 2.4 for further documentation on this API callback, or Section 2.4 for further documentation on this API
...@@ -137,7 +137,7 @@ The .get_cost() allows to provide the 'cost' values which reflect the ...@@ -137,7 +137,7 @@ The .get_cost() allows to provide the 'cost' values which reflect the
efficiency of the CPUs. This would allow to provide EAS information which efficiency of the CPUs. This would allow to provide EAS information which
has different relation than what would be forced by the EM internal has different relation than what would be forced by the EM internal
formulas calculating 'cost' values. To register an EM for such platform, the formulas calculating 'cost' values. To register an EM for such platform, the
driver must set the flag 'milliwatts' to 0, provide .get_power() callback driver must set the flag 'microwatts' to 0, provide .get_power() callback
and provide .get_cost() callback. The EM framework would handle such platform and provide .get_cost() callback. The EM framework would handle such platform
properly during registration. A flag EM_PERF_DOMAIN_ARTIFICIAL is set for such properly during registration. A flag EM_PERF_DOMAIN_ARTIFICIAL is set for such
platform. Special care should be taken by other frameworks which are using EM platform. Special care should be taken by other frameworks which are using EM
......
...@@ -315,7 +315,7 @@ that these callbacks operate on:: ...@@ -315,7 +315,7 @@ that these callbacks operate on::
configuration space */ configuration space */
unsigned int pme_support:5; /* Bitmask of states from which PME# unsigned int pme_support:5; /* Bitmask of states from which PME#
can be generated */ can be generated */
unsigned int pme_interrupt:1;/* Is native PCIe PME signaling used? */ unsigned int pme_poll:1; /* Poll device's PME status bit */
unsigned int d1_support:1; /* Low power state D1 is supported */ unsigned int d1_support:1; /* Low power state D1 is supported */
unsigned int d2_support:1; /* Low power state D2 is supported */ unsigned int d2_support:1; /* Low power state D2 is supported */
unsigned int no_d1d2:1; /* D1 and D2 are forbidden */ unsigned int no_d1d2:1; /* D1 and D2 are forbidden */
......
...@@ -4408,7 +4408,7 @@ L: linux-pm@vger.kernel.org ...@@ -4408,7 +4408,7 @@ L: linux-pm@vger.kernel.org
L: linux-samsung-soc@vger.kernel.org L: linux-samsung-soc@vger.kernel.org
S: Maintained S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
F: Documentation/devicetree/bindings/devfreq/exynos-bus.txt F: Documentation/devicetree/bindings/interconnect/samsung,exynos-bus.yaml
F: drivers/devfreq/exynos-bus.c F: drivers/devfreq/exynos-bus.c
BUSLOGIC SCSI DRIVER BUSLOGIC SCSI DRIVER
...@@ -5890,6 +5890,7 @@ L: linux-pm@vger.kernel.org ...@@ -5890,6 +5890,7 @@ L: linux-pm@vger.kernel.org
S: Maintained S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git T: git git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux.git
F: Documentation/devicetree/bindings/devfreq/ F: Documentation/devicetree/bindings/devfreq/
F: Documentation/devicetree/bindings/interconnect/mediatek,cci.yaml
F: drivers/devfreq/ F: drivers/devfreq/
F: include/linux/devfreq.h F: include/linux/devfreq.h
F: include/trace/events/devfreq.h F: include/trace/events/devfreq.h
......
...@@ -222,6 +222,9 @@ static void genpd_debug_remove(struct generic_pm_domain *genpd) ...@@ -222,6 +222,9 @@ static void genpd_debug_remove(struct generic_pm_domain *genpd)
{ {
struct dentry *d; struct dentry *d;
if (!genpd_debugfs_dir)
return;
d = debugfs_lookup(genpd->name, genpd_debugfs_dir); d = debugfs_lookup(genpd->name, genpd_debugfs_dir);
debugfs_remove(d); debugfs_remove(d);
} }
......
...@@ -1862,10 +1862,13 @@ int pm_runtime_force_suspend(struct device *dev) ...@@ -1862,10 +1862,13 @@ int pm_runtime_force_suspend(struct device *dev)
callback = RPM_GET_CALLBACK(dev, runtime_suspend); callback = RPM_GET_CALLBACK(dev, runtime_suspend);
dev_pm_enable_wake_irq_check(dev, true);
ret = callback ? callback(dev) : 0; ret = callback ? callback(dev) : 0;
if (ret) if (ret)
goto err; goto err;
dev_pm_enable_wake_irq_complete(dev);
/* /*
* If the device can stay in suspend after the system-wide transition * If the device can stay in suspend after the system-wide transition
* to the working state that will follow, drop the children counter of * to the working state that will follow, drop the children counter of
...@@ -1882,6 +1885,7 @@ int pm_runtime_force_suspend(struct device *dev) ...@@ -1882,6 +1885,7 @@ int pm_runtime_force_suspend(struct device *dev)
return 0; return 0;
err: err:
dev_pm_disable_wake_irq_check(dev, true);
pm_runtime_enable(dev); pm_runtime_enable(dev);
return ret; return ret;
} }
...@@ -1915,9 +1919,11 @@ int pm_runtime_force_resume(struct device *dev) ...@@ -1915,9 +1919,11 @@ int pm_runtime_force_resume(struct device *dev)
callback = RPM_GET_CALLBACK(dev, runtime_resume); callback = RPM_GET_CALLBACK(dev, runtime_resume);
dev_pm_disable_wake_irq_check(dev, false);
ret = callback ? callback(dev) : 0; ret = callback ? callback(dev) : 0;
if (ret) { if (ret) {
pm_runtime_set_suspended(dev); pm_runtime_set_suspended(dev);
dev_pm_enable_wake_irq_check(dev, false);
goto out; goto out;
} }
......
...@@ -500,36 +500,6 @@ void device_set_wakeup_capable(struct device *dev, bool capable) ...@@ -500,36 +500,6 @@ void device_set_wakeup_capable(struct device *dev, bool capable)
} }
EXPORT_SYMBOL_GPL(device_set_wakeup_capable); EXPORT_SYMBOL_GPL(device_set_wakeup_capable);
/**
* device_init_wakeup - Device wakeup initialization.
* @dev: Device to handle.
* @enable: Whether or not to enable @dev as a wakeup device.
*
* By default, most devices should leave wakeup disabled. The exceptions are
* devices that everyone expects to be wakeup sources: keyboards, power buttons,
* possibly network interfaces, etc. Also, devices that don't generate their
* own wakeup requests but merely forward requests from one bus to another
* (like PCI bridges) should have wakeup enabled by default.
*/
int device_init_wakeup(struct device *dev, bool enable)
{
int ret = 0;
if (!dev)
return -EINVAL;
if (enable) {
device_set_wakeup_capable(dev, true);
ret = device_wakeup_enable(dev);
} else {
device_wakeup_disable(dev);
device_set_wakeup_capable(dev, false);
}
return ret;
}
EXPORT_SYMBOL_GPL(device_init_wakeup);
/** /**
* device_set_wakeup_enable - Enable or disable a device to wake up the system. * device_set_wakeup_enable - Enable or disable a device to wake up the system.
* @dev: Device to handle. * @dev: Device to handle.
......
...@@ -268,7 +268,7 @@ config LOONGSON2_CPUFREQ ...@@ -268,7 +268,7 @@ config LOONGSON2_CPUFREQ
This option adds a CPUFreq driver for loongson processors which This option adds a CPUFreq driver for loongson processors which
support software configurable cpu frequency. support software configurable cpu frequency.
Loongson2F and it's successors support this feature. Loongson2F and its successors support this feature.
If in doubt, say N. If in doubt, say N.
......
...@@ -78,6 +78,8 @@ static bool boost_state(unsigned int cpu) ...@@ -78,6 +78,8 @@ static bool boost_state(unsigned int cpu)
switch (boot_cpu_data.x86_vendor) { switch (boot_cpu_data.x86_vendor) {
case X86_VENDOR_INTEL: case X86_VENDOR_INTEL:
case X86_VENDOR_CENTAUR:
case X86_VENDOR_ZHAOXIN:
rdmsr_on_cpu(cpu, MSR_IA32_MISC_ENABLE, &lo, &hi); rdmsr_on_cpu(cpu, MSR_IA32_MISC_ENABLE, &lo, &hi);
msr = lo | ((u64)hi << 32); msr = lo | ((u64)hi << 32);
return !(msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE); return !(msr & MSR_IA32_MISC_ENABLE_TURBO_DISABLE);
...@@ -97,6 +99,8 @@ static int boost_set_msr(bool enable) ...@@ -97,6 +99,8 @@ static int boost_set_msr(bool enable)
switch (boot_cpu_data.x86_vendor) { switch (boot_cpu_data.x86_vendor) {
case X86_VENDOR_INTEL: case X86_VENDOR_INTEL:
case X86_VENDOR_CENTAUR:
case X86_VENDOR_ZHAOXIN:
msr_addr = MSR_IA32_MISC_ENABLE; msr_addr = MSR_IA32_MISC_ENABLE;
msr_mask = MSR_IA32_MISC_ENABLE_TURBO_DISABLE; msr_mask = MSR_IA32_MISC_ENABLE_TURBO_DISABLE;
break; break;
......
...@@ -843,12 +843,14 @@ ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf) ...@@ -843,12 +843,14 @@ ssize_t cpufreq_show_cpus(const struct cpumask *mask, char *buf)
unsigned int cpu; unsigned int cpu;
for_each_cpu(cpu, mask) { for_each_cpu(cpu, mask) {
if (i) i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u ", cpu);
i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), " ");
i += scnprintf(&buf[i], (PAGE_SIZE - i - 2), "%u", cpu);
if (i >= (PAGE_SIZE - 5)) if (i >= (PAGE_SIZE - 5))
break; break;
} }
/* Remove the extra space at the end */
i--;
i += sprintf(&buf[i], "\n"); i += sprintf(&buf[i], "\n");
return i; return i;
} }
...@@ -971,21 +973,10 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, ...@@ -971,21 +973,10 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr,
if (!fattr->store) if (!fattr->store)
return -EIO; return -EIO;
/*
* cpus_read_trylock() is used here to work around a circular lock
* dependency problem with respect to the cpufreq_register_driver().
*/
if (!cpus_read_trylock())
return -EBUSY;
if (cpu_online(policy->cpu)) {
down_write(&policy->rwsem); down_write(&policy->rwsem);
if (likely(!policy_is_inactive(policy))) if (likely(!policy_is_inactive(policy)))
ret = fattr->store(policy, buf, count); ret = fattr->store(policy, buf, count);
up_write(&policy->rwsem); up_write(&policy->rwsem);
}
cpus_read_unlock();
return ret; return ret;
} }
...@@ -1282,6 +1273,13 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy) ...@@ -1282,6 +1273,13 @@ static void cpufreq_policy_free(struct cpufreq_policy *policy)
unsigned long flags; unsigned long flags;
int cpu; int cpu;
/*
* The callers must ensure the policy is inactive by now, to avoid any
* races with show()/store() callbacks.
*/
if (unlikely(!policy_is_inactive(policy)))
pr_warn("%s: Freeing active policy\n", __func__);
/* Remove policy from list */ /* Remove policy from list */
write_lock_irqsave(&cpufreq_driver_lock, flags); write_lock_irqsave(&cpufreq_driver_lock, flags);
list_del(&policy->policy_list); list_del(&policy->policy_list);
...@@ -1536,8 +1534,6 @@ static int cpufreq_online(unsigned int cpu) ...@@ -1536,8 +1534,6 @@ static int cpufreq_online(unsigned int cpu)
for_each_cpu(j, policy->real_cpus) for_each_cpu(j, policy->real_cpus)
remove_cpu_dev_symlink(policy, j, get_cpu_device(j)); remove_cpu_dev_symlink(policy, j, get_cpu_device(j));
cpumask_clear(policy->cpus);
out_offline_policy: out_offline_policy:
if (cpufreq_driver->offline) if (cpufreq_driver->offline)
cpufreq_driver->offline(policy); cpufreq_driver->offline(policy);
...@@ -1547,6 +1543,7 @@ static int cpufreq_online(unsigned int cpu) ...@@ -1547,6 +1543,7 @@ static int cpufreq_online(unsigned int cpu)
cpufreq_driver->exit(policy); cpufreq_driver->exit(policy);
out_free_policy: out_free_policy:
cpumask_clear(policy->cpus);
up_write(&policy->rwsem); up_write(&policy->rwsem);
cpufreq_policy_free(policy); cpufreq_policy_free(policy);
......
...@@ -416,10 +416,13 @@ static struct dbs_governor od_dbs_gov = { ...@@ -416,10 +416,13 @@ static struct dbs_governor od_dbs_gov = {
static void od_set_powersave_bias(unsigned int powersave_bias) static void od_set_powersave_bias(unsigned int powersave_bias)
{ {
unsigned int cpu; unsigned int cpu;
cpumask_t done; cpumask_var_t done;
if (!alloc_cpumask_var(&done, GFP_KERNEL))
return;
default_powersave_bias = powersave_bias; default_powersave_bias = powersave_bias;
cpumask_clear(&done); cpumask_clear(done);
cpus_read_lock(); cpus_read_lock();
for_each_online_cpu(cpu) { for_each_online_cpu(cpu) {
...@@ -428,7 +431,7 @@ static void od_set_powersave_bias(unsigned int powersave_bias) ...@@ -428,7 +431,7 @@ static void od_set_powersave_bias(unsigned int powersave_bias)
struct dbs_data *dbs_data; struct dbs_data *dbs_data;
struct od_dbs_tuners *od_tuners; struct od_dbs_tuners *od_tuners;
if (cpumask_test_cpu(cpu, &done)) if (cpumask_test_cpu(cpu, done))
continue; continue;
policy = cpufreq_cpu_get_raw(cpu); policy = cpufreq_cpu_get_raw(cpu);
...@@ -439,13 +442,15 @@ static void od_set_powersave_bias(unsigned int powersave_bias) ...@@ -439,13 +442,15 @@ static void od_set_powersave_bias(unsigned int powersave_bias)
if (!policy_dbs) if (!policy_dbs)
continue; continue;
cpumask_or(&done, &done, policy->cpus); cpumask_or(done, done, policy->cpus);
dbs_data = policy_dbs->dbs_data; dbs_data = policy_dbs->dbs_data;
od_tuners = dbs_data->tuners; od_tuners = dbs_data->tuners;
od_tuners->powersave_bias = default_powersave_bias; od_tuners->powersave_bias = default_powersave_bias;
} }
cpus_read_unlock(); cpus_read_unlock();
free_cpumask_var(done);
} }
void od_register_powersave_bias_handler(unsigned int (*f) void od_register_powersave_bias_handler(unsigned int (*f)
......
...@@ -51,7 +51,7 @@ static const u16 cpufreq_mtk_offsets[REG_ARRAY_SIZE] = { ...@@ -51,7 +51,7 @@ static const u16 cpufreq_mtk_offsets[REG_ARRAY_SIZE] = {
}; };
static int __maybe_unused static int __maybe_unused
mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *mW, mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *uW,
unsigned long *KHz) unsigned long *KHz)
{ {
struct mtk_cpufreq_data *data; struct mtk_cpufreq_data *data;
...@@ -71,8 +71,9 @@ mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *mW, ...@@ -71,8 +71,9 @@ mtk_cpufreq_get_cpu_power(struct device *cpu_dev, unsigned long *mW,
i--; i--;
*KHz = data->table[i].frequency; *KHz = data->table[i].frequency;
*mW = readl_relaxed(data->reg_bases[REG_EM_POWER_TBL] + /* Provide micro-Watts value to the Energy Model */
i * LUT_ROW_SIZE) / 1000; *uW = readl_relaxed(data->reg_bases[REG_EM_POWER_TBL] +
i * LUT_ROW_SIZE);
return 0; return 0;
} }
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/scmi_protocol.h> #include <linux/scmi_protocol.h>
#include <linux/types.h> #include <linux/types.h>
#include <linux/units.h>
struct scmi_data { struct scmi_data {
int domain_id; int domain_id;
...@@ -99,6 +100,7 @@ static int __maybe_unused ...@@ -99,6 +100,7 @@ static int __maybe_unused
scmi_get_cpu_power(struct device *cpu_dev, unsigned long *power, scmi_get_cpu_power(struct device *cpu_dev, unsigned long *power,
unsigned long *KHz) unsigned long *KHz)
{ {
enum scmi_power_scale power_scale = perf_ops->power_scale_get(ph);
unsigned long Hz; unsigned long Hz;
int ret, domain; int ret, domain;
...@@ -112,6 +114,10 @@ scmi_get_cpu_power(struct device *cpu_dev, unsigned long *power, ...@@ -112,6 +114,10 @@ scmi_get_cpu_power(struct device *cpu_dev, unsigned long *power,
if (ret) if (ret)
return ret; return ret;
/* Convert the power to uW if it is mW (ignore bogoW) */
if (power_scale == SCMI_POWER_MILLIWATTS)
*power *= MICROWATT_PER_MILLIWATT;
/* The EM framework specifies the frequency in KHz. */ /* The EM framework specifies the frequency in KHz. */
*KHz = Hz / 1000; *KHz = Hz / 1000;
...@@ -249,8 +255,9 @@ static int scmi_cpufreq_exit(struct cpufreq_policy *policy) ...@@ -249,8 +255,9 @@ static int scmi_cpufreq_exit(struct cpufreq_policy *policy)
static void scmi_cpufreq_register_em(struct cpufreq_policy *policy) static void scmi_cpufreq_register_em(struct cpufreq_policy *policy)
{ {
struct em_data_callback em_cb = EM_DATA_CB(scmi_get_cpu_power); struct em_data_callback em_cb = EM_DATA_CB(scmi_get_cpu_power);
bool power_scale_mw = perf_ops->power_scale_mw_get(ph); enum scmi_power_scale power_scale = perf_ops->power_scale_get(ph);
struct scmi_data *priv = policy->driver_data; struct scmi_data *priv = policy->driver_data;
bool em_power_scale = false;
/* /*
* This callback will be called for each policy, but we don't need to * This callback will be called for each policy, but we don't need to
...@@ -262,9 +269,13 @@ static void scmi_cpufreq_register_em(struct cpufreq_policy *policy) ...@@ -262,9 +269,13 @@ static void scmi_cpufreq_register_em(struct cpufreq_policy *policy)
if (!priv->nr_opp) if (!priv->nr_opp)
return; return;
if (power_scale == SCMI_POWER_MILLIWATTS
|| power_scale == SCMI_POWER_MICROWATTS)
em_power_scale = true;
em_dev_register_perf_domain(get_cpu_device(policy->cpu), priv->nr_opp, em_dev_register_perf_domain(get_cpu_device(policy->cpu), priv->nr_opp,
&em_cb, priv->opp_shared_cpus, &em_cb, priv->opp_shared_cpus,
power_scale_mw); em_power_scale);
} }
static struct cpufreq_driver scmi_cpufreq_driver = { static struct cpufreq_driver scmi_cpufreq_driver = {
......
...@@ -19,6 +19,7 @@ ...@@ -19,6 +19,7 @@
#include <linux/sched.h> #include <linux/sched.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/kvm_para.h> #include <linux/kvm_para.h>
#include <trace/events/power.h>
static unsigned int guest_halt_poll_ns __read_mostly = 200000; static unsigned int guest_halt_poll_ns __read_mostly = 200000;
module_param(guest_halt_poll_ns, uint, 0644); module_param(guest_halt_poll_ns, uint, 0644);
...@@ -90,6 +91,7 @@ static void adjust_poll_limit(struct cpuidle_device *dev, u64 block_ns) ...@@ -90,6 +91,7 @@ static void adjust_poll_limit(struct cpuidle_device *dev, u64 block_ns)
if (val > guest_halt_poll_ns) if (val > guest_halt_poll_ns)
val = guest_halt_poll_ns; val = guest_halt_poll_ns;
trace_guest_halt_poll_ns_grow(val, dev->poll_limit_ns);
dev->poll_limit_ns = val; dev->poll_limit_ns = val;
} else if (block_ns > guest_halt_poll_ns && } else if (block_ns > guest_halt_poll_ns &&
guest_halt_poll_allow_shrink) { guest_halt_poll_allow_shrink) {
...@@ -100,6 +102,7 @@ static void adjust_poll_limit(struct cpuidle_device *dev, u64 block_ns) ...@@ -100,6 +102,7 @@ static void adjust_poll_limit(struct cpuidle_device *dev, u64 block_ns)
val = 0; val = 0;
else else
val /= shrink; val /= shrink;
trace_guest_halt_poll_ns_shrink(val, dev->poll_limit_ns);
dev->poll_limit_ns = val; dev->poll_limit_ns = val;
} }
} }
......
...@@ -120,6 +120,16 @@ config ARM_TEGRA_DEVFREQ ...@@ -120,6 +120,16 @@ config ARM_TEGRA_DEVFREQ
It reads ACTMON counters of memory controllers and adjusts the It reads ACTMON counters of memory controllers and adjusts the
operating frequencies and voltages with OPP support. operating frequencies and voltages with OPP support.
config ARM_MEDIATEK_CCI_DEVFREQ
tristate "MEDIATEK CCI DEVFREQ Driver"
depends on ARM_MEDIATEK_CPUFREQ || COMPILE_TEST
select DEVFREQ_GOV_PASSIVE
help
This adds a devfreq driver for MediaTek Cache Coherent Interconnect
which is shared the same regulators with the cpu cluster. It can track
buck voltages and update a proper CCI frequency. Use the notification
to get the regulator status.
config ARM_RK3399_DMC_DEVFREQ config ARM_RK3399_DMC_DEVFREQ
tristate "ARM RK3399 DMC DEVFREQ Driver" tristate "ARM RK3399 DMC DEVFREQ Driver"
depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \ depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \
......
...@@ -11,6 +11,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o ...@@ -11,6 +11,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o
obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o
obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ) += imx-bus.o obj-$(CONFIG_ARM_IMX_BUS_DEVFREQ) += imx-bus.o
obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ) += imx8m-ddrc.o obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ) += imx8m-ddrc.o
obj-$(CONFIG_ARM_MEDIATEK_CCI_DEVFREQ) += mtk-cci-devfreq.o
obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o
obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ) += sun8i-a33-mbus.o obj-$(CONFIG_ARM_SUN8I_A33_MBUS_DEVFREQ) += sun8i-a33-mbus.o
obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o
......
...@@ -696,6 +696,8 @@ static int qos_notifier_call(struct devfreq *devfreq) ...@@ -696,6 +696,8 @@ static int qos_notifier_call(struct devfreq *devfreq)
/** /**
* qos_min_notifier_call() - Callback for QoS min_freq changes. * qos_min_notifier_call() - Callback for QoS min_freq changes.
* @nb: Should be devfreq->nb_min * @nb: Should be devfreq->nb_min
* @val: not used
* @ptr: not used
*/ */
static int qos_min_notifier_call(struct notifier_block *nb, static int qos_min_notifier_call(struct notifier_block *nb,
unsigned long val, void *ptr) unsigned long val, void *ptr)
...@@ -706,6 +708,8 @@ static int qos_min_notifier_call(struct notifier_block *nb, ...@@ -706,6 +708,8 @@ static int qos_min_notifier_call(struct notifier_block *nb,
/** /**
* qos_max_notifier_call() - Callback for QoS max_freq changes. * qos_max_notifier_call() - Callback for QoS max_freq changes.
* @nb: Should be devfreq->nb_max * @nb: Should be devfreq->nb_max
* @val: not used
* @ptr: not used
*/ */
static int qos_max_notifier_call(struct notifier_block *nb, static int qos_max_notifier_call(struct notifier_block *nb,
unsigned long val, void *ptr) unsigned long val, void *ptr)
......
...@@ -59,7 +59,7 @@ static int imx_bus_init_icc(struct device *dev) ...@@ -59,7 +59,7 @@ static int imx_bus_init_icc(struct device *dev)
struct imx_bus *priv = dev_get_drvdata(dev); struct imx_bus *priv = dev_get_drvdata(dev);
const char *icc_driver_name; const char *icc_driver_name;
if (!of_get_property(dev->of_node, "#interconnect-cells", 0)) if (!of_get_property(dev->of_node, "#interconnect-cells", NULL))
return 0; return 0;
if (!IS_ENABLED(CONFIG_INTERCONNECT_IMX)) { if (!IS_ENABLED(CONFIG_INTERCONNECT_IMX)) {
dev_warn(dev, "imx interconnect drivers disabled\n"); dev_warn(dev, "imx interconnect drivers disabled\n");
......
This diff is collapsed.
...@@ -922,8 +922,10 @@ static int tegra_devfreq_probe(struct platform_device *pdev) ...@@ -922,8 +922,10 @@ static int tegra_devfreq_probe(struct platform_device *pdev)
devfreq = devm_devfreq_add_device(&pdev->dev, &tegra_devfreq_profile, devfreq = devm_devfreq_add_device(&pdev->dev, &tegra_devfreq_profile,
"tegra_actmon", NULL); "tegra_actmon", NULL);
if (IS_ERR(devfreq)) if (IS_ERR(devfreq)) {
dev_err(&pdev->dev, "Failed to add device: %pe\n", devfreq);
return PTR_ERR(devfreq); return PTR_ERR(devfreq);
}
return 0; return 0;
} }
......
...@@ -140,8 +140,7 @@ struct perf_dom_info { ...@@ -140,8 +140,7 @@ struct perf_dom_info {
struct scmi_perf_info { struct scmi_perf_info {
u32 version; u32 version;
int num_domains; int num_domains;
bool power_scale_mw; enum scmi_power_scale power_scale;
bool power_scale_uw;
u64 stats_addr; u64 stats_addr;
u32 stats_size; u32 stats_size;
struct perf_dom_info *dom_info; struct perf_dom_info *dom_info;
...@@ -171,9 +170,13 @@ static int scmi_perf_attributes_get(const struct scmi_protocol_handle *ph, ...@@ -171,9 +170,13 @@ static int scmi_perf_attributes_get(const struct scmi_protocol_handle *ph,
u16 flags = le16_to_cpu(attr->flags); u16 flags = le16_to_cpu(attr->flags);
pi->num_domains = le16_to_cpu(attr->num_domains); pi->num_domains = le16_to_cpu(attr->num_domains);
pi->power_scale_mw = POWER_SCALE_IN_MILLIWATT(flags);
if (POWER_SCALE_IN_MILLIWATT(flags))
pi->power_scale = SCMI_POWER_MILLIWATTS;
if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3) if (PROTOCOL_REV_MAJOR(pi->version) >= 0x3)
pi->power_scale_uw = POWER_SCALE_IN_MICROWATT(flags); if (POWER_SCALE_IN_MICROWATT(flags))
pi->power_scale = SCMI_POWER_MICROWATTS;
pi->stats_addr = le32_to_cpu(attr->stats_addr_low) | pi->stats_addr = le32_to_cpu(attr->stats_addr_low) |
(u64)le32_to_cpu(attr->stats_addr_high) << 32; (u64)le32_to_cpu(attr->stats_addr_high) << 32;
pi->stats_size = le32_to_cpu(attr->stats_size); pi->stats_size = le32_to_cpu(attr->stats_size);
...@@ -675,11 +678,12 @@ static bool scmi_fast_switch_possible(const struct scmi_protocol_handle *ph, ...@@ -675,11 +678,12 @@ static bool scmi_fast_switch_possible(const struct scmi_protocol_handle *ph,
return dom->fc_info && dom->fc_info[PERF_FC_LEVEL].set_addr; return dom->fc_info && dom->fc_info[PERF_FC_LEVEL].set_addr;
} }
static bool scmi_power_scale_mw_get(const struct scmi_protocol_handle *ph) static enum scmi_power_scale
scmi_power_scale_get(const struct scmi_protocol_handle *ph)
{ {
struct scmi_perf_info *pi = ph->get_priv(ph); struct scmi_perf_info *pi = ph->get_priv(ph);
return pi->power_scale_mw; return pi->power_scale;
} }
static const struct scmi_perf_proto_ops perf_proto_ops = { static const struct scmi_perf_proto_ops perf_proto_ops = {
...@@ -694,7 +698,7 @@ static const struct scmi_perf_proto_ops perf_proto_ops = { ...@@ -694,7 +698,7 @@ static const struct scmi_perf_proto_ops perf_proto_ops = {
.freq_get = scmi_dvfs_freq_get, .freq_get = scmi_dvfs_freq_get,
.est_power_get = scmi_dvfs_est_power_get, .est_power_get = scmi_dvfs_est_power_get,
.fast_switch_possible = scmi_fast_switch_possible, .fast_switch_possible = scmi_fast_switch_possible,
.power_scale_mw_get = scmi_power_scale_mw_get, .power_scale_get = scmi_power_scale_get,
}; };
static int scmi_perf_set_notify_enabled(const struct scmi_protocol_handle *ph, static int scmi_perf_set_notify_enabled(const struct scmi_protocol_handle *ph,
......
...@@ -928,16 +928,6 @@ static struct cpuidle_state adl_l_cstates[] __initdata = { ...@@ -928,16 +928,6 @@ static struct cpuidle_state adl_l_cstates[] __initdata = {
.enter = NULL } .enter = NULL }
}; };
/*
* On Sapphire Rapids Xeon C1 has to be disabled if C1E is enabled, and vice
* versa. On SPR C1E is enabled only if "C1E promotion" bit is set in
* MSR_IA32_POWER_CTL. But in this case there effectively no C1, because C1
* requests are promoted to C1E. If the "C1E promotion" bit is cleared, then
* both C1 and C1E requests end up with C1, so there is effectively no C1E.
*
* By default we enable C1 and disable C1E by marking it with
* 'CPUIDLE_FLAG_UNUSABLE'.
*/
static struct cpuidle_state spr_cstates[] __initdata = { static struct cpuidle_state spr_cstates[] __initdata = {
{ {
.name = "C1", .name = "C1",
...@@ -950,8 +940,7 @@ static struct cpuidle_state spr_cstates[] __initdata = { ...@@ -950,8 +940,7 @@ static struct cpuidle_state spr_cstates[] __initdata = {
{ {
.name = "C1E", .name = "C1E",
.desc = "MWAIT 0x01", .desc = "MWAIT 0x01",
.flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE | .flags = MWAIT2flg(0x01) | CPUIDLE_FLAG_ALWAYS_ENABLE,
CPUIDLE_FLAG_UNUSABLE,
.exit_latency = 2, .exit_latency = 2,
.target_residency = 4, .target_residency = 4,
.enter = &intel_idle, .enter = &intel_idle,
...@@ -1774,17 +1763,6 @@ static void __init spr_idle_state_table_update(void) ...@@ -1774,17 +1763,6 @@ static void __init spr_idle_state_table_update(void)
{ {
unsigned long long msr; unsigned long long msr;
/* Check if user prefers C1E over C1. */
if ((preferred_states_mask & BIT(2)) &&
!(preferred_states_mask & BIT(1))) {
/* Disable C1 and enable C1E. */
spr_cstates[0].flags |= CPUIDLE_FLAG_UNUSABLE;
spr_cstates[1].flags &= ~CPUIDLE_FLAG_UNUSABLE;
/* Enable C1E using the "C1E promotion" bit. */
c1e_promotion = C1E_PROMOTION_ENABLE;
}
/* /*
* By default, the C6 state assumes the worst-case scenario of package * By default, the C6 state assumes the worst-case scenario of package
* C6. However, if PC6 is disabled, we update the numbers to match * C6. However, if PC6 is disabled, we update the numbers to match
......
...@@ -1443,12 +1443,12 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node); ...@@ -1443,12 +1443,12 @@ EXPORT_SYMBOL_GPL(dev_pm_opp_get_of_node);
* It provides the power used by @dev at @kHz if it is the frequency of an * It provides the power used by @dev at @kHz if it is the frequency of an
* existing OPP, or at the frequency of the first OPP above @kHz otherwise * existing OPP, or at the frequency of the first OPP above @kHz otherwise
* (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled * (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled
* frequency and @mW to the associated power. * frequency and @uW to the associated power.
* *
* Returns 0 on success or a proper -EINVAL value in case of error. * Returns 0 on success or a proper -EINVAL value in case of error.
*/ */
static int __maybe_unused static int __maybe_unused
_get_dt_power(struct device *dev, unsigned long *mW, unsigned long *kHz) _get_dt_power(struct device *dev, unsigned long *uW, unsigned long *kHz)
{ {
struct dev_pm_opp *opp; struct dev_pm_opp *opp;
unsigned long opp_freq, opp_power; unsigned long opp_freq, opp_power;
...@@ -1465,7 +1465,7 @@ _get_dt_power(struct device *dev, unsigned long *mW, unsigned long *kHz) ...@@ -1465,7 +1465,7 @@ _get_dt_power(struct device *dev, unsigned long *mW, unsigned long *kHz)
return -EINVAL; return -EINVAL;
*kHz = opp_freq / 1000; *kHz = opp_freq / 1000;
*mW = opp_power / 1000; *uW = opp_power;
return 0; return 0;
} }
...@@ -1475,14 +1475,14 @@ _get_dt_power(struct device *dev, unsigned long *mW, unsigned long *kHz) ...@@ -1475,14 +1475,14 @@ _get_dt_power(struct device *dev, unsigned long *mW, unsigned long *kHz)
* This computes the power estimated by @dev at @kHz if it is the frequency * This computes the power estimated by @dev at @kHz if it is the frequency
* of an existing OPP, or at the frequency of the first OPP above @kHz otherwise * of an existing OPP, or at the frequency of the first OPP above @kHz otherwise
* (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled * (see dev_pm_opp_find_freq_ceil()). This function updates @kHz to the ceiled
* frequency and @mW to the associated power. The power is estimated as * frequency and @uW to the associated power. The power is estimated as
* P = C * V^2 * f with C being the device's capacitance and V and f * P = C * V^2 * f with C being the device's capacitance and V and f
* respectively the voltage and frequency of the OPP. * respectively the voltage and frequency of the OPP.
* *
* Returns -EINVAL if the power calculation failed because of missing * Returns -EINVAL if the power calculation failed because of missing
* parameters, 0 otherwise. * parameters, 0 otherwise.
*/ */
static int __maybe_unused _get_power(struct device *dev, unsigned long *mW, static int __maybe_unused _get_power(struct device *dev, unsigned long *uW,
unsigned long *kHz) unsigned long *kHz)
{ {
struct dev_pm_opp *opp; struct dev_pm_opp *opp;
...@@ -1512,9 +1512,10 @@ static int __maybe_unused _get_power(struct device *dev, unsigned long *mW, ...@@ -1512,9 +1512,10 @@ static int __maybe_unused _get_power(struct device *dev, unsigned long *mW,
return -EINVAL; return -EINVAL;
tmp = (u64)cap * mV * mV * (Hz / 1000000); tmp = (u64)cap * mV * mV * (Hz / 1000000);
do_div(tmp, 1000000000); /* Provide power in micro-Watts */
do_div(tmp, 1000000);
*mW = (unsigned long)tmp; *uW = (unsigned long)tmp;
*kHz = Hz / 1000; *kHz = Hz / 1000;
return 0; return 0;
......
...@@ -53,7 +53,7 @@ static u64 set_pd_power_limit(struct dtpm *dtpm, u64 power_limit) ...@@ -53,7 +53,7 @@ static u64 set_pd_power_limit(struct dtpm *dtpm, u64 power_limit)
for (i = 0; i < pd->nr_perf_states; i++) { for (i = 0; i < pd->nr_perf_states; i++) {
power = pd->table[i].power * MICROWATT_PER_MILLIWATT * nr_cpus; power = pd->table[i].power * nr_cpus;
if (power > power_limit) if (power > power_limit)
break; break;
...@@ -63,8 +63,7 @@ static u64 set_pd_power_limit(struct dtpm *dtpm, u64 power_limit) ...@@ -63,8 +63,7 @@ static u64 set_pd_power_limit(struct dtpm *dtpm, u64 power_limit)
freq_qos_update_request(&dtpm_cpu->qos_req, freq); freq_qos_update_request(&dtpm_cpu->qos_req, freq);
power_limit = pd->table[i - 1].power * power_limit = pd->table[i - 1].power * nr_cpus;
MICROWATT_PER_MILLIWATT * nr_cpus;
return power_limit; return power_limit;
} }
......
...@@ -1109,6 +1109,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = { ...@@ -1109,6 +1109,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = {
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, &rapl_defaults_core), X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_L, &rapl_defaults_core),
X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, &rapl_defaults_core), X86_MATCH_INTEL_FAM6_MODEL(ALDERLAKE_N, &rapl_defaults_core),
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, &rapl_defaults_core), X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE, &rapl_defaults_core),
X86_MATCH_INTEL_FAM6_MODEL(RAPTORLAKE_P, &rapl_defaults_core),
X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, &rapl_defaults_spr_server), X86_MATCH_INTEL_FAM6_MODEL(SAPPHIRERAPIDS_X, &rapl_defaults_spr_server),
X86_MATCH_INTEL_FAM6_MODEL(LAKEFIELD, &rapl_defaults_core), X86_MATCH_INTEL_FAM6_MODEL(LAKEFIELD, &rapl_defaults_core),
......
...@@ -140,7 +140,9 @@ static const struct x86_cpu_id pl4_support_ids[] = { ...@@ -140,7 +140,9 @@ static const struct x86_cpu_id pl4_support_ids[] = {
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_TIGERLAKE_L, X86_FEATURE_ANY }, { X86_VENDOR_INTEL, 6, INTEL_FAM6_TIGERLAKE_L, X86_FEATURE_ANY },
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE, X86_FEATURE_ANY }, { X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE, X86_FEATURE_ANY },
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE_L, X86_FEATURE_ANY }, { X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE_L, X86_FEATURE_ANY },
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_ALDERLAKE_N, X86_FEATURE_ANY },
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_RAPTORLAKE, X86_FEATURE_ANY }, { X86_VENDOR_INTEL, 6, INTEL_FAM6_RAPTORLAKE, X86_FEATURE_ANY },
{ X86_VENDOR_INTEL, 6, INTEL_FAM6_RAPTORLAKE_P, X86_FEATURE_ANY },
{} {}
}; };
......
...@@ -21,6 +21,7 @@ ...@@ -21,6 +21,7 @@
#include <linux/pm_qos.h> #include <linux/pm_qos.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/thermal.h> #include <linux/thermal.h>
#include <linux/units.h>
#include <trace/events/thermal.h> #include <trace/events/thermal.h>
...@@ -101,6 +102,7 @@ static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_cdev, ...@@ -101,6 +102,7 @@ static unsigned long get_level(struct cpufreq_cooling_device *cpufreq_cdev,
static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_cdev, static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_cdev,
u32 freq) u32 freq)
{ {
unsigned long power_mw;
int i; int i;
for (i = cpufreq_cdev->max_level - 1; i >= 0; i--) { for (i = cpufreq_cdev->max_level - 1; i >= 0; i--) {
...@@ -108,16 +110,23 @@ static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_cdev, ...@@ -108,16 +110,23 @@ static u32 cpu_freq_to_power(struct cpufreq_cooling_device *cpufreq_cdev,
break; break;
} }
return cpufreq_cdev->em->table[i + 1].power; power_mw = cpufreq_cdev->em->table[i + 1].power;
power_mw /= MICROWATT_PER_MILLIWATT;
return power_mw;
} }
static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev, static u32 cpu_power_to_freq(struct cpufreq_cooling_device *cpufreq_cdev,
u32 power) u32 power)
{ {
unsigned long em_power_mw;
int i; int i;
for (i = cpufreq_cdev->max_level; i > 0; i--) { for (i = cpufreq_cdev->max_level; i > 0; i--) {
if (power >= cpufreq_cdev->em->table[i].power) /* Convert EM power to milli-Watts to make safe comparison */
em_power_mw = cpufreq_cdev->em->table[i].power;
em_power_mw /= MICROWATT_PER_MILLIWATT;
if (power >= em_power_mw)
break; break;
} }
......
...@@ -200,7 +200,11 @@ static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cd ...@@ -200,7 +200,11 @@ static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cd
res = dfc->power_ops->get_real_power(df, power, freq, voltage); res = dfc->power_ops->get_real_power(df, power, freq, voltage);
if (!res) { if (!res) {
state = dfc->capped_state; state = dfc->capped_state;
/* Convert EM power into milli-Watts first */
dfc->res_util = dfc->em_pd->table[state].power; dfc->res_util = dfc->em_pd->table[state].power;
dfc->res_util /= MICROWATT_PER_MILLIWATT;
dfc->res_util *= SCALE_ERROR_MITIGATION; dfc->res_util *= SCALE_ERROR_MITIGATION;
if (*power > 1) if (*power > 1)
...@@ -218,8 +222,10 @@ static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cd ...@@ -218,8 +222,10 @@ static int devfreq_cooling_get_requested_power(struct thermal_cooling_device *cd
_normalize_load(&status); _normalize_load(&status);
/* Scale power for utilization */ /* Convert EM power into milli-Watts first */
*power = dfc->em_pd->table[perf_idx].power; *power = dfc->em_pd->table[perf_idx].power;
*power /= MICROWATT_PER_MILLIWATT;
/* Scale power for utilization */
*power *= status.busy_time; *power *= status.busy_time;
*power >>= 10; *power >>= 10;
} }
...@@ -244,6 +250,7 @@ static int devfreq_cooling_state2power(struct thermal_cooling_device *cdev, ...@@ -244,6 +250,7 @@ static int devfreq_cooling_state2power(struct thermal_cooling_device *cdev,
perf_idx = dfc->max_state - state; perf_idx = dfc->max_state - state;
*power = dfc->em_pd->table[perf_idx].power; *power = dfc->em_pd->table[perf_idx].power;
*power /= MICROWATT_PER_MILLIWATT;
return 0; return 0;
} }
...@@ -254,7 +261,7 @@ static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev, ...@@ -254,7 +261,7 @@ static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev,
struct devfreq_cooling_device *dfc = cdev->devdata; struct devfreq_cooling_device *dfc = cdev->devdata;
struct devfreq *df = dfc->devfreq; struct devfreq *df = dfc->devfreq;
struct devfreq_dev_status status; struct devfreq_dev_status status;
unsigned long freq; unsigned long freq, em_power_mw;
s32 est_power; s32 est_power;
int i; int i;
...@@ -279,9 +286,13 @@ static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev, ...@@ -279,9 +286,13 @@ static int devfreq_cooling_power2state(struct thermal_cooling_device *cdev,
* Find the first cooling state that is within the power * Find the first cooling state that is within the power
* budget. The EM power table is sorted ascending. * budget. The EM power table is sorted ascending.
*/ */
for (i = dfc->max_state; i > 0; i--) for (i = dfc->max_state; i > 0; i--) {
if (est_power >= dfc->em_pd->table[i].power) /* Convert EM power to milli-Watts to make safe comparison */
em_power_mw = dfc->em_pd->table[i].power;
em_power_mw /= MICROWATT_PER_MILLIWATT;
if (est_power >= em_power_mw)
break; break;
}
*state = dfc->max_state - i; *state = dfc->max_state - i;
dfc->capped_state = *state; dfc->capped_state = *state;
......
...@@ -62,7 +62,7 @@ struct em_perf_domain { ...@@ -62,7 +62,7 @@ struct em_perf_domain {
/* /*
* em_perf_domain flags: * em_perf_domain flags:
* *
* EM_PERF_DOMAIN_MILLIWATTS: The power values are in milli-Watts or some * EM_PERF_DOMAIN_MICROWATTS: The power values are in micro-Watts or some
* other scale. * other scale.
* *
* EM_PERF_DOMAIN_SKIP_INEFFICIENCIES: Skip inefficient states when estimating * EM_PERF_DOMAIN_SKIP_INEFFICIENCIES: Skip inefficient states when estimating
...@@ -71,7 +71,7 @@ struct em_perf_domain { ...@@ -71,7 +71,7 @@ struct em_perf_domain {
* EM_PERF_DOMAIN_ARTIFICIAL: The power values are artificial and might be * EM_PERF_DOMAIN_ARTIFICIAL: The power values are artificial and might be
* created by platform missing real power information * created by platform missing real power information
*/ */
#define EM_PERF_DOMAIN_MILLIWATTS BIT(0) #define EM_PERF_DOMAIN_MICROWATTS BIT(0)
#define EM_PERF_DOMAIN_SKIP_INEFFICIENCIES BIT(1) #define EM_PERF_DOMAIN_SKIP_INEFFICIENCIES BIT(1)
#define EM_PERF_DOMAIN_ARTIFICIAL BIT(2) #define EM_PERF_DOMAIN_ARTIFICIAL BIT(2)
...@@ -79,22 +79,44 @@ struct em_perf_domain { ...@@ -79,22 +79,44 @@ struct em_perf_domain {
#define em_is_artificial(em) ((em)->flags & EM_PERF_DOMAIN_ARTIFICIAL) #define em_is_artificial(em) ((em)->flags & EM_PERF_DOMAIN_ARTIFICIAL)
#ifdef CONFIG_ENERGY_MODEL #ifdef CONFIG_ENERGY_MODEL
#define EM_MAX_POWER 0xFFFF /*
* The max power value in micro-Watts. The limit of 64 Watts is set as
* a safety net to not overflow multiplications on 32bit platforms. The
* 32bit value limit for total Perf Domain power implies a limit of
* maximum CPUs in such domain to 64.
*/
#define EM_MAX_POWER (64000000) /* 64 Watts */
/*
* To avoid possible energy estimation overflow on 32bit machines add
* limits to number of CPUs in the Perf. Domain.
* We are safe on 64bit machine, thus some big number.
*/
#ifdef CONFIG_64BIT
#define EM_MAX_NUM_CPUS 4096
#else
#define EM_MAX_NUM_CPUS 16
#endif
/* /*
* Increase resolution of energy estimation calculations for 64-bit * To avoid an overflow on 32bit machines while calculating the energy
* architectures. The extra resolution improves decision made by EAS for the * use a different order in the operation. First divide by the 'cpu_scale'
* task placement when two Performance Domains might provide similar energy * which would reduce big value stored in the 'cost' field, then multiply by
* estimation values (w/o better resolution the values could be equal). * the 'sum_util'. This would allow to handle existing platforms, which have
* e.g. power ~1.3 Watt at max freq, so the 'cost' value > 1mln micro-Watts.
* In such scenario, where there are 4 CPUs in the Perf. Domain the 'sum_util'
* could be 4096, then multiplication: 'cost' * 'sum_util' would overflow.
* This reordering of operations has some limitations, we lose small
* precision in the estimation (comparing to 64bit platform w/o reordering).
* *
* We increase resolution only if we have enough bits to allow this increased * We are safe on 64bit machine.
* resolution (i.e. 64-bit). The costs for increasing resolution when 32-bit
* are pretty high and the returns do not justify the increased costs.
*/ */
#ifdef CONFIG_64BIT #ifdef CONFIG_64BIT
#define em_scale_power(p) ((p) * 1000) #define em_estimate_energy(cost, sum_util, scale_cpu) \
(((cost) * (sum_util)) / (scale_cpu))
#else #else
#define em_scale_power(p) (p) #define em_estimate_energy(cost, sum_util, scale_cpu) \
(((cost) / (scale_cpu)) * (sum_util))
#endif #endif
struct em_data_callback { struct em_data_callback {
...@@ -112,7 +134,7 @@ struct em_data_callback { ...@@ -112,7 +134,7 @@ struct em_data_callback {
* and frequency. * and frequency.
* *
* In case of CPUs, the power is the one of a single CPU in the domain, * In case of CPUs, the power is the one of a single CPU in the domain,
* expressed in milli-Watts or an abstract scale. It is expected to * expressed in micro-Watts or an abstract scale. It is expected to
* fit in the [0, EM_MAX_POWER] range. * fit in the [0, EM_MAX_POWER] range.
* *
* Return 0 on success. * Return 0 on success.
...@@ -148,7 +170,7 @@ struct em_perf_domain *em_cpu_get(int cpu); ...@@ -148,7 +170,7 @@ struct em_perf_domain *em_cpu_get(int cpu);
struct em_perf_domain *em_pd_get(struct device *dev); struct em_perf_domain *em_pd_get(struct device *dev);
int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
struct em_data_callback *cb, cpumask_t *span, struct em_data_callback *cb, cpumask_t *span,
bool milliwatts); bool microwatts);
void em_dev_unregister_perf_domain(struct device *dev); void em_dev_unregister_perf_domain(struct device *dev);
/** /**
...@@ -273,7 +295,7 @@ static inline unsigned long em_cpu_energy(struct em_perf_domain *pd, ...@@ -273,7 +295,7 @@ static inline unsigned long em_cpu_energy(struct em_perf_domain *pd,
* pd_nrg = ------------------------ (4) * pd_nrg = ------------------------ (4)
* scale_cpu * scale_cpu
*/ */
return ps->cost * sum_util / scale_cpu; return em_estimate_energy(ps->cost, sum_util, scale_cpu);
} }
/** /**
...@@ -297,7 +319,7 @@ struct em_data_callback {}; ...@@ -297,7 +319,7 @@ struct em_data_callback {};
static inline static inline
int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
struct em_data_callback *cb, cpumask_t *span, struct em_data_callback *cb, cpumask_t *span,
bool milliwatts) bool microwatts)
{ {
return -EINVAL; return -EINVAL;
} }
......
...@@ -109,7 +109,6 @@ extern struct wakeup_source *wakeup_sources_walk_next(struct wakeup_source *ws); ...@@ -109,7 +109,6 @@ extern struct wakeup_source *wakeup_sources_walk_next(struct wakeup_source *ws);
extern int device_wakeup_enable(struct device *dev); extern int device_wakeup_enable(struct device *dev);
extern int device_wakeup_disable(struct device *dev); extern int device_wakeup_disable(struct device *dev);
extern void device_set_wakeup_capable(struct device *dev, bool capable); extern void device_set_wakeup_capable(struct device *dev, bool capable);
extern int device_init_wakeup(struct device *dev, bool val);
extern int device_set_wakeup_enable(struct device *dev, bool enable); extern int device_set_wakeup_enable(struct device *dev, bool enable);
extern void __pm_stay_awake(struct wakeup_source *ws); extern void __pm_stay_awake(struct wakeup_source *ws);
extern void pm_stay_awake(struct device *dev); extern void pm_stay_awake(struct device *dev);
...@@ -167,13 +166,6 @@ static inline int device_set_wakeup_enable(struct device *dev, bool enable) ...@@ -167,13 +166,6 @@ static inline int device_set_wakeup_enable(struct device *dev, bool enable)
return 0; return 0;
} }
static inline int device_init_wakeup(struct device *dev, bool val)
{
device_set_wakeup_capable(dev, val);
device_set_wakeup_enable(dev, val);
return 0;
}
static inline bool device_may_wakeup(struct device *dev) static inline bool device_may_wakeup(struct device *dev)
{ {
return dev->power.can_wakeup && dev->power.should_wakeup; return dev->power.can_wakeup && dev->power.should_wakeup;
...@@ -217,4 +209,27 @@ static inline void pm_wakeup_hard_event(struct device *dev) ...@@ -217,4 +209,27 @@ static inline void pm_wakeup_hard_event(struct device *dev)
return pm_wakeup_dev_event(dev, 0, true); return pm_wakeup_dev_event(dev, 0, true);
} }
/**
* device_init_wakeup - Device wakeup initialization.
* @dev: Device to handle.
* @enable: Whether or not to enable @dev as a wakeup device.
*
* By default, most devices should leave wakeup disabled. The exceptions are
* devices that everyone expects to be wakeup sources: keyboards, power buttons,
* possibly network interfaces, etc. Also, devices that don't generate their
* own wakeup requests but merely forward requests from one bus to another
* (like PCI bridges) should have wakeup enabled by default.
*/
static inline int device_init_wakeup(struct device *dev, bool enable)
{
if (enable) {
device_set_wakeup_capable(dev, true);
return device_wakeup_enable(dev);
} else {
device_wakeup_disable(dev);
device_set_wakeup_capable(dev, false);
return 0;
}
}
#endif /* _LINUX_PM_WAKEUP_H */ #endif /* _LINUX_PM_WAKEUP_H */
...@@ -60,6 +60,12 @@ struct scmi_clock_info { ...@@ -60,6 +60,12 @@ struct scmi_clock_info {
}; };
}; };
enum scmi_power_scale {
SCMI_POWER_BOGOWATTS,
SCMI_POWER_MILLIWATTS,
SCMI_POWER_MICROWATTS
};
struct scmi_handle; struct scmi_handle;
struct scmi_device; struct scmi_device;
struct scmi_protocol_handle; struct scmi_protocol_handle;
...@@ -135,7 +141,7 @@ struct scmi_perf_proto_ops { ...@@ -135,7 +141,7 @@ struct scmi_perf_proto_ops {
unsigned long *rate, unsigned long *power); unsigned long *rate, unsigned long *power);
bool (*fast_switch_possible)(const struct scmi_protocol_handle *ph, bool (*fast_switch_possible)(const struct scmi_protocol_handle *ph,
struct device *dev); struct device *dev);
bool (*power_scale_mw_get)(const struct scmi_protocol_handle *ph); enum scmi_power_scale (*power_scale_get)(const struct scmi_protocol_handle *ph);
}; };
/** /**
......
...@@ -500,6 +500,35 @@ DEFINE_EVENT(dev_pm_qos_request, dev_pm_qos_remove_request, ...@@ -500,6 +500,35 @@ DEFINE_EVENT(dev_pm_qos_request, dev_pm_qos_remove_request,
TP_ARGS(name, type, new_value) TP_ARGS(name, type, new_value)
); );
TRACE_EVENT(guest_halt_poll_ns,
TP_PROTO(bool grow, unsigned int new, unsigned int old),
TP_ARGS(grow, new, old),
TP_STRUCT__entry(
__field(bool, grow)
__field(unsigned int, new)
__field(unsigned int, old)
),
TP_fast_assign(
__entry->grow = grow;
__entry->new = new;
__entry->old = old;
),
TP_printk("halt_poll_ns %u (%s %u)",
__entry->new,
__entry->grow ? "grow" : "shrink",
__entry->old)
);
#define trace_guest_halt_poll_ns_grow(new, old) \
trace_guest_halt_poll_ns(true, new, old)
#define trace_guest_halt_poll_ns_shrink(new, old) \
trace_guest_halt_poll_ns(false, new, old)
#endif /* _TRACE_POWER_H */ #endif /* _TRACE_POWER_H */
/* This part must be outside protection */ /* This part must be outside protection */
......
...@@ -145,7 +145,7 @@ static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd, ...@@ -145,7 +145,7 @@ static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd,
/* /*
* The power returned by active_state() is expected to be * The power returned by active_state() is expected to be
* positive and to fit into 16 bits. * positive and be in range.
*/ */
if (!power || power > EM_MAX_POWER) { if (!power || power > EM_MAX_POWER) {
dev_err(dev, "EM: invalid power: %lu\n", dev_err(dev, "EM: invalid power: %lu\n",
...@@ -170,7 +170,7 @@ static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd, ...@@ -170,7 +170,7 @@ static int em_create_perf_table(struct device *dev, struct em_perf_domain *pd,
goto free_ps_table; goto free_ps_table;
} }
} else { } else {
power_res = em_scale_power(table[i].power); power_res = table[i].power;
cost = div64_u64(fmax * power_res, table[i].frequency); cost = div64_u64(fmax * power_res, table[i].frequency);
} }
...@@ -201,9 +201,17 @@ static int em_create_pd(struct device *dev, int nr_states, ...@@ -201,9 +201,17 @@ static int em_create_pd(struct device *dev, int nr_states,
{ {
struct em_perf_domain *pd; struct em_perf_domain *pd;
struct device *cpu_dev; struct device *cpu_dev;
int cpu, ret; int cpu, ret, num_cpus;
if (_is_cpu_device(dev)) { if (_is_cpu_device(dev)) {
num_cpus = cpumask_weight(cpus);
/* Prevent max possible energy calculation to not overflow */
if (num_cpus > EM_MAX_NUM_CPUS) {
dev_err(dev, "EM: too many CPUs, overflow possible\n");
return -EINVAL;
}
pd = kzalloc(sizeof(*pd) + cpumask_size(), GFP_KERNEL); pd = kzalloc(sizeof(*pd) + cpumask_size(), GFP_KERNEL);
if (!pd) if (!pd)
return -ENOMEM; return -ENOMEM;
...@@ -314,13 +322,13 @@ EXPORT_SYMBOL_GPL(em_cpu_get); ...@@ -314,13 +322,13 @@ EXPORT_SYMBOL_GPL(em_cpu_get);
* @cpus : Pointer to cpumask_t, which in case of a CPU device is * @cpus : Pointer to cpumask_t, which in case of a CPU device is
* obligatory. It can be taken from i.e. 'policy->cpus'. For other * obligatory. It can be taken from i.e. 'policy->cpus'. For other
* type of devices this should be set to NULL. * type of devices this should be set to NULL.
* @milliwatts : Flag indicating that the power values are in milliWatts or * @microwatts : Flag indicating that the power values are in micro-Watts or
* in some other scale. It must be set properly. * in some other scale. It must be set properly.
* *
* Create Energy Model tables for a performance domain using the callbacks * Create Energy Model tables for a performance domain using the callbacks
* defined in cb. * defined in cb.
* *
* The @milliwatts is important to set with correct value. Some kernel * The @microwatts is important to set with correct value. Some kernel
* sub-systems might rely on this flag and check if all devices in the EM are * sub-systems might rely on this flag and check if all devices in the EM are
* using the same scale. * using the same scale.
* *
...@@ -331,7 +339,7 @@ EXPORT_SYMBOL_GPL(em_cpu_get); ...@@ -331,7 +339,7 @@ EXPORT_SYMBOL_GPL(em_cpu_get);
*/ */
int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
struct em_data_callback *cb, cpumask_t *cpus, struct em_data_callback *cb, cpumask_t *cpus,
bool milliwatts) bool microwatts)
{ {
unsigned long cap, prev_cap = 0; unsigned long cap, prev_cap = 0;
unsigned long flags = 0; unsigned long flags = 0;
...@@ -381,8 +389,8 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states, ...@@ -381,8 +389,8 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
} }
} }
if (milliwatts) if (microwatts)
flags |= EM_PERF_DOMAIN_MILLIWATTS; flags |= EM_PERF_DOMAIN_MICROWATTS;
else if (cb->get_cost) else if (cb->get_cost)
flags |= EM_PERF_DOMAIN_ARTIFICIAL; flags |= EM_PERF_DOMAIN_ARTIFICIAL;
......
...@@ -531,7 +531,7 @@ int freq_qos_add_request(struct freq_constraints *qos, ...@@ -531,7 +531,7 @@ int freq_qos_add_request(struct freq_constraints *qos,
{ {
int ret; int ret;
if (IS_ERR_OR_NULL(qos) || !req) if (IS_ERR_OR_NULL(qos) || !req || value < 0)
return -EINVAL; return -EINVAL;
if (WARN(freq_qos_request_active(req), if (WARN(freq_qos_request_active(req),
...@@ -563,7 +563,7 @@ EXPORT_SYMBOL_GPL(freq_qos_add_request); ...@@ -563,7 +563,7 @@ EXPORT_SYMBOL_GPL(freq_qos_add_request);
*/ */
int freq_qos_update_request(struct freq_qos_request *req, s32 new_value) int freq_qos_update_request(struct freq_qos_request *req, s32 new_value)
{ {
if (!req) if (!req || new_value < 0)
return -EINVAL; return -EINVAL;
if (WARN(!freq_qos_request_active(req), if (WARN(!freq_qos_request_active(req),
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "power.h" #include "power.h"
static bool need_wait;
static struct snapshot_data { static struct snapshot_data {
struct snapshot_handle handle; struct snapshot_handle handle;
...@@ -78,7 +79,7 @@ static int snapshot_open(struct inode *inode, struct file *filp) ...@@ -78,7 +79,7 @@ static int snapshot_open(struct inode *inode, struct file *filp)
* Resuming. We may need to wait for the image device to * Resuming. We may need to wait for the image device to
* appear. * appear.
*/ */
wait_for_device_probe(); need_wait = true;
data->swap = -1; data->swap = -1;
data->mode = O_WRONLY; data->mode = O_WRONLY;
...@@ -168,6 +169,11 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf, ...@@ -168,6 +169,11 @@ static ssize_t snapshot_write(struct file *filp, const char __user *buf,
ssize_t res; ssize_t res;
loff_t pg_offp = *offp & ~PAGE_MASK; loff_t pg_offp = *offp & ~PAGE_MASK;
if (need_wait) {
wait_for_device_probe();
need_wait = false;
}
lock_system_sleep(); lock_system_sleep();
data = filp->private_data; data = filp->private_data;
...@@ -244,6 +250,11 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd, ...@@ -244,6 +250,11 @@ static long snapshot_ioctl(struct file *filp, unsigned int cmd,
loff_t size; loff_t size;
sector_t offset; sector_t offset;
if (need_wait) {
wait_for_device_probe();
need_wait = false;
}
if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC) if (_IOC_TYPE(cmd) != SNAPSHOT_IOC_MAGIC)
return -ENOTTY; return -ENOTTY;
if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR) if (_IOC_NR(cmd) > SNAPSHOT_IOC_MAXNR)
......
...@@ -6,7 +6,7 @@ ...@@ -6,7 +6,7 @@
|_| |___/ |_| |_| |___/ |_|
pm-graph: suspend/resume/boot timing analysis tools pm-graph: suspend/resume/boot timing analysis tools
Version: 5.8 Version: 5.9
Author: Todd Brandt <todd.e.brandt@intel.com> Author: Todd Brandt <todd.e.brandt@intel.com>
Home Page: https://01.org/pm-graph Home Page: https://01.org/pm-graph
...@@ -97,8 +97,8 @@ ...@@ -97,8 +97,8 @@
(kernel/pre-3.15/enable_trace_events_suspend_resume.patch) (kernel/pre-3.15/enable_trace_events_suspend_resume.patch)
(kernel/pre-3.15/enable_trace_events_device_pm_callback.patch) (kernel/pre-3.15/enable_trace_events_device_pm_callback.patch)
If you're using a kernel older than 3.15.0, the following If you're using bootgraph, or sleepgraph with a kernel older than 3.15.0,
additional kernel parameters are required: the following additional kernel parameters are required:
(e.g. in file /etc/default/grub) (e.g. in file /etc/default/grub)
GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=32M ..." GRUB_CMDLINE_LINUX_DEFAULT="... initcall_debug log_buf_len=32M ..."
......
...@@ -69,20 +69,22 @@ class SystemValues(aslib.SystemValues): ...@@ -69,20 +69,22 @@ class SystemValues(aslib.SystemValues):
bootloader = 'grub' bootloader = 'grub'
blexec = [] blexec = []
def __init__(self): def __init__(self):
self.hostname = platform.node() self.kernel, self.hostname = 'unknown', platform.node()
self.testtime = datetime.now().strftime('%Y-%m-%d_%H:%M:%S') self.testtime = datetime.now().strftime('%Y-%m-%d_%H:%M:%S')
if os.path.exists('/proc/version'): if os.path.exists('/proc/version'):
fp = open('/proc/version', 'r') fp = open('/proc/version', 'r')
val = fp.read().strip() self.kernel = self.kernelVersion(fp.read().strip())
fp.close() fp.close()
self.kernel = self.kernelVersion(val)
else:
self.kernel = 'unknown'
self.testdir = datetime.now().strftime('boot-%y%m%d-%H%M%S') self.testdir = datetime.now().strftime('boot-%y%m%d-%H%M%S')
def kernelVersion(self, msg): def kernelVersion(self, msg):
return msg.split()[2] m = re.match('^[Ll]inux *[Vv]ersion *(?P<v>\S*) .*', msg)
if m:
return m.group('v')
return 'unknown'
def checkFtraceKernelVersion(self): def checkFtraceKernelVersion(self):
val = tuple(map(int, self.kernel.split('-')[0].split('.'))) m = re.match('^(?P<x>[0-9]*)\.(?P<y>[0-9]*)\.(?P<z>[0-9]*).*', self.kernel)
if m:
val = tuple(map(int, m.groups()))
if val >= (4, 10, 0): if val >= (4, 10, 0):
return True return True
return False return False
......
...@@ -125,7 +125,7 @@ acpi_suspend_begin: ...@@ -125,7 +125,7 @@ acpi_suspend_begin:
suspend_console: suspend_console:
acpi_pm_prepare: acpi_pm_prepare:
syscore_suspend: syscore_suspend:
arch_thaw_secondary_cpus_end: arch_enable_nonboot_cpus_end:
syscore_resume: syscore_resume:
acpi_pm_finish: acpi_pm_finish:
resume_console: resume_console:
......
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment