mirror of
https://github.com/torvalds/linux.git
synced 2024-12-29 14:21:47 +00:00
Power management updates for 5.13-rc1
- Add idle states table for IceLake-D to the intel_idle driver and update IceLake-X C6 data in it (Artem Bityutskiy). - Fix the C7 idle state on Tegra114 in the tegra cpuidle driver and drop the unused do_idle() firmware call from it (Dmitry Osipenko). - Fix cpuidle-qcom-spm Kconfig entry (He Ying). - Fix handling of possible negative tick_nohz_get_next_hrtimer() return values of in cpuidle governors (Rafael Wysocki). - Add support for frequency-invariance to the ACPI CPPC cpufreq driver and update the frequency-invariance engine (FIE) to use it as needed (Viresh Kumar). - Simplify the default delay_us setting in the ACPI CPPC cpufreq driver (Tom Saeger). - Clean up frequency-related computations in the intel_pstate cpufreq driver (Rafael Wysocki). - Fix TBG parent setting for load levels in the armada-37xx cpufreq driver and drop the CPU PM clock .set_parent method for armada-37xx (Marek Behún). - Fix multiple issues in the armada-37xx cpufreq driver (Pali Rohár). - Fix handling of dev_pm_opp_of_cpumask_add_table() return values in cpufreq-dt to take the -EPROBE_DEFER one into acconut as appropriate (Quanyang Wang). - Fix format string in ia64-acpi-cpufreq (Sergei Trofimovich). - Drop the unused for_each_policy() macro from cpufreq (Shaokun Zhang). - Simplify computations in the schedutil cpufreq governor to avoid unnecessary overhead (Yue Hu). - Fix typos in the s5pv210 cpufreq driver (Bhaskar Chowdhury). - Fix cpufreq documentation links in Kconfig (Alexander Monakov). - Fix PCI device power state handling in pci_enable_device_flags() to avoid issuse in some cases when the device depends on an ACPI power resource (Rafael Wysocki). - Add missing documentation of pm_runtime_resume_and_get() (Alan Stern). - Add missing static inline stub for pm_runtime_has_no_callbacks() to pm_runtime.h and drop the unused try_to_freeze_nowarn() definition (YueHaibing). - Drop duplicate struct device declaration from pm.h and fix a structure type declaration in intel_rapl.h (Wan Jiabing). - Use dev_set_name() instead of an open-coded equivalent of it in the wakeup sources code and drop a redundant local variable initialization from it (Andy Shevchenko, Colin Ian King). - Use crc32 instead of md5 for e820 memory map integrity check during resume from hibernation on x86 (Chris von Recklinghausen). - Fix typos in comments in the system-wide and hibernation support code (Lu Jialin). - Modify the generic power domains (genpd) code to avoid resuming devices in the "prepare" phase of system-wide suspend and hibernation (Ulf Hansson). - Add Hygon Fam18h RAPL support to the intel_rapl power capping driver (Pu Wen). - Add MAINTAINERS entry for the dynamic thermal power management (DTPM) code (Daniel Lezcano). - Add devm variants of operating performance points (OPP) API functions and switch over some users of the OPP framework to the new resource-managed API (Yangtao Li and Dmitry Osipenko). - Update devfreq core: * Register devfreq devices as cooling devices on demand (Daniel Lezcano). * Add missing unlock opeation in devfreq_add_device() (Lukasz Luba). * Use the next frequency as resume_freq instead of the previous frequency when using the opp-suspend property (Dong Aisheng). * Check get_dev_status in devfreq_update_stats() (Dong Aisheng). * Fix set_freq path for the userspace governor in Kconfig (Dong Aisheng). * Remove invalid description of get_target_freq() (Dong Aisheng). - Update devfreq drivers: * imx8m-ddrc: Remove imx8m_ddrc_get_dev_status() and unneeded of_match_ptr() (Dong Aisheng, Fabio Estevam). * rk3399_dmc: dt-bindings: Add rockchip,pmu phandle and drop references to undefined symbols (Enric Balletbo i Serra, Gaël PORTAY). * rk3399_dmc: Use dev_err_probe() to simplify the code (Krzysztof Kozlowski). * imx-bus: Remove unneeded of_match_ptr() (Fabio Estevam). - Fix kernel-doc warnings in three places (Pierre-Louis Bossart). - Fix typo in the pm-graph utility code (Ricardo Ribalda). -----BEGIN PGP SIGNATURE----- iQJGBAABCAAwFiEE4fcc61cGeeHD/fCwgsRv/nhiVHEFAmCHAUISHHJqd0Byand5 c29ja2kubmV0AAoJEILEb/54YlRxAxMP/0tFjgxeaJ3chYaiqoPlk2QX/XdwqJvm 8OOu2qBMWbt2bubcIlAPpdlCNaERI4itF7E8za7t9alswdq7YPWGmNR9snCXUKhD BzERuicZTeOcCk2P3DTgzLVc4EzF6wutA3lTdYYZIpf+LuuB+guG8zgMzScRHIsM N3I83O+iLTA9ifIqN0/wH//a0ISvo6rSWtcbx+48d5bYvYixW7CsBmoxWHhGiYsw 4PJ4AzbdNJEhQp91SBYPIAmqwV88FZUPoYnRazXMxOSevMewhP9JuCHXAujC3gLV l5d2TBaBV4EBYLD5tfCpJvHMXhv/yBpg6KRivjri+zEnY1TAqIlfR4vYiL7puVvQ PdwjyvNFDNGyUSX/AAwYF6F4WCtIhw8hCahw6Dw2zcDz0plFdRZmWAiTdmIjECJK 8EvwJNlmdl27G1y+EBc6NnwzEFZQwiu9F5bUHUkmc3fF1M1aFTza8WDNDo30TC94 94c+uVBRL2fBePl4FfGZATfJbOMb8+vDIkroQxrIjQDT/7Ha3Mz75JZDRHItZo92 +4fES2eFdfZISCLIQMBY5TeXox3O8qsirC1k4qELwy71gPUE9CpP3FkxKIvyZLlv +6fS9ttpUfyFBF7gqrEy+ziVk1Rm4oorLmWCtthz4xyerzj5+vtZQqKzcySk0GA5 hYkseZkedR6y =t+SG -----END PGP SIGNATURE----- Merge tag 'pm-5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm Pull power management updates from Rafael Wysocki: "These add some new hardware support (for example, IceLake-D idle states in intel_idle), fix some issues (for example, the handling of negative "sleep length" values in cpuidle governors), add new functionality to the existing drivers (for example, scale-invariance support in the ACPI CPPC cpufreq driver) and clean up code all over. Specifics: - Add idle states table for IceLake-D to the intel_idle driver and update IceLake-X C6 data in it (Artem Bityutskiy). - Fix the C7 idle state on Tegra114 in the tegra cpuidle driver and drop the unused do_idle() firmware call from it (Dmitry Osipenko). - Fix cpuidle-qcom-spm Kconfig entry (He Ying). - Fix handling of possible negative tick_nohz_get_next_hrtimer() return values of in cpuidle governors (Rafael Wysocki). - Add support for frequency-invariance to the ACPI CPPC cpufreq driver and update the frequency-invariance engine (FIE) to use it as needed (Viresh Kumar). - Simplify the default delay_us setting in the ACPI CPPC cpufreq driver (Tom Saeger). - Clean up frequency-related computations in the intel_pstate cpufreq driver (Rafael Wysocki). - Fix TBG parent setting for load levels in the armada-37xx cpufreq driver and drop the CPU PM clock .set_parent method for armada-37xx (Marek Behún). - Fix multiple issues in the armada-37xx cpufreq driver (Pali Rohár). - Fix handling of dev_pm_opp_of_cpumask_add_table() return values in cpufreq-dt to take the -EPROBE_DEFER one into acconut as appropriate (Quanyang Wang). - Fix format string in ia64-acpi-cpufreq (Sergei Trofimovich). - Drop the unused for_each_policy() macro from cpufreq (Shaokun Zhang). - Simplify computations in the schedutil cpufreq governor to avoid unnecessary overhead (Yue Hu). - Fix typos in the s5pv210 cpufreq driver (Bhaskar Chowdhury). - Fix cpufreq documentation links in Kconfig (Alexander Monakov). - Fix PCI device power state handling in pci_enable_device_flags() to avoid issuse in some cases when the device depends on an ACPI power resource (Rafael Wysocki). - Add missing documentation of pm_runtime_resume_and_get() (Alan Stern). - Add missing static inline stub for pm_runtime_has_no_callbacks() to pm_runtime.h and drop the unused try_to_freeze_nowarn() definition (YueHaibing). - Drop duplicate struct device declaration from pm.h and fix a structure type declaration in intel_rapl.h (Wan Jiabing). - Use dev_set_name() instead of an open-coded equivalent of it in the wakeup sources code and drop a redundant local variable initialization from it (Andy Shevchenko, Colin Ian King). - Use crc32 instead of md5 for e820 memory map integrity check during resume from hibernation on x86 (Chris von Recklinghausen). - Fix typos in comments in the system-wide and hibernation support code (Lu Jialin). - Modify the generic power domains (genpd) code to avoid resuming devices in the "prepare" phase of system-wide suspend and hibernation (Ulf Hansson). - Add Hygon Fam18h RAPL support to the intel_rapl power capping driver (Pu Wen). - Add MAINTAINERS entry for the dynamic thermal power management (DTPM) code (Daniel Lezcano). - Add devm variants of operating performance points (OPP) API functions and switch over some users of the OPP framework to the new resource-managed API (Yangtao Li and Dmitry Osipenko). - Update devfreq core: * Register devfreq devices as cooling devices on demand (Daniel Lezcano). * Add missing unlock opeation in devfreq_add_device() (Lukasz Luba). * Use the next frequency as resume_freq instead of the previous frequency when using the opp-suspend property (Dong Aisheng). * Check get_dev_status in devfreq_update_stats() (Dong Aisheng). * Fix set_freq path for the userspace governor in Kconfig (Dong Aisheng). * Remove invalid description of get_target_freq() (Dong Aisheng). - Update devfreq drivers: * imx8m-ddrc: Remove imx8m_ddrc_get_dev_status() and unneeded of_match_ptr() (Dong Aisheng, Fabio Estevam). * rk3399_dmc: dt-bindings: Add rockchip,pmu phandle and drop references to undefined symbols (Enric Balletbo i Serra, Gaël PORTAY). * rk3399_dmc: Use dev_err_probe() to simplify the code (Krzysztof Kozlowski). * imx-bus: Remove unneeded of_match_ptr() (Fabio Estevam). - Fix kernel-doc warnings in three places (Pierre-Louis Bossart). - Fix typo in the pm-graph utility code (Ricardo Ribalda)" * tag 'pm-5.13-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (74 commits) PM: wakeup: remove redundant assignment to variable retval PM: hibernate: x86: Use crc32 instead of md5 for hibernation e820 integrity check cpufreq: Kconfig: fix documentation links PM: wakeup: use dev_set_name() directly PM: runtime: Add documentation for pm_runtime_resume_and_get() cpufreq: intel_pstate: Simplify intel_pstate_update_perf_limits() cpufreq: armada-37xx: Fix module unloading cpufreq: armada-37xx: Remove cur_frequency variable cpufreq: armada-37xx: Fix determining base CPU frequency cpufreq: armada-37xx: Fix driver cleanup when registration failed clk: mvebu: armada-37xx-periph: Fix workaround for switching from L1 to L0 clk: mvebu: armada-37xx-periph: Fix switching CPU freq from 250 Mhz to 1 GHz cpufreq: armada-37xx: Fix the AVS value for load L1 clk: mvebu: armada-37xx-periph: remove .set_parent method for CPU PM clock cpufreq: armada-37xx: Fix setting TBG parent for load levels cpuidle: Fix ARM_QCOM_SPM_CPUIDLE configuration cpuidle: tegra: Remove do_idle firmware call cpuidle: tegra: Fix C7 idling state on Tegra114 PM: sleep: fix typos in comments cpufreq: Remove unused for_each_policy macro ...
This commit is contained in:
commit
5469f160e6
@ -97,10 +97,7 @@ Description:
|
||||
object. The values are represented in ms. If the value is
|
||||
less than 1 jiffy, it is considered to be 0, which means
|
||||
no polling. This value is meaningless if the governor is
|
||||
not polling; thus. If the governor is not using
|
||||
devfreq-provided central polling
|
||||
(/sys/class/devfreq/.../central_polling is 0), this value
|
||||
may be useless.
|
||||
not polling.
|
||||
|
||||
A list of governors that support the node:
|
||||
- simple_ondmenad
|
||||
|
@ -12,6 +12,8 @@ Required properties:
|
||||
for details.
|
||||
- center-supply: DMC supply node.
|
||||
- status: Marks the node enabled/disabled.
|
||||
- rockchip,pmu: Phandle to the syscon managing the "PMU general register
|
||||
files".
|
||||
|
||||
Optional properties:
|
||||
- interrupts: The CPU interrupt number. The interrupt specifier
|
||||
@ -77,24 +79,23 @@ Following properties relate to DDR timing:
|
||||
|
||||
- rockchip,ddr3_drv : When the DRAM type is DDR3, this parameter defines
|
||||
the DRAM side driver strength in ohms. Default
|
||||
value is DDR3_DS_40ohm.
|
||||
value is 40.
|
||||
|
||||
- rockchip,ddr3_odt : When the DRAM type is DDR3, this parameter defines
|
||||
the DRAM side ODT strength in ohms. Default value
|
||||
is DDR3_ODT_120ohm.
|
||||
is 120.
|
||||
|
||||
- rockchip,phy_ddr3_ca_drv : When the DRAM type is DDR3, this parameter defines
|
||||
the phy side CA line (incluing command line,
|
||||
address line and clock line) driver strength.
|
||||
Default value is PHY_DRV_ODT_40.
|
||||
Default value is 40.
|
||||
|
||||
- rockchip,phy_ddr3_dq_drv : When the DRAM type is DDR3, this parameter defines
|
||||
the PHY side DQ line (including DQS/DQ/DM line)
|
||||
driver strength. Default value is PHY_DRV_ODT_40.
|
||||
driver strength. Default value is 40.
|
||||
|
||||
- rockchip,phy_ddr3_odt : When the DRAM type is DDR3, this parameter defines
|
||||
the PHY side ODT strength. Default value is
|
||||
PHY_DRV_ODT_240.
|
||||
the PHY side ODT strength. Default value is 240.
|
||||
|
||||
- rockchip,lpddr3_odt_dis_freq : When the DRAM type is LPDDR3, this parameter defines
|
||||
then ODT disable frequency in MHz (Mega Hz).
|
||||
@ -104,25 +105,23 @@ Following properties relate to DDR timing:
|
||||
|
||||
- rockchip,lpddr3_drv : When the DRAM type is LPDDR3, this parameter defines
|
||||
the DRAM side driver strength in ohms. Default
|
||||
value is LP3_DS_34ohm.
|
||||
value is 34.
|
||||
|
||||
- rockchip,lpddr3_odt : When the DRAM type is LPDDR3, this parameter defines
|
||||
the DRAM side ODT strength in ohms. Default value
|
||||
is LP3_ODT_240ohm.
|
||||
is 240.
|
||||
|
||||
- rockchip,phy_lpddr3_ca_drv : When the DRAM type is LPDDR3, this parameter defines
|
||||
the PHY side CA line (including command line,
|
||||
address line and clock line) driver strength.
|
||||
Default value is PHY_DRV_ODT_40.
|
||||
Default value is 40.
|
||||
|
||||
- rockchip,phy_lpddr3_dq_drv : When the DRAM type is LPDDR3, this parameter defines
|
||||
the PHY side DQ line (including DQS/DQ/DM line)
|
||||
driver strength. Default value is
|
||||
PHY_DRV_ODT_40.
|
||||
driver strength. Default value is 40.
|
||||
|
||||
- rockchip,phy_lpddr3_odt : When dram type is LPDDR3, this parameter define
|
||||
the phy side odt strength, default value is
|
||||
PHY_DRV_ODT_240.
|
||||
the phy side odt strength, default value is 240.
|
||||
|
||||
- rockchip,lpddr4_odt_dis_freq : When the DRAM type is LPDDR4, this parameter
|
||||
defines the ODT disable frequency in
|
||||
@ -132,32 +131,30 @@ Following properties relate to DDR timing:
|
||||
|
||||
- rockchip,lpddr4_drv : When the DRAM type is LPDDR4, this parameter defines
|
||||
the DRAM side driver strength in ohms. Default
|
||||
value is LP4_PDDS_60ohm.
|
||||
value is 60.
|
||||
|
||||
- rockchip,lpddr4_dq_odt : When the DRAM type is LPDDR4, this parameter defines
|
||||
the DRAM side ODT on DQS/DQ line strength in ohms.
|
||||
Default value is LP4_DQ_ODT_40ohm.
|
||||
Default value is 40.
|
||||
|
||||
- rockchip,lpddr4_ca_odt : When the DRAM type is LPDDR4, this parameter defines
|
||||
the DRAM side ODT on CA line strength in ohms.
|
||||
Default value is LP4_CA_ODT_40ohm.
|
||||
Default value is 40.
|
||||
|
||||
- rockchip,phy_lpddr4_ca_drv : When the DRAM type is LPDDR4, this parameter defines
|
||||
the PHY side CA line (including command address
|
||||
line) driver strength. Default value is
|
||||
PHY_DRV_ODT_40.
|
||||
line) driver strength. Default value is 40.
|
||||
|
||||
- rockchip,phy_lpddr4_ck_cs_drv : When the DRAM type is LPDDR4, this parameter defines
|
||||
the PHY side clock line and CS line driver
|
||||
strength. Default value is PHY_DRV_ODT_80.
|
||||
strength. Default value is 80.
|
||||
|
||||
- rockchip,phy_lpddr4_dq_drv : When the DRAM type is LPDDR4, this parameter defines
|
||||
the PHY side DQ line (including DQS/DQ/DM line)
|
||||
driver strength. Default value is PHY_DRV_ODT_80.
|
||||
driver strength. Default value is 80.
|
||||
|
||||
- rockchip,phy_lpddr4_odt : When the DRAM type is LPDDR4, this parameter defines
|
||||
the PHY side ODT strength. Default value is
|
||||
PHY_DRV_ODT_60.
|
||||
the PHY side ODT strength. Default value is 60.
|
||||
|
||||
Example:
|
||||
dmc_opp_table: dmc_opp_table {
|
||||
@ -193,23 +190,23 @@ Example:
|
||||
rockchip,phy_dll_dis_freq = <125>;
|
||||
rockchip,auto_pd_dis_freq = <666>;
|
||||
rockchip,ddr3_odt_dis_freq = <333>;
|
||||
rockchip,ddr3_drv = <DDR3_DS_40ohm>;
|
||||
rockchip,ddr3_odt = <DDR3_ODT_120ohm>;
|
||||
rockchip,phy_ddr3_ca_drv = <PHY_DRV_ODT_40>;
|
||||
rockchip,phy_ddr3_dq_drv = <PHY_DRV_ODT_40>;
|
||||
rockchip,phy_ddr3_odt = <PHY_DRV_ODT_240>;
|
||||
rockchip,ddr3_drv = <40>;
|
||||
rockchip,ddr3_odt = <120>;
|
||||
rockchip,phy_ddr3_ca_drv = <40>;
|
||||
rockchip,phy_ddr3_dq_drv = <40>;
|
||||
rockchip,phy_ddr3_odt = <240>;
|
||||
rockchip,lpddr3_odt_dis_freq = <333>;
|
||||
rockchip,lpddr3_drv = <LP3_DS_34ohm>;
|
||||
rockchip,lpddr3_odt = <LP3_ODT_240ohm>;
|
||||
rockchip,phy_lpddr3_ca_drv = <PHY_DRV_ODT_40>;
|
||||
rockchip,phy_lpddr3_dq_drv = <PHY_DRV_ODT_40>;
|
||||
rockchip,phy_lpddr3_odt = <PHY_DRV_ODT_240>;
|
||||
rockchip,lpddr3_drv = <34>;
|
||||
rockchip,lpddr3_odt = <240>;
|
||||
rockchip,phy_lpddr3_ca_drv = <40>;
|
||||
rockchip,phy_lpddr3_dq_drv = <40>;
|
||||
rockchip,phy_lpddr3_odt = <240>;
|
||||
rockchip,lpddr4_odt_dis_freq = <333>;
|
||||
rockchip,lpddr4_drv = <LP4_PDDS_60ohm>;
|
||||
rockchip,lpddr4_dq_odt = <LP4_DQ_ODT_40ohm>;
|
||||
rockchip,lpddr4_ca_odt = <LP4_CA_ODT_40ohm>;
|
||||
rockchip,phy_lpddr4_ca_drv = <PHY_DRV_ODT_40>;
|
||||
rockchip,phy_lpddr4_ck_cs_drv = <PHY_DRV_ODT_80>;
|
||||
rockchip,phy_lpddr4_dq_drv = <PHY_DRV_ODT_80>;
|
||||
rockchip,phy_lpddr4_odt = <PHY_DRV_ODT_60>;
|
||||
rockchip,lpddr4_drv = <60>;
|
||||
rockchip,lpddr4_dq_odt = <40>;
|
||||
rockchip,lpddr4_ca_odt = <40>;
|
||||
rockchip,phy_lpddr4_ca_drv = <40>;
|
||||
rockchip,phy_lpddr4_ck_cs_drv = <80>;
|
||||
rockchip,phy_lpddr4_dq_drv = <80>;
|
||||
rockchip,phy_lpddr4_odt = <60>;
|
||||
};
|
||||
|
@ -339,6 +339,10 @@ drivers/base/power/runtime.c and include/linux/pm_runtime.h:
|
||||
checked additionally, and -EACCES means that 'power.disable_depth' is
|
||||
different from 0
|
||||
|
||||
`int pm_runtime_resume_and_get(struct device *dev);`
|
||||
- run pm_runtime_resume(dev) and if successful, increment the device's
|
||||
usage counter; return the result of pm_runtime_resume
|
||||
|
||||
`int pm_request_idle(struct device *dev);`
|
||||
- submit a request to execute the subsystem-level idle callback for the
|
||||
device (the request is represented by a work item in pm_wq); returns 0 on
|
||||
|
@ -14439,6 +14439,15 @@ F: include/linux/pm_*
|
||||
F: include/linux/powercap.h
|
||||
F: kernel/configs/nopm.config
|
||||
|
||||
DYNAMIC THERMAL POWER MANAGEMENT (DTPM)
|
||||
M: Daniel Lezcano <daniel.lezcano@kernel.org>
|
||||
L: linux-pm@vger.kernel.org
|
||||
S: Supported
|
||||
B: https://bugzilla.kernel.org
|
||||
T: git git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
|
||||
F: drivers/powercap/dtpm*
|
||||
F: include/linux/dtpm.h
|
||||
|
||||
POWER STATE COORDINATION INTERFACE (PSCI)
|
||||
M: Mark Rutland <mark.rutland@arm.com>
|
||||
M: Lorenzo Pieralisi <lorenzo.pieralisi@arm.com>
|
||||
|
@ -17,17 +17,9 @@ int pcibus_to_node(struct pci_bus *bus);
|
||||
#include <linux/arch_topology.h>
|
||||
|
||||
void update_freq_counters_refs(void);
|
||||
void topology_scale_freq_tick(void);
|
||||
|
||||
#ifdef CONFIG_ARM64_AMU_EXTN
|
||||
/*
|
||||
* Replace task scheduler's default counter-based
|
||||
* frequency-invariance scale factor setting.
|
||||
*/
|
||||
#define arch_scale_freq_tick topology_scale_freq_tick
|
||||
#endif /* CONFIG_ARM64_AMU_EXTN */
|
||||
|
||||
/* Replace task scheduler's default frequency-invariant accounting */
|
||||
#define arch_scale_freq_tick topology_scale_freq_tick
|
||||
#define arch_set_freq_scale topology_set_freq_scale
|
||||
#define arch_scale_freq_capacity topology_get_freq_scale
|
||||
#define arch_scale_freq_invariant topology_scale_freq_invariant
|
||||
|
@ -199,107 +199,10 @@ static int freq_inv_set_max_ratio(int cpu, u64 max_rate, u64 ref_rate)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static DEFINE_STATIC_KEY_FALSE(amu_fie_key);
|
||||
#define amu_freq_invariant() static_branch_unlikely(&amu_fie_key)
|
||||
|
||||
static void amu_fie_setup(const struct cpumask *cpus)
|
||||
{
|
||||
bool invariant;
|
||||
int cpu;
|
||||
|
||||
/* We are already set since the last insmod of cpufreq driver */
|
||||
if (unlikely(cpumask_subset(cpus, amu_fie_cpus)))
|
||||
return;
|
||||
|
||||
for_each_cpu(cpu, cpus) {
|
||||
if (!freq_counters_valid(cpu) ||
|
||||
freq_inv_set_max_ratio(cpu,
|
||||
cpufreq_get_hw_max_freq(cpu) * 1000,
|
||||
arch_timer_get_rate()))
|
||||
return;
|
||||
}
|
||||
|
||||
cpumask_or(amu_fie_cpus, amu_fie_cpus, cpus);
|
||||
|
||||
invariant = topology_scale_freq_invariant();
|
||||
|
||||
/* We aren't fully invariant yet */
|
||||
if (!invariant && !cpumask_equal(amu_fie_cpus, cpu_present_mask))
|
||||
return;
|
||||
|
||||
static_branch_enable(&amu_fie_key);
|
||||
|
||||
pr_debug("CPUs[%*pbl]: counters will be used for FIE.",
|
||||
cpumask_pr_args(cpus));
|
||||
|
||||
/*
|
||||
* Task scheduler behavior depends on frequency invariance support,
|
||||
* either cpufreq or counter driven. If the support status changes as
|
||||
* a result of counter initialisation and use, retrigger the build of
|
||||
* scheduling domains to ensure the information is propagated properly.
|
||||
*/
|
||||
if (!invariant)
|
||||
rebuild_sched_domains_energy();
|
||||
}
|
||||
|
||||
static int init_amu_fie_callback(struct notifier_block *nb, unsigned long val,
|
||||
void *data)
|
||||
{
|
||||
struct cpufreq_policy *policy = data;
|
||||
|
||||
if (val == CPUFREQ_CREATE_POLICY)
|
||||
amu_fie_setup(policy->related_cpus);
|
||||
|
||||
/*
|
||||
* We don't need to handle CPUFREQ_REMOVE_POLICY event as the AMU
|
||||
* counters don't have any dependency on cpufreq driver once we have
|
||||
* initialized AMU support and enabled invariance. The AMU counters will
|
||||
* keep on working just fine in the absence of the cpufreq driver, and
|
||||
* for the CPUs for which there are no counters available, the last set
|
||||
* value of freq_scale will remain valid as that is the frequency those
|
||||
* CPUs are running at.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block init_amu_fie_notifier = {
|
||||
.notifier_call = init_amu_fie_callback,
|
||||
};
|
||||
|
||||
static int __init init_amu_fie(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!zalloc_cpumask_var(&amu_fie_cpus, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
ret = cpufreq_register_notifier(&init_amu_fie_notifier,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
if (ret)
|
||||
free_cpumask_var(amu_fie_cpus);
|
||||
|
||||
return ret;
|
||||
}
|
||||
core_initcall(init_amu_fie);
|
||||
|
||||
bool arch_freq_counters_available(const struct cpumask *cpus)
|
||||
{
|
||||
return amu_freq_invariant() &&
|
||||
cpumask_subset(cpus, amu_fie_cpus);
|
||||
}
|
||||
|
||||
void topology_scale_freq_tick(void)
|
||||
static void amu_scale_freq_tick(void)
|
||||
{
|
||||
u64 prev_core_cnt, prev_const_cnt;
|
||||
u64 core_cnt, const_cnt, scale;
|
||||
int cpu = smp_processor_id();
|
||||
|
||||
if (!amu_freq_invariant())
|
||||
return;
|
||||
|
||||
if (!cpumask_test_cpu(cpu, amu_fie_cpus))
|
||||
return;
|
||||
|
||||
prev_const_cnt = this_cpu_read(arch_const_cycles_prev);
|
||||
prev_core_cnt = this_cpu_read(arch_core_cycles_prev);
|
||||
@ -327,9 +230,79 @@ void topology_scale_freq_tick(void)
|
||||
const_cnt - prev_const_cnt);
|
||||
|
||||
scale = min_t(unsigned long, scale, SCHED_CAPACITY_SCALE);
|
||||
this_cpu_write(freq_scale, (unsigned long)scale);
|
||||
this_cpu_write(arch_freq_scale, (unsigned long)scale);
|
||||
}
|
||||
|
||||
static struct scale_freq_data amu_sfd = {
|
||||
.source = SCALE_FREQ_SOURCE_ARCH,
|
||||
.set_freq_scale = amu_scale_freq_tick,
|
||||
};
|
||||
|
||||
static void amu_fie_setup(const struct cpumask *cpus)
|
||||
{
|
||||
int cpu;
|
||||
|
||||
/* We are already set since the last insmod of cpufreq driver */
|
||||
if (unlikely(cpumask_subset(cpus, amu_fie_cpus)))
|
||||
return;
|
||||
|
||||
for_each_cpu(cpu, cpus) {
|
||||
if (!freq_counters_valid(cpu) ||
|
||||
freq_inv_set_max_ratio(cpu,
|
||||
cpufreq_get_hw_max_freq(cpu) * 1000,
|
||||
arch_timer_get_rate()))
|
||||
return;
|
||||
}
|
||||
|
||||
cpumask_or(amu_fie_cpus, amu_fie_cpus, cpus);
|
||||
|
||||
topology_set_scale_freq_source(&amu_sfd, amu_fie_cpus);
|
||||
|
||||
pr_debug("CPUs[%*pbl]: counters will be used for FIE.",
|
||||
cpumask_pr_args(cpus));
|
||||
}
|
||||
|
||||
static int init_amu_fie_callback(struct notifier_block *nb, unsigned long val,
|
||||
void *data)
|
||||
{
|
||||
struct cpufreq_policy *policy = data;
|
||||
|
||||
if (val == CPUFREQ_CREATE_POLICY)
|
||||
amu_fie_setup(policy->related_cpus);
|
||||
|
||||
/*
|
||||
* We don't need to handle CPUFREQ_REMOVE_POLICY event as the AMU
|
||||
* counters don't have any dependency on cpufreq driver once we have
|
||||
* initialized AMU support and enabled invariance. The AMU counters will
|
||||
* keep on working just fine in the absence of the cpufreq driver, and
|
||||
* for the CPUs for which there are no counters available, the last set
|
||||
* value of arch_freq_scale will remain valid as that is the frequency
|
||||
* those CPUs are running at.
|
||||
*/
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct notifier_block init_amu_fie_notifier = {
|
||||
.notifier_call = init_amu_fie_callback,
|
||||
};
|
||||
|
||||
static int __init init_amu_fie(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if (!zalloc_cpumask_var(&amu_fie_cpus, GFP_KERNEL))
|
||||
return -ENOMEM;
|
||||
|
||||
ret = cpufreq_register_notifier(&init_amu_fie_notifier,
|
||||
CPUFREQ_POLICY_NOTIFIER);
|
||||
if (ret)
|
||||
free_cpumask_var(amu_fie_cpus);
|
||||
|
||||
return ret;
|
||||
}
|
||||
core_initcall(init_amu_fie);
|
||||
|
||||
#ifdef CONFIG_ACPI_CPPC_LIB
|
||||
#include <acpi/cppc_acpi.h>
|
||||
|
||||
|
@ -31,8 +31,8 @@
|
||||
* - inform the user about the firmware's notion of memory layout
|
||||
* via /sys/firmware/memmap
|
||||
*
|
||||
* - the hibernation code uses it to generate a kernel-independent MD5
|
||||
* fingerprint of the physical memory layout of a system.
|
||||
* - the hibernation code uses it to generate a kernel-independent CRC32
|
||||
* checksum of the physical memory layout of a system.
|
||||
*
|
||||
* - 'e820_table_kexec': a slightly modified (by the kernel) firmware version
|
||||
* passed to us by the bootloader - the major difference between
|
||||
|
@ -13,8 +13,8 @@
|
||||
#include <linux/kdebug.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/pgtable.h>
|
||||
|
||||
#include <crypto/hash.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/crc32.h>
|
||||
|
||||
#include <asm/e820/api.h>
|
||||
#include <asm/init.h>
|
||||
@ -54,95 +54,33 @@ int pfn_is_nosave(unsigned long pfn)
|
||||
return pfn >= nosave_begin_pfn && pfn < nosave_end_pfn;
|
||||
}
|
||||
|
||||
|
||||
#define MD5_DIGEST_SIZE 16
|
||||
|
||||
struct restore_data_record {
|
||||
unsigned long jump_address;
|
||||
unsigned long jump_address_phys;
|
||||
unsigned long cr3;
|
||||
unsigned long magic;
|
||||
u8 e820_digest[MD5_DIGEST_SIZE];
|
||||
unsigned long e820_checksum;
|
||||
};
|
||||
|
||||
#if IS_BUILTIN(CONFIG_CRYPTO_MD5)
|
||||
/**
|
||||
* get_e820_md5 - calculate md5 according to given e820 table
|
||||
* compute_e820_crc32 - calculate crc32 of a given e820 table
|
||||
*
|
||||
* @table: the e820 table to be calculated
|
||||
* @buf: the md5 result to be stored to
|
||||
*
|
||||
* Return: the resulting checksum
|
||||
*/
|
||||
static int get_e820_md5(struct e820_table *table, void *buf)
|
||||
static inline u32 compute_e820_crc32(struct e820_table *table)
|
||||
{
|
||||
struct crypto_shash *tfm;
|
||||
struct shash_desc *desc;
|
||||
int size;
|
||||
int ret = 0;
|
||||
|
||||
tfm = crypto_alloc_shash("md5", 0, 0);
|
||||
if (IS_ERR(tfm))
|
||||
return -ENOMEM;
|
||||
|
||||
desc = kmalloc(sizeof(struct shash_desc) + crypto_shash_descsize(tfm),
|
||||
GFP_KERNEL);
|
||||
if (!desc) {
|
||||
ret = -ENOMEM;
|
||||
goto free_tfm;
|
||||
}
|
||||
|
||||
desc->tfm = tfm;
|
||||
|
||||
size = offsetof(struct e820_table, entries) +
|
||||
int size = offsetof(struct e820_table, entries) +
|
||||
sizeof(struct e820_entry) * table->nr_entries;
|
||||
|
||||
if (crypto_shash_digest(desc, (u8 *)table, size, buf))
|
||||
ret = -EINVAL;
|
||||
|
||||
kfree_sensitive(desc);
|
||||
|
||||
free_tfm:
|
||||
crypto_free_shash(tfm);
|
||||
return ret;
|
||||
return ~crc32_le(~0, (unsigned char const *)table, size);
|
||||
}
|
||||
|
||||
static int hibernation_e820_save(void *buf)
|
||||
{
|
||||
return get_e820_md5(e820_table_firmware, buf);
|
||||
}
|
||||
|
||||
static bool hibernation_e820_mismatch(void *buf)
|
||||
{
|
||||
int ret;
|
||||
u8 result[MD5_DIGEST_SIZE];
|
||||
|
||||
memset(result, 0, MD5_DIGEST_SIZE);
|
||||
/* If there is no digest in suspend kernel, let it go. */
|
||||
if (!memcmp(result, buf, MD5_DIGEST_SIZE))
|
||||
return false;
|
||||
|
||||
ret = get_e820_md5(e820_table_firmware, result);
|
||||
if (ret)
|
||||
return true;
|
||||
|
||||
return memcmp(result, buf, MD5_DIGEST_SIZE) ? true : false;
|
||||
}
|
||||
#else
|
||||
static int hibernation_e820_save(void *buf)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool hibernation_e820_mismatch(void *buf)
|
||||
{
|
||||
/* If md5 is not builtin for restore kernel, let it go. */
|
||||
return false;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_X86_64
|
||||
#define RESTORE_MAGIC 0x23456789ABCDEF01UL
|
||||
#define RESTORE_MAGIC 0x23456789ABCDEF02UL
|
||||
#else
|
||||
#define RESTORE_MAGIC 0x12345678UL
|
||||
#define RESTORE_MAGIC 0x12345679UL
|
||||
#endif
|
||||
|
||||
/**
|
||||
@ -179,7 +117,8 @@ int arch_hibernation_header_save(void *addr, unsigned int max_size)
|
||||
*/
|
||||
rdr->cr3 = restore_cr3 & ~CR3_PCID_MASK;
|
||||
|
||||
return hibernation_e820_save(rdr->e820_digest);
|
||||
rdr->e820_checksum = compute_e820_crc32(e820_table_firmware);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -200,7 +139,7 @@ int arch_hibernation_header_restore(void *addr)
|
||||
jump_address_phys = rdr->jump_address_phys;
|
||||
restore_cr3 = rdr->cr3;
|
||||
|
||||
if (hibernation_e820_mismatch(rdr->e820_digest)) {
|
||||
if (rdr->e820_checksum != compute_e820_crc32(e820_table_firmware)) {
|
||||
pr_crit("Hibernate inconsistent memory map detected!\n");
|
||||
return -ENODEV;
|
||||
}
|
||||
|
@ -21,17 +21,94 @@
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
|
||||
static DEFINE_PER_CPU(struct scale_freq_data *, sft_data);
|
||||
static struct cpumask scale_freq_counters_mask;
|
||||
static bool scale_freq_invariant;
|
||||
|
||||
static bool supports_scale_freq_counters(const struct cpumask *cpus)
|
||||
{
|
||||
return cpumask_subset(cpus, &scale_freq_counters_mask);
|
||||
}
|
||||
|
||||
bool topology_scale_freq_invariant(void)
|
||||
{
|
||||
return cpufreq_supports_freq_invariance() ||
|
||||
arch_freq_counters_available(cpu_online_mask);
|
||||
supports_scale_freq_counters(cpu_online_mask);
|
||||
}
|
||||
|
||||
__weak bool arch_freq_counters_available(const struct cpumask *cpus)
|
||||
static void update_scale_freq_invariant(bool status)
|
||||
{
|
||||
return false;
|
||||
if (scale_freq_invariant == status)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Task scheduler behavior depends on frequency invariance support,
|
||||
* either cpufreq or counter driven. If the support status changes as
|
||||
* a result of counter initialisation and use, retrigger the build of
|
||||
* scheduling domains to ensure the information is propagated properly.
|
||||
*/
|
||||
if (topology_scale_freq_invariant() == status) {
|
||||
scale_freq_invariant = status;
|
||||
rebuild_sched_domains_energy();
|
||||
}
|
||||
}
|
||||
DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE;
|
||||
|
||||
void topology_set_scale_freq_source(struct scale_freq_data *data,
|
||||
const struct cpumask *cpus)
|
||||
{
|
||||
struct scale_freq_data *sfd;
|
||||
int cpu;
|
||||
|
||||
/*
|
||||
* Avoid calling rebuild_sched_domains() unnecessarily if FIE is
|
||||
* supported by cpufreq.
|
||||
*/
|
||||
if (cpumask_empty(&scale_freq_counters_mask))
|
||||
scale_freq_invariant = topology_scale_freq_invariant();
|
||||
|
||||
for_each_cpu(cpu, cpus) {
|
||||
sfd = per_cpu(sft_data, cpu);
|
||||
|
||||
/* Use ARCH provided counters whenever possible */
|
||||
if (!sfd || sfd->source != SCALE_FREQ_SOURCE_ARCH) {
|
||||
per_cpu(sft_data, cpu) = data;
|
||||
cpumask_set_cpu(cpu, &scale_freq_counters_mask);
|
||||
}
|
||||
}
|
||||
|
||||
update_scale_freq_invariant(true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(topology_set_scale_freq_source);
|
||||
|
||||
void topology_clear_scale_freq_source(enum scale_freq_source source,
|
||||
const struct cpumask *cpus)
|
||||
{
|
||||
struct scale_freq_data *sfd;
|
||||
int cpu;
|
||||
|
||||
for_each_cpu(cpu, cpus) {
|
||||
sfd = per_cpu(sft_data, cpu);
|
||||
|
||||
if (sfd && sfd->source == source) {
|
||||
per_cpu(sft_data, cpu) = NULL;
|
||||
cpumask_clear_cpu(cpu, &scale_freq_counters_mask);
|
||||
}
|
||||
}
|
||||
|
||||
update_scale_freq_invariant(false);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(topology_clear_scale_freq_source);
|
||||
|
||||
void topology_scale_freq_tick(void)
|
||||
{
|
||||
struct scale_freq_data *sfd = *this_cpu_ptr(&sft_data);
|
||||
|
||||
if (sfd)
|
||||
sfd->set_freq_scale();
|
||||
}
|
||||
|
||||
DEFINE_PER_CPU(unsigned long, arch_freq_scale) = SCHED_CAPACITY_SCALE;
|
||||
EXPORT_PER_CPU_SYMBOL_GPL(arch_freq_scale);
|
||||
|
||||
void topology_set_freq_scale(const struct cpumask *cpus, unsigned long cur_freq,
|
||||
unsigned long max_freq)
|
||||
@ -47,13 +124,13 @@ void topology_set_freq_scale(const struct cpumask *cpus, unsigned long cur_freq,
|
||||
* want to update the scale factor with information from CPUFREQ.
|
||||
* Instead the scale factor will be updated from arch_scale_freq_tick.
|
||||
*/
|
||||
if (arch_freq_counters_available(cpus))
|
||||
if (supports_scale_freq_counters(cpus))
|
||||
return;
|
||||
|
||||
scale = (cur_freq << SCHED_CAPACITY_SHIFT) / max_freq;
|
||||
|
||||
for_each_cpu(i, cpus)
|
||||
per_cpu(freq_scale, i) = scale;
|
||||
per_cpu(arch_freq_scale, i) = scale;
|
||||
}
|
||||
|
||||
DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;
|
||||
|
@ -140,7 +140,7 @@ static void pm_clk_op_unlock(struct pm_subsys_data *psd, unsigned long *flags)
|
||||
}
|
||||
|
||||
/**
|
||||
* pm_clk_enable - Enable a clock, reporting any errors
|
||||
* __pm_clk_enable - Enable a clock, reporting any errors
|
||||
* @dev: The device for the given clock
|
||||
* @ce: PM clock entry corresponding to the clock.
|
||||
*/
|
||||
|
@ -1087,34 +1087,6 @@ static void genpd_sync_power_on(struct generic_pm_domain *genpd, bool use_lock,
|
||||
genpd->status = GENPD_STATE_ON;
|
||||
}
|
||||
|
||||
/**
|
||||
* resume_needed - Check whether to resume a device before system suspend.
|
||||
* @dev: Device to check.
|
||||
* @genpd: PM domain the device belongs to.
|
||||
*
|
||||
* There are two cases in which a device that can wake up the system from sleep
|
||||
* states should be resumed by genpd_prepare(): (1) if the device is enabled
|
||||
* to wake up the system and it has to remain active for this purpose while the
|
||||
* system is in the sleep state and (2) if the device is not enabled to wake up
|
||||
* the system from sleep states and it generally doesn't generate wakeup signals
|
||||
* by itself (those signals are generated on its behalf by other parts of the
|
||||
* system). In the latter case it may be necessary to reconfigure the device's
|
||||
* wakeup settings during system suspend, because it may have been set up to
|
||||
* signal remote wakeup from the system's working state as needed by runtime PM.
|
||||
* Return 'true' in either of the above cases.
|
||||
*/
|
||||
static bool resume_needed(struct device *dev,
|
||||
const struct generic_pm_domain *genpd)
|
||||
{
|
||||
bool active_wakeup;
|
||||
|
||||
if (!device_can_wakeup(dev))
|
||||
return false;
|
||||
|
||||
active_wakeup = genpd_is_active_wakeup(genpd);
|
||||
return device_may_wakeup(dev) ? active_wakeup : !active_wakeup;
|
||||
}
|
||||
|
||||
/**
|
||||
* genpd_prepare - Start power transition of a device in a PM domain.
|
||||
* @dev: Device to start the transition of.
|
||||
@ -1135,14 +1107,6 @@ static int genpd_prepare(struct device *dev)
|
||||
if (IS_ERR(genpd))
|
||||
return -EINVAL;
|
||||
|
||||
/*
|
||||
* If a wakeup request is pending for the device, it should be woken up
|
||||
* at this point and a system wakeup event should be reported if it's
|
||||
* set up to wake up the system from sleep states.
|
||||
*/
|
||||
if (resume_needed(dev, genpd))
|
||||
pm_runtime_resume(dev);
|
||||
|
||||
genpd_lock(genpd);
|
||||
|
||||
if (genpd->prepared_count++ == 0)
|
||||
|
@ -951,7 +951,7 @@ static void pm_runtime_work(struct work_struct *work)
|
||||
|
||||
/**
|
||||
* pm_suspend_timer_fn - Timer function for pm_schedule_suspend().
|
||||
* @data: Device pointer passed by pm_schedule_suspend().
|
||||
* @timer: hrtimer used by pm_schedule_suspend().
|
||||
*
|
||||
* Check if the time is right and queue a suspend request.
|
||||
*/
|
||||
|
@ -400,9 +400,9 @@ void device_wakeup_detach_irq(struct device *dev)
|
||||
}
|
||||
|
||||
/**
|
||||
* device_wakeup_arm_wake_irqs(void)
|
||||
* device_wakeup_arm_wake_irqs -
|
||||
*
|
||||
* Itereates over the list of device wakeirqs to arm them.
|
||||
* Iterates over the list of device wakeirqs to arm them.
|
||||
*/
|
||||
void device_wakeup_arm_wake_irqs(void)
|
||||
{
|
||||
@ -416,9 +416,9 @@ void device_wakeup_arm_wake_irqs(void)
|
||||
}
|
||||
|
||||
/**
|
||||
* device_wakeup_disarm_wake_irqs(void)
|
||||
* device_wakeup_disarm_wake_irqs -
|
||||
*
|
||||
* Itereates over the list of device wakeirqs to disarm them.
|
||||
* Iterates over the list of device wakeirqs to disarm them.
|
||||
*/
|
||||
void device_wakeup_disarm_wake_irqs(void)
|
||||
{
|
||||
@ -532,6 +532,7 @@ EXPORT_SYMBOL_GPL(device_init_wakeup);
|
||||
/**
|
||||
* device_set_wakeup_enable - Enable or disable a device to wake up the system.
|
||||
* @dev: Device to handle.
|
||||
* @enable: enable/disable flag
|
||||
*/
|
||||
int device_set_wakeup_enable(struct device *dev, bool enable)
|
||||
{
|
||||
@ -581,7 +582,7 @@ static bool wakeup_source_not_registered(struct wakeup_source *ws)
|
||||
*/
|
||||
|
||||
/**
|
||||
* wakup_source_activate - Mark given wakeup source as active.
|
||||
* wakeup_source_activate - Mark given wakeup source as active.
|
||||
* @ws: Wakeup source to handle.
|
||||
*
|
||||
* Update the @ws' statistics and, if @ws has just been activated, notify the PM
|
||||
@ -686,7 +687,7 @@ static inline void update_prevent_sleep_time(struct wakeup_source *ws,
|
||||
#endif
|
||||
|
||||
/**
|
||||
* wakup_source_deactivate - Mark given wakeup source as inactive.
|
||||
* wakeup_source_deactivate - Mark given wakeup source as inactive.
|
||||
* @ws: Wakeup source to handle.
|
||||
*
|
||||
* Update the @ws' statistics and notify the PM core that the wakeup source has
|
||||
@ -785,7 +786,7 @@ EXPORT_SYMBOL_GPL(pm_relax);
|
||||
|
||||
/**
|
||||
* pm_wakeup_timer_fn - Delayed finalization of a wakeup event.
|
||||
* @data: Address of the wakeup source object associated with the event source.
|
||||
* @t: timer list
|
||||
*
|
||||
* Call wakeup_source_deactivate() for the wakeup source whose address is stored
|
||||
* in @data if it is currently active and its timer has not been canceled and
|
||||
@ -1021,7 +1022,7 @@ bool pm_save_wakeup_count(unsigned int count)
|
||||
#ifdef CONFIG_PM_AUTOSLEEP
|
||||
/**
|
||||
* pm_wakep_autosleep_enabled - Modify autosleep_enabled for all wakeup sources.
|
||||
* @enabled: Whether to set or to clear the autosleep_enabled flags.
|
||||
* @set: Whether to set or to clear the autosleep_enabled flags.
|
||||
*/
|
||||
void pm_wakep_autosleep_enabled(bool set)
|
||||
{
|
||||
|
@ -137,7 +137,7 @@ static struct device *wakeup_source_device_create(struct device *parent,
|
||||
struct wakeup_source *ws)
|
||||
{
|
||||
struct device *dev = NULL;
|
||||
int retval = -ENODEV;
|
||||
int retval;
|
||||
|
||||
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
|
||||
if (!dev) {
|
||||
|
@ -84,6 +84,7 @@ struct clk_pm_cpu {
|
||||
void __iomem *reg_div;
|
||||
u8 shift_div;
|
||||
struct regmap *nb_pm_base;
|
||||
unsigned long l1_expiration;
|
||||
};
|
||||
|
||||
#define to_clk_double_div(_hw) container_of(_hw, struct clk_double_div, hw)
|
||||
@ -440,33 +441,6 @@ static u8 clk_pm_cpu_get_parent(struct clk_hw *hw)
|
||||
return val;
|
||||
}
|
||||
|
||||
static int clk_pm_cpu_set_parent(struct clk_hw *hw, u8 index)
|
||||
{
|
||||
struct clk_pm_cpu *pm_cpu = to_clk_pm_cpu(hw);
|
||||
struct regmap *base = pm_cpu->nb_pm_base;
|
||||
int load_level;
|
||||
|
||||
/*
|
||||
* We set the clock parent only if the DVFS is available but
|
||||
* not enabled.
|
||||
*/
|
||||
if (IS_ERR(base) || armada_3700_pm_dvfs_is_enabled(base))
|
||||
return -EINVAL;
|
||||
|
||||
/* Set the parent clock for all the load level */
|
||||
for (load_level = 0; load_level < LOAD_LEVEL_NR; load_level++) {
|
||||
unsigned int reg, mask, val,
|
||||
offset = ARMADA_37XX_NB_TBG_SEL_OFF;
|
||||
|
||||
armada_3700_pm_dvfs_update_regs(load_level, ®, &offset);
|
||||
|
||||
val = index << offset;
|
||||
mask = ARMADA_37XX_NB_TBG_SEL_MASK << offset;
|
||||
regmap_update_bits(base, reg, mask, val);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned long clk_pm_cpu_recalc_rate(struct clk_hw *hw,
|
||||
unsigned long parent_rate)
|
||||
{
|
||||
@ -514,8 +488,10 @@ static long clk_pm_cpu_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
}
|
||||
|
||||
/*
|
||||
* Switching the CPU from the L2 or L3 frequencies (300 and 200 Mhz
|
||||
* respectively) to L0 frequency (1.2 Ghz) requires a significant
|
||||
* Workaround when base CPU frequnecy is 1000 or 1200 MHz
|
||||
*
|
||||
* Switching the CPU from the L2 or L3 frequencies (250/300 or 200 MHz
|
||||
* respectively) to L0 frequency (1/1.2 GHz) requires a significant
|
||||
* amount of time to let VDD stabilize to the appropriate
|
||||
* voltage. This amount of time is large enough that it cannot be
|
||||
* covered by the hardware countdown register. Due to this, the CPU
|
||||
@ -525,26 +501,56 @@ static long clk_pm_cpu_round_rate(struct clk_hw *hw, unsigned long rate,
|
||||
* To work around this problem, we prevent switching directly from the
|
||||
* L2/L3 frequencies to the L0 frequency, and instead switch to the L1
|
||||
* frequency in-between. The sequence therefore becomes:
|
||||
* 1. First switch from L2/L3(200/300MHz) to L1(600MHZ)
|
||||
* 1. First switch from L2/L3 (200/250/300 MHz) to L1 (500/600 MHz)
|
||||
* 2. Sleep 20ms for stabling VDD voltage
|
||||
* 3. Then switch from L1(600MHZ) to L0(1200Mhz).
|
||||
* 3. Then switch from L1 (500/600 MHz) to L0 (1000/1200 MHz).
|
||||
*/
|
||||
static void clk_pm_cpu_set_rate_wa(unsigned long rate, struct regmap *base)
|
||||
static void clk_pm_cpu_set_rate_wa(struct clk_pm_cpu *pm_cpu,
|
||||
unsigned int new_level, unsigned long rate,
|
||||
struct regmap *base)
|
||||
{
|
||||
unsigned int cur_level;
|
||||
|
||||
if (rate != 1200 * 1000 * 1000)
|
||||
return;
|
||||
|
||||
regmap_read(base, ARMADA_37XX_NB_CPU_LOAD, &cur_level);
|
||||
cur_level &= ARMADA_37XX_NB_CPU_LOAD_MASK;
|
||||
if (cur_level <= ARMADA_37XX_DVFS_LOAD_1)
|
||||
|
||||
if (cur_level == new_level)
|
||||
return;
|
||||
|
||||
/*
|
||||
* System wants to go to L1 on its own. If we are going from L2/L3,
|
||||
* remember when 20ms will expire. If from L0, set the value so that
|
||||
* next switch to L0 won't have to wait.
|
||||
*/
|
||||
if (new_level == ARMADA_37XX_DVFS_LOAD_1) {
|
||||
if (cur_level == ARMADA_37XX_DVFS_LOAD_0)
|
||||
pm_cpu->l1_expiration = jiffies;
|
||||
else
|
||||
pm_cpu->l1_expiration = jiffies + msecs_to_jiffies(20);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* If we are setting to L2/L3, just invalidate L1 expiration time,
|
||||
* sleeping is not needed.
|
||||
*/
|
||||
if (rate < 1000*1000*1000)
|
||||
goto invalidate_l1_exp;
|
||||
|
||||
/*
|
||||
* We are going to L0 with rate >= 1GHz. Check whether we have been at
|
||||
* L1 for long enough time. If not, go to L1 for 20ms.
|
||||
*/
|
||||
if (pm_cpu->l1_expiration && jiffies >= pm_cpu->l1_expiration)
|
||||
goto invalidate_l1_exp;
|
||||
|
||||
regmap_update_bits(base, ARMADA_37XX_NB_CPU_LOAD,
|
||||
ARMADA_37XX_NB_CPU_LOAD_MASK,
|
||||
ARMADA_37XX_DVFS_LOAD_1);
|
||||
msleep(20);
|
||||
|
||||
invalidate_l1_exp:
|
||||
pm_cpu->l1_expiration = 0;
|
||||
}
|
||||
|
||||
static int clk_pm_cpu_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
@ -578,7 +584,9 @@ static int clk_pm_cpu_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
reg = ARMADA_37XX_NB_CPU_LOAD;
|
||||
mask = ARMADA_37XX_NB_CPU_LOAD_MASK;
|
||||
|
||||
clk_pm_cpu_set_rate_wa(rate, base);
|
||||
/* Apply workaround when base CPU frequency is 1000 or 1200 MHz */
|
||||
if (parent_rate >= 1000*1000*1000)
|
||||
clk_pm_cpu_set_rate_wa(pm_cpu, load_level, rate, base);
|
||||
|
||||
regmap_update_bits(base, reg, mask, load_level);
|
||||
|
||||
@ -592,7 +600,6 @@ static int clk_pm_cpu_set_rate(struct clk_hw *hw, unsigned long rate,
|
||||
|
||||
static const struct clk_ops clk_pm_cpu_ops = {
|
||||
.get_parent = clk_pm_cpu_get_parent,
|
||||
.set_parent = clk_pm_cpu_set_parent,
|
||||
.round_rate = clk_pm_cpu_round_rate,
|
||||
.set_rate = clk_pm_cpu_set_rate,
|
||||
.recalc_rate = clk_pm_cpu_recalc_rate,
|
||||
|
@ -13,7 +13,8 @@ config CPU_FREQ
|
||||
clock speed, you need to either enable a dynamic cpufreq governor
|
||||
(see below) after boot, or use a userspace tool.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq>.
|
||||
For details, take a look at
|
||||
<file:Documentation/admin-guide/pm/cpufreq.rst>.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
@ -140,8 +141,6 @@ config CPU_FREQ_GOV_USERSPACE
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cpufreq_userspace.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq/>.
|
||||
|
||||
If in doubt, say Y.
|
||||
|
||||
config CPU_FREQ_GOV_ONDEMAND
|
||||
@ -158,7 +157,8 @@ config CPU_FREQ_GOV_ONDEMAND
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cpufreq_ondemand.
|
||||
|
||||
For details, take a look at linux/Documentation/cpu-freq.
|
||||
For details, take a look at
|
||||
<file:Documentation/admin-guide/pm/cpufreq.rst>.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
@ -182,7 +182,8 @@ config CPU_FREQ_GOV_CONSERVATIVE
|
||||
To compile this driver as a module, choose M here: the
|
||||
module will be called cpufreq_conservative.
|
||||
|
||||
For details, take a look at linux/Documentation/cpu-freq.
|
||||
For details, take a look at
|
||||
<file:Documentation/admin-guide/pm/cpufreq.rst>.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
@ -246,8 +247,6 @@ config IA64_ACPI_CPUFREQ
|
||||
This driver adds a CPUFreq driver which utilizes the ACPI
|
||||
Processor Performance States.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq/>.
|
||||
|
||||
If in doubt, say N.
|
||||
endif
|
||||
|
||||
@ -271,8 +270,6 @@ config LOONGSON2_CPUFREQ
|
||||
|
||||
Loongson2F and it's successors support this feature.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq/>.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config LOONGSON1_CPUFREQ
|
||||
@ -282,8 +279,6 @@ config LOONGSON1_CPUFREQ
|
||||
This option adds a CPUFreq driver for loongson1 processors which
|
||||
support software configurable cpu frequency.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq/>.
|
||||
|
||||
If in doubt, say N.
|
||||
endif
|
||||
|
||||
@ -293,8 +288,6 @@ config SPARC_US3_CPUFREQ
|
||||
help
|
||||
This adds the CPUFreq driver for UltraSPARC-III processors.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq>.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config SPARC_US2E_CPUFREQ
|
||||
@ -302,8 +295,6 @@ config SPARC_US2E_CPUFREQ
|
||||
help
|
||||
This adds the CPUFreq driver for UltraSPARC-IIe processors.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq>.
|
||||
|
||||
If in doubt, say N.
|
||||
endif
|
||||
|
||||
@ -318,8 +309,6 @@ config SH_CPU_FREQ
|
||||
will also generate a notice in the boot log before disabling
|
||||
itself if the CPU in question is not capable of rate rounding.
|
||||
|
||||
For details, take a look at <file:Documentation/cpu-freq>.
|
||||
|
||||
If unsure, say N.
|
||||
endif
|
||||
|
||||
|
@ -19,6 +19,16 @@ config ACPI_CPPC_CPUFREQ
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config ACPI_CPPC_CPUFREQ_FIE
|
||||
bool "Frequency Invariance support for CPPC cpufreq driver"
|
||||
depends on ACPI_CPPC_CPUFREQ && GENERIC_ARCH_TOPOLOGY
|
||||
default y
|
||||
help
|
||||
This extends frequency invariance support in the CPPC cpufreq driver,
|
||||
by using CPPC delivered and reference performance counters.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config ARM_ALLWINNER_SUN50I_CPUFREQ_NVMEM
|
||||
tristate "Allwinner nvmem based SUN50I CPUFreq driver"
|
||||
depends on ARCH_SUNXI
|
||||
|
@ -25,6 +25,10 @@
|
||||
|
||||
#include "cpufreq-dt.h"
|
||||
|
||||
/* Clk register set */
|
||||
#define ARMADA_37XX_CLK_TBG_SEL 0
|
||||
#define ARMADA_37XX_CLK_TBG_SEL_CPU_OFF 22
|
||||
|
||||
/* Power management in North Bridge register set */
|
||||
#define ARMADA_37XX_NB_L0L1 0x18
|
||||
#define ARMADA_37XX_NB_L2L3 0x1C
|
||||
@ -69,6 +73,8 @@
|
||||
#define LOAD_LEVEL_NR 4
|
||||
|
||||
#define MIN_VOLT_MV 1000
|
||||
#define MIN_VOLT_MV_FOR_L1_1000MHZ 1108
|
||||
#define MIN_VOLT_MV_FOR_L1_1200MHZ 1155
|
||||
|
||||
/* AVS value for the corresponding voltage (in mV) */
|
||||
static int avs_map[] = {
|
||||
@ -80,6 +86,8 @@ static int avs_map[] = {
|
||||
};
|
||||
|
||||
struct armada37xx_cpufreq_state {
|
||||
struct platform_device *pdev;
|
||||
struct device *cpu_dev;
|
||||
struct regmap *regmap;
|
||||
u32 nb_l0l1;
|
||||
u32 nb_l2l3;
|
||||
@ -120,10 +128,15 @@ static struct armada_37xx_dvfs *armada_37xx_cpu_freq_info_get(u32 freq)
|
||||
* will be configured then the DVFS will be enabled.
|
||||
*/
|
||||
static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base,
|
||||
struct clk *clk, u8 *divider)
|
||||
struct regmap *clk_base, u8 *divider)
|
||||
{
|
||||
u32 cpu_tbg_sel;
|
||||
int load_lvl;
|
||||
struct clk *parent;
|
||||
|
||||
/* Determine to which TBG clock is CPU connected */
|
||||
regmap_read(clk_base, ARMADA_37XX_CLK_TBG_SEL, &cpu_tbg_sel);
|
||||
cpu_tbg_sel >>= ARMADA_37XX_CLK_TBG_SEL_CPU_OFF;
|
||||
cpu_tbg_sel &= ARMADA_37XX_NB_TBG_SEL_MASK;
|
||||
|
||||
for (load_lvl = 0; load_lvl < LOAD_LEVEL_NR; load_lvl++) {
|
||||
unsigned int reg, mask, val, offset = 0;
|
||||
@ -142,6 +155,11 @@ static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base,
|
||||
mask = (ARMADA_37XX_NB_CLK_SEL_MASK
|
||||
<< ARMADA_37XX_NB_CLK_SEL_OFF);
|
||||
|
||||
/* Set TBG index, for all levels we use the same TBG */
|
||||
val = cpu_tbg_sel << ARMADA_37XX_NB_TBG_SEL_OFF;
|
||||
mask = (ARMADA_37XX_NB_TBG_SEL_MASK
|
||||
<< ARMADA_37XX_NB_TBG_SEL_OFF);
|
||||
|
||||
/*
|
||||
* Set cpu divider based on the pre-computed array in
|
||||
* order to have balanced step.
|
||||
@ -160,14 +178,6 @@ static void __init armada37xx_cpufreq_dvfs_setup(struct regmap *base,
|
||||
|
||||
regmap_update_bits(base, reg, mask, val);
|
||||
}
|
||||
|
||||
/*
|
||||
* Set cpu clock source, for all the level we keep the same
|
||||
* clock source that the one already configured. For this one
|
||||
* we need to use the clock framework
|
||||
*/
|
||||
parent = clk_get_parent(clk);
|
||||
clk_set_parent(clk, parent);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -202,6 +212,8 @@ static u32 armada_37xx_avs_val_match(int target_vm)
|
||||
* - L2 & L3 voltage should be about 150mv smaller than L0 voltage.
|
||||
* This function calculates L1 & L2 & L3 AVS values dynamically based
|
||||
* on L0 voltage and fill all AVS values to the AVS value table.
|
||||
* When base CPU frequency is 1000 or 1200 MHz then there is additional
|
||||
* minimal avs value for load L1.
|
||||
*/
|
||||
static void __init armada37xx_cpufreq_avs_configure(struct regmap *base,
|
||||
struct armada_37xx_dvfs *dvfs)
|
||||
@ -233,6 +245,19 @@ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base,
|
||||
for (load_level = 1; load_level < LOAD_LEVEL_NR; load_level++)
|
||||
dvfs->avs[load_level] = avs_min;
|
||||
|
||||
/*
|
||||
* Set the avs values for load L0 and L1 when base CPU frequency
|
||||
* is 1000/1200 MHz to its typical initial values according to
|
||||
* the Armada 3700 Hardware Specifications.
|
||||
*/
|
||||
if (dvfs->cpu_freq_max >= 1000*1000*1000) {
|
||||
if (dvfs->cpu_freq_max >= 1200*1000*1000)
|
||||
avs_min = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L1_1200MHZ);
|
||||
else
|
||||
avs_min = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L1_1000MHZ);
|
||||
dvfs->avs[0] = dvfs->avs[1] = avs_min;
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@ -252,6 +277,26 @@ static void __init armada37xx_cpufreq_avs_configure(struct regmap *base,
|
||||
target_vm = avs_map[l0_vdd_min] - 150;
|
||||
target_vm = target_vm > MIN_VOLT_MV ? target_vm : MIN_VOLT_MV;
|
||||
dvfs->avs[2] = dvfs->avs[3] = armada_37xx_avs_val_match(target_vm);
|
||||
|
||||
/*
|
||||
* Fix the avs value for load L1 when base CPU frequency is 1000/1200 MHz,
|
||||
* otherwise the CPU gets stuck when switching from load L1 to load L0.
|
||||
* Also ensure that avs value for load L1 is not higher than for L0.
|
||||
*/
|
||||
if (dvfs->cpu_freq_max >= 1000*1000*1000) {
|
||||
u32 avs_min_l1;
|
||||
|
||||
if (dvfs->cpu_freq_max >= 1200*1000*1000)
|
||||
avs_min_l1 = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L1_1200MHZ);
|
||||
else
|
||||
avs_min_l1 = armada_37xx_avs_val_match(MIN_VOLT_MV_FOR_L1_1000MHZ);
|
||||
|
||||
if (avs_min_l1 > dvfs->avs[0])
|
||||
avs_min_l1 = dvfs->avs[0];
|
||||
|
||||
if (dvfs->avs[1] < avs_min_l1)
|
||||
dvfs->avs[1] = avs_min_l1;
|
||||
}
|
||||
}
|
||||
|
||||
static void __init armada37xx_cpufreq_avs_setup(struct regmap *base,
|
||||
@ -357,12 +402,17 @@ static int __init armada37xx_cpufreq_driver_init(void)
|
||||
struct armada_37xx_dvfs *dvfs;
|
||||
struct platform_device *pdev;
|
||||
unsigned long freq;
|
||||
unsigned int cur_frequency, base_frequency;
|
||||
struct regmap *nb_pm_base, *avs_base;
|
||||
unsigned int base_frequency;
|
||||
struct regmap *nb_clk_base, *nb_pm_base, *avs_base;
|
||||
struct device *cpu_dev;
|
||||
int load_lvl, ret;
|
||||
struct clk *clk, *parent;
|
||||
|
||||
nb_clk_base =
|
||||
syscon_regmap_lookup_by_compatible("marvell,armada-3700-periph-clock-nb");
|
||||
if (IS_ERR(nb_clk_base))
|
||||
return -ENODEV;
|
||||
|
||||
nb_pm_base =
|
||||
syscon_regmap_lookup_by_compatible("marvell,armada-3700-nb-pm");
|
||||
|
||||
@ -413,15 +463,7 @@ static int __init armada37xx_cpufreq_driver_init(void)
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/* Get nominal (current) CPU frequency */
|
||||
cur_frequency = clk_get_rate(clk);
|
||||
if (!cur_frequency) {
|
||||
dev_err(cpu_dev, "Failed to get clock rate for CPU\n");
|
||||
clk_put(clk);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
dvfs = armada_37xx_cpu_freq_info_get(cur_frequency);
|
||||
dvfs = armada_37xx_cpu_freq_info_get(base_frequency);
|
||||
if (!dvfs) {
|
||||
clk_put(clk);
|
||||
return -EINVAL;
|
||||
@ -439,7 +481,7 @@ static int __init armada37xx_cpufreq_driver_init(void)
|
||||
armada37xx_cpufreq_avs_configure(avs_base, dvfs);
|
||||
armada37xx_cpufreq_avs_setup(avs_base, dvfs);
|
||||
|
||||
armada37xx_cpufreq_dvfs_setup(nb_pm_base, clk, dvfs->divider);
|
||||
armada37xx_cpufreq_dvfs_setup(nb_pm_base, nb_clk_base, dvfs->divider);
|
||||
clk_put(clk);
|
||||
|
||||
for (load_lvl = ARMADA_37XX_DVFS_LOAD_0; load_lvl < LOAD_LEVEL_NR;
|
||||
@ -466,6 +508,9 @@ static int __init armada37xx_cpufreq_driver_init(void)
|
||||
if (ret)
|
||||
goto disable_dvfs;
|
||||
|
||||
armada37xx_cpufreq_state->cpu_dev = cpu_dev;
|
||||
armada37xx_cpufreq_state->pdev = pdev;
|
||||
platform_set_drvdata(pdev, dvfs);
|
||||
return 0;
|
||||
|
||||
disable_dvfs:
|
||||
@ -473,7 +518,7 @@ disable_dvfs:
|
||||
remove_opp:
|
||||
/* clean-up the already added opp before leaving */
|
||||
while (load_lvl-- > ARMADA_37XX_DVFS_LOAD_0) {
|
||||
freq = cur_frequency / dvfs->divider[load_lvl];
|
||||
freq = base_frequency / dvfs->divider[load_lvl];
|
||||
dev_pm_opp_remove(cpu_dev, freq);
|
||||
}
|
||||
|
||||
@ -484,6 +529,26 @@ remove_opp:
|
||||
/* late_initcall, to guarantee the driver is loaded after A37xx clock driver */
|
||||
late_initcall(armada37xx_cpufreq_driver_init);
|
||||
|
||||
static void __exit armada37xx_cpufreq_driver_exit(void)
|
||||
{
|
||||
struct platform_device *pdev = armada37xx_cpufreq_state->pdev;
|
||||
struct armada_37xx_dvfs *dvfs = platform_get_drvdata(pdev);
|
||||
unsigned long freq;
|
||||
int load_lvl;
|
||||
|
||||
platform_device_unregister(pdev);
|
||||
|
||||
armada37xx_cpufreq_disable_dvfs(armada37xx_cpufreq_state->regmap);
|
||||
|
||||
for (load_lvl = ARMADA_37XX_DVFS_LOAD_0; load_lvl < LOAD_LEVEL_NR; load_lvl++) {
|
||||
freq = dvfs->cpu_freq_max / dvfs->divider[load_lvl];
|
||||
dev_pm_opp_remove(armada37xx_cpufreq_state->cpu_dev, freq);
|
||||
}
|
||||
|
||||
kfree(armada37xx_cpufreq_state);
|
||||
}
|
||||
module_exit(armada37xx_cpufreq_driver_exit);
|
||||
|
||||
static const struct of_device_id __maybe_unused armada37xx_cpufreq_of_match[] = {
|
||||
{ .compatible = "marvell,armada-3700-nb-pm" },
|
||||
{ },
|
||||
|
@ -10,14 +10,18 @@
|
||||
|
||||
#define pr_fmt(fmt) "CPPC Cpufreq:" fmt
|
||||
|
||||
#include <linux/arch_topology.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/module.h>
|
||||
#include <linux/delay.h>
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/dmi.h>
|
||||
#include <linux/irq_work.h>
|
||||
#include <linux/kthread.h>
|
||||
#include <linux/time.h>
|
||||
#include <linux/vmalloc.h>
|
||||
#include <uapi/linux/sched/types.h>
|
||||
|
||||
#include <asm/unaligned.h>
|
||||
|
||||
@ -57,6 +61,204 @@ static struct cppc_workaround_oem_info wa_info[] = {
|
||||
}
|
||||
};
|
||||
|
||||
#ifdef CONFIG_ACPI_CPPC_CPUFREQ_FIE
|
||||
|
||||
/* Frequency invariance support */
|
||||
struct cppc_freq_invariance {
|
||||
int cpu;
|
||||
struct irq_work irq_work;
|
||||
struct kthread_work work;
|
||||
struct cppc_perf_fb_ctrs prev_perf_fb_ctrs;
|
||||
struct cppc_cpudata *cpu_data;
|
||||
};
|
||||
|
||||
static DEFINE_PER_CPU(struct cppc_freq_invariance, cppc_freq_inv);
|
||||
static struct kthread_worker *kworker_fie;
|
||||
static bool fie_disabled;
|
||||
|
||||
static struct cpufreq_driver cppc_cpufreq_driver;
|
||||
static unsigned int hisi_cppc_cpufreq_get_rate(unsigned int cpu);
|
||||
static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data,
|
||||
struct cppc_perf_fb_ctrs fb_ctrs_t0,
|
||||
struct cppc_perf_fb_ctrs fb_ctrs_t1);
|
||||
|
||||
/**
|
||||
* cppc_scale_freq_workfn - CPPC arch_freq_scale updater for frequency invariance
|
||||
* @work: The work item.
|
||||
*
|
||||
* The CPPC driver register itself with the topology core to provide its own
|
||||
* implementation (cppc_scale_freq_tick()) of topology_scale_freq_tick() which
|
||||
* gets called by the scheduler on every tick.
|
||||
*
|
||||
* Note that the arch specific counters have higher priority than CPPC counters,
|
||||
* if available, though the CPPC driver doesn't need to have any special
|
||||
* handling for that.
|
||||
*
|
||||
* On an invocation of cppc_scale_freq_tick(), we schedule an irq work (since we
|
||||
* reach here from hard-irq context), which then schedules a normal work item
|
||||
* and cppc_scale_freq_workfn() updates the per_cpu arch_freq_scale variable
|
||||
* based on the counter updates since the last tick.
|
||||
*/
|
||||
static void cppc_scale_freq_workfn(struct kthread_work *work)
|
||||
{
|
||||
struct cppc_freq_invariance *cppc_fi;
|
||||
struct cppc_perf_fb_ctrs fb_ctrs = {0};
|
||||
struct cppc_cpudata *cpu_data;
|
||||
unsigned long local_freq_scale;
|
||||
u64 perf;
|
||||
|
||||
cppc_fi = container_of(work, struct cppc_freq_invariance, work);
|
||||
cpu_data = cppc_fi->cpu_data;
|
||||
|
||||
if (cppc_get_perf_ctrs(cppc_fi->cpu, &fb_ctrs)) {
|
||||
pr_warn("%s: failed to read perf counters\n", __func__);
|
||||
return;
|
||||
}
|
||||
|
||||
cppc_fi->prev_perf_fb_ctrs = fb_ctrs;
|
||||
perf = cppc_perf_from_fbctrs(cpu_data, cppc_fi->prev_perf_fb_ctrs,
|
||||
fb_ctrs);
|
||||
|
||||
perf <<= SCHED_CAPACITY_SHIFT;
|
||||
local_freq_scale = div64_u64(perf, cpu_data->perf_caps.highest_perf);
|
||||
if (WARN_ON(local_freq_scale > 1024))
|
||||
local_freq_scale = 1024;
|
||||
|
||||
per_cpu(arch_freq_scale, cppc_fi->cpu) = local_freq_scale;
|
||||
}
|
||||
|
||||
static void cppc_irq_work(struct irq_work *irq_work)
|
||||
{
|
||||
struct cppc_freq_invariance *cppc_fi;
|
||||
|
||||
cppc_fi = container_of(irq_work, struct cppc_freq_invariance, irq_work);
|
||||
kthread_queue_work(kworker_fie, &cppc_fi->work);
|
||||
}
|
||||
|
||||
static void cppc_scale_freq_tick(void)
|
||||
{
|
||||
struct cppc_freq_invariance *cppc_fi = &per_cpu(cppc_freq_inv, smp_processor_id());
|
||||
|
||||
/*
|
||||
* cppc_get_perf_ctrs() can potentially sleep, call that from the right
|
||||
* context.
|
||||
*/
|
||||
irq_work_queue(&cppc_fi->irq_work);
|
||||
}
|
||||
|
||||
static struct scale_freq_data cppc_sftd = {
|
||||
.source = SCALE_FREQ_SOURCE_CPPC,
|
||||
.set_freq_scale = cppc_scale_freq_tick,
|
||||
};
|
||||
|
||||
static void cppc_freq_invariance_policy_init(struct cpufreq_policy *policy,
|
||||
struct cppc_cpudata *cpu_data)
|
||||
{
|
||||
struct cppc_perf_fb_ctrs fb_ctrs = {0};
|
||||
struct cppc_freq_invariance *cppc_fi;
|
||||
int i, ret;
|
||||
|
||||
if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
|
||||
return;
|
||||
|
||||
if (fie_disabled)
|
||||
return;
|
||||
|
||||
for_each_cpu(i, policy->cpus) {
|
||||
cppc_fi = &per_cpu(cppc_freq_inv, i);
|
||||
cppc_fi->cpu = i;
|
||||
cppc_fi->cpu_data = cpu_data;
|
||||
kthread_init_work(&cppc_fi->work, cppc_scale_freq_workfn);
|
||||
init_irq_work(&cppc_fi->irq_work, cppc_irq_work);
|
||||
|
||||
ret = cppc_get_perf_ctrs(i, &fb_ctrs);
|
||||
if (ret) {
|
||||
pr_warn("%s: failed to read perf counters: %d\n",
|
||||
__func__, ret);
|
||||
fie_disabled = true;
|
||||
} else {
|
||||
cppc_fi->prev_perf_fb_ctrs = fb_ctrs;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void __init cppc_freq_invariance_init(void)
|
||||
{
|
||||
struct sched_attr attr = {
|
||||
.size = sizeof(struct sched_attr),
|
||||
.sched_policy = SCHED_DEADLINE,
|
||||
.sched_nice = 0,
|
||||
.sched_priority = 0,
|
||||
/*
|
||||
* Fake (unused) bandwidth; workaround to "fix"
|
||||
* priority inheritance.
|
||||
*/
|
||||
.sched_runtime = 1000000,
|
||||
.sched_deadline = 10000000,
|
||||
.sched_period = 10000000,
|
||||
};
|
||||
int ret;
|
||||
|
||||
if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
|
||||
return;
|
||||
|
||||
if (fie_disabled)
|
||||
return;
|
||||
|
||||
kworker_fie = kthread_create_worker(0, "cppc_fie");
|
||||
if (IS_ERR(kworker_fie))
|
||||
return;
|
||||
|
||||
ret = sched_setattr_nocheck(kworker_fie->task, &attr);
|
||||
if (ret) {
|
||||
pr_warn("%s: failed to set SCHED_DEADLINE: %d\n", __func__,
|
||||
ret);
|
||||
kthread_destroy_worker(kworker_fie);
|
||||
return;
|
||||
}
|
||||
|
||||
/* Register for freq-invariance */
|
||||
topology_set_scale_freq_source(&cppc_sftd, cpu_present_mask);
|
||||
}
|
||||
|
||||
static void cppc_freq_invariance_exit(void)
|
||||
{
|
||||
struct cppc_freq_invariance *cppc_fi;
|
||||
int i;
|
||||
|
||||
if (cppc_cpufreq_driver.get == hisi_cppc_cpufreq_get_rate)
|
||||
return;
|
||||
|
||||
if (fie_disabled)
|
||||
return;
|
||||
|
||||
topology_clear_scale_freq_source(SCALE_FREQ_SOURCE_CPPC, cpu_present_mask);
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
cppc_fi = &per_cpu(cppc_freq_inv, i);
|
||||
irq_work_sync(&cppc_fi->irq_work);
|
||||
}
|
||||
|
||||
kthread_destroy_worker(kworker_fie);
|
||||
kworker_fie = NULL;
|
||||
}
|
||||
|
||||
#else
|
||||
static inline void
|
||||
cppc_freq_invariance_policy_init(struct cpufreq_policy *policy,
|
||||
struct cppc_cpudata *cpu_data)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void cppc_freq_invariance_init(void)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void cppc_freq_invariance_exit(void)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_ACPI_CPPC_CPUFREQ_FIE */
|
||||
|
||||
/* Callback function used to retrieve the max frequency from DMI */
|
||||
static void cppc_find_dmi_mhz(const struct dmi_header *dm, void *private)
|
||||
{
|
||||
@ -216,26 +418,16 @@ static unsigned int cppc_cpufreq_get_transition_delay_us(unsigned int cpu)
|
||||
{
|
||||
unsigned long implementor = read_cpuid_implementor();
|
||||
unsigned long part_num = read_cpuid_part_number();
|
||||
unsigned int delay_us = 0;
|
||||
|
||||
switch (implementor) {
|
||||
case ARM_CPU_IMP_QCOM:
|
||||
switch (part_num) {
|
||||
case QCOM_CPU_PART_FALKOR_V1:
|
||||
case QCOM_CPU_PART_FALKOR:
|
||||
delay_us = 10000;
|
||||
break;
|
||||
default:
|
||||
delay_us = cppc_get_transition_latency(cpu) / NSEC_PER_USEC;
|
||||
break;
|
||||
return 10000;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
delay_us = cppc_get_transition_latency(cpu) / NSEC_PER_USEC;
|
||||
break;
|
||||
}
|
||||
|
||||
return delay_us;
|
||||
return cppc_get_transition_latency(cpu) / NSEC_PER_USEC;
|
||||
}
|
||||
|
||||
#else
|
||||
@ -355,9 +547,12 @@ static int cppc_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
cpu_data->perf_ctrls.desired_perf = caps->highest_perf;
|
||||
|
||||
ret = cppc_set_perf(cpu, &cpu_data->perf_ctrls);
|
||||
if (ret)
|
||||
if (ret) {
|
||||
pr_debug("Err setting perf value:%d on CPU:%d. ret:%d\n",
|
||||
caps->highest_perf, cpu, ret);
|
||||
} else {
|
||||
cppc_freq_invariance_policy_init(policy, cpu_data);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -370,12 +565,12 @@ static inline u64 get_delta(u64 t1, u64 t0)
|
||||
return (u32)t1 - (u32)t0;
|
||||
}
|
||||
|
||||
static int cppc_get_rate_from_fbctrs(struct cppc_cpudata *cpu_data,
|
||||
struct cppc_perf_fb_ctrs fb_ctrs_t0,
|
||||
struct cppc_perf_fb_ctrs fb_ctrs_t1)
|
||||
static int cppc_perf_from_fbctrs(struct cppc_cpudata *cpu_data,
|
||||
struct cppc_perf_fb_ctrs fb_ctrs_t0,
|
||||
struct cppc_perf_fb_ctrs fb_ctrs_t1)
|
||||
{
|
||||
u64 delta_reference, delta_delivered;
|
||||
u64 reference_perf, delivered_perf;
|
||||
u64 reference_perf;
|
||||
|
||||
reference_perf = fb_ctrs_t0.reference_perf;
|
||||
|
||||
@ -384,12 +579,21 @@ static int cppc_get_rate_from_fbctrs(struct cppc_cpudata *cpu_data,
|
||||
delta_delivered = get_delta(fb_ctrs_t1.delivered,
|
||||
fb_ctrs_t0.delivered);
|
||||
|
||||
/* Check to avoid divide-by zero */
|
||||
if (delta_reference || delta_delivered)
|
||||
delivered_perf = (reference_perf * delta_delivered) /
|
||||
delta_reference;
|
||||
else
|
||||
delivered_perf = cpu_data->perf_ctrls.desired_perf;
|
||||
/* Check to avoid divide-by zero and invalid delivered_perf */
|
||||
if (!delta_reference || !delta_delivered)
|
||||
return cpu_data->perf_ctrls.desired_perf;
|
||||
|
||||
return (reference_perf * delta_delivered) / delta_reference;
|
||||
}
|
||||
|
||||
static int cppc_get_rate_from_fbctrs(struct cppc_cpudata *cpu_data,
|
||||
struct cppc_perf_fb_ctrs fb_ctrs_t0,
|
||||
struct cppc_perf_fb_ctrs fb_ctrs_t1)
|
||||
{
|
||||
u64 delivered_perf;
|
||||
|
||||
delivered_perf = cppc_perf_from_fbctrs(cpu_data, fb_ctrs_t0,
|
||||
fb_ctrs_t1);
|
||||
|
||||
return cppc_cpufreq_perf_to_khz(cpu_data, delivered_perf);
|
||||
}
|
||||
@ -514,6 +718,8 @@ static void cppc_check_hisi_workaround(void)
|
||||
|
||||
static int __init cppc_cpufreq_init(void)
|
||||
{
|
||||
int ret;
|
||||
|
||||
if ((acpi_disabled) || !acpi_cpc_valid())
|
||||
return -ENODEV;
|
||||
|
||||
@ -521,7 +727,11 @@ static int __init cppc_cpufreq_init(void)
|
||||
|
||||
cppc_check_hisi_workaround();
|
||||
|
||||
return cpufreq_register_driver(&cppc_cpufreq_driver);
|
||||
ret = cpufreq_register_driver(&cppc_cpufreq_driver);
|
||||
if (!ret)
|
||||
cppc_freq_invariance_init();
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static inline void free_cpu_data(void)
|
||||
@ -538,6 +748,7 @@ static inline void free_cpu_data(void)
|
||||
|
||||
static void __exit cppc_cpufreq_exit(void)
|
||||
{
|
||||
cppc_freq_invariance_exit();
|
||||
cpufreq_unregister_driver(&cppc_cpufreq_driver);
|
||||
|
||||
free_cpu_data();
|
||||
|
@ -255,10 +255,15 @@ static int dt_cpufreq_early_init(struct device *dev, int cpu)
|
||||
* before updating priv->cpus. Otherwise, we will end up creating
|
||||
* duplicate OPPs for the CPUs.
|
||||
*
|
||||
* OPPs might be populated at runtime, don't check for error here.
|
||||
* OPPs might be populated at runtime, don't fail for error here unless
|
||||
* it is -EPROBE_DEFER.
|
||||
*/
|
||||
if (!dev_pm_opp_of_cpumask_add_table(priv->cpus))
|
||||
ret = dev_pm_opp_of_cpumask_add_table(priv->cpus);
|
||||
if (!ret) {
|
||||
priv->have_static_opps = true;
|
||||
} else if (ret == -EPROBE_DEFER) {
|
||||
goto out;
|
||||
}
|
||||
|
||||
/*
|
||||
* The OPP table must be initialized, statically or dynamically, by this
|
||||
|
@ -42,9 +42,6 @@ static LIST_HEAD(cpufreq_policy_list);
|
||||
#define for_each_inactive_policy(__policy) \
|
||||
for_each_suitable_policy(__policy, false)
|
||||
|
||||
#define for_each_policy(__policy) \
|
||||
list_for_each_entry(__policy, &cpufreq_policy_list, policy_list)
|
||||
|
||||
/* Iterate over governors */
|
||||
static LIST_HEAD(cpufreq_governor_list);
|
||||
#define for_each_governor(__governor) \
|
||||
|
@ -54,7 +54,7 @@ processor_set_pstate (
|
||||
retval = ia64_pal_set_pstate((u64)value);
|
||||
|
||||
if (retval) {
|
||||
pr_debug("Failed to set freq to 0x%x, with error 0x%lx\n",
|
||||
pr_debug("Failed to set freq to 0x%x, with error 0x%llx\n",
|
||||
value, retval);
|
||||
return -ENODEV;
|
||||
}
|
||||
@ -77,7 +77,7 @@ processor_get_pstate (
|
||||
|
||||
if (retval)
|
||||
pr_debug("Failed to get current freq with "
|
||||
"error 0x%lx, idx 0x%x\n", retval, *value);
|
||||
"error 0x%llx, idx 0x%x\n", retval, *value);
|
||||
|
||||
return (int)retval;
|
||||
}
|
||||
|
@ -819,19 +819,21 @@ static struct freq_attr *hwp_cpufreq_attrs[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
static void intel_pstate_get_hwp_max(struct cpudata *cpu, int *phy_max,
|
||||
int *current_max)
|
||||
static void __intel_pstate_get_hwp_cap(struct cpudata *cpu)
|
||||
{
|
||||
u64 cap;
|
||||
|
||||
rdmsrl_on_cpu(cpu->cpu, MSR_HWP_CAPABILITIES, &cap);
|
||||
WRITE_ONCE(cpu->hwp_cap_cached, cap);
|
||||
if (global.no_turbo || global.turbo_disabled)
|
||||
*current_max = HWP_GUARANTEED_PERF(cap);
|
||||
else
|
||||
*current_max = HWP_HIGHEST_PERF(cap);
|
||||
cpu->pstate.max_pstate = HWP_GUARANTEED_PERF(cap);
|
||||
cpu->pstate.turbo_pstate = HWP_HIGHEST_PERF(cap);
|
||||
}
|
||||
|
||||
*phy_max = HWP_HIGHEST_PERF(cap);
|
||||
static void intel_pstate_get_hwp_cap(struct cpudata *cpu)
|
||||
{
|
||||
__intel_pstate_get_hwp_cap(cpu);
|
||||
cpu->pstate.max_freq = cpu->pstate.max_pstate * cpu->pstate.scaling;
|
||||
cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * cpu->pstate.scaling;
|
||||
}
|
||||
|
||||
static void intel_pstate_hwp_set(unsigned int cpu)
|
||||
@ -1195,12 +1197,13 @@ static ssize_t store_no_turbo(struct kobject *a, struct kobj_attribute *b,
|
||||
|
||||
static void update_qos_request(enum freq_qos_req_type type)
|
||||
{
|
||||
int max_state, turbo_max, freq, i, perf_pct;
|
||||
struct freq_qos_request *req;
|
||||
struct cpufreq_policy *policy;
|
||||
int i;
|
||||
|
||||
for_each_possible_cpu(i) {
|
||||
struct cpudata *cpu = all_cpu_data[i];
|
||||
unsigned int freq, perf_pct;
|
||||
|
||||
policy = cpufreq_cpu_get(i);
|
||||
if (!policy)
|
||||
@ -1213,9 +1216,7 @@ static void update_qos_request(enum freq_qos_req_type type)
|
||||
continue;
|
||||
|
||||
if (hwp_active)
|
||||
intel_pstate_get_hwp_max(cpu, &turbo_max, &max_state);
|
||||
else
|
||||
turbo_max = cpu->pstate.turbo_pstate;
|
||||
intel_pstate_get_hwp_cap(cpu);
|
||||
|
||||
if (type == FREQ_QOS_MIN) {
|
||||
perf_pct = global.min_perf_pct;
|
||||
@ -1224,8 +1225,7 @@ static void update_qos_request(enum freq_qos_req_type type)
|
||||
perf_pct = global.max_perf_pct;
|
||||
}
|
||||
|
||||
freq = DIV_ROUND_UP(turbo_max * perf_pct, 100);
|
||||
freq *= cpu->pstate.scaling;
|
||||
freq = DIV_ROUND_UP(cpu->pstate.turbo_freq * perf_pct, 100);
|
||||
|
||||
if (freq_qos_update_request(req, freq) < 0)
|
||||
pr_warn("Failed to update freq constraint: CPU%d\n", i);
|
||||
@ -1715,21 +1715,17 @@ static void intel_pstate_get_cpu_pstates(struct cpudata *cpu)
|
||||
{
|
||||
cpu->pstate.min_pstate = pstate_funcs.get_min();
|
||||
cpu->pstate.max_pstate_physical = pstate_funcs.get_max_physical();
|
||||
cpu->pstate.turbo_pstate = pstate_funcs.get_turbo();
|
||||
cpu->pstate.scaling = pstate_funcs.get_scaling();
|
||||
|
||||
if (hwp_active && !hwp_mode_bdw) {
|
||||
unsigned int phy_max, current_max;
|
||||
|
||||
intel_pstate_get_hwp_max(cpu, &phy_max, ¤t_max);
|
||||
cpu->pstate.turbo_freq = phy_max * cpu->pstate.scaling;
|
||||
cpu->pstate.turbo_pstate = phy_max;
|
||||
cpu->pstate.max_pstate = HWP_GUARANTEED_PERF(READ_ONCE(cpu->hwp_cap_cached));
|
||||
__intel_pstate_get_hwp_cap(cpu);
|
||||
} else {
|
||||
cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * cpu->pstate.scaling;
|
||||
cpu->pstate.max_pstate = pstate_funcs.get_max();
|
||||
cpu->pstate.turbo_pstate = pstate_funcs.get_turbo();
|
||||
}
|
||||
|
||||
cpu->pstate.max_freq = cpu->pstate.max_pstate * cpu->pstate.scaling;
|
||||
cpu->pstate.turbo_freq = cpu->pstate.turbo_pstate * cpu->pstate.scaling;
|
||||
|
||||
if (pstate_funcs.get_aperf_mperf_shift)
|
||||
cpu->aperf_mperf_shift = pstate_funcs.get_aperf_mperf_shift();
|
||||
@ -2199,41 +2195,34 @@ static void intel_pstate_update_perf_limits(struct cpudata *cpu,
|
||||
unsigned int policy_min,
|
||||
unsigned int policy_max)
|
||||
{
|
||||
int scaling = cpu->pstate.scaling;
|
||||
int32_t max_policy_perf, min_policy_perf;
|
||||
int max_state, turbo_max;
|
||||
int max_freq;
|
||||
|
||||
/*
|
||||
* HWP needs some special consideration, because on BDX the
|
||||
* HWP_REQUEST uses abstract value to represent performance
|
||||
* rather than pure ratios.
|
||||
* HWP needs some special consideration, because HWP_REQUEST uses
|
||||
* abstract values to represent performance rather than pure ratios.
|
||||
*/
|
||||
if (hwp_active) {
|
||||
intel_pstate_get_hwp_max(cpu, &turbo_max, &max_state);
|
||||
} else {
|
||||
max_state = global.no_turbo || global.turbo_disabled ?
|
||||
cpu->pstate.max_pstate : cpu->pstate.turbo_pstate;
|
||||
turbo_max = cpu->pstate.turbo_pstate;
|
||||
}
|
||||
max_freq = max_state * cpu->pstate.scaling;
|
||||
if (hwp_active)
|
||||
intel_pstate_get_hwp_cap(cpu);
|
||||
|
||||
max_policy_perf = max_state * policy_max / max_freq;
|
||||
max_policy_perf = policy_max / scaling;
|
||||
if (policy_max == policy_min) {
|
||||
min_policy_perf = max_policy_perf;
|
||||
} else {
|
||||
min_policy_perf = max_state * policy_min / max_freq;
|
||||
min_policy_perf = policy_min / scaling;
|
||||
min_policy_perf = clamp_t(int32_t, min_policy_perf,
|
||||
0, max_policy_perf);
|
||||
}
|
||||
|
||||
pr_debug("cpu:%d max_state %d min_policy_perf:%d max_policy_perf:%d\n",
|
||||
cpu->cpu, max_state, min_policy_perf, max_policy_perf);
|
||||
pr_debug("cpu:%d min_policy_perf:%d max_policy_perf:%d\n",
|
||||
cpu->cpu, min_policy_perf, max_policy_perf);
|
||||
|
||||
/* Normalize user input to [min_perf, max_perf] */
|
||||
if (per_cpu_limits) {
|
||||
cpu->min_perf_ratio = min_policy_perf;
|
||||
cpu->max_perf_ratio = max_policy_perf;
|
||||
} else {
|
||||
int turbo_max = cpu->pstate.turbo_pstate;
|
||||
int32_t global_min, global_max;
|
||||
|
||||
/* Global limits are in percent of the maximum turbo P-state. */
|
||||
@ -2322,10 +2311,9 @@ static void intel_pstate_verify_cpu_policy(struct cpudata *cpu,
|
||||
|
||||
update_turbo_state();
|
||||
if (hwp_active) {
|
||||
int max_state, turbo_max;
|
||||
|
||||
intel_pstate_get_hwp_max(cpu, &turbo_max, &max_state);
|
||||
max_freq = max_state * cpu->pstate.scaling;
|
||||
intel_pstate_get_hwp_cap(cpu);
|
||||
max_freq = global.no_turbo || global.turbo_disabled ?
|
||||
cpu->pstate.max_freq : cpu->pstate.turbo_freq;
|
||||
} else {
|
||||
max_freq = intel_pstate_get_max_freq(cpu);
|
||||
}
|
||||
@ -2416,25 +2404,15 @@ static int __intel_pstate_cpu_init(struct cpufreq_policy *policy)
|
||||
cpu->max_perf_ratio = 0xFF;
|
||||
cpu->min_perf_ratio = 0;
|
||||
|
||||
policy->min = cpu->pstate.min_pstate * cpu->pstate.scaling;
|
||||
policy->max = cpu->pstate.turbo_pstate * cpu->pstate.scaling;
|
||||
|
||||
/* cpuinfo and default policy values */
|
||||
policy->cpuinfo.min_freq = cpu->pstate.min_pstate * cpu->pstate.scaling;
|
||||
update_turbo_state();
|
||||
global.turbo_disabled_mf = global.turbo_disabled;
|
||||
policy->cpuinfo.max_freq = global.turbo_disabled ?
|
||||
cpu->pstate.max_pstate : cpu->pstate.turbo_pstate;
|
||||
policy->cpuinfo.max_freq *= cpu->pstate.scaling;
|
||||
|
||||
if (hwp_active) {
|
||||
unsigned int max_freq;
|
||||
|
||||
max_freq = global.turbo_disabled ?
|
||||
cpu->pstate.max_freq : cpu->pstate.turbo_freq;
|
||||
if (max_freq < policy->cpuinfo.max_freq)
|
||||
policy->cpuinfo.max_freq = max_freq;
|
||||
}
|
||||
|
||||
policy->min = policy->cpuinfo.min_freq;
|
||||
policy->max = policy->cpuinfo.max_freq;
|
||||
|
||||
intel_pstate_init_acpi_perf_limits(policy);
|
||||
|
||||
@ -2683,10 +2661,10 @@ static void intel_cpufreq_adjust_perf(unsigned int cpunum,
|
||||
|
||||
static int intel_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
int max_state, turbo_max, min_freq, max_freq, ret;
|
||||
struct freq_qos_request *req;
|
||||
struct cpudata *cpu;
|
||||
struct device *dev;
|
||||
int ret, freq;
|
||||
|
||||
dev = get_cpu_device(policy->cpu);
|
||||
if (!dev)
|
||||
@ -2711,30 +2689,31 @@ static int intel_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
||||
if (hwp_active) {
|
||||
u64 value;
|
||||
|
||||
intel_pstate_get_hwp_max(cpu, &turbo_max, &max_state);
|
||||
policy->transition_delay_us = INTEL_CPUFREQ_TRANSITION_DELAY_HWP;
|
||||
|
||||
intel_pstate_get_hwp_cap(cpu);
|
||||
|
||||
rdmsrl_on_cpu(cpu->cpu, MSR_HWP_REQUEST, &value);
|
||||
WRITE_ONCE(cpu->hwp_req_cached, value);
|
||||
|
||||
cpu->epp_cached = intel_pstate_get_epp(cpu, value);
|
||||
} else {
|
||||
turbo_max = cpu->pstate.turbo_pstate;
|
||||
policy->transition_delay_us = INTEL_CPUFREQ_TRANSITION_DELAY;
|
||||
}
|
||||
|
||||
min_freq = DIV_ROUND_UP(turbo_max * global.min_perf_pct, 100);
|
||||
min_freq *= cpu->pstate.scaling;
|
||||
max_freq = DIV_ROUND_UP(turbo_max * global.max_perf_pct, 100);
|
||||
max_freq *= cpu->pstate.scaling;
|
||||
freq = DIV_ROUND_UP(cpu->pstate.turbo_freq * global.min_perf_pct, 100);
|
||||
|
||||
ret = freq_qos_add_request(&policy->constraints, req, FREQ_QOS_MIN,
|
||||
min_freq);
|
||||
freq);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to add min-freq constraint (%d)\n", ret);
|
||||
goto free_req;
|
||||
}
|
||||
|
||||
freq = DIV_ROUND_UP(cpu->pstate.turbo_freq * global.max_perf_pct, 100);
|
||||
|
||||
ret = freq_qos_add_request(&policy->constraints, req + 1, FREQ_QOS_MAX,
|
||||
max_freq);
|
||||
freq);
|
||||
if (ret < 0) {
|
||||
dev_err(dev, "Failed to add max-freq constraint (%d)\n", ret);
|
||||
goto remove_min_req;
|
||||
|
@ -91,7 +91,7 @@ static DEFINE_MUTEX(set_freq_lock);
|
||||
/* Use 800MHz when entering sleep mode */
|
||||
#define SLEEP_FREQ (800 * 1000)
|
||||
|
||||
/* Tracks if cpu freqency can be updated anymore */
|
||||
/* Tracks if CPU frequency can be updated anymore */
|
||||
static bool no_cpufreq_access;
|
||||
|
||||
/*
|
||||
@ -190,7 +190,7 @@ static u32 clkdiv_val[5][11] = {
|
||||
|
||||
/*
|
||||
* This function set DRAM refresh counter
|
||||
* accoriding to operating frequency of DRAM
|
||||
* according to operating frequency of DRAM
|
||||
* ch: DMC port number 0 or 1
|
||||
* freq: Operating frequency of DRAM(KHz)
|
||||
*/
|
||||
@ -320,7 +320,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
|
||||
/*
|
||||
* 3. DMC1 refresh count for 133Mhz if (index == L4) is
|
||||
* true refresh counter is already programed in upper
|
||||
* true refresh counter is already programmed in upper
|
||||
* code. 0x287@83Mhz
|
||||
*/
|
||||
if (!bus_speed_changing)
|
||||
@ -378,7 +378,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
/*
|
||||
* 6. Turn on APLL
|
||||
* 6-1. Set PMS values
|
||||
* 6-2. Wait untile the PLL is locked
|
||||
* 6-2. Wait until the PLL is locked
|
||||
*/
|
||||
if (index == L0)
|
||||
writel_relaxed(APLL_VAL_1000, S5P_APLL_CON);
|
||||
@ -390,7 +390,7 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
} while (!(reg & (0x1 << 29)));
|
||||
|
||||
/*
|
||||
* 7. Change souce clock from SCLKMPLL(667Mhz)
|
||||
* 7. Change source clock from SCLKMPLL(667Mhz)
|
||||
* to SCLKA2M(200Mhz) in MFC_MUX and G3D MUX
|
||||
* (667/4=166)->(200/4=50)Mhz
|
||||
*/
|
||||
@ -439,8 +439,8 @@ static int s5pv210_target(struct cpufreq_policy *policy, unsigned int index)
|
||||
}
|
||||
|
||||
/*
|
||||
* L4 level need to change memory bus speed, hence onedram clock divier
|
||||
* and memory refresh parameter should be changed
|
||||
* L4 level needs to change memory bus speed, hence ONEDRAM clock
|
||||
* divider and memory refresh parameter should be changed
|
||||
*/
|
||||
if (bus_speed_changing) {
|
||||
reg = readl_relaxed(S5P_CLK_DIV6);
|
||||
|
@ -107,7 +107,7 @@ config ARM_TEGRA_CPUIDLE
|
||||
|
||||
config ARM_QCOM_SPM_CPUIDLE
|
||||
bool "CPU Idle Driver for Qualcomm Subsystem Power Manager (SPM)"
|
||||
depends on (ARCH_QCOM || COMPILE_TEST) && !ARM64
|
||||
depends on (ARCH_QCOM || COMPILE_TEST) && !ARM64 && MMU
|
||||
select ARM_CPU_SUSPEND
|
||||
select CPU_IDLE_MULTIPLE_DRIVERS
|
||||
select DT_IDLE_STATES
|
||||
|
@ -48,11 +48,6 @@ enum tegra_state {
|
||||
static atomic_t tegra_idle_barrier;
|
||||
static atomic_t tegra_abort_flag;
|
||||
|
||||
static inline bool tegra_cpuidle_using_firmware(void)
|
||||
{
|
||||
return firmware_ops->prepare_idle && firmware_ops->do_idle;
|
||||
}
|
||||
|
||||
static void tegra_cpuidle_report_cpus_state(void)
|
||||
{
|
||||
unsigned long cpu, lcpu, csr;
|
||||
@ -135,13 +130,9 @@ static int tegra_cpuidle_c7_enter(void)
|
||||
{
|
||||
int err;
|
||||
|
||||
if (tegra_cpuidle_using_firmware()) {
|
||||
err = call_firmware_op(prepare_idle, TF_PM_MODE_LP2_NOFLUSH_L2);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
return call_firmware_op(do_idle, 0);
|
||||
}
|
||||
err = call_firmware_op(prepare_idle, TF_PM_MODE_LP2_NOFLUSH_L2);
|
||||
if (err && err != -ENOSYS)
|
||||
return err;
|
||||
|
||||
return cpu_suspend(0, tegra30_pm_secondary_cpu_suspend);
|
||||
}
|
||||
@ -356,9 +347,7 @@ static int tegra_cpuidle_probe(struct platform_device *pdev)
|
||||
* is disabled.
|
||||
*/
|
||||
if (!IS_ENABLED(CONFIG_PM_SLEEP)) {
|
||||
if (!tegra_cpuidle_using_firmware())
|
||||
tegra_cpuidle_disable_state(TEGRA_C7);
|
||||
|
||||
tegra_cpuidle_disable_state(TEGRA_C7);
|
||||
tegra_cpuidle_disable_state(TEGRA_CC6);
|
||||
}
|
||||
|
||||
|
@ -181,9 +181,13 @@ static void __cpuidle_driver_init(struct cpuidle_driver *drv)
|
||||
*/
|
||||
if (s->target_residency > 0)
|
||||
s->target_residency_ns = s->target_residency * NSEC_PER_USEC;
|
||||
else if (s->target_residency_ns < 0)
|
||||
s->target_residency_ns = 0;
|
||||
|
||||
if (s->exit_latency > 0)
|
||||
s->exit_latency_ns = s->exit_latency * NSEC_PER_USEC;
|
||||
else if (s->exit_latency_ns < 0)
|
||||
s->exit_latency_ns = 0;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -271,7 +271,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
||||
u64 predicted_ns;
|
||||
u64 interactivity_req;
|
||||
unsigned long nr_iowaiters;
|
||||
ktime_t delta_next;
|
||||
ktime_t delta, delta_tick;
|
||||
int i, idx;
|
||||
|
||||
if (data->needs_update) {
|
||||
@ -280,7 +280,12 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
||||
}
|
||||
|
||||
/* determine the expected residency time, round up */
|
||||
data->next_timer_ns = tick_nohz_get_sleep_length(&delta_next);
|
||||
delta = tick_nohz_get_sleep_length(&delta_tick);
|
||||
if (unlikely(delta < 0)) {
|
||||
delta = 0;
|
||||
delta_tick = 0;
|
||||
}
|
||||
data->next_timer_ns = delta;
|
||||
|
||||
nr_iowaiters = nr_iowait_cpu(dev->cpu);
|
||||
data->bucket = which_bucket(data->next_timer_ns, nr_iowaiters);
|
||||
@ -318,7 +323,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
||||
* state selection.
|
||||
*/
|
||||
if (predicted_ns < TICK_NSEC)
|
||||
predicted_ns = delta_next;
|
||||
predicted_ns = data->next_timer_ns;
|
||||
} else {
|
||||
/*
|
||||
* Use the performance multiplier and the user-configurable
|
||||
@ -377,7 +382,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
||||
* stuck in the shallow one for too long.
|
||||
*/
|
||||
if (drv->states[idx].target_residency_ns < TICK_NSEC &&
|
||||
s->target_residency_ns <= delta_next)
|
||||
s->target_residency_ns <= delta_tick)
|
||||
idx = i;
|
||||
|
||||
return idx;
|
||||
@ -399,7 +404,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
||||
predicted_ns < TICK_NSEC) && !tick_nohz_tick_stopped()) {
|
||||
*stop_tick = false;
|
||||
|
||||
if (idx > 0 && drv->states[idx].target_residency_ns > delta_next) {
|
||||
if (idx > 0 && drv->states[idx].target_residency_ns > delta_tick) {
|
||||
/*
|
||||
* The tick is not going to be stopped and the target
|
||||
* residency of the state to be returned is not within
|
||||
@ -411,7 +416,7 @@ static int menu_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
||||
continue;
|
||||
|
||||
idx = i;
|
||||
if (drv->states[i].target_residency_ns <= delta_next)
|
||||
if (drv->states[i].target_residency_ns <= delta_tick)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -100,8 +100,8 @@ struct teo_idle_state {
|
||||
* @intervals: Saved idle duration values.
|
||||
*/
|
||||
struct teo_cpu {
|
||||
u64 time_span_ns;
|
||||
u64 sleep_length_ns;
|
||||
s64 time_span_ns;
|
||||
s64 sleep_length_ns;
|
||||
struct teo_idle_state states[CPUIDLE_STATE_MAX];
|
||||
int interval_idx;
|
||||
u64 intervals[INTERVALS];
|
||||
@ -117,7 +117,8 @@ static DEFINE_PER_CPU(struct teo_cpu, teo_cpus);
|
||||
static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
|
||||
{
|
||||
struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
|
||||
int i, idx_hit = -1, idx_timer = -1;
|
||||
int i, idx_hit = 0, idx_timer = 0;
|
||||
unsigned int hits, misses;
|
||||
u64 measured_ns;
|
||||
|
||||
if (cpu_data->time_span_ns >= cpu_data->sleep_length_ns) {
|
||||
@ -174,25 +175,22 @@ static void teo_update(struct cpuidle_driver *drv, struct cpuidle_device *dev)
|
||||
* also increase the "early hits" metric for the state that actually
|
||||
* matches the measured idle duration.
|
||||
*/
|
||||
if (idx_timer >= 0) {
|
||||
unsigned int hits = cpu_data->states[idx_timer].hits;
|
||||
unsigned int misses = cpu_data->states[idx_timer].misses;
|
||||
hits = cpu_data->states[idx_timer].hits;
|
||||
hits -= hits >> DECAY_SHIFT;
|
||||
|
||||
hits -= hits >> DECAY_SHIFT;
|
||||
misses -= misses >> DECAY_SHIFT;
|
||||
misses = cpu_data->states[idx_timer].misses;
|
||||
misses -= misses >> DECAY_SHIFT;
|
||||
|
||||
if (idx_timer > idx_hit) {
|
||||
misses += PULSE;
|
||||
if (idx_hit >= 0)
|
||||
cpu_data->states[idx_hit].early_hits += PULSE;
|
||||
} else {
|
||||
hits += PULSE;
|
||||
}
|
||||
|
||||
cpu_data->states[idx_timer].misses = misses;
|
||||
cpu_data->states[idx_timer].hits = hits;
|
||||
if (idx_timer == idx_hit) {
|
||||
hits += PULSE;
|
||||
} else {
|
||||
misses += PULSE;
|
||||
cpu_data->states[idx_hit].early_hits += PULSE;
|
||||
}
|
||||
|
||||
cpu_data->states[idx_timer].misses = misses;
|
||||
cpu_data->states[idx_timer].hits = hits;
|
||||
|
||||
/*
|
||||
* Save idle duration values corresponding to non-timer wakeups for
|
||||
* pattern detection.
|
||||
@ -216,7 +214,7 @@ static bool teo_time_ok(u64 interval_ns)
|
||||
*/
|
||||
static int teo_find_shallower_state(struct cpuidle_driver *drv,
|
||||
struct cpuidle_device *dev, int state_idx,
|
||||
u64 duration_ns)
|
||||
s64 duration_ns)
|
||||
{
|
||||
int i;
|
||||
|
||||
@ -242,10 +240,10 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
||||
{
|
||||
struct teo_cpu *cpu_data = per_cpu_ptr(&teo_cpus, dev->cpu);
|
||||
s64 latency_req = cpuidle_governor_latency_req(dev->cpu);
|
||||
u64 duration_ns;
|
||||
int max_early_idx, prev_max_early_idx, constraint_idx, idx0, idx, i;
|
||||
unsigned int hits, misses, early_hits;
|
||||
int max_early_idx, prev_max_early_idx, constraint_idx, idx, i;
|
||||
ktime_t delta_tick;
|
||||
s64 duration_ns;
|
||||
|
||||
if (dev->last_state_idx >= 0) {
|
||||
teo_update(drv, dev);
|
||||
@ -264,6 +262,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
||||
prev_max_early_idx = -1;
|
||||
constraint_idx = drv->state_count;
|
||||
idx = -1;
|
||||
idx0 = idx;
|
||||
|
||||
for (i = 0; i < drv->state_count; i++) {
|
||||
struct cpuidle_state *s = &drv->states[i];
|
||||
@ -324,6 +323,7 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
||||
idx = i; /* first enabled state */
|
||||
hits = cpu_data->states[i].hits;
|
||||
misses = cpu_data->states[i].misses;
|
||||
idx0 = i;
|
||||
}
|
||||
|
||||
if (s->target_residency_ns > duration_ns)
|
||||
@ -376,11 +376,16 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
||||
|
||||
if (idx < 0) {
|
||||
idx = 0; /* No states enabled. Must use 0. */
|
||||
} else if (idx > 0) {
|
||||
} else if (idx > idx0) {
|
||||
unsigned int count = 0;
|
||||
u64 sum = 0;
|
||||
|
||||
/*
|
||||
* The target residencies of at least two different enabled idle
|
||||
* states are less than or equal to the current expected idle
|
||||
* duration. Try to refine the selection using the most recent
|
||||
* measured idle duration values.
|
||||
*
|
||||
* Count and sum the most recent idle duration values less than
|
||||
* the current expected idle duration value.
|
||||
*/
|
||||
@ -428,7 +433,8 @@ static int teo_select(struct cpuidle_driver *drv, struct cpuidle_device *dev,
|
||||
* till the closest timer including the tick, try to correct
|
||||
* that.
|
||||
*/
|
||||
if (idx > 0 && drv->states[idx].target_residency_ns > delta_tick)
|
||||
if (idx > idx0 &&
|
||||
drv->states[idx].target_residency_ns > delta_tick)
|
||||
idx = teo_find_shallower_state(drv, dev, idx, delta_tick);
|
||||
}
|
||||
|
||||
|
@ -62,7 +62,7 @@ config DEVFREQ_GOV_USERSPACE
|
||||
help
|
||||
Sets the frequency at the user specified one.
|
||||
This governor returns the user configured frequency if there
|
||||
has been an input to /sys/devices/.../power/devfreq_set_freq.
|
||||
has been an input to /sys/devices/.../userspace/set_freq.
|
||||
Otherwise, the governor does not change the frequency
|
||||
given at the initialization.
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include <linux/kmod.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/debugfs.h>
|
||||
#include <linux/devfreq_cooling.h>
|
||||
#include <linux/errno.h>
|
||||
#include <linux/err.h>
|
||||
#include <linux/init.h>
|
||||
@ -387,7 +388,7 @@ static int devfreq_set_target(struct devfreq *devfreq, unsigned long new_freq,
|
||||
devfreq->previous_freq = new_freq;
|
||||
|
||||
if (devfreq->suspend_freq)
|
||||
devfreq->resume_freq = cur_freq;
|
||||
devfreq->resume_freq = new_freq;
|
||||
|
||||
return err;
|
||||
}
|
||||
@ -821,7 +822,8 @@ struct devfreq *devfreq_add_device(struct device *dev,
|
||||
|
||||
if (devfreq->profile->timer < 0
|
||||
|| devfreq->profile->timer >= DEVFREQ_TIMER_NUM) {
|
||||
goto err_out;
|
||||
mutex_unlock(&devfreq->lock);
|
||||
goto err_dev;
|
||||
}
|
||||
|
||||
if (!devfreq->profile->max_state && !devfreq->profile->freq_table) {
|
||||
@ -935,6 +937,12 @@ struct devfreq *devfreq_add_device(struct device *dev,
|
||||
|
||||
mutex_unlock(&devfreq_list_lock);
|
||||
|
||||
if (devfreq->profile->is_cooling_device) {
|
||||
devfreq->cdev = devfreq_cooling_em_register(devfreq, NULL);
|
||||
if (IS_ERR(devfreq->cdev))
|
||||
devfreq->cdev = NULL;
|
||||
}
|
||||
|
||||
return devfreq;
|
||||
|
||||
err_init:
|
||||
@ -960,6 +968,8 @@ int devfreq_remove_device(struct devfreq *devfreq)
|
||||
if (!devfreq)
|
||||
return -EINVAL;
|
||||
|
||||
devfreq_cooling_unregister(devfreq->cdev);
|
||||
|
||||
if (devfreq->governor) {
|
||||
devfreq->governor->event_handler(devfreq,
|
||||
DEVFREQ_GOV_STOP, NULL);
|
||||
|
@ -57,8 +57,6 @@
|
||||
* Basically, get_target_freq will run
|
||||
* devfreq_dev_profile.get_dev_status() to get the
|
||||
* status of the device (load = busy_time / total_time).
|
||||
* If no_central_polling is set, this callback is called
|
||||
* only with update_devfreq() notified by OPP.
|
||||
* @event_handler: Callback for devfreq core framework to notify events
|
||||
* to governors. Events include per device governor
|
||||
* init and exit, opp changes out of devfreq, suspend
|
||||
@ -91,6 +89,9 @@ int devfreq_update_target(struct devfreq *devfreq, unsigned long freq);
|
||||
|
||||
static inline int devfreq_update_stats(struct devfreq *df)
|
||||
{
|
||||
if (!df->profile->get_dev_status)
|
||||
return -EINVAL;
|
||||
|
||||
return df->profile->get_dev_status(df->dev.parent, &df->last_status);
|
||||
}
|
||||
#endif /* _GOVERNOR_H */
|
||||
|
@ -169,7 +169,7 @@ static struct platform_driver imx_bus_platdrv = {
|
||||
.probe = imx_bus_probe,
|
||||
.driver = {
|
||||
.name = "imx-bus-devfreq",
|
||||
.of_match_table = of_match_ptr(imx_bus_of_match),
|
||||
.of_match_table = imx_bus_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(imx_bus_platdrv);
|
||||
|
@ -280,18 +280,6 @@ static int imx8m_ddrc_get_cur_freq(struct device *dev, unsigned long *freq)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx8m_ddrc_get_dev_status(struct device *dev,
|
||||
struct devfreq_dev_status *stat)
|
||||
{
|
||||
struct imx8m_ddrc *priv = dev_get_drvdata(dev);
|
||||
|
||||
stat->busy_time = 0;
|
||||
stat->total_time = 0;
|
||||
stat->current_frequency = clk_get_rate(priv->dram_core);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int imx8m_ddrc_init_freq_info(struct device *dev)
|
||||
{
|
||||
struct imx8m_ddrc *priv = dev_get_drvdata(dev);
|
||||
@ -429,9 +417,7 @@ static int imx8m_ddrc_probe(struct platform_device *pdev)
|
||||
if (ret < 0)
|
||||
goto err;
|
||||
|
||||
priv->profile.polling_ms = 1000;
|
||||
priv->profile.target = imx8m_ddrc_target;
|
||||
priv->profile.get_dev_status = imx8m_ddrc_get_dev_status;
|
||||
priv->profile.exit = imx8m_ddrc_exit;
|
||||
priv->profile.get_cur_freq = imx8m_ddrc_get_cur_freq;
|
||||
priv->profile.initial_freq = clk_get_rate(priv->dram_core);
|
||||
@ -461,7 +447,7 @@ static struct platform_driver imx8m_ddrc_platdrv = {
|
||||
.probe = imx8m_ddrc_probe,
|
||||
.driver = {
|
||||
.name = "imx8m-ddrc-devfreq",
|
||||
.of_match_table = of_match_ptr(imx8m_ddrc_of_match),
|
||||
.of_match_table = imx8m_ddrc_of_match,
|
||||
},
|
||||
};
|
||||
module_platform_driver(imx8m_ddrc_platdrv);
|
||||
|
@ -324,22 +324,14 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
|
||||
mutex_init(&data->lock);
|
||||
|
||||
data->vdd_center = devm_regulator_get(dev, "center");
|
||||
if (IS_ERR(data->vdd_center)) {
|
||||
if (PTR_ERR(data->vdd_center) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dev_err(dev, "Cannot get the regulator \"center\"\n");
|
||||
return PTR_ERR(data->vdd_center);
|
||||
}
|
||||
if (IS_ERR(data->vdd_center))
|
||||
return dev_err_probe(dev, PTR_ERR(data->vdd_center),
|
||||
"Cannot get the regulator \"center\"\n");
|
||||
|
||||
data->dmc_clk = devm_clk_get(dev, "dmc_clk");
|
||||
if (IS_ERR(data->dmc_clk)) {
|
||||
if (PTR_ERR(data->dmc_clk) == -EPROBE_DEFER)
|
||||
return -EPROBE_DEFER;
|
||||
|
||||
dev_err(dev, "Cannot get the clk dmc_clk\n");
|
||||
return PTR_ERR(data->dmc_clk);
|
||||
}
|
||||
if (IS_ERR(data->dmc_clk))
|
||||
return dev_err_probe(dev, PTR_ERR(data->dmc_clk),
|
||||
"Cannot get the clk dmc_clk\n");
|
||||
|
||||
data->edev = devfreq_event_get_edev_by_phandle(dev, "devfreq-events", 0);
|
||||
if (IS_ERR(data->edev))
|
||||
|
@ -99,20 +99,12 @@ void lima_devfreq_fini(struct lima_device *ldev)
|
||||
devm_devfreq_remove_device(ldev->dev, devfreq->devfreq);
|
||||
devfreq->devfreq = NULL;
|
||||
}
|
||||
|
||||
dev_pm_opp_of_remove_table(ldev->dev);
|
||||
|
||||
dev_pm_opp_put_regulators(devfreq->regulators_opp_table);
|
||||
dev_pm_opp_put_clkname(devfreq->clkname_opp_table);
|
||||
devfreq->regulators_opp_table = NULL;
|
||||
devfreq->clkname_opp_table = NULL;
|
||||
}
|
||||
|
||||
int lima_devfreq_init(struct lima_device *ldev)
|
||||
{
|
||||
struct thermal_cooling_device *cooling;
|
||||
struct device *dev = ldev->dev;
|
||||
struct opp_table *opp_table;
|
||||
struct devfreq *devfreq;
|
||||
struct lima_devfreq *ldevfreq = &ldev->devfreq;
|
||||
struct dev_pm_opp *opp;
|
||||
@ -125,40 +117,28 @@ int lima_devfreq_init(struct lima_device *ldev)
|
||||
|
||||
spin_lock_init(&ldevfreq->lock);
|
||||
|
||||
opp_table = dev_pm_opp_set_clkname(dev, "core");
|
||||
if (IS_ERR(opp_table)) {
|
||||
ret = PTR_ERR(opp_table);
|
||||
goto err_fini;
|
||||
}
|
||||
|
||||
ldevfreq->clkname_opp_table = opp_table;
|
||||
|
||||
opp_table = dev_pm_opp_set_regulators(dev,
|
||||
(const char *[]){ "mali" },
|
||||
1);
|
||||
if (IS_ERR(opp_table)) {
|
||||
ret = PTR_ERR(opp_table);
|
||||
ret = devm_pm_opp_set_clkname(dev, "core");
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
ret = devm_pm_opp_set_regulators(dev, (const char *[]){ "mali" }, 1);
|
||||
if (ret) {
|
||||
/* Continue if the optional regulator is missing */
|
||||
if (ret != -ENODEV)
|
||||
goto err_fini;
|
||||
} else {
|
||||
ldevfreq->regulators_opp_table = opp_table;
|
||||
return ret;
|
||||
}
|
||||
|
||||
ret = dev_pm_opp_of_add_table(dev);
|
||||
ret = devm_pm_opp_of_add_table(dev);
|
||||
if (ret)
|
||||
goto err_fini;
|
||||
return ret;
|
||||
|
||||
lima_devfreq_reset(ldevfreq);
|
||||
|
||||
cur_freq = clk_get_rate(ldev->clk_gpu);
|
||||
|
||||
opp = devfreq_recommended_opp(dev, &cur_freq, 0);
|
||||
if (IS_ERR(opp)) {
|
||||
ret = PTR_ERR(opp);
|
||||
goto err_fini;
|
||||
}
|
||||
if (IS_ERR(opp))
|
||||
return PTR_ERR(opp);
|
||||
|
||||
lima_devfreq_profile.initial_freq = cur_freq;
|
||||
dev_pm_opp_put(opp);
|
||||
@ -167,8 +147,7 @@ int lima_devfreq_init(struct lima_device *ldev)
|
||||
DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL);
|
||||
if (IS_ERR(devfreq)) {
|
||||
dev_err(dev, "Couldn't initialize GPU devfreq\n");
|
||||
ret = PTR_ERR(devfreq);
|
||||
goto err_fini;
|
||||
return PTR_ERR(devfreq);
|
||||
}
|
||||
|
||||
ldevfreq->devfreq = devfreq;
|
||||
@ -180,10 +159,6 @@ int lima_devfreq_init(struct lima_device *ldev)
|
||||
ldevfreq->cooling = cooling;
|
||||
|
||||
return 0;
|
||||
|
||||
err_fini:
|
||||
lima_devfreq_fini(ldev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void lima_devfreq_record_busy(struct lima_devfreq *devfreq)
|
||||
|
@ -8,15 +8,12 @@
|
||||
#include <linux/ktime.h>
|
||||
|
||||
struct devfreq;
|
||||
struct opp_table;
|
||||
struct thermal_cooling_device;
|
||||
|
||||
struct lima_device;
|
||||
|
||||
struct lima_devfreq {
|
||||
struct devfreq *devfreq;
|
||||
struct opp_table *clkname_opp_table;
|
||||
struct opp_table *regulators_opp_table;
|
||||
struct thermal_cooling_device *cooling;
|
||||
|
||||
ktime_t busy_time;
|
||||
|
@ -89,29 +89,25 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
|
||||
unsigned long cur_freq;
|
||||
struct device *dev = &pfdev->pdev->dev;
|
||||
struct devfreq *devfreq;
|
||||
struct opp_table *opp_table;
|
||||
struct thermal_cooling_device *cooling;
|
||||
struct panfrost_devfreq *pfdevfreq = &pfdev->pfdevfreq;
|
||||
|
||||
opp_table = dev_pm_opp_set_regulators(dev, pfdev->comp->supply_names,
|
||||
pfdev->comp->num_supplies);
|
||||
if (IS_ERR(opp_table)) {
|
||||
ret = PTR_ERR(opp_table);
|
||||
ret = devm_pm_opp_set_regulators(dev, pfdev->comp->supply_names,
|
||||
pfdev->comp->num_supplies);
|
||||
if (ret) {
|
||||
/* Continue if the optional regulator is missing */
|
||||
if (ret != -ENODEV) {
|
||||
DRM_DEV_ERROR(dev, "Couldn't set OPP regulators\n");
|
||||
goto err_fini;
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
pfdevfreq->regulators_opp_table = opp_table;
|
||||
}
|
||||
|
||||
ret = dev_pm_opp_of_add_table(dev);
|
||||
ret = devm_pm_opp_of_add_table(dev);
|
||||
if (ret) {
|
||||
/* Optional, continue without devfreq */
|
||||
if (ret == -ENODEV)
|
||||
ret = 0;
|
||||
goto err_fini;
|
||||
return ret;
|
||||
}
|
||||
pfdevfreq->opp_of_table_added = true;
|
||||
|
||||
@ -122,10 +118,8 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
|
||||
cur_freq = clk_get_rate(pfdev->clock);
|
||||
|
||||
opp = devfreq_recommended_opp(dev, &cur_freq, 0);
|
||||
if (IS_ERR(opp)) {
|
||||
ret = PTR_ERR(opp);
|
||||
goto err_fini;
|
||||
}
|
||||
if (IS_ERR(opp))
|
||||
return PTR_ERR(opp);
|
||||
|
||||
panfrost_devfreq_profile.initial_freq = cur_freq;
|
||||
dev_pm_opp_put(opp);
|
||||
@ -134,8 +128,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
|
||||
DEVFREQ_GOV_SIMPLE_ONDEMAND, NULL);
|
||||
if (IS_ERR(devfreq)) {
|
||||
DRM_DEV_ERROR(dev, "Couldn't initialize GPU devfreq\n");
|
||||
ret = PTR_ERR(devfreq);
|
||||
goto err_fini;
|
||||
return PTR_ERR(devfreq);
|
||||
}
|
||||
pfdevfreq->devfreq = devfreq;
|
||||
|
||||
@ -146,10 +139,6 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
|
||||
pfdevfreq->cooling = cooling;
|
||||
|
||||
return 0;
|
||||
|
||||
err_fini:
|
||||
panfrost_devfreq_fini(pfdev);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void panfrost_devfreq_fini(struct panfrost_device *pfdev)
|
||||
@ -160,14 +149,6 @@ void panfrost_devfreq_fini(struct panfrost_device *pfdev)
|
||||
devfreq_cooling_unregister(pfdevfreq->cooling);
|
||||
pfdevfreq->cooling = NULL;
|
||||
}
|
||||
|
||||
if (pfdevfreq->opp_of_table_added) {
|
||||
dev_pm_opp_of_remove_table(&pfdev->pdev->dev);
|
||||
pfdevfreq->opp_of_table_added = false;
|
||||
}
|
||||
|
||||
dev_pm_opp_put_regulators(pfdevfreq->regulators_opp_table);
|
||||
pfdevfreq->regulators_opp_table = NULL;
|
||||
}
|
||||
|
||||
void panfrost_devfreq_resume(struct panfrost_device *pfdev)
|
||||
|
@ -8,14 +8,12 @@
|
||||
#include <linux/ktime.h>
|
||||
|
||||
struct devfreq;
|
||||
struct opp_table;
|
||||
struct thermal_cooling_device;
|
||||
|
||||
struct panfrost_device;
|
||||
|
||||
struct panfrost_devfreq {
|
||||
struct devfreq *devfreq;
|
||||
struct opp_table *regulators_opp_table;
|
||||
struct thermal_cooling_device *cooling;
|
||||
bool opp_of_table_added;
|
||||
|
||||
|
@ -744,8 +744,8 @@ static struct cpuidle_state icx_cstates[] __initdata = {
|
||||
.name = "C6",
|
||||
.desc = "MWAIT 0x20",
|
||||
.flags = MWAIT2flg(0x20) | CPUIDLE_FLAG_TLB_FLUSHED,
|
||||
.exit_latency = 128,
|
||||
.target_residency = 384,
|
||||
.exit_latency = 170,
|
||||
.target_residency = 600,
|
||||
.enter = &intel_idle,
|
||||
.enter_s2idle = intel_idle_s2idle, },
|
||||
{
|
||||
@ -1156,6 +1156,7 @@ static const struct x86_cpu_id intel_idle_ids[] __initconst = {
|
||||
X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, &idle_cpu_skl),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, &idle_cpu_skx),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_X, &idle_cpu_icx),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ICELAKE_D, &idle_cpu_icx),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNL, &idle_cpu_knl),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(XEON_PHI_KNM, &idle_cpu_knl),
|
||||
X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, &idle_cpu_bxt),
|
||||
|
@ -343,7 +343,7 @@ static int exynos5_init_freq_table(struct exynos5_dmc *dmc,
|
||||
int idx;
|
||||
unsigned long freq;
|
||||
|
||||
ret = dev_pm_opp_of_add_table(dmc->dev);
|
||||
ret = devm_pm_opp_of_add_table(dmc->dev);
|
||||
if (ret < 0) {
|
||||
dev_err(dmc->dev, "Failed to get OPP table\n");
|
||||
return ret;
|
||||
@ -354,7 +354,7 @@ static int exynos5_init_freq_table(struct exynos5_dmc *dmc,
|
||||
dmc->opp = devm_kmalloc_array(dmc->dev, dmc->opp_count,
|
||||
sizeof(struct dmc_opp_table), GFP_KERNEL);
|
||||
if (!dmc->opp)
|
||||
goto err_opp;
|
||||
return -ENOMEM;
|
||||
|
||||
idx = dmc->opp_count - 1;
|
||||
for (i = 0, freq = ULONG_MAX; i < dmc->opp_count; i++, freq--) {
|
||||
@ -362,7 +362,7 @@ static int exynos5_init_freq_table(struct exynos5_dmc *dmc,
|
||||
|
||||
opp = dev_pm_opp_find_freq_floor(dmc->dev, &freq);
|
||||
if (IS_ERR(opp))
|
||||
goto err_opp;
|
||||
return PTR_ERR(opp);
|
||||
|
||||
dmc->opp[idx - i].freq_hz = freq;
|
||||
dmc->opp[idx - i].volt_uv = dev_pm_opp_get_voltage(opp);
|
||||
@ -371,11 +371,6 @@ static int exynos5_init_freq_table(struct exynos5_dmc *dmc,
|
||||
}
|
||||
|
||||
return 0;
|
||||
|
||||
err_opp:
|
||||
dev_pm_opp_of_remove_table(dmc->dev);
|
||||
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1569,8 +1564,6 @@ static int exynos5_dmc_remove(struct platform_device *pdev)
|
||||
clk_disable_unprepare(dmc->mout_bpll);
|
||||
clk_disable_unprepare(dmc->fout_bpll);
|
||||
|
||||
dev_pm_opp_remove_table(dmc->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -264,7 +264,6 @@ struct sdhci_msm_host {
|
||||
struct clk_bulk_data bulk_clks[5];
|
||||
unsigned long clk_rate;
|
||||
struct mmc_host *mmc;
|
||||
struct opp_table *opp_table;
|
||||
bool use_14lpp_dll_reset;
|
||||
bool tuning_done;
|
||||
bool calibration_done;
|
||||
@ -2551,17 +2550,15 @@ static int sdhci_msm_probe(struct platform_device *pdev)
|
||||
if (ret)
|
||||
goto bus_clk_disable;
|
||||
|
||||
msm_host->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "core");
|
||||
if (IS_ERR(msm_host->opp_table)) {
|
||||
ret = PTR_ERR(msm_host->opp_table);
|
||||
ret = devm_pm_opp_set_clkname(&pdev->dev, "core");
|
||||
if (ret)
|
||||
goto bus_clk_disable;
|
||||
}
|
||||
|
||||
/* OPP table is optional */
|
||||
ret = dev_pm_opp_of_add_table(&pdev->dev);
|
||||
ret = devm_pm_opp_of_add_table(&pdev->dev);
|
||||
if (ret && ret != -ENODEV) {
|
||||
dev_err(&pdev->dev, "Invalid OPP table in Device tree\n");
|
||||
goto opp_put_clkname;
|
||||
goto bus_clk_disable;
|
||||
}
|
||||
|
||||
/* Vote for maximum clock rate for maximum performance */
|
||||
@ -2587,7 +2584,7 @@ static int sdhci_msm_probe(struct platform_device *pdev)
|
||||
ret = clk_bulk_prepare_enable(ARRAY_SIZE(msm_host->bulk_clks),
|
||||
msm_host->bulk_clks);
|
||||
if (ret)
|
||||
goto opp_cleanup;
|
||||
goto bus_clk_disable;
|
||||
|
||||
/*
|
||||
* xo clock is needed for FLL feature of cm_dll.
|
||||
@ -2732,10 +2729,6 @@ pm_runtime_disable:
|
||||
clk_disable:
|
||||
clk_bulk_disable_unprepare(ARRAY_SIZE(msm_host->bulk_clks),
|
||||
msm_host->bulk_clks);
|
||||
opp_cleanup:
|
||||
dev_pm_opp_of_remove_table(&pdev->dev);
|
||||
opp_put_clkname:
|
||||
dev_pm_opp_put_clkname(msm_host->opp_table);
|
||||
bus_clk_disable:
|
||||
if (!IS_ERR(msm_host->bus_clk))
|
||||
clk_disable_unprepare(msm_host->bus_clk);
|
||||
@ -2754,8 +2747,6 @@ static int sdhci_msm_remove(struct platform_device *pdev)
|
||||
|
||||
sdhci_remove_host(host, dead);
|
||||
|
||||
dev_pm_opp_of_remove_table(&pdev->dev);
|
||||
dev_pm_opp_put_clkname(msm_host->opp_table);
|
||||
pm_runtime_get_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
pm_runtime_put_noidle(&pdev->dev);
|
||||
|
@ -1857,6 +1857,35 @@ void dev_pm_opp_put_supported_hw(struct opp_table *opp_table)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_put_supported_hw);
|
||||
|
||||
static void devm_pm_opp_supported_hw_release(void *data)
|
||||
{
|
||||
dev_pm_opp_put_supported_hw(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_pm_opp_set_supported_hw() - Set supported platforms
|
||||
* @dev: Device for which supported-hw has to be set.
|
||||
* @versions: Array of hierarchy of versions to match.
|
||||
* @count: Number of elements in the array.
|
||||
*
|
||||
* This is a resource-managed variant of dev_pm_opp_set_supported_hw().
|
||||
*
|
||||
* Return: 0 on success and errorno otherwise.
|
||||
*/
|
||||
int devm_pm_opp_set_supported_hw(struct device *dev, const u32 *versions,
|
||||
unsigned int count)
|
||||
{
|
||||
struct opp_table *opp_table;
|
||||
|
||||
opp_table = dev_pm_opp_set_supported_hw(dev, versions, count);
|
||||
if (IS_ERR(opp_table))
|
||||
return PTR_ERR(opp_table);
|
||||
|
||||
return devm_add_action_or_reset(dev, devm_pm_opp_supported_hw_release,
|
||||
opp_table);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pm_opp_set_supported_hw);
|
||||
|
||||
/**
|
||||
* dev_pm_opp_set_prop_name() - Set prop-extn name
|
||||
* @dev: Device for which the prop-name has to be set.
|
||||
@ -2047,6 +2076,36 @@ put_opp_table:
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_put_regulators);
|
||||
|
||||
static void devm_pm_opp_regulators_release(void *data)
|
||||
{
|
||||
dev_pm_opp_put_regulators(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_pm_opp_set_regulators() - Set regulator names for the device
|
||||
* @dev: Device for which regulator name is being set.
|
||||
* @names: Array of pointers to the names of the regulator.
|
||||
* @count: Number of regulators.
|
||||
*
|
||||
* This is a resource-managed variant of dev_pm_opp_set_regulators().
|
||||
*
|
||||
* Return: 0 on success and errorno otherwise.
|
||||
*/
|
||||
int devm_pm_opp_set_regulators(struct device *dev,
|
||||
const char * const names[],
|
||||
unsigned int count)
|
||||
{
|
||||
struct opp_table *opp_table;
|
||||
|
||||
opp_table = dev_pm_opp_set_regulators(dev, names, count);
|
||||
if (IS_ERR(opp_table))
|
||||
return PTR_ERR(opp_table);
|
||||
|
||||
return devm_add_action_or_reset(dev, devm_pm_opp_regulators_release,
|
||||
opp_table);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pm_opp_set_regulators);
|
||||
|
||||
/**
|
||||
* dev_pm_opp_set_clkname() - Set clk name for the device
|
||||
* @dev: Device for which clk name is being set.
|
||||
@ -2119,6 +2178,33 @@ void dev_pm_opp_put_clkname(struct opp_table *opp_table)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dev_pm_opp_put_clkname);
|
||||
|
||||
static void devm_pm_opp_clkname_release(void *data)
|
||||
{
|
||||
dev_pm_opp_put_clkname(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_pm_opp_set_clkname() - Set clk name for the device
|
||||
* @dev: Device for which clk name is being set.
|
||||
* @name: Clk name.
|
||||
*
|
||||
* This is a resource-managed variant of dev_pm_opp_set_clkname().
|
||||
*
|
||||
* Return: 0 on success and errorno otherwise.
|
||||
*/
|
||||
int devm_pm_opp_set_clkname(struct device *dev, const char *name)
|
||||
{
|
||||
struct opp_table *opp_table;
|
||||
|
||||
opp_table = dev_pm_opp_set_clkname(dev, name);
|
||||
if (IS_ERR(opp_table))
|
||||
return PTR_ERR(opp_table);
|
||||
|
||||
return devm_add_action_or_reset(dev, devm_pm_opp_clkname_release,
|
||||
opp_table);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pm_opp_set_clkname);
|
||||
|
||||
/**
|
||||
* dev_pm_opp_register_set_opp_helper() - Register custom set OPP helper
|
||||
* @dev: Device for which the helper is getting registered.
|
||||
@ -2209,25 +2295,19 @@ static void devm_pm_opp_unregister_set_opp_helper(void *data)
|
||||
*
|
||||
* This is a resource-managed version of dev_pm_opp_register_set_opp_helper().
|
||||
*
|
||||
* Return: pointer to 'struct opp_table' on success and errorno otherwise.
|
||||
* Return: 0 on success and errorno otherwise.
|
||||
*/
|
||||
struct opp_table *
|
||||
devm_pm_opp_register_set_opp_helper(struct device *dev,
|
||||
int (*set_opp)(struct dev_pm_set_opp_data *data))
|
||||
int devm_pm_opp_register_set_opp_helper(struct device *dev,
|
||||
int (*set_opp)(struct dev_pm_set_opp_data *data))
|
||||
{
|
||||
struct opp_table *opp_table;
|
||||
int err;
|
||||
|
||||
opp_table = dev_pm_opp_register_set_opp_helper(dev, set_opp);
|
||||
if (IS_ERR(opp_table))
|
||||
return opp_table;
|
||||
return PTR_ERR(opp_table);
|
||||
|
||||
err = devm_add_action_or_reset(dev, devm_pm_opp_unregister_set_opp_helper,
|
||||
opp_table);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
return opp_table;
|
||||
return devm_add_action_or_reset(dev, devm_pm_opp_unregister_set_opp_helper,
|
||||
opp_table);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pm_opp_register_set_opp_helper);
|
||||
|
||||
@ -2380,25 +2460,19 @@ static void devm_pm_opp_detach_genpd(void *data)
|
||||
*
|
||||
* This is a resource-managed version of dev_pm_opp_attach_genpd().
|
||||
*
|
||||
* Return: pointer to 'struct opp_table' on success and errorno otherwise.
|
||||
* Return: 0 on success and errorno otherwise.
|
||||
*/
|
||||
struct opp_table *
|
||||
devm_pm_opp_attach_genpd(struct device *dev, const char **names,
|
||||
struct device ***virt_devs)
|
||||
int devm_pm_opp_attach_genpd(struct device *dev, const char **names,
|
||||
struct device ***virt_devs)
|
||||
{
|
||||
struct opp_table *opp_table;
|
||||
int err;
|
||||
|
||||
opp_table = dev_pm_opp_attach_genpd(dev, names, virt_devs);
|
||||
if (IS_ERR(opp_table))
|
||||
return opp_table;
|
||||
return PTR_ERR(opp_table);
|
||||
|
||||
err = devm_add_action_or_reset(dev, devm_pm_opp_detach_genpd,
|
||||
opp_table);
|
||||
if (err)
|
||||
return ERR_PTR(err);
|
||||
|
||||
return opp_table;
|
||||
return devm_add_action_or_reset(dev, devm_pm_opp_detach_genpd,
|
||||
opp_table);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pm_opp_attach_genpd);
|
||||
|
||||
|
@ -1104,6 +1104,42 @@ static int _of_add_table_indexed(struct device *dev, int index, bool getclk)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void devm_pm_opp_of_table_release(void *data)
|
||||
{
|
||||
dev_pm_opp_of_remove_table(data);
|
||||
}
|
||||
|
||||
/**
|
||||
* devm_pm_opp_of_add_table() - Initialize opp table from device tree
|
||||
* @dev: device pointer used to lookup OPP table.
|
||||
*
|
||||
* Register the initial OPP table with the OPP library for given device.
|
||||
*
|
||||
* The opp_table structure will be freed after the device is destroyed.
|
||||
*
|
||||
* Return:
|
||||
* 0 On success OR
|
||||
* Duplicate OPPs (both freq and volt are same) and opp->available
|
||||
* -EEXIST Freq are same and volt are different OR
|
||||
* Duplicate OPPs (both freq and volt are same) and !opp->available
|
||||
* -ENOMEM Memory allocation failure
|
||||
* -ENODEV when 'operating-points' property is not found or is invalid data
|
||||
* in device node.
|
||||
* -ENODATA when empty 'operating-points' property is found
|
||||
* -EINVAL when invalid entries are found in opp-v2 table
|
||||
*/
|
||||
int devm_pm_opp_of_add_table(struct device *dev)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = dev_pm_opp_of_add_table(dev);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return devm_add_action_or_reset(dev, devm_pm_opp_of_table_release, dev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(devm_pm_opp_of_add_table);
|
||||
|
||||
/**
|
||||
* dev_pm_opp_of_add_table() - Initialize opp table from device tree
|
||||
* @dev: device pointer used to lookup OPP table.
|
||||
|
@ -1870,20 +1870,10 @@ static int pci_enable_device_flags(struct pci_dev *dev, unsigned long flags)
|
||||
int err;
|
||||
int i, bars = 0;
|
||||
|
||||
/*
|
||||
* Power state could be unknown at this point, either due to a fresh
|
||||
* boot or a device removal call. So get the current power state
|
||||
* so that things like MSI message writing will behave as expected
|
||||
* (e.g. if the device really is in D0 at enable time).
|
||||
*/
|
||||
if (dev->pm_cap) {
|
||||
u16 pmcsr;
|
||||
pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
|
||||
dev->current_state = (pmcsr & PCI_PM_CTRL_STATE_MASK);
|
||||
}
|
||||
|
||||
if (atomic_inc_return(&dev->enable_cnt) > 1)
|
||||
if (atomic_inc_return(&dev->enable_cnt) > 1) {
|
||||
pci_update_current_state(dev, dev->current_state);
|
||||
return 0; /* already enabled */
|
||||
}
|
||||
|
||||
bridge = pci_upstream_bridge(dev);
|
||||
if (bridge)
|
||||
|
@ -1069,6 +1069,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = {
|
||||
|
||||
X86_MATCH_VENDOR_FAM(AMD, 0x17, &rapl_defaults_amd),
|
||||
X86_MATCH_VENDOR_FAM(AMD, 0x19, &rapl_defaults_amd),
|
||||
X86_MATCH_VENDOR_FAM(HYGON, 0x18, &rapl_defaults_amd),
|
||||
{}
|
||||
};
|
||||
MODULE_DEVICE_TABLE(x86cpu, rapl_ids);
|
||||
|
@ -150,6 +150,7 @@ static int rapl_msr_probe(struct platform_device *pdev)
|
||||
case X86_VENDOR_INTEL:
|
||||
rapl_msr_priv = &rapl_msr_priv_intel;
|
||||
break;
|
||||
case X86_VENDOR_HYGON:
|
||||
case X86_VENDOR_AMD:
|
||||
rapl_msr_priv = &rapl_msr_priv_amd;
|
||||
break;
|
||||
|
@ -691,14 +691,15 @@ static int spi_geni_probe(struct platform_device *pdev)
|
||||
mas->se.wrapper = dev_get_drvdata(dev->parent);
|
||||
mas->se.base = base;
|
||||
mas->se.clk = clk;
|
||||
mas->se.opp_table = dev_pm_opp_set_clkname(&pdev->dev, "se");
|
||||
if (IS_ERR(mas->se.opp_table))
|
||||
return PTR_ERR(mas->se.opp_table);
|
||||
|
||||
ret = devm_pm_opp_set_clkname(&pdev->dev, "se");
|
||||
if (ret)
|
||||
return ret;
|
||||
/* OPP table is optional */
|
||||
ret = dev_pm_opp_of_add_table(&pdev->dev);
|
||||
ret = devm_pm_opp_of_add_table(&pdev->dev);
|
||||
if (ret && ret != -ENODEV) {
|
||||
dev_err(&pdev->dev, "invalid OPP table in device tree\n");
|
||||
goto put_clkname;
|
||||
return ret;
|
||||
}
|
||||
|
||||
spi->bus_num = -1;
|
||||
@ -750,9 +751,6 @@ spi_geni_probe_free_irq:
|
||||
free_irq(mas->irq, spi);
|
||||
spi_geni_probe_runtime_disable:
|
||||
pm_runtime_disable(dev);
|
||||
dev_pm_opp_of_remove_table(&pdev->dev);
|
||||
put_clkname:
|
||||
dev_pm_opp_put_clkname(mas->se.opp_table);
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -766,8 +764,6 @@ static int spi_geni_remove(struct platform_device *pdev)
|
||||
|
||||
free_irq(mas->irq, spi);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
dev_pm_opp_of_remove_table(&pdev->dev);
|
||||
dev_pm_opp_put_clkname(mas->se.opp_table);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -142,7 +142,6 @@ struct qcom_qspi {
|
||||
struct clk_bulk_data *clks;
|
||||
struct qspi_xfer xfer;
|
||||
struct icc_path *icc_path_cpu_to_qspi;
|
||||
struct opp_table *opp_table;
|
||||
unsigned long last_speed;
|
||||
/* Lock to protect data accessed by IRQs */
|
||||
spinlock_t lock;
|
||||
@ -530,14 +529,14 @@ static int qcom_qspi_probe(struct platform_device *pdev)
|
||||
master->handle_err = qcom_qspi_handle_err;
|
||||
master->auto_runtime_pm = true;
|
||||
|
||||
ctrl->opp_table = dev_pm_opp_set_clkname(&pdev->dev, "core");
|
||||
if (IS_ERR(ctrl->opp_table))
|
||||
return PTR_ERR(ctrl->opp_table);
|
||||
ret = devm_pm_opp_set_clkname(&pdev->dev, "core");
|
||||
if (ret)
|
||||
return ret;
|
||||
/* OPP table is optional */
|
||||
ret = dev_pm_opp_of_add_table(&pdev->dev);
|
||||
ret = devm_pm_opp_of_add_table(&pdev->dev);
|
||||
if (ret && ret != -ENODEV) {
|
||||
dev_err(&pdev->dev, "invalid OPP table in device tree\n");
|
||||
goto exit_probe_put_clkname;
|
||||
return ret;
|
||||
}
|
||||
|
||||
pm_runtime_use_autosuspend(dev);
|
||||
@ -549,10 +548,6 @@ static int qcom_qspi_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
|
||||
pm_runtime_disable(dev);
|
||||
dev_pm_opp_of_remove_table(&pdev->dev);
|
||||
|
||||
exit_probe_put_clkname:
|
||||
dev_pm_opp_put_clkname(ctrl->opp_table);
|
||||
|
||||
return ret;
|
||||
}
|
||||
@ -560,14 +555,11 @@ exit_probe_put_clkname:
|
||||
static int qcom_qspi_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct spi_master *master = platform_get_drvdata(pdev);
|
||||
struct qcom_qspi *ctrl = spi_master_get_devdata(master);
|
||||
|
||||
/* Unregister _before_ disabling pm_runtime() so we stop transfers */
|
||||
spi_unregister_master(master);
|
||||
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
dev_pm_opp_of_remove_table(&pdev->dev);
|
||||
dev_pm_opp_put_clkname(ctrl->opp_table);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
@ -1426,14 +1426,14 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
|
||||
if (of_property_read_bool(pdev->dev.of_node, "cts-rts-swap"))
|
||||
port->cts_rts_swap = true;
|
||||
|
||||
port->se.opp_table = dev_pm_opp_set_clkname(&pdev->dev, "se");
|
||||
if (IS_ERR(port->se.opp_table))
|
||||
return PTR_ERR(port->se.opp_table);
|
||||
ret = devm_pm_opp_set_clkname(&pdev->dev, "se");
|
||||
if (ret)
|
||||
return ret;
|
||||
/* OPP table is optional */
|
||||
ret = dev_pm_opp_of_add_table(&pdev->dev);
|
||||
ret = devm_pm_opp_of_add_table(&pdev->dev);
|
||||
if (ret && ret != -ENODEV) {
|
||||
dev_err(&pdev->dev, "invalid OPP table in device tree\n");
|
||||
goto put_clkname;
|
||||
return ret;
|
||||
}
|
||||
|
||||
port->private_data.drv = drv;
|
||||
@ -1443,7 +1443,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
|
||||
|
||||
ret = uart_add_one_port(drv, uport);
|
||||
if (ret)
|
||||
goto err;
|
||||
return ret;
|
||||
|
||||
irq_set_status_flags(uport->irq, IRQ_NOAUTOEN);
|
||||
ret = devm_request_irq(uport->dev, uport->irq, qcom_geni_serial_isr,
|
||||
@ -1451,7 +1451,7 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
|
||||
if (ret) {
|
||||
dev_err(uport->dev, "Failed to get IRQ ret %d\n", ret);
|
||||
uart_remove_one_port(drv, uport);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -1468,16 +1468,11 @@ static int qcom_geni_serial_probe(struct platform_device *pdev)
|
||||
if (ret) {
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
uart_remove_one_port(drv, uport);
|
||||
goto err;
|
||||
return ret;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
err:
|
||||
dev_pm_opp_of_remove_table(&pdev->dev);
|
||||
put_clkname:
|
||||
dev_pm_opp_put_clkname(port->se.opp_table);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int qcom_geni_serial_remove(struct platform_device *pdev)
|
||||
@ -1485,8 +1480,6 @@ static int qcom_geni_serial_remove(struct platform_device *pdev)
|
||||
struct qcom_geni_serial_port *port = platform_get_drvdata(pdev);
|
||||
struct uart_driver *drv = port->private_data.drv;
|
||||
|
||||
dev_pm_opp_of_remove_table(&pdev->dev);
|
||||
dev_pm_opp_put_clkname(port->se.opp_table);
|
||||
dev_pm_clear_wake_irq(&pdev->dev);
|
||||
device_init_wakeup(&pdev->dev, false);
|
||||
uart_remove_one_port(drv, &port->uport);
|
||||
|
@ -23,18 +23,31 @@ static inline unsigned long topology_get_cpu_scale(int cpu)
|
||||
|
||||
void topology_set_cpu_scale(unsigned int cpu, unsigned long capacity);
|
||||
|
||||
DECLARE_PER_CPU(unsigned long, freq_scale);
|
||||
DECLARE_PER_CPU(unsigned long, arch_freq_scale);
|
||||
|
||||
static inline unsigned long topology_get_freq_scale(int cpu)
|
||||
{
|
||||
return per_cpu(freq_scale, cpu);
|
||||
return per_cpu(arch_freq_scale, cpu);
|
||||
}
|
||||
|
||||
void topology_set_freq_scale(const struct cpumask *cpus, unsigned long cur_freq,
|
||||
unsigned long max_freq);
|
||||
bool topology_scale_freq_invariant(void);
|
||||
|
||||
bool arch_freq_counters_available(const struct cpumask *cpus);
|
||||
enum scale_freq_source {
|
||||
SCALE_FREQ_SOURCE_CPUFREQ = 0,
|
||||
SCALE_FREQ_SOURCE_ARCH,
|
||||
SCALE_FREQ_SOURCE_CPPC,
|
||||
};
|
||||
|
||||
struct scale_freq_data {
|
||||
enum scale_freq_source source;
|
||||
void (*set_freq_scale)(void);
|
||||
};
|
||||
|
||||
void topology_scale_freq_tick(void);
|
||||
void topology_set_scale_freq_source(struct scale_freq_data *data, const struct cpumask *cpus);
|
||||
void topology_clear_scale_freq_source(enum scale_freq_source source, const struct cpumask *cpus);
|
||||
|
||||
DECLARE_PER_CPU(unsigned long, thermal_pressure);
|
||||
|
||||
|
@ -49,8 +49,8 @@ struct cpuidle_state {
|
||||
char name[CPUIDLE_NAME_LEN];
|
||||
char desc[CPUIDLE_DESC_LEN];
|
||||
|
||||
u64 exit_latency_ns;
|
||||
u64 target_residency_ns;
|
||||
s64 exit_latency_ns;
|
||||
s64 target_residency_ns;
|
||||
unsigned int flags;
|
||||
unsigned int exit_latency; /* in US */
|
||||
int power_usage; /* in mW */
|
||||
|
@ -38,6 +38,7 @@ enum devfreq_timer {
|
||||
|
||||
struct devfreq;
|
||||
struct devfreq_governor;
|
||||
struct thermal_cooling_device;
|
||||
|
||||
/**
|
||||
* struct devfreq_dev_status - Data given from devfreq user device to
|
||||
@ -98,11 +99,15 @@ struct devfreq_dev_status {
|
||||
* @freq_table: Optional list of frequencies to support statistics
|
||||
* and freq_table must be generated in ascending order.
|
||||
* @max_state: The size of freq_table.
|
||||
*
|
||||
* @is_cooling_device: A self-explanatory boolean giving the device a
|
||||
* cooling effect property.
|
||||
*/
|
||||
struct devfreq_dev_profile {
|
||||
unsigned long initial_freq;
|
||||
unsigned int polling_ms;
|
||||
enum devfreq_timer timer;
|
||||
bool is_cooling_device;
|
||||
|
||||
int (*target)(struct device *dev, unsigned long *freq, u32 flags);
|
||||
int (*get_dev_status)(struct device *dev,
|
||||
@ -156,6 +161,7 @@ struct devfreq_stats {
|
||||
* @suspend_count: suspend requests counter for a device.
|
||||
* @stats: Statistics of devfreq device behavior
|
||||
* @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
|
||||
* @cdev: Cooling device pointer if the devfreq has cooling property
|
||||
* @nb_min: Notifier block for DEV_PM_QOS_MIN_FREQUENCY
|
||||
* @nb_max: Notifier block for DEV_PM_QOS_MAX_FREQUENCY
|
||||
*
|
||||
@ -198,6 +204,9 @@ struct devfreq {
|
||||
|
||||
struct srcu_notifier_head transition_notifier_list;
|
||||
|
||||
/* Pointer to the cooling device if used for thermal mitigation */
|
||||
struct thermal_cooling_device *cdev;
|
||||
|
||||
struct notifier_block nb_min;
|
||||
struct notifier_block nb_max;
|
||||
};
|
||||
|
@ -279,7 +279,6 @@ static inline int freeze_kernel_threads(void) { return -ENOSYS; }
|
||||
static inline void thaw_processes(void) {}
|
||||
static inline void thaw_kernel_threads(void) {}
|
||||
|
||||
static inline bool try_to_freeze_nowarn(void) { return false; }
|
||||
static inline bool try_to_freeze(void) { return false; }
|
||||
|
||||
static inline void freezer_do_not_count(void) {}
|
||||
|
@ -33,7 +33,7 @@ enum rapl_domain_reg_id {
|
||||
RAPL_DOMAIN_REG_MAX,
|
||||
};
|
||||
|
||||
struct rapl_package;
|
||||
struct rapl_domain;
|
||||
|
||||
enum rapl_primitives {
|
||||
ENERGY_COUNTER,
|
||||
|
@ -39,7 +39,6 @@ static inline void pm_vt_switch_unregister(struct device *dev)
|
||||
* Device power management
|
||||
*/
|
||||
|
||||
struct device;
|
||||
|
||||
#ifdef CONFIG_PM
|
||||
extern const char power_group_name[]; /* = "power" */
|
||||
|
@ -144,18 +144,21 @@ int dev_pm_opp_unregister_notifier(struct device *dev, struct notifier_block *nb
|
||||
|
||||
struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count);
|
||||
void dev_pm_opp_put_supported_hw(struct opp_table *opp_table);
|
||||
int devm_pm_opp_set_supported_hw(struct device *dev, const u32 *versions, unsigned int count);
|
||||
struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name);
|
||||
void dev_pm_opp_put_prop_name(struct opp_table *opp_table);
|
||||
struct opp_table *dev_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
|
||||
void dev_pm_opp_put_regulators(struct opp_table *opp_table);
|
||||
int devm_pm_opp_set_regulators(struct device *dev, const char * const names[], unsigned int count);
|
||||
struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name);
|
||||
void dev_pm_opp_put_clkname(struct opp_table *opp_table);
|
||||
int devm_pm_opp_set_clkname(struct device *dev, const char *name);
|
||||
struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
|
||||
void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table);
|
||||
struct opp_table *devm_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
|
||||
int devm_pm_opp_register_set_opp_helper(struct device *dev, int (*set_opp)(struct dev_pm_set_opp_data *data));
|
||||
struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs);
|
||||
void dev_pm_opp_detach_genpd(struct opp_table *opp_table);
|
||||
struct opp_table *devm_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs);
|
||||
int devm_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs);
|
||||
struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table, struct opp_table *dst_table, struct dev_pm_opp *src_opp);
|
||||
int dev_pm_opp_xlate_performance_state(struct opp_table *src_table, struct opp_table *dst_table, unsigned int pstate);
|
||||
int dev_pm_opp_set_rate(struct device *dev, unsigned long target_freq);
|
||||
@ -319,6 +322,13 @@ static inline struct opp_table *dev_pm_opp_set_supported_hw(struct device *dev,
|
||||
|
||||
static inline void dev_pm_opp_put_supported_hw(struct opp_table *opp_table) {}
|
||||
|
||||
static inline int devm_pm_opp_set_supported_hw(struct device *dev,
|
||||
const u32 *versions,
|
||||
unsigned int count)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline struct opp_table *dev_pm_opp_register_set_opp_helper(struct device *dev,
|
||||
int (*set_opp)(struct dev_pm_set_opp_data *data))
|
||||
{
|
||||
@ -327,11 +337,10 @@ static inline struct opp_table *dev_pm_opp_register_set_opp_helper(struct device
|
||||
|
||||
static inline void dev_pm_opp_unregister_set_opp_helper(struct opp_table *opp_table) {}
|
||||
|
||||
static inline struct opp_table *
|
||||
devm_pm_opp_register_set_opp_helper(struct device *dev,
|
||||
static inline int devm_pm_opp_register_set_opp_helper(struct device *dev,
|
||||
int (*set_opp)(struct dev_pm_set_opp_data *data))
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline struct opp_table *dev_pm_opp_set_prop_name(struct device *dev, const char *name)
|
||||
@ -348,6 +357,13 @@ static inline struct opp_table *dev_pm_opp_set_regulators(struct device *dev, co
|
||||
|
||||
static inline void dev_pm_opp_put_regulators(struct opp_table *opp_table) {}
|
||||
|
||||
static inline int devm_pm_opp_set_regulators(struct device *dev,
|
||||
const char * const names[],
|
||||
unsigned int count)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const char *name)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
@ -355,6 +371,11 @@ static inline struct opp_table *dev_pm_opp_set_clkname(struct device *dev, const
|
||||
|
||||
static inline void dev_pm_opp_put_clkname(struct opp_table *opp_table) {}
|
||||
|
||||
static inline int devm_pm_opp_set_clkname(struct device *dev, const char *name)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, const char **names, struct device ***virt_devs)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
@ -362,10 +383,11 @@ static inline struct opp_table *dev_pm_opp_attach_genpd(struct device *dev, cons
|
||||
|
||||
static inline void dev_pm_opp_detach_genpd(struct opp_table *opp_table) {}
|
||||
|
||||
static inline struct opp_table *devm_pm_opp_attach_genpd(struct device *dev,
|
||||
const char **names, struct device ***virt_devs)
|
||||
static inline int devm_pm_opp_attach_genpd(struct device *dev,
|
||||
const char **names,
|
||||
struct device ***virt_devs)
|
||||
{
|
||||
return ERR_PTR(-EOPNOTSUPP);
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline struct dev_pm_opp *dev_pm_opp_xlate_required_opp(struct opp_table *src_table,
|
||||
@ -419,6 +441,7 @@ int dev_pm_opp_of_add_table(struct device *dev);
|
||||
int dev_pm_opp_of_add_table_indexed(struct device *dev, int index);
|
||||
int dev_pm_opp_of_add_table_noclk(struct device *dev, int index);
|
||||
void dev_pm_opp_of_remove_table(struct device *dev);
|
||||
int devm_pm_opp_of_add_table(struct device *dev);
|
||||
int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask);
|
||||
void dev_pm_opp_of_cpumask_remove_table(const struct cpumask *cpumask);
|
||||
int dev_pm_opp_of_get_sharing_cpus(struct device *cpu_dev, struct cpumask *cpumask);
|
||||
@ -451,6 +474,11 @@ static inline void dev_pm_opp_of_remove_table(struct device *dev)
|
||||
{
|
||||
}
|
||||
|
||||
static inline int devm_pm_opp_of_add_table(struct device *dev)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
|
||||
static inline int dev_pm_opp_of_cpumask_add_table(const struct cpumask *cpumask)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
|
@ -265,7 +265,7 @@ static inline void pm_runtime_no_callbacks(struct device *dev) {}
|
||||
static inline void pm_runtime_irq_safe(struct device *dev) {}
|
||||
static inline bool pm_runtime_is_irq_safe(struct device *dev) { return false; }
|
||||
|
||||
static inline bool pm_runtime_callbacks_present(struct device *dev) { return false; }
|
||||
static inline bool pm_runtime_has_no_callbacks(struct device *dev) { return false; }
|
||||
static inline void pm_runtime_mark_last_busy(struct device *dev) {}
|
||||
static inline void __pm_runtime_use_autosuspend(struct device *dev,
|
||||
bool use) {}
|
||||
|
@ -47,7 +47,6 @@ struct geni_icc_path {
|
||||
* @num_clk_levels: Number of valid clock levels in clk_perf_tbl
|
||||
* @clk_perf_tbl: Table of clock frequency input to serial engine clock
|
||||
* @icc_paths: Array of ICC paths for SE
|
||||
* @opp_table: Pointer to the OPP table
|
||||
*/
|
||||
struct geni_se {
|
||||
void __iomem *base;
|
||||
@ -57,7 +56,6 @@ struct geni_se {
|
||||
unsigned int num_clk_levels;
|
||||
unsigned long *clk_perf_tbl;
|
||||
struct geni_icc_path icc_paths[3];
|
||||
struct opp_table *opp_table;
|
||||
};
|
||||
|
||||
/* Common SE registers */
|
||||
|
@ -54,7 +54,7 @@ static void try_to_suspend(struct work_struct *work)
|
||||
goto out;
|
||||
|
||||
/*
|
||||
* If the wakeup occured for an unknown reason, wait to prevent the
|
||||
* If the wakeup occurred for an unknown reason, wait to prevent the
|
||||
* system from trying to suspend and waking up in a tight loop.
|
||||
*/
|
||||
if (final_count == initial_count)
|
||||
|
@ -329,7 +329,7 @@ static void *chain_alloc(struct chain_allocator *ca, unsigned int size)
|
||||
/**
|
||||
* Data types related to memory bitmaps.
|
||||
*
|
||||
* Memory bitmap is a structure consiting of many linked lists of
|
||||
* Memory bitmap is a structure consisting of many linked lists of
|
||||
* objects. The main list's elements are of type struct zone_bitmap
|
||||
* and each of them corresonds to one zone. For each zone bitmap
|
||||
* object there is a list of objects of type struct bm_block that
|
||||
|
@ -884,7 +884,7 @@ out_clean:
|
||||
* enough_swap - Make sure we have enough swap to save the image.
|
||||
*
|
||||
* Returns TRUE or FALSE after checking the total amount of swap
|
||||
* space avaiable from the resume partition.
|
||||
* space available from the resume partition.
|
||||
*/
|
||||
|
||||
static int enough_swap(unsigned int nr_pages)
|
||||
|
@ -6384,6 +6384,7 @@ int sched_setattr_nocheck(struct task_struct *p, const struct sched_attr *attr)
|
||||
{
|
||||
return __sched_setscheduler(p, attr, false, true);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(sched_setattr_nocheck);
|
||||
|
||||
/**
|
||||
* sched_setscheduler_nocheck - change the scheduling policy and/or RT priority of a thread from kernelspace.
|
||||
|
@ -114,19 +114,8 @@ static bool sugov_update_next_freq(struct sugov_policy *sg_policy, u64 time,
|
||||
return true;
|
||||
}
|
||||
|
||||
static void sugov_fast_switch(struct sugov_policy *sg_policy, u64 time,
|
||||
unsigned int next_freq)
|
||||
static void sugov_deferred_update(struct sugov_policy *sg_policy)
|
||||
{
|
||||
if (sugov_update_next_freq(sg_policy, time, next_freq))
|
||||
cpufreq_driver_fast_switch(sg_policy->policy, next_freq);
|
||||
}
|
||||
|
||||
static void sugov_deferred_update(struct sugov_policy *sg_policy, u64 time,
|
||||
unsigned int next_freq)
|
||||
{
|
||||
if (!sugov_update_next_freq(sg_policy, time, next_freq))
|
||||
return;
|
||||
|
||||
if (!sg_policy->work_in_progress) {
|
||||
sg_policy->work_in_progress = true;
|
||||
irq_work_queue(&sg_policy->irq_work);
|
||||
@ -366,16 +355,19 @@ static void sugov_update_single_freq(struct update_util_data *hook, u64 time,
|
||||
sg_policy->cached_raw_freq = cached_freq;
|
||||
}
|
||||
|
||||
if (!sugov_update_next_freq(sg_policy, time, next_f))
|
||||
return;
|
||||
|
||||
/*
|
||||
* This code runs under rq->lock for the target CPU, so it won't run
|
||||
* concurrently on two different CPUs for the same target and it is not
|
||||
* necessary to acquire the lock in the fast switch case.
|
||||
*/
|
||||
if (sg_policy->policy->fast_switch_enabled) {
|
||||
sugov_fast_switch(sg_policy, time, next_f);
|
||||
cpufreq_driver_fast_switch(sg_policy->policy, next_f);
|
||||
} else {
|
||||
raw_spin_lock(&sg_policy->update_lock);
|
||||
sugov_deferred_update(sg_policy, time, next_f);
|
||||
sugov_deferred_update(sg_policy);
|
||||
raw_spin_unlock(&sg_policy->update_lock);
|
||||
}
|
||||
}
|
||||
@ -454,12 +446,15 @@ sugov_update_shared(struct update_util_data *hook, u64 time, unsigned int flags)
|
||||
if (sugov_should_update_freq(sg_policy, time)) {
|
||||
next_f = sugov_next_freq_shared(sg_cpu, time);
|
||||
|
||||
if (sg_policy->policy->fast_switch_enabled)
|
||||
sugov_fast_switch(sg_policy, time, next_f);
|
||||
else
|
||||
sugov_deferred_update(sg_policy, time, next_f);
|
||||
}
|
||||
if (!sugov_update_next_freq(sg_policy, time, next_f))
|
||||
goto unlock;
|
||||
|
||||
if (sg_policy->policy->fast_switch_enabled)
|
||||
cpufreq_driver_fast_switch(sg_policy->policy, next_f);
|
||||
else
|
||||
sugov_deferred_update(sg_policy);
|
||||
}
|
||||
unlock:
|
||||
raw_spin_unlock(&sg_policy->update_lock);
|
||||
}
|
||||
|
||||
|
@ -1124,7 +1124,11 @@ ktime_t tick_nohz_get_next_hrtimer(void)
|
||||
* tick_nohz_get_sleep_length - return the expected length of the current sleep
|
||||
* @delta_next: duration until the next event if the tick cannot be stopped
|
||||
*
|
||||
* Called from power state control code with interrupts disabled
|
||||
* Called from power state control code with interrupts disabled.
|
||||
*
|
||||
* The return value of this function and/or the value returned by it through the
|
||||
* @delta_next pointer can be negative which must be taken into account by its
|
||||
* callers.
|
||||
*/
|
||||
ktime_t tick_nohz_get_sleep_length(ktime_t *delta_next)
|
||||
{
|
||||
|
@ -6819,7 +6819,7 @@ if __name__ == '__main__':
|
||||
sysvals.outdir = val
|
||||
sysvals.notestrun = True
|
||||
if(os.path.isdir(val) == False):
|
||||
doError('%s is not accesible' % val)
|
||||
doError('%s is not accessible' % val)
|
||||
elif(arg == '-filter'):
|
||||
try:
|
||||
val = next(args)
|
||||
|
Loading…
Reference in New Issue
Block a user