mirror of
https://github.com/BobTheBlinker/android_kernel_motorola_sm6375.git
synced 2026-10-28 10:41:38 -04:00
Power management material for v4.10-rc1
- New cpufreq driver for Broadcom STB SoCs and a Device Tree binding
for it (Markus Mayer).
- Support for ARM Integrator/AP and Integrator/CP in the generic
DT cpufreq driver and elimination of the old Integrator cpufreq
driver (Linus Walleij).
- Support for the zx296718, r8a7743 and r8a7745, Socionext UniPhier,
and PXA SoCs in the the generic DT cpufreq driver (Baoyou Xie,
Geert Uytterhoeven, Masahiro Yamada, Robert Jarzmik).
- cpufreq core fix to eliminate races that may lead to using
inactive policy objects and related cleanups (Rafael Wysocki).
- cpufreq schedutil governor update to make it use SCHED_FIFO
kernel threads (instead of regular workqueues) for doing delayed
work (to reduce the response latency in some cases) and related
cleanups (Viresh Kumar).
- New cpufreq sysfs attribute for resetting statistics (Markus
Mayer).
- cpufreq governors fixes and cleanups (Chen Yu, Stratos Karafotis,
Viresh Kumar).
- Support for using generic cpufreq governors in the intel_pstate
driver (Rafael Wysocki).
- Support for per-logical-CPU P-state limits and the EPP/EPB
(Energy Performance Preference/Energy Performance Bias) knobs
in the intel_pstate driver (Srinivas Pandruvada).
- New CPU ID for Knights Mill in intel_pstate (Piotr Luc).
- intel_pstate driver modification to use the P-state selection
algorithm based on CPU load on platforms with the system profile
in the ACPI tables set to "mobile" (Srinivas Pandruvada).
- intel_pstate driver cleanups (Arnd Bergmann, Rafael Wysocki,
Srinivas Pandruvada).
- cpufreq powernv driver updates including fast switching support
(for the schedutil governor), fixes and cleanus (Akshay Adiga,
Andrew Donnellan, Denis Kirjanov).
- acpi-cpufreq driver rework to switch it over to the new CPU
offline/online state machine (Sebastian Andrzej Siewior).
- Assorted cleanups in cpufreq drivers (Wei Yongjun, Prashanth
Prakash).
- Idle injection rework (to make it use the regular idle path
instead of a home-grown custom one) and related powerclamp
thermal driver updates (Peter Zijlstra, Jacob Pan, Petr Mladek,
Sebastian Andrzej Siewior).
- New CPU IDs for Atom Z34xx and Knights Mill in intel_idle (Andy
Shevchenko, Piotr Luc).
- intel_idle driver cleanups and switch over to using the new CPU
offline/online state machine (Anna-Maria Gleixner, Sebastian
Andrzej Siewior).
- cpuidle DT driver update to support suspend-to-idle properly
(Sudeep Holla).
- cpuidle core cleanups and misc updates (Daniel Lezcano, Pan Bian,
Rafael Wysocki).
- Preliminary support for power domains including CPUs in the
generic power domains (genpd) framework and related DT bindings
(Lina Iyer).
- Assorted fixes and cleanups in the generic power domains (genpd)
framework (Colin Ian King, Dan Carpenter, Geert Uytterhoeven).
- Preliminary support for devices with multiple voltage regulators
and related fixes and cleanups in the Operating Performance Points
(OPP) library (Viresh Kumar, Masahiro Yamada, Stephen Boyd).
- System sleep state selection interface rework to make it easier
to support suspend-to-idle as the default system suspend method
(Rafael Wysocki).
- PM core fixes and cleanups, mostly related to the interactions
between the system suspend and runtime PM frameworks (Ulf Hansson,
Sahitya Tummala, Tony Lindgren).
- Latency tolerance PM QoS framework imorovements (Andrew
Lutomirski).
- New Knights Mill CPU ID for the Intel RAPL power capping driver
(Piotr Luc).
- Intel RAPL power capping driver fixes, cleanups and switch over
to using the new CPU offline/online state machine (Jacob Pan,
Thomas Gleixner, Sebastian Andrzej Siewior).
- Fixes and cleanups in the exynos-ppmu, exynos-nocp, rk3399_dmc,
rockchip-dfi devfreq drivers and the devfreq core (Axel Lin,
Chanwoo Choi, Javier Martinez Canillas, MyungJoo Ham, Viresh
Kumar).
- Fix for false-positive KASAN warnings during resume from ACPI S3
(suspend-to-RAM) on x86 (Josh Poimboeuf).
- Memory map verification during resume from hibernation on x86 to
ensure a consistent address space layout (Chen Yu).
- Wakeup sources debugging enhancement (Xing Wei).
- rockchip-io AVS driver cleanup (Shawn Lin).
-----BEGIN PGP SIGNATURE-----
Version: GnuPG v2
iQIcBAABCAAGBQJYTx4+AAoJEILEb/54YlRx9f8P/2SlNHUENW5qh6FtCw00oC2u
UqJerQJ2L38UgbgxbE/0VYblma9rFABDWC1eO2xN2XdcdW5UPBKPVvNcOgNe1Clh
gjy3RxZXVpmjfzt2kGfsTLEuGnHqwvx51hTUkeA2LwvkOal45xb8ZESmy8opCtiv
iG4LwmPHoxdX5Za5nA9ItFKzxyO1EoyNSnBYAVwALDHxmNOfxEcRevfurASt/0M9
brCCZJA0/sZxeL0lBdy8fNQPIBTUfCoTJG/MtmzGrObJ9wMFvEDfXrVEyZiWs/zA
AAZ4kQL77enrIKgrLN8e0G6LzTLHoVcvn38Xjf24dKUqhd7ACBhYcnW+jK3+7EAd
gjZ8efObQsiuyK/EDLUNw35tt96CHOqfrQCj2tIwRVvk9EekLqAGXdIndTCr2kYW
RpefmP5kMljnm/nQFOVLwMEUQMuVkvUE7EgxADy7DoDmepBFC4ICRDWPye70R2kC
0O1Tn2PAQq4Fd1tyI9TYYz0YQQkRoaRb5rfYUSzbRbeCdsphUopp4Vhsiyn6IcnF
XnLbg6pRAat82MoS9n4pfO/VCo8vkErKA8tut9G7TDakkrJoEE7l31PdKW0hP3f6
sBo6xXy6WTeivU/o/i8TbM6K4mA37pBaj78ooIkWLgg5fzRaS2+0xSPVy2H9x1m5
LymHcobCK9rSZ1l208Fe
=vhxI
-----END PGP SIGNATURE-----
Merge tag 'pm-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm
Pull power management updates from Rafael Wysocki:
"Again, cpufreq gets more changes than the other parts this time (one
new driver, one old driver less, a bunch of enhancements of the
existing code, new CPU IDs, fixes, cleanups)
There also are some changes in cpuidle (idle injection rework, a
couple of new CPU IDs, online/offline rework in intel_idle, fixes and
cleanups), in the generic power domains framework (mostly related to
supporting power domains containing CPUs), and in the Operating
Performance Points (OPP) library (mostly related to supporting devices
with multiple voltage regulators)
In addition to that, the system sleep state selection interface is
modified to make it easier for distributions with unchanged user space
to support suspend-to-idle as the default system suspend method, some
issues are fixed in the PM core, the latency tolerance PM QoS
framework is improved a bit, the Intel RAPL power capping driver is
cleaned up and there are some fixes and cleanups in the devfreq
subsystem
Specifics:
- New cpufreq driver for Broadcom STB SoCs and a Device Tree binding
for it (Markus Mayer)
- Support for ARM Integrator/AP and Integrator/CP in the generic DT
cpufreq driver and elimination of the old Integrator cpufreq driver
(Linus Walleij)
- Support for the zx296718, r8a7743 and r8a7745, Socionext UniPhier,
and PXA SoCs in the the generic DT cpufreq driver (Baoyou Xie,
Geert Uytterhoeven, Masahiro Yamada, Robert Jarzmik)
- cpufreq core fix to eliminate races that may lead to using inactive
policy objects and related cleanups (Rafael Wysocki)
- cpufreq schedutil governor update to make it use SCHED_FIFO kernel
threads (instead of regular workqueues) for doing delayed work (to
reduce the response latency in some cases) and related cleanups
(Viresh Kumar)
- New cpufreq sysfs attribute for resetting statistics (Markus Mayer)
- cpufreq governors fixes and cleanups (Chen Yu, Stratos Karafotis,
Viresh Kumar)
- Support for using generic cpufreq governors in the intel_pstate
driver (Rafael Wysocki)
- Support for per-logical-CPU P-state limits and the EPP/EPB (Energy
Performance Preference/Energy Performance Bias) knobs in the
intel_pstate driver (Srinivas Pandruvada)
- New CPU ID for Knights Mill in intel_pstate (Piotr Luc)
- intel_pstate driver modification to use the P-state selection
algorithm based on CPU load on platforms with the system profile in
the ACPI tables set to "mobile" (Srinivas Pandruvada)
- intel_pstate driver cleanups (Arnd Bergmann, Rafael Wysocki,
Srinivas Pandruvada)
- cpufreq powernv driver updates including fast switching support
(for the schedutil governor), fixes and cleanus (Akshay Adiga,
Andrew Donnellan, Denis Kirjanov)
- acpi-cpufreq driver rework to switch it over to the new CPU
offline/online state machine (Sebastian Andrzej Siewior)
- Assorted cleanups in cpufreq drivers (Wei Yongjun, Prashanth
Prakash)
- Idle injection rework (to make it use the regular idle path instead
of a home-grown custom one) and related powerclamp thermal driver
updates (Peter Zijlstra, Jacob Pan, Petr Mladek, Sebastian Andrzej
Siewior)
- New CPU IDs for Atom Z34xx and Knights Mill in intel_idle (Andy
Shevchenko, Piotr Luc)
- intel_idle driver cleanups and switch over to using the new CPU
offline/online state machine (Anna-Maria Gleixner, Sebastian
Andrzej Siewior)
- cpuidle DT driver update to support suspend-to-idle properly
(Sudeep Holla)
- cpuidle core cleanups and misc updates (Daniel Lezcano, Pan Bian,
Rafael Wysocki)
- Preliminary support for power domains including CPUs in the generic
power domains (genpd) framework and related DT bindings (Lina Iyer)
- Assorted fixes and cleanups in the generic power domains (genpd)
framework (Colin Ian King, Dan Carpenter, Geert Uytterhoeven)
- Preliminary support for devices with multiple voltage regulators
and related fixes and cleanups in the Operating Performance Points
(OPP) library (Viresh Kumar, Masahiro Yamada, Stephen Boyd)
- System sleep state selection interface rework to make it easier to
support suspend-to-idle as the default system suspend method
(Rafael Wysocki)
- PM core fixes and cleanups, mostly related to the interactions
between the system suspend and runtime PM frameworks (Ulf Hansson,
Sahitya Tummala, Tony Lindgren)
- Latency tolerance PM QoS framework imorovements (Andrew Lutomirski)
- New Knights Mill CPU ID for the Intel RAPL power capping driver
(Piotr Luc)
- Intel RAPL power capping driver fixes, cleanups and switch over to
using the new CPU offline/online state machine (Jacob Pan, Thomas
Gleixner, Sebastian Andrzej Siewior)
- Fixes and cleanups in the exynos-ppmu, exynos-nocp, rk3399_dmc,
rockchip-dfi devfreq drivers and the devfreq core (Axel Lin,
Chanwoo Choi, Javier Martinez Canillas, MyungJoo Ham, Viresh Kumar)
- Fix for false-positive KASAN warnings during resume from ACPI S3
(suspend-to-RAM) on x86 (Josh Poimboeuf)
- Memory map verification during resume from hibernation on x86 to
ensure a consistent address space layout (Chen Yu)
- Wakeup sources debugging enhancement (Xing Wei)
- rockchip-io AVS driver cleanup (Shawn Lin)"
* tag 'pm-4.10-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (127 commits)
devfreq: rk3399_dmc: Don't use OPP structures outside of RCU locks
devfreq: rk3399_dmc: Remove dangling rcu_read_unlock()
devfreq: exynos: Don't use OPP structures outside of RCU locks
Documentation: intel_pstate: Document HWP energy/performance hints
cpufreq: intel_pstate: Support for energy performance hints with HWP
cpufreq: intel_pstate: Add locking around HWP requests
PM / sleep: Print active wakeup sources when blocking on wakeup_count reads
PM / core: Fix bug in the error handling of async suspend
PM / wakeirq: Fix dedicated wakeirq for drivers not using autosuspend
PM / Domains: Fix compatible for domain idle state
PM / OPP: Don't WARN on multiple calls to dev_pm_opp_set_regulators()
PM / OPP: Allow platform specific custom set_opp() callbacks
PM / OPP: Separate out _generic_set_opp()
PM / OPP: Add infrastructure to manage multiple regulators
PM / OPP: Pass struct dev_pm_opp_supply to _set_opp_voltage()
PM / OPP: Manage supply's voltage/current in a separate structure
PM / OPP: Don't use OPP structure outside of rcu protected section
PM / OPP: Reword binding supporting multiple regulators per device
PM / OPP: Fix incorrect cpu-supply property in binding
cpuidle: Add a kerneldoc comment to cpuidle_use_deepest_state()
..
This commit is contained in:
commit
7b9dc3f75f
79 changed files with 4399 additions and 1549 deletions
|
|
@ -12,6 +12,27 @@ config ARM_BIG_LITTLE_CPUFREQ
|
|||
help
|
||||
This enables the Generic CPUfreq driver for ARM big.LITTLE platforms.
|
||||
|
||||
config ARM_BRCMSTB_AVS_CPUFREQ
|
||||
tristate "Broadcom STB AVS CPUfreq driver"
|
||||
depends on ARCH_BRCMSTB || COMPILE_TEST
|
||||
default y
|
||||
help
|
||||
Some Broadcom STB SoCs use a co-processor running proprietary firmware
|
||||
("AVS") to handle voltage and frequency scaling. This driver provides
|
||||
a standard CPUfreq interface to to the firmware.
|
||||
|
||||
Say Y, if you have a Broadcom SoC with AVS support for DFS or DVFS.
|
||||
|
||||
config ARM_BRCMSTB_AVS_CPUFREQ_DEBUG
|
||||
bool "Broadcom STB AVS CPUfreq driver sysfs debug capability"
|
||||
depends on ARM_BRCMSTB_AVS_CPUFREQ
|
||||
help
|
||||
Enabling this option turns on debug support via sysfs under
|
||||
/sys/kernel/debug/brcmstb-avs-cpufreq. It is possible to read all and
|
||||
write some AVS mailbox registers through sysfs entries.
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config ARM_DT_BL_CPUFREQ
|
||||
tristate "Generic probing via DT for ARM big LITTLE CPUfreq driver"
|
||||
depends on ARM_BIG_LITTLE_CPUFREQ && OF
|
||||
|
|
@ -60,14 +81,6 @@ config ARM_IMX6Q_CPUFREQ
|
|||
|
||||
If in doubt, say N.
|
||||
|
||||
config ARM_INTEGRATOR
|
||||
tristate "CPUfreq driver for ARM Integrator CPUs"
|
||||
depends on ARCH_INTEGRATOR
|
||||
default y
|
||||
help
|
||||
This enables the CPUfreq driver for ARM Integrator CPUs.
|
||||
If in doubt, say Y.
|
||||
|
||||
config ARM_KIRKWOOD_CPUFREQ
|
||||
def_bool MACH_KIRKWOOD
|
||||
help
|
||||
|
|
|
|||
|
|
@ -51,12 +51,12 @@ obj-$(CONFIG_ARM_BIG_LITTLE_CPUFREQ) += arm_big_little.o
|
|||
# LITTLE drivers, so that it is probed last.
|
||||
obj-$(CONFIG_ARM_DT_BL_CPUFREQ) += arm_big_little_dt.o
|
||||
|
||||
obj-$(CONFIG_ARM_BRCMSTB_AVS_CPUFREQ) += brcmstb-avs-cpufreq.o
|
||||
obj-$(CONFIG_ARCH_DAVINCI) += davinci-cpufreq.o
|
||||
obj-$(CONFIG_UX500_SOC_DB8500) += dbx500-cpufreq.o
|
||||
obj-$(CONFIG_ARM_EXYNOS5440_CPUFREQ) += exynos5440-cpufreq.o
|
||||
obj-$(CONFIG_ARM_HIGHBANK_CPUFREQ) += highbank-cpufreq.o
|
||||
obj-$(CONFIG_ARM_IMX6Q_CPUFREQ) += imx6q-cpufreq.o
|
||||
obj-$(CONFIG_ARM_INTEGRATOR) += integrator-cpufreq.o
|
||||
obj-$(CONFIG_ARM_KIRKWOOD_CPUFREQ) += kirkwood-cpufreq.o
|
||||
obj-$(CONFIG_ARM_MT8173_CPUFREQ) += mt8173-cpufreq.o
|
||||
obj-$(CONFIG_ARM_OMAP2PLUS_CPUFREQ) += omap-cpufreq.o
|
||||
|
|
|
|||
|
|
@ -84,7 +84,6 @@ static inline struct acpi_processor_performance *to_perf_data(struct acpi_cpufre
|
|||
static struct cpufreq_driver acpi_cpufreq_driver;
|
||||
|
||||
static unsigned int acpi_pstate_strict;
|
||||
static struct msr __percpu *msrs;
|
||||
|
||||
static bool boost_state(unsigned int cpu)
|
||||
{
|
||||
|
|
@ -104,11 +103,10 @@ static bool boost_state(unsigned int cpu)
|
|||
return false;
|
||||
}
|
||||
|
||||
static void boost_set_msrs(bool enable, const struct cpumask *cpumask)
|
||||
static int boost_set_msr(bool enable)
|
||||
{
|
||||
u32 cpu;
|
||||
u32 msr_addr;
|
||||
u64 msr_mask;
|
||||
u64 msr_mask, val;
|
||||
|
||||
switch (boot_cpu_data.x86_vendor) {
|
||||
case X86_VENDOR_INTEL:
|
||||
|
|
@ -120,26 +118,31 @@ static void boost_set_msrs(bool enable, const struct cpumask *cpumask)
|
|||
msr_mask = MSR_K7_HWCR_CPB_DIS;
|
||||
break;
|
||||
default:
|
||||
return;
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rdmsr_on_cpus(cpumask, msr_addr, msrs);
|
||||
rdmsrl(msr_addr, val);
|
||||
|
||||
for_each_cpu(cpu, cpumask) {
|
||||
struct msr *reg = per_cpu_ptr(msrs, cpu);
|
||||
if (enable)
|
||||
reg->q &= ~msr_mask;
|
||||
else
|
||||
reg->q |= msr_mask;
|
||||
}
|
||||
if (enable)
|
||||
val &= ~msr_mask;
|
||||
else
|
||||
val |= msr_mask;
|
||||
|
||||
wrmsr_on_cpus(cpumask, msr_addr, msrs);
|
||||
wrmsrl(msr_addr, val);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void boost_set_msr_each(void *p_en)
|
||||
{
|
||||
bool enable = (bool) p_en;
|
||||
|
||||
boost_set_msr(enable);
|
||||
}
|
||||
|
||||
static int set_boost(int val)
|
||||
{
|
||||
get_online_cpus();
|
||||
boost_set_msrs(val, cpu_online_mask);
|
||||
on_each_cpu(boost_set_msr_each, (void *)(long)val, 1);
|
||||
put_online_cpus();
|
||||
pr_debug("Core Boosting %sabled.\n", val ? "en" : "dis");
|
||||
|
||||
|
|
@ -536,45 +539,23 @@ static void free_acpi_perf_data(void)
|
|||
free_percpu(acpi_perf_data);
|
||||
}
|
||||
|
||||
static int boost_notify(struct notifier_block *nb, unsigned long action,
|
||||
void *hcpu)
|
||||
static int cpufreq_boost_online(unsigned int cpu)
|
||||
{
|
||||
unsigned cpu = (long)hcpu;
|
||||
const struct cpumask *cpumask;
|
||||
|
||||
cpumask = get_cpu_mask(cpu);
|
||||
|
||||
/*
|
||||
* Clear the boost-disable bit on the CPU_DOWN path so that
|
||||
* this cpu cannot block the remaining ones from boosting. On
|
||||
* the CPU_UP path we simply keep the boost-disable flag in
|
||||
* sync with the current global state.
|
||||
* On the CPU_UP path we simply keep the boost-disable flag
|
||||
* in sync with the current global state.
|
||||
*/
|
||||
|
||||
switch (action) {
|
||||
case CPU_DOWN_FAILED:
|
||||
case CPU_DOWN_FAILED_FROZEN:
|
||||
case CPU_ONLINE:
|
||||
case CPU_ONLINE_FROZEN:
|
||||
boost_set_msrs(acpi_cpufreq_driver.boost_enabled, cpumask);
|
||||
break;
|
||||
|
||||
case CPU_DOWN_PREPARE:
|
||||
case CPU_DOWN_PREPARE_FROZEN:
|
||||
boost_set_msrs(1, cpumask);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return NOTIFY_OK;
|
||||
return boost_set_msr(acpi_cpufreq_driver.boost_enabled);
|
||||
}
|
||||
|
||||
|
||||
static struct notifier_block boost_nb = {
|
||||
.notifier_call = boost_notify,
|
||||
};
|
||||
static int cpufreq_boost_down_prep(unsigned int cpu)
|
||||
{
|
||||
/*
|
||||
* Clear the boost-disable bit on the CPU_DOWN path so that
|
||||
* this cpu cannot block the remaining ones from boosting.
|
||||
*/
|
||||
return boost_set_msr(1);
|
||||
}
|
||||
|
||||
/*
|
||||
* acpi_cpufreq_early_init - initialize ACPI P-States library
|
||||
|
|
@ -922,37 +903,35 @@ static struct cpufreq_driver acpi_cpufreq_driver = {
|
|||
.attr = acpi_cpufreq_attr,
|
||||
};
|
||||
|
||||
static enum cpuhp_state acpi_cpufreq_online;
|
||||
|
||||
static void __init acpi_cpufreq_boost_init(void)
|
||||
{
|
||||
if (boot_cpu_has(X86_FEATURE_CPB) || boot_cpu_has(X86_FEATURE_IDA)) {
|
||||
msrs = msrs_alloc();
|
||||
int ret;
|
||||
|
||||
if (!msrs)
|
||||
return;
|
||||
if (!(boot_cpu_has(X86_FEATURE_CPB) || boot_cpu_has(X86_FEATURE_IDA)))
|
||||
return;
|
||||
|
||||
acpi_cpufreq_driver.set_boost = set_boost;
|
||||
acpi_cpufreq_driver.boost_enabled = boost_state(0);
|
||||
acpi_cpufreq_driver.set_boost = set_boost;
|
||||
acpi_cpufreq_driver.boost_enabled = boost_state(0);
|
||||
|
||||
cpu_notifier_register_begin();
|
||||
|
||||
/* Force all MSRs to the same value */
|
||||
boost_set_msrs(acpi_cpufreq_driver.boost_enabled,
|
||||
cpu_online_mask);
|
||||
|
||||
__register_cpu_notifier(&boost_nb);
|
||||
|
||||
cpu_notifier_register_done();
|
||||
/*
|
||||
* This calls the online callback on all online cpu and forces all
|
||||
* MSRs to the same value.
|
||||
*/
|
||||
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "cpufreq/acpi:online",
|
||||
cpufreq_boost_online, cpufreq_boost_down_prep);
|
||||
if (ret < 0) {
|
||||
pr_err("acpi_cpufreq: failed to register hotplug callbacks\n");
|
||||
return;
|
||||
}
|
||||
acpi_cpufreq_online = ret;
|
||||
}
|
||||
|
||||
static void acpi_cpufreq_boost_exit(void)
|
||||
{
|
||||
if (msrs) {
|
||||
unregister_cpu_notifier(&boost_nb);
|
||||
|
||||
msrs_free(msrs);
|
||||
msrs = NULL;
|
||||
}
|
||||
if (acpi_cpufreq_online >= 0)
|
||||
cpuhp_remove_state_nocalls(acpi_cpufreq_online);
|
||||
}
|
||||
|
||||
static int __init acpi_cpufreq_init(void)
|
||||
|
|
|
|||
1057
drivers/cpufreq/brcmstb-avs-cpufreq.c
Normal file
1057
drivers/cpufreq/brcmstb-avs-cpufreq.c
Normal file
File diff suppressed because it is too large
Load diff
|
|
@ -247,3 +247,10 @@ MODULE_DESCRIPTION("CPUFreq driver based on the ACPI CPPC v5.0+ spec");
|
|||
MODULE_LICENSE("GPL");
|
||||
|
||||
late_initcall(cppc_cpufreq_init);
|
||||
|
||||
static const struct acpi_device_id cppc_acpi_ids[] = {
|
||||
{ACPI_PROCESSOR_DEVICE_HID, },
|
||||
{}
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(acpi, cppc_acpi_ids);
|
||||
|
|
|
|||
|
|
@ -26,6 +26,9 @@ static const struct of_device_id machines[] __initconst = {
|
|||
{ .compatible = "allwinner,sun8i-a83t", },
|
||||
{ .compatible = "allwinner,sun8i-h3", },
|
||||
|
||||
{ .compatible = "arm,integrator-ap", },
|
||||
{ .compatible = "arm,integrator-cp", },
|
||||
|
||||
{ .compatible = "hisilicon,hi6220", },
|
||||
|
||||
{ .compatible = "fsl,imx27", },
|
||||
|
|
@ -34,6 +37,8 @@ static const struct of_device_id machines[] __initconst = {
|
|||
{ .compatible = "fsl,imx7d", },
|
||||
|
||||
{ .compatible = "marvell,berlin", },
|
||||
{ .compatible = "marvell,pxa250", },
|
||||
{ .compatible = "marvell,pxa270", },
|
||||
|
||||
{ .compatible = "samsung,exynos3250", },
|
||||
{ .compatible = "samsung,exynos4210", },
|
||||
|
|
@ -50,6 +55,8 @@ static const struct of_device_id machines[] __initconst = {
|
|||
{ .compatible = "renesas,r7s72100", },
|
||||
{ .compatible = "renesas,r8a73a4", },
|
||||
{ .compatible = "renesas,r8a7740", },
|
||||
{ .compatible = "renesas,r8a7743", },
|
||||
{ .compatible = "renesas,r8a7745", },
|
||||
{ .compatible = "renesas,r8a7778", },
|
||||
{ .compatible = "renesas,r8a7779", },
|
||||
{ .compatible = "renesas,r8a7790", },
|
||||
|
|
@ -72,6 +79,12 @@ static const struct of_device_id machines[] __initconst = {
|
|||
|
||||
{ .compatible = "sigma,tango4" },
|
||||
|
||||
{ .compatible = "socionext,uniphier-pro5", },
|
||||
{ .compatible = "socionext,uniphier-pxs2", },
|
||||
{ .compatible = "socionext,uniphier-ld6b", },
|
||||
{ .compatible = "socionext,uniphier-ld11", },
|
||||
{ .compatible = "socionext,uniphier-ld20", },
|
||||
|
||||
{ .compatible = "ti,am33xx", },
|
||||
{ .compatible = "ti,dra7", },
|
||||
{ .compatible = "ti,omap2", },
|
||||
|
|
@ -81,6 +94,8 @@ static const struct of_device_id machines[] __initconst = {
|
|||
|
||||
{ .compatible = "xlnx,zynq-7000", },
|
||||
|
||||
{ .compatible = "zte,zx296718", },
|
||||
|
||||
{ }
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -28,6 +28,7 @@
|
|||
#include "cpufreq-dt.h"
|
||||
|
||||
struct private_data {
|
||||
struct opp_table *opp_table;
|
||||
struct device *cpu_dev;
|
||||
struct thermal_cooling_device *cdev;
|
||||
const char *reg_name;
|
||||
|
|
@ -143,6 +144,7 @@ static int resources_available(void)
|
|||
static int cpufreq_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct cpufreq_frequency_table *freq_table;
|
||||
struct opp_table *opp_table = NULL;
|
||||
struct private_data *priv;
|
||||
struct device *cpu_dev;
|
||||
struct clk *cpu_clk;
|
||||
|
|
@ -186,8 +188,9 @@ static int cpufreq_init(struct cpufreq_policy *policy)
|
|||
*/
|
||||
name = find_supply_name(cpu_dev);
|
||||
if (name) {
|
||||
ret = dev_pm_opp_set_regulator(cpu_dev, name);
|
||||
if (ret) {
|
||||
opp_table = dev_pm_opp_set_regulators(cpu_dev, &name, 1);
|
||||
if (IS_ERR(opp_table)) {
|
||||
ret = PTR_ERR(opp_table);
|
||||
dev_err(cpu_dev, "Failed to set regulator for cpu%d: %d\n",
|
||||
policy->cpu, ret);
|
||||
goto out_put_clk;
|
||||
|
|
@ -237,6 +240,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
|
|||
}
|
||||
|
||||
priv->reg_name = name;
|
||||
priv->opp_table = opp_table;
|
||||
|
||||
ret = dev_pm_opp_init_cpufreq_table(cpu_dev, &freq_table);
|
||||
if (ret) {
|
||||
|
|
@ -285,7 +289,7 @@ out_free_priv:
|
|||
out_free_opp:
|
||||
dev_pm_opp_of_cpumask_remove_table(policy->cpus);
|
||||
if (name)
|
||||
dev_pm_opp_put_regulator(cpu_dev);
|
||||
dev_pm_opp_put_regulators(opp_table);
|
||||
out_put_clk:
|
||||
clk_put(cpu_clk);
|
||||
|
||||
|
|
@ -300,7 +304,7 @@ static int cpufreq_exit(struct cpufreq_policy *policy)
|
|||
dev_pm_opp_free_cpufreq_table(priv->cpu_dev, &policy->freq_table);
|
||||
dev_pm_opp_of_cpumask_remove_table(policy->related_cpus);
|
||||
if (priv->reg_name)
|
||||
dev_pm_opp_put_regulator(priv->cpu_dev);
|
||||
dev_pm_opp_put_regulators(priv->opp_table);
|
||||
|
||||
clk_put(policy->clk);
|
||||
kfree(priv);
|
||||
|
|
|
|||
|
|
@ -1526,7 +1526,10 @@ unsigned int cpufreq_get(unsigned int cpu)
|
|||
|
||||
if (policy) {
|
||||
down_read(&policy->rwsem);
|
||||
ret_freq = __cpufreq_get(policy);
|
||||
|
||||
if (!policy_is_inactive(policy))
|
||||
ret_freq = __cpufreq_get(policy);
|
||||
|
||||
up_read(&policy->rwsem);
|
||||
|
||||
cpufreq_cpu_put(policy);
|
||||
|
|
@ -2254,17 +2257,19 @@ static int cpufreq_set_policy(struct cpufreq_policy *policy,
|
|||
* Useful for policy notifiers which have different necessities
|
||||
* at different times.
|
||||
*/
|
||||
int cpufreq_update_policy(unsigned int cpu)
|
||||
void cpufreq_update_policy(unsigned int cpu)
|
||||
{
|
||||
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
|
||||
struct cpufreq_policy new_policy;
|
||||
int ret;
|
||||
|
||||
if (!policy)
|
||||
return -ENODEV;
|
||||
return;
|
||||
|
||||
down_write(&policy->rwsem);
|
||||
|
||||
if (policy_is_inactive(policy))
|
||||
goto unlock;
|
||||
|
||||
pr_debug("updating policy for CPU %u\n", cpu);
|
||||
memcpy(&new_policy, policy, sizeof(*policy));
|
||||
new_policy.min = policy->user_policy.min;
|
||||
|
|
@ -2275,24 +2280,20 @@ int cpufreq_update_policy(unsigned int cpu)
|
|||
* -> ask driver for current freq and notify governors about a change
|
||||
*/
|
||||
if (cpufreq_driver->get && !cpufreq_driver->setpolicy) {
|
||||
if (cpufreq_suspended) {
|
||||
ret = -EAGAIN;
|
||||
if (cpufreq_suspended)
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
new_policy.cur = cpufreq_update_current_freq(policy);
|
||||
if (WARN_ON(!new_policy.cur)) {
|
||||
ret = -EIO;
|
||||
if (WARN_ON(!new_policy.cur))
|
||||
goto unlock;
|
||||
}
|
||||
}
|
||||
|
||||
ret = cpufreq_set_policy(policy, &new_policy);
|
||||
cpufreq_set_policy(policy, &new_policy);
|
||||
|
||||
unlock:
|
||||
up_write(&policy->rwsem);
|
||||
|
||||
cpufreq_cpu_put(policy);
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL(cpufreq_update_policy);
|
||||
|
||||
|
|
|
|||
|
|
@ -37,16 +37,16 @@ struct cs_dbs_tuners {
|
|||
#define DEF_SAMPLING_DOWN_FACTOR (1)
|
||||
#define MAX_SAMPLING_DOWN_FACTOR (10)
|
||||
|
||||
static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners,
|
||||
struct cpufreq_policy *policy)
|
||||
static inline unsigned int get_freq_step(struct cs_dbs_tuners *cs_tuners,
|
||||
struct cpufreq_policy *policy)
|
||||
{
|
||||
unsigned int freq_target = (cs_tuners->freq_step * policy->max) / 100;
|
||||
unsigned int freq_step = (cs_tuners->freq_step * policy->max) / 100;
|
||||
|
||||
/* max freq cannot be less than 100. But who knows... */
|
||||
if (unlikely(freq_target == 0))
|
||||
freq_target = DEF_FREQUENCY_STEP;
|
||||
if (unlikely(freq_step == 0))
|
||||
freq_step = DEF_FREQUENCY_STEP;
|
||||
|
||||
return freq_target;
|
||||
return freq_step;
|
||||
}
|
||||
|
||||
/*
|
||||
|
|
@ -55,10 +55,10 @@ static inline unsigned int get_freq_target(struct cs_dbs_tuners *cs_tuners,
|
|||
* sampling_down_factor, we check, if current idle time is more than 80%
|
||||
* (default), then we try to decrease frequency
|
||||
*
|
||||
* Any frequency increase takes it to the maximum frequency. Frequency reduction
|
||||
* happens at minimum steps of 5% (default) of maximum frequency
|
||||
* Frequency updates happen at minimum steps of 5% (default) of maximum
|
||||
* frequency
|
||||
*/
|
||||
static unsigned int cs_dbs_timer(struct cpufreq_policy *policy)
|
||||
static unsigned int cs_dbs_update(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct policy_dbs_info *policy_dbs = policy->governor_data;
|
||||
struct cs_policy_dbs_info *dbs_info = to_dbs_info(policy_dbs);
|
||||
|
|
@ -66,6 +66,7 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy)
|
|||
struct dbs_data *dbs_data = policy_dbs->dbs_data;
|
||||
struct cs_dbs_tuners *cs_tuners = dbs_data->tuners;
|
||||
unsigned int load = dbs_update(policy);
|
||||
unsigned int freq_step;
|
||||
|
||||
/*
|
||||
* break out if we 'cannot' reduce the speed as the user might
|
||||
|
|
@ -82,6 +83,23 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy)
|
|||
if (requested_freq > policy->max || requested_freq < policy->min)
|
||||
requested_freq = policy->cur;
|
||||
|
||||
freq_step = get_freq_step(cs_tuners, policy);
|
||||
|
||||
/*
|
||||
* Decrease requested_freq one freq_step for each idle period that
|
||||
* we didn't update the frequency.
|
||||
*/
|
||||
if (policy_dbs->idle_periods < UINT_MAX) {
|
||||
unsigned int freq_steps = policy_dbs->idle_periods * freq_step;
|
||||
|
||||
if (requested_freq > freq_steps)
|
||||
requested_freq -= freq_steps;
|
||||
else
|
||||
requested_freq = policy->min;
|
||||
|
||||
policy_dbs->idle_periods = UINT_MAX;
|
||||
}
|
||||
|
||||
/* Check for frequency increase */
|
||||
if (load > dbs_data->up_threshold) {
|
||||
dbs_info->down_skip = 0;
|
||||
|
|
@ -90,7 +108,7 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy)
|
|||
if (requested_freq == policy->max)
|
||||
goto out;
|
||||
|
||||
requested_freq += get_freq_target(cs_tuners, policy);
|
||||
requested_freq += freq_step;
|
||||
if (requested_freq > policy->max)
|
||||
requested_freq = policy->max;
|
||||
|
||||
|
|
@ -106,16 +124,14 @@ static unsigned int cs_dbs_timer(struct cpufreq_policy *policy)
|
|||
|
||||
/* Check for frequency decrease */
|
||||
if (load < cs_tuners->down_threshold) {
|
||||
unsigned int freq_target;
|
||||
/*
|
||||
* if we cannot reduce the frequency anymore, break out early
|
||||
*/
|
||||
if (requested_freq == policy->min)
|
||||
goto out;
|
||||
|
||||
freq_target = get_freq_target(cs_tuners, policy);
|
||||
if (requested_freq > freq_target)
|
||||
requested_freq -= freq_target;
|
||||
if (requested_freq > freq_step)
|
||||
requested_freq -= freq_step;
|
||||
else
|
||||
requested_freq = policy->min;
|
||||
|
||||
|
|
@ -305,7 +321,7 @@ static void cs_start(struct cpufreq_policy *policy)
|
|||
static struct dbs_governor cs_governor = {
|
||||
.gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("conservative"),
|
||||
.kobj_type = { .default_attrs = cs_attributes },
|
||||
.gov_dbs_timer = cs_dbs_timer,
|
||||
.gov_dbs_update = cs_dbs_update,
|
||||
.alloc = cs_alloc,
|
||||
.free = cs_free,
|
||||
.init = cs_init,
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ ssize_t store_sampling_rate(struct gov_attr_set *attr_set, const char *buf,
|
|||
* entries can't be freed concurrently.
|
||||
*/
|
||||
list_for_each_entry(policy_dbs, &attr_set->policy_list, list) {
|
||||
mutex_lock(&policy_dbs->timer_mutex);
|
||||
mutex_lock(&policy_dbs->update_mutex);
|
||||
/*
|
||||
* On 32-bit architectures this may race with the
|
||||
* sample_delay_ns read in dbs_update_util_handler(), but that
|
||||
|
|
@ -76,7 +76,7 @@ ssize_t store_sampling_rate(struct gov_attr_set *attr_set, const char *buf,
|
|||
* taken, so it shouldn't be significant.
|
||||
*/
|
||||
gov_update_sample_delay(policy_dbs, 0);
|
||||
mutex_unlock(&policy_dbs->timer_mutex);
|
||||
mutex_unlock(&policy_dbs->update_mutex);
|
||||
}
|
||||
|
||||
return count;
|
||||
|
|
@ -117,7 +117,7 @@ unsigned int dbs_update(struct cpufreq_policy *policy)
|
|||
struct policy_dbs_info *policy_dbs = policy->governor_data;
|
||||
struct dbs_data *dbs_data = policy_dbs->dbs_data;
|
||||
unsigned int ignore_nice = dbs_data->ignore_nice_load;
|
||||
unsigned int max_load = 0;
|
||||
unsigned int max_load = 0, idle_periods = UINT_MAX;
|
||||
unsigned int sampling_rate, io_busy, j;
|
||||
|
||||
/*
|
||||
|
|
@ -215,9 +215,19 @@ unsigned int dbs_update(struct cpufreq_policy *policy)
|
|||
j_cdbs->prev_load = load;
|
||||
}
|
||||
|
||||
if (time_elapsed > 2 * sampling_rate) {
|
||||
unsigned int periods = time_elapsed / sampling_rate;
|
||||
|
||||
if (periods < idle_periods)
|
||||
idle_periods = periods;
|
||||
}
|
||||
|
||||
if (load > max_load)
|
||||
max_load = load;
|
||||
}
|
||||
|
||||
policy_dbs->idle_periods = idle_periods;
|
||||
|
||||
return max_load;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(dbs_update);
|
||||
|
|
@ -236,9 +246,9 @@ static void dbs_work_handler(struct work_struct *work)
|
|||
* Make sure cpufreq_governor_limits() isn't evaluating load or the
|
||||
* ondemand governor isn't updating the sampling rate in parallel.
|
||||
*/
|
||||
mutex_lock(&policy_dbs->timer_mutex);
|
||||
gov_update_sample_delay(policy_dbs, gov->gov_dbs_timer(policy));
|
||||
mutex_unlock(&policy_dbs->timer_mutex);
|
||||
mutex_lock(&policy_dbs->update_mutex);
|
||||
gov_update_sample_delay(policy_dbs, gov->gov_dbs_update(policy));
|
||||
mutex_unlock(&policy_dbs->update_mutex);
|
||||
|
||||
/* Allow the utilization update handler to queue up more work. */
|
||||
atomic_set(&policy_dbs->work_count, 0);
|
||||
|
|
@ -348,7 +358,7 @@ static struct policy_dbs_info *alloc_policy_dbs_info(struct cpufreq_policy *poli
|
|||
return NULL;
|
||||
|
||||
policy_dbs->policy = policy;
|
||||
mutex_init(&policy_dbs->timer_mutex);
|
||||
mutex_init(&policy_dbs->update_mutex);
|
||||
atomic_set(&policy_dbs->work_count, 0);
|
||||
init_irq_work(&policy_dbs->irq_work, dbs_irq_work);
|
||||
INIT_WORK(&policy_dbs->work, dbs_work_handler);
|
||||
|
|
@ -367,7 +377,7 @@ static void free_policy_dbs_info(struct policy_dbs_info *policy_dbs,
|
|||
{
|
||||
int j;
|
||||
|
||||
mutex_destroy(&policy_dbs->timer_mutex);
|
||||
mutex_destroy(&policy_dbs->update_mutex);
|
||||
|
||||
for_each_cpu(j, policy_dbs->policy->related_cpus) {
|
||||
struct cpu_dbs_info *j_cdbs = &per_cpu(cpu_dbs, j);
|
||||
|
|
@ -547,10 +557,10 @@ void cpufreq_dbs_governor_limits(struct cpufreq_policy *policy)
|
|||
{
|
||||
struct policy_dbs_info *policy_dbs = policy->governor_data;
|
||||
|
||||
mutex_lock(&policy_dbs->timer_mutex);
|
||||
mutex_lock(&policy_dbs->update_mutex);
|
||||
cpufreq_policy_apply_limits(policy);
|
||||
gov_update_sample_delay(policy_dbs, 0);
|
||||
|
||||
mutex_unlock(&policy_dbs->timer_mutex);
|
||||
mutex_unlock(&policy_dbs->update_mutex);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(cpufreq_dbs_governor_limits);
|
||||
|
|
|
|||
|
|
@ -85,7 +85,7 @@ struct policy_dbs_info {
|
|||
* Per policy mutex that serializes load evaluation from limit-change
|
||||
* and work-handler.
|
||||
*/
|
||||
struct mutex timer_mutex;
|
||||
struct mutex update_mutex;
|
||||
|
||||
u64 last_sample_time;
|
||||
s64 sample_delay_ns;
|
||||
|
|
@ -97,6 +97,7 @@ struct policy_dbs_info {
|
|||
struct list_head list;
|
||||
/* Multiplier for increasing sample delay temporarily. */
|
||||
unsigned int rate_mult;
|
||||
unsigned int idle_periods; /* For conservative */
|
||||
/* Status indicators */
|
||||
bool is_shared; /* This object is used by multiple CPUs */
|
||||
bool work_in_progress; /* Work is being queued up or in progress */
|
||||
|
|
@ -135,7 +136,7 @@ struct dbs_governor {
|
|||
*/
|
||||
struct dbs_data *gdbs_data;
|
||||
|
||||
unsigned int (*gov_dbs_timer)(struct cpufreq_policy *policy);
|
||||
unsigned int (*gov_dbs_update)(struct cpufreq_policy *policy);
|
||||
struct policy_dbs_info *(*alloc)(void);
|
||||
void (*free)(struct policy_dbs_info *policy_dbs);
|
||||
int (*init)(struct dbs_data *dbs_data);
|
||||
|
|
|
|||
|
|
@ -25,7 +25,7 @@
|
|||
#define MAX_SAMPLING_DOWN_FACTOR (100000)
|
||||
#define MICRO_FREQUENCY_UP_THRESHOLD (95)
|
||||
#define MICRO_FREQUENCY_MIN_SAMPLE_RATE (10000)
|
||||
#define MIN_FREQUENCY_UP_THRESHOLD (11)
|
||||
#define MIN_FREQUENCY_UP_THRESHOLD (1)
|
||||
#define MAX_FREQUENCY_UP_THRESHOLD (100)
|
||||
|
||||
static struct od_ops od_ops;
|
||||
|
|
@ -169,7 +169,7 @@ static void od_update(struct cpufreq_policy *policy)
|
|||
}
|
||||
}
|
||||
|
||||
static unsigned int od_dbs_timer(struct cpufreq_policy *policy)
|
||||
static unsigned int od_dbs_update(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct policy_dbs_info *policy_dbs = policy->governor_data;
|
||||
struct dbs_data *dbs_data = policy_dbs->dbs_data;
|
||||
|
|
@ -191,7 +191,7 @@ static unsigned int od_dbs_timer(struct cpufreq_policy *policy)
|
|||
od_update(policy);
|
||||
|
||||
if (dbs_info->freq_lo) {
|
||||
/* Setup timer for SUB_SAMPLE */
|
||||
/* Setup SUB_SAMPLE */
|
||||
dbs_info->sample_type = OD_SUB_SAMPLE;
|
||||
return dbs_info->freq_hi_delay_us;
|
||||
}
|
||||
|
|
@ -255,11 +255,11 @@ static ssize_t store_sampling_down_factor(struct gov_attr_set *attr_set,
|
|||
list_for_each_entry(policy_dbs, &attr_set->policy_list, list) {
|
||||
/*
|
||||
* Doing this without locking might lead to using different
|
||||
* rate_mult values in od_update() and od_dbs_timer().
|
||||
* rate_mult values in od_update() and od_dbs_update().
|
||||
*/
|
||||
mutex_lock(&policy_dbs->timer_mutex);
|
||||
mutex_lock(&policy_dbs->update_mutex);
|
||||
policy_dbs->rate_mult = 1;
|
||||
mutex_unlock(&policy_dbs->timer_mutex);
|
||||
mutex_unlock(&policy_dbs->update_mutex);
|
||||
}
|
||||
|
||||
return count;
|
||||
|
|
@ -374,8 +374,7 @@ static int od_init(struct dbs_data *dbs_data)
|
|||
dbs_data->up_threshold = MICRO_FREQUENCY_UP_THRESHOLD;
|
||||
/*
|
||||
* In nohz/micro accounting case we set the minimum frequency
|
||||
* not depending on HZ, but fixed (very low). The deferred
|
||||
* timer might skip some samples if idle/sleeping as needed.
|
||||
* not depending on HZ, but fixed (very low).
|
||||
*/
|
||||
dbs_data->min_sampling_rate = MICRO_FREQUENCY_MIN_SAMPLE_RATE;
|
||||
} else {
|
||||
|
|
@ -415,7 +414,7 @@ static struct od_ops od_ops = {
|
|||
static struct dbs_governor od_dbs_gov = {
|
||||
.gov = CPUFREQ_DBS_GOVERNOR_INITIALIZER("ondemand"),
|
||||
.kobj_type = { .default_attrs = od_attributes },
|
||||
.gov_dbs_timer = od_dbs_timer,
|
||||
.gov_dbs_update = od_dbs_update,
|
||||
.alloc = od_alloc,
|
||||
.free = od_free,
|
||||
.init = od_init,
|
||||
|
|
|
|||
|
|
@ -41,6 +41,18 @@ static int cpufreq_stats_update(struct cpufreq_stats *stats)
|
|||
return 0;
|
||||
}
|
||||
|
||||
static void cpufreq_stats_clear_table(struct cpufreq_stats *stats)
|
||||
{
|
||||
unsigned int count = stats->max_state;
|
||||
|
||||
memset(stats->time_in_state, 0, count * sizeof(u64));
|
||||
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
|
||||
memset(stats->trans_table, 0, count * count * sizeof(int));
|
||||
#endif
|
||||
stats->last_time = get_jiffies_64();
|
||||
stats->total_trans = 0;
|
||||
}
|
||||
|
||||
static ssize_t show_total_trans(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%d\n", policy->stats->total_trans);
|
||||
|
|
@ -64,6 +76,14 @@ static ssize_t show_time_in_state(struct cpufreq_policy *policy, char *buf)
|
|||
return len;
|
||||
}
|
||||
|
||||
static ssize_t store_reset(struct cpufreq_policy *policy, const char *buf,
|
||||
size_t count)
|
||||
{
|
||||
/* We don't care what is written to the attribute. */
|
||||
cpufreq_stats_clear_table(policy->stats);
|
||||
return count;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
|
||||
static ssize_t show_trans_table(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
|
|
@ -113,10 +133,12 @@ cpufreq_freq_attr_ro(trans_table);
|
|||
|
||||
cpufreq_freq_attr_ro(total_trans);
|
||||
cpufreq_freq_attr_ro(time_in_state);
|
||||
cpufreq_freq_attr_wo(reset);
|
||||
|
||||
static struct attribute *default_attrs[] = {
|
||||
&total_trans.attr,
|
||||
&time_in_state.attr,
|
||||
&reset.attr,
|
||||
#ifdef CONFIG_CPU_FREQ_STAT_DETAILS
|
||||
&trans_table.attr,
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -1,239 +0,0 @@
|
|||
/*
|
||||
* Copyright (C) 2001-2002 Deep Blue Solutions Ltd.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* CPU support functions
|
||||
*/
|
||||
#include <linux/module.h>
|
||||
#include <linux/types.h>
|
||||
#include <linux/kernel.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/smp.h>
|
||||
#include <linux/init.h>
|
||||
#include <linux/io.h>
|
||||
#include <linux/platform_device.h>
|
||||
#include <linux/of.h>
|
||||
#include <linux/of_address.h>
|
||||
|
||||
#include <asm/mach-types.h>
|
||||
#include <asm/hardware/icst.h>
|
||||
|
||||
static void __iomem *cm_base;
|
||||
/* The cpufreq driver only use the OSC register */
|
||||
#define INTEGRATOR_HDR_OSC_OFFSET 0x08
|
||||
#define INTEGRATOR_HDR_LOCK_OFFSET 0x14
|
||||
|
||||
static struct cpufreq_driver integrator_driver;
|
||||
|
||||
static const struct icst_params lclk_params = {
|
||||
.ref = 24000000,
|
||||
.vco_max = ICST525_VCO_MAX_5V,
|
||||
.vco_min = ICST525_VCO_MIN,
|
||||
.vd_min = 8,
|
||||
.vd_max = 132,
|
||||
.rd_min = 24,
|
||||
.rd_max = 24,
|
||||
.s2div = icst525_s2div,
|
||||
.idx2s = icst525_idx2s,
|
||||
};
|
||||
|
||||
static const struct icst_params cclk_params = {
|
||||
.ref = 24000000,
|
||||
.vco_max = ICST525_VCO_MAX_5V,
|
||||
.vco_min = ICST525_VCO_MIN,
|
||||
.vd_min = 12,
|
||||
.vd_max = 160,
|
||||
.rd_min = 24,
|
||||
.rd_max = 24,
|
||||
.s2div = icst525_s2div,
|
||||
.idx2s = icst525_idx2s,
|
||||
};
|
||||
|
||||
/*
|
||||
* Validate the speed policy.
|
||||
*/
|
||||
static int integrator_verify_policy(struct cpufreq_policy *policy)
|
||||
{
|
||||
struct icst_vco vco;
|
||||
|
||||
cpufreq_verify_within_cpu_limits(policy);
|
||||
|
||||
vco = icst_hz_to_vco(&cclk_params, policy->max * 1000);
|
||||
policy->max = icst_hz(&cclk_params, vco) / 1000;
|
||||
|
||||
vco = icst_hz_to_vco(&cclk_params, policy->min * 1000);
|
||||
policy->min = icst_hz(&cclk_params, vco) / 1000;
|
||||
|
||||
cpufreq_verify_within_cpu_limits(policy);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int integrator_set_target(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq,
|
||||
unsigned int relation)
|
||||
{
|
||||
cpumask_t cpus_allowed;
|
||||
int cpu = policy->cpu;
|
||||
struct icst_vco vco;
|
||||
struct cpufreq_freqs freqs;
|
||||
u_int cm_osc;
|
||||
|
||||
/*
|
||||
* Save this threads cpus_allowed mask.
|
||||
*/
|
||||
cpus_allowed = current->cpus_allowed;
|
||||
|
||||
/*
|
||||
* Bind to the specified CPU. When this call returns,
|
||||
* we should be running on the right CPU.
|
||||
*/
|
||||
set_cpus_allowed_ptr(current, cpumask_of(cpu));
|
||||
BUG_ON(cpu != smp_processor_id());
|
||||
|
||||
/* get current setting */
|
||||
cm_osc = __raw_readl(cm_base + INTEGRATOR_HDR_OSC_OFFSET);
|
||||
|
||||
if (machine_is_integrator())
|
||||
vco.s = (cm_osc >> 8) & 7;
|
||||
else if (machine_is_cintegrator())
|
||||
vco.s = 1;
|
||||
vco.v = cm_osc & 255;
|
||||
vco.r = 22;
|
||||
freqs.old = icst_hz(&cclk_params, vco) / 1000;
|
||||
|
||||
/* icst_hz_to_vco rounds down -- so we need the next
|
||||
* larger freq in case of CPUFREQ_RELATION_L.
|
||||
*/
|
||||
if (relation == CPUFREQ_RELATION_L)
|
||||
target_freq += 999;
|
||||
if (target_freq > policy->max)
|
||||
target_freq = policy->max;
|
||||
vco = icst_hz_to_vco(&cclk_params, target_freq * 1000);
|
||||
freqs.new = icst_hz(&cclk_params, vco) / 1000;
|
||||
|
||||
if (freqs.old == freqs.new) {
|
||||
set_cpus_allowed_ptr(current, &cpus_allowed);
|
||||
return 0;
|
||||
}
|
||||
|
||||
cpufreq_freq_transition_begin(policy, &freqs);
|
||||
|
||||
cm_osc = __raw_readl(cm_base + INTEGRATOR_HDR_OSC_OFFSET);
|
||||
|
||||
if (machine_is_integrator()) {
|
||||
cm_osc &= 0xfffff800;
|
||||
cm_osc |= vco.s << 8;
|
||||
} else if (machine_is_cintegrator()) {
|
||||
cm_osc &= 0xffffff00;
|
||||
}
|
||||
cm_osc |= vco.v;
|
||||
|
||||
__raw_writel(0xa05f, cm_base + INTEGRATOR_HDR_LOCK_OFFSET);
|
||||
__raw_writel(cm_osc, cm_base + INTEGRATOR_HDR_OSC_OFFSET);
|
||||
__raw_writel(0, cm_base + INTEGRATOR_HDR_LOCK_OFFSET);
|
||||
|
||||
/*
|
||||
* Restore the CPUs allowed mask.
|
||||
*/
|
||||
set_cpus_allowed_ptr(current, &cpus_allowed);
|
||||
|
||||
cpufreq_freq_transition_end(policy, &freqs, 0);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static unsigned int integrator_get(unsigned int cpu)
|
||||
{
|
||||
cpumask_t cpus_allowed;
|
||||
unsigned int current_freq;
|
||||
u_int cm_osc;
|
||||
struct icst_vco vco;
|
||||
|
||||
cpus_allowed = current->cpus_allowed;
|
||||
|
||||
set_cpus_allowed_ptr(current, cpumask_of(cpu));
|
||||
BUG_ON(cpu != smp_processor_id());
|
||||
|
||||
/* detect memory etc. */
|
||||
cm_osc = __raw_readl(cm_base + INTEGRATOR_HDR_OSC_OFFSET);
|
||||
|
||||
if (machine_is_integrator())
|
||||
vco.s = (cm_osc >> 8) & 7;
|
||||
else
|
||||
vco.s = 1;
|
||||
vco.v = cm_osc & 255;
|
||||
vco.r = 22;
|
||||
|
||||
current_freq = icst_hz(&cclk_params, vco) / 1000; /* current freq */
|
||||
|
||||
set_cpus_allowed_ptr(current, &cpus_allowed);
|
||||
|
||||
return current_freq;
|
||||
}
|
||||
|
||||
static int integrator_cpufreq_init(struct cpufreq_policy *policy)
|
||||
{
|
||||
|
||||
/* set default policy and cpuinfo */
|
||||
policy->max = policy->cpuinfo.max_freq = 160000;
|
||||
policy->min = policy->cpuinfo.min_freq = 12000;
|
||||
policy->cpuinfo.transition_latency = 1000000; /* 1 ms, assumed */
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct cpufreq_driver integrator_driver = {
|
||||
.flags = CPUFREQ_NEED_INITIAL_FREQ_CHECK,
|
||||
.verify = integrator_verify_policy,
|
||||
.target = integrator_set_target,
|
||||
.get = integrator_get,
|
||||
.init = integrator_cpufreq_init,
|
||||
.name = "integrator",
|
||||
};
|
||||
|
||||
static int __init integrator_cpufreq_probe(struct platform_device *pdev)
|
||||
{
|
||||
struct resource *res;
|
||||
|
||||
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
|
||||
if (!res)
|
||||
return -ENODEV;
|
||||
|
||||
cm_base = devm_ioremap(&pdev->dev, res->start, resource_size(res));
|
||||
if (!cm_base)
|
||||
return -ENODEV;
|
||||
|
||||
return cpufreq_register_driver(&integrator_driver);
|
||||
}
|
||||
|
||||
static int __exit integrator_cpufreq_remove(struct platform_device *pdev)
|
||||
{
|
||||
return cpufreq_unregister_driver(&integrator_driver);
|
||||
}
|
||||
|
||||
static const struct of_device_id integrator_cpufreq_match[] = {
|
||||
{ .compatible = "arm,core-module-integrator"},
|
||||
{ },
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, integrator_cpufreq_match);
|
||||
|
||||
static struct platform_driver integrator_cpufreq_driver = {
|
||||
.driver = {
|
||||
.name = "integrator-cpufreq",
|
||||
.of_match_table = integrator_cpufreq_match,
|
||||
},
|
||||
.remove = __exit_p(integrator_cpufreq_remove),
|
||||
};
|
||||
|
||||
module_platform_driver_probe(integrator_cpufreq_driver,
|
||||
integrator_cpufreq_probe);
|
||||
|
||||
MODULE_AUTHOR("Russell M. King");
|
||||
MODULE_DESCRIPTION("cpufreq driver for ARM Integrator CPUs");
|
||||
MODULE_LICENSE("GPL");
|
||||
File diff suppressed because it is too large
Load diff
|
|
@ -42,6 +42,10 @@
|
|||
#define PMSR_PSAFE_ENABLE (1UL << 30)
|
||||
#define PMSR_SPR_EM_DISABLE (1UL << 31)
|
||||
#define PMSR_MAX(x) ((x >> 32) & 0xFF)
|
||||
#define LPSTATE_SHIFT 48
|
||||
#define GPSTATE_SHIFT 56
|
||||
#define GET_LPSTATE(x) (((x) >> LPSTATE_SHIFT) & 0xFF)
|
||||
#define GET_GPSTATE(x) (((x) >> GPSTATE_SHIFT) & 0xFF)
|
||||
|
||||
#define MAX_RAMP_DOWN_TIME 5120
|
||||
/*
|
||||
|
|
@ -592,7 +596,8 @@ void gpstate_timer_handler(unsigned long data)
|
|||
{
|
||||
struct cpufreq_policy *policy = (struct cpufreq_policy *)data;
|
||||
struct global_pstate_info *gpstates = policy->driver_data;
|
||||
int gpstate_idx;
|
||||
int gpstate_idx, lpstate_idx;
|
||||
unsigned long val;
|
||||
unsigned int time_diff = jiffies_to_msecs(jiffies)
|
||||
- gpstates->last_sampled_time;
|
||||
struct powernv_smp_call_data freq_data;
|
||||
|
|
@ -600,21 +605,37 @@ void gpstate_timer_handler(unsigned long data)
|
|||
if (!spin_trylock(&gpstates->gpstate_lock))
|
||||
return;
|
||||
|
||||
/*
|
||||
* If PMCR was last updated was using fast_swtich then
|
||||
* We may have wrong in gpstate->last_lpstate_idx
|
||||
* value. Hence, read from PMCR to get correct data.
|
||||
*/
|
||||
val = get_pmspr(SPRN_PMCR);
|
||||
freq_data.gpstate_id = (s8)GET_GPSTATE(val);
|
||||
freq_data.pstate_id = (s8)GET_LPSTATE(val);
|
||||
if (freq_data.gpstate_id == freq_data.pstate_id) {
|
||||
reset_gpstates(policy);
|
||||
spin_unlock(&gpstates->gpstate_lock);
|
||||
return;
|
||||
}
|
||||
|
||||
gpstates->last_sampled_time += time_diff;
|
||||
gpstates->elapsed_time += time_diff;
|
||||
freq_data.pstate_id = idx_to_pstate(gpstates->last_lpstate_idx);
|
||||
|
||||
if ((gpstates->last_gpstate_idx == gpstates->last_lpstate_idx) ||
|
||||
(gpstates->elapsed_time > MAX_RAMP_DOWN_TIME)) {
|
||||
if (gpstates->elapsed_time > MAX_RAMP_DOWN_TIME) {
|
||||
gpstate_idx = pstate_to_idx(freq_data.pstate_id);
|
||||
lpstate_idx = gpstate_idx;
|
||||
reset_gpstates(policy);
|
||||
gpstates->highest_lpstate_idx = gpstate_idx;
|
||||
} else {
|
||||
lpstate_idx = pstate_to_idx(freq_data.pstate_id);
|
||||
gpstate_idx = calc_global_pstate(gpstates->elapsed_time,
|
||||
gpstates->highest_lpstate_idx,
|
||||
gpstates->last_lpstate_idx);
|
||||
lpstate_idx);
|
||||
}
|
||||
|
||||
freq_data.gpstate_id = idx_to_pstate(gpstate_idx);
|
||||
gpstates->last_gpstate_idx = gpstate_idx;
|
||||
gpstates->last_lpstate_idx = lpstate_idx;
|
||||
/*
|
||||
* If local pstate is equal to global pstate, rampdown is over
|
||||
* So timer is not required to be queued.
|
||||
|
|
@ -622,10 +643,6 @@ void gpstate_timer_handler(unsigned long data)
|
|||
if (gpstate_idx != gpstates->last_lpstate_idx)
|
||||
queue_gpstate_timer(gpstates);
|
||||
|
||||
freq_data.gpstate_id = idx_to_pstate(gpstate_idx);
|
||||
gpstates->last_gpstate_idx = pstate_to_idx(freq_data.gpstate_id);
|
||||
gpstates->last_lpstate_idx = pstate_to_idx(freq_data.pstate_id);
|
||||
|
||||
spin_unlock(&gpstates->gpstate_lock);
|
||||
|
||||
/* Timer may get migrated to a different cpu on cpu hot unplug */
|
||||
|
|
@ -647,8 +664,14 @@ static int powernv_cpufreq_target_index(struct cpufreq_policy *policy,
|
|||
if (unlikely(rebooting) && new_index != get_nominal_index())
|
||||
return 0;
|
||||
|
||||
if (!throttled)
|
||||
if (!throttled) {
|
||||
/* we don't want to be preempted while
|
||||
* checking if the CPU frequency has been throttled
|
||||
*/
|
||||
preempt_disable();
|
||||
powernv_cpufreq_throttle_check(NULL);
|
||||
preempt_enable();
|
||||
}
|
||||
|
||||
cur_msec = jiffies_to_msecs(get_jiffies_64());
|
||||
|
||||
|
|
@ -752,9 +775,12 @@ static int powernv_cpufreq_cpu_init(struct cpufreq_policy *policy)
|
|||
spin_lock_init(&gpstates->gpstate_lock);
|
||||
ret = cpufreq_table_validate_and_show(policy, powernv_freqs);
|
||||
|
||||
if (ret < 0)
|
||||
if (ret < 0) {
|
||||
kfree(policy->driver_data);
|
||||
return ret;
|
||||
}
|
||||
|
||||
policy->fast_switch_possible = true;
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
|
@ -897,6 +923,20 @@ static void powernv_cpufreq_stop_cpu(struct cpufreq_policy *policy)
|
|||
del_timer_sync(&gpstates->timer);
|
||||
}
|
||||
|
||||
static unsigned int powernv_fast_switch(struct cpufreq_policy *policy,
|
||||
unsigned int target_freq)
|
||||
{
|
||||
int index;
|
||||
struct powernv_smp_call_data freq_data;
|
||||
|
||||
index = cpufreq_table_find_index_dl(policy, target_freq);
|
||||
freq_data.pstate_id = powernv_freqs[index].driver_data;
|
||||
freq_data.gpstate_id = powernv_freqs[index].driver_data;
|
||||
set_pstate(&freq_data);
|
||||
|
||||
return powernv_freqs[index].frequency;
|
||||
}
|
||||
|
||||
static struct cpufreq_driver powernv_cpufreq_driver = {
|
||||
.name = "powernv-cpufreq",
|
||||
.flags = CPUFREQ_CONST_LOOPS,
|
||||
|
|
@ -904,6 +944,7 @@ static struct cpufreq_driver powernv_cpufreq_driver = {
|
|||
.exit = powernv_cpufreq_cpu_exit,
|
||||
.verify = cpufreq_generic_frequency_table_verify,
|
||||
.target_index = powernv_cpufreq_target_index,
|
||||
.fast_switch = powernv_fast_switch,
|
||||
.get = powernv_cpufreq_get,
|
||||
.stop_cpu = powernv_cpufreq_stop_cpu,
|
||||
.attr = powernv_cpu_freq_attr,
|
||||
|
|
|
|||
Loading…
Reference in a new issue