Commit 6d277aca authored by Linus Torvalds's avatar Linus Torvalds

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

Pull power management updates from Rafael Wysocki:
 "These add ACPI support to the intel_idle driver along with an admin
  guide document for it, add support for CPR (Core Power Reduction) to
  the AVS (Adaptive Voltage Scaling) subsystem, add new hardware support
  in a few places, add some new sysfs attributes, debugfs files and
  tracepoints, fix bugs and clean up a bunch of things all over.

  Specifics:

   - Update the ACPI processor driver in order to export
     acpi_processor_evaluate_cst() to the code outside of it, add ACPI
     support to the intel_idle driver based on that and clean up that
     driver somewhat (Rafael Wysocki).

   - Add an admin guide document for the intel_idle driver (Rafael
     Wysocki).

   - Clean up cpuidle core and drivers, enable compilation testing for
     some of them (Benjamin Gaignard, Krzysztof Kozlowski, Rafael
     Wysocki, Yangtao Li).

   - Fix reference counting of OPP (operating performance points) table
     structures (Viresh Kumar).

   - Add support for CPR (Core Power Reduction) to the AVS (Adaptive
     Voltage Scaling) subsystem (Niklas Cassel, Colin Ian King,
     YueHaibing).

   - Add support for TigerLake Mobile and JasperLake to the Intel RAPL
     power capping driver (Zhang Rui).

   - Update cpufreq drivers:
      - Add i.MX8MP support to imx-cpufreq-dt (Anson Huang).
      - Fix usage of a macro in loongson2_cpufreq (Alexandre Oliva).
      - Fix cpufreq policy reference counting issues in s3c and
        brcmstb-avs (chenqiwu).
      - Fix ACPI table reference counting issue and HiSilicon quirk
        handling in the CPPC driver (Hanjun Guo).
      - Clean up spelling mistake in intel_pstate (Harry Pan).
      - Convert the kirkwood and tegra186 drivers to using
        devm_platform_ioremap_resource() (Yangtao Li).

   - Update devfreq core:
      - Add 'name' sysfs attribute for devfreq devices (Chanwoo Choi).
      - Clean up the handing of transition statistics and allow them to
        be reset by writing 0 to the 'trans_stat' devfreq device
        attribute in sysfs (Kamil Konieczny).
      - Add 'devfreq_summary' to debugfs (Chanwoo Choi).
      - Clean up kerneldoc comments and Kconfig indentation (Krzysztof
        Kozlowski, Randy Dunlap).

   - Update devfreq drivers:
      - Add dynamic scaling for the imx8m DDR controller and clean up
        imx8m-ddrc (Leonard Crestez, YueHaibing).
      - Fix DT node reference counting and nitialization error code path
        in rk3399_dmc and add COMPILE_TEST and HAVE_ARM_SMCCC dependency
        for it (Chanwoo Choi, Yangtao Li).
      - Fix DT node reference counting in rockchip-dfi and make it use
        devm_platform_ioremap_resource() (Yangtao Li).
      - Fix excessive stack usage in exynos-ppmu (Arnd Bergmann).
      - Fix initialization error code paths in exynos-bus (Yangtao Li).
      - Clean up exynos-bus and exynos somewhat (Artur Świgoń, Krzysztof
        Kozlowski).

   - Add tracepoints for tracking usage_count updates unrelated to
     status changes in PM-runtime (Michał Mirosław).

   - Add sysfs attribute to control the "sync on suspend" behavior
     during system-wide suspend (Jonas Meurer).

   - Switch system-wide suspend tests over to 64-bit time (Alexandre
     Belloni).

   - Make wakeup sources statistics in debugfs cover deleted ones which
     used to be the case some time ago (zhuguangqing).

   - Clean up computations carried out during hibernation, update
     messages related to hibernation and fix a spelling mistake in one
     of them (Wen Yang, Luigi Semenzato, Colin Ian King).

   - Add mailmap entry for maintainer e-mail address that has not been
     functional for several years (Rafael Wysocki)"

* tag 'pm-5.6-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (83 commits)
  cpufreq: loongson2_cpufreq: adjust cpufreq uses of LOONGSON_CHIPCFG
  intel_idle: Clean up irtl_2_usec()
  intel_idle: Move 3 functions closer to their callers
  intel_idle: Annotate initialization code and data structures
  intel_idle: Move and clean up intel_idle_cpuidle_devices_uninit()
  intel_idle: Rearrange intel_idle_cpuidle_driver_init()
  intel_idle: Clean up NULL pointer check in intel_idle_init()
  intel_idle: Fold intel_idle_probe() into intel_idle_init()
  intel_idle: Eliminate __setup_broadcast_timer()
  cpuidle: fix cpuidle_find_deepest_state() kerneldoc warnings
  cpuidle: sysfs: fix warnings when compiling with W=1
  cpuidle: coupled: fix warnings when compiling with W=1
  cpufreq: brcmstb-avs: fix imbalance of cpufreq policy refcount
  PM: suspend: Add sysfs attribute to control the "sync on suspend" behavior
  PM / devfreq: Add debugfs support with devfreq_summary file
  Documentation: admin-guide: PM: Add intel_idle document
  cpuidle: arm: Enable compile testing for some of drivers
  PM-runtime: add tracepoints for usage_count changes
  cpufreq: intel_pstate: fix spelling mistake: "Whethet" -> "Whether"
  PM: hibernate: fix spelling mistake "shapshot" -> "snapshot"
  ...
parents aae1464f c102671a
......@@ -217,6 +217,7 @@ Praveen BP <praveenbp@ti.com>
Punit Agrawal <punitagrawal@gmail.com> <punit.agrawal@arm.com>
Qais Yousef <qsyousef@gmail.com> <qais.yousef@imgtec.com>
Quentin Perret <qperret@qperret.net> <quentin.perret@arm.com>
Rafael J. Wysocki <rjw@rjwysocki.net> <rjw@sisk.pl>
Rajesh Shah <rajesh.shah@intel.com>
Ralf Baechle <ralf@linux-mips.org>
Ralf Wildenhues <Ralf.Wildenhues@gmx.de>
......
......@@ -7,6 +7,13 @@ Description:
The name of devfreq object denoted as ... is same as the
name of device using devfreq.
What: /sys/class/devfreq/.../name
Date: November 2019
Contact: Chanwoo Choi <cw00.choi@samsung.com>
Description:
The /sys/class/devfreq/.../name shows the name of device
of the corresponding devfreq object.
What: /sys/class/devfreq/.../governor
Date: September 2011
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
......@@ -48,12 +55,15 @@ What: /sys/class/devfreq/.../trans_stat
Date: October 2012
Contact: MyungJoo Ham <myungjoo.ham@samsung.com>
Description:
This ABI shows the statistics of devfreq behavior on a
specific device. It shows the time spent in each state and
the number of transitions between states.
This ABI shows or clears the statistics of devfreq behavior
on a specific device. It shows the time spent in each state
and the number of transitions between states.
In order to activate this ABI, the devfreq target device
driver should provide the list of available frequencies
with its profile.
with its profile. If need to reset the statistics of devfreq
behavior on a specific device, enter 0(zero) to 'trans_stat'
as following:
echo 0 > /sys/class/devfreq/.../trans_stat
What: /sys/class/devfreq/.../userspace/set_freq
Date: September 2011
......
......@@ -196,6 +196,12 @@ Description:
does not reflect it. Likewise, if one enables a deep state but a
lighter state still is disabled, then this has no effect.
What: /sys/devices/system/cpu/cpuX/cpuidle/stateN/default_status
Date: December 2019
KernelVersion: v5.6
Contact: Linux power management list <linux-pm@vger.kernel.org>
Description:
(RO) The default status of this state, "enabled" or "disabled".
What: /sys/devices/system/cpu/cpuX/cpuidle/stateN/residency
Date: March 2014
......
......@@ -407,3 +407,16 @@ Contact: Kalesh Singh <kaleshsingh96@gmail.com>
Description:
The /sys/power/suspend_stats/last_failed_step file contains
the last failed step in the suspend/resume path.
What: /sys/power/sync_on_suspend
Date: October 2019
Contact: Jonas Meurer <jonas@freesources.org>
Description:
This file controls whether or not the kernel will sync()
filesystems during system suspend (after freezing user space
and before suspending devices).
Writing a "1" to this file enables the sync() and writing a "0"
disables it. Reads from the file return the current value.
The default is "1" if the build-time "SUSPEND_SKIP_SYNC" config
flag is unset, or "0" otherwise.
......@@ -506,6 +506,9 @@ object corresponding to it, as follows:
``disable``
Whether or not this idle state is disabled.
``default_status``
The default status of this state, "enabled" or "disabled".
``latency``
Exit latency of the idle state in microseconds.
......
This diff is collapsed.
......@@ -8,6 +8,7 @@ Working-State Power Management
:maxdepth: 2
cpuidle
intel_idle
cpufreq
intel_pstate
intel_epb
# SPDX-License-Identifier: GPL-2.0
%YAML 1.2
---
$id: http://devicetree.org/schemas/memory-controllers/fsl/imx8m-ddrc.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: i.MX8M DDR Controller
maintainers:
- Leonard Crestez <leonard.crestez@nxp.com>
description:
The DDRC block is integrated in i.MX8M for interfacing with DDR based
memories.
It supports switching between different frequencies at runtime but during
this process RAM itself becomes briefly inaccessible so actual frequency
switching is implemented by TF-A code which runs from a SRAM area.
The Linux driver for the DDRC doesn't even map registers (they're included
for the sake of "describing hardware"), it mostly just exposes firmware
capabilities through standard Linux mechanism like devfreq and OPP tables.
properties:
compatible:
items:
- enum:
- fsl,imx8mn-ddrc
- fsl,imx8mm-ddrc
- fsl,imx8mq-ddrc
- const: fsl,imx8m-ddrc
reg:
maxItems: 1
description:
Base address and size of DDRC CTL area.
This is not currently mapped by the imx8m-ddrc driver.
clocks:
maxItems: 4
clock-names:
items:
- const: core
- const: pll
- const: alt
- const: apb
operating-points-v2: true
opp-table: true
required:
- reg
- compatible
- clocks
- clock-names
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/imx8mm-clock.h>
ddrc: memory-controller@3d400000 {
compatible = "fsl,imx8mm-ddrc", "fsl,imx8m-ddrc";
reg = <0x3d400000 0x400000>;
clock-names = "core", "pll", "alt", "apb";
clocks = <&clk IMX8MM_CLK_DRAM_CORE>,
<&clk IMX8MM_DRAM_PLL>,
<&clk IMX8MM_CLK_DRAM_ALT>,
<&clk IMX8MM_CLK_DRAM_APB>;
operating-points-v2 = <&ddrc_opp_table>;
};
QCOM CPR (Core Power Reduction)
CPR (Core Power Reduction) is a technology to reduce core power on a CPU
or other device. Each OPP of a device corresponds to a "corner" that has
a range of valid voltages for a particular frequency. While the device is
running at a particular frequency, CPR monitors dynamic factors such as
temperature, etc. and suggests adjustments to the voltage to save power
and meet silicon characteristic requirements.
- compatible:
Usage: required
Value type: <string>
Definition: should be "qcom,qcs404-cpr", "qcom,cpr" for qcs404
- reg:
Usage: required
Value type: <prop-encoded-array>
Definition: base address and size of the rbcpr register region
- interrupts:
Usage: required
Value type: <prop-encoded-array>
Definition: should specify the CPR interrupt
- clocks:
Usage: required
Value type: <prop-encoded-array>
Definition: phandle to the reference clock
- clock-names:
Usage: required
Value type: <stringlist>
Definition: must be "ref"
- vdd-apc-supply:
Usage: required
Value type: <phandle>
Definition: phandle to the vdd-apc-supply regulator
- #power-domain-cells:
Usage: required
Value type: <u32>
Definition: should be 0
- operating-points-v2:
Usage: required
Value type: <phandle>
Definition: A phandle to the OPP table containing the
performance states supported by the CPR
power domain
- acc-syscon:
Usage: optional
Value type: <phandle>
Definition: phandle to syscon for writing ACC settings
- nvmem-cells:
Usage: required
Value type: <phandle>
Definition: phandle to nvmem cells containing the data
that makes up a fuse corner, for each fuse corner.
As well as the CPR fuse revision.
- nvmem-cell-names:
Usage: required
Value type: <stringlist>
Definition: should be "cpr_quotient_offset1", "cpr_quotient_offset2",
"cpr_quotient_offset3", "cpr_init_voltage1",
"cpr_init_voltage2", "cpr_init_voltage3", "cpr_quotient1",
"cpr_quotient2", "cpr_quotient3", "cpr_ring_osc1",
"cpr_ring_osc2", "cpr_ring_osc3", "cpr_fuse_revision"
for qcs404.
Example:
cpr_opp_table: cpr-opp-table {
compatible = "operating-points-v2-qcom-level";
cpr_opp1: opp1 {
opp-level = <1>;
qcom,opp-fuse-level = <1>;
};
cpr_opp2: opp2 {
opp-level = <2>;
qcom,opp-fuse-level = <2>;
};
cpr_opp3: opp3 {
opp-level = <3>;
qcom,opp-fuse-level = <3>;
};
};
power-controller@b018000 {
compatible = "qcom,qcs404-cpr", "qcom,cpr";
reg = <0x0b018000 0x1000>;
interrupts = <0 15 IRQ_TYPE_EDGE_RISING>;
clocks = <&xo_board>;
clock-names = "ref";
vdd-apc-supply = <&pms405_s3>;
#power-domain-cells = <0>;
operating-points-v2 = <&cpr_opp_table>;
acc-syscon = <&tcsr>;
nvmem-cells = <&cpr_efuse_quot_offset1>,
<&cpr_efuse_quot_offset2>,
<&cpr_efuse_quot_offset3>,
<&cpr_efuse_init_voltage1>,
<&cpr_efuse_init_voltage2>,
<&cpr_efuse_init_voltage3>,
<&cpr_efuse_quot1>,
<&cpr_efuse_quot2>,
<&cpr_efuse_quot3>,
<&cpr_efuse_ring1>,
<&cpr_efuse_ring2>,
<&cpr_efuse_ring3>,
<&cpr_efuse_revision>;
nvmem-cell-names = "cpr_quotient_offset1",
"cpr_quotient_offset2",
"cpr_quotient_offset3",
"cpr_init_voltage1",
"cpr_init_voltage2",
"cpr_init_voltage3",
"cpr_quotient1",
"cpr_quotient2",
"cpr_quotient3",
"cpr_ring_osc1",
"cpr_ring_osc2",
"cpr_ring_osc3",
"cpr_fuse_revision";
};
......@@ -13715,6 +13715,14 @@ S: Maintained
F: Documentation/devicetree/bindings/opp/qcom-nvmem-cpufreq.txt
F: drivers/cpufreq/qcom-cpufreq-nvmem.c
QUALCOMM CORE POWER REDUCTION (CPR) AVS DRIVER
M: Niklas Cassel <nks@flawful.org>
L: linux-pm@vger.kernel.org
L: linux-arm-msm@vger.kernel.org
S: Maintained
F: Documentation/devicetree/bindings/power/avs/qcom,cpr.txt
F: drivers/power/avs/qcom-cpr.c
QUALCOMM EMAC GIGABIT ETHERNET DRIVER
M: Timur Tabi <timur@kernel.org>
L: netdev@vger.kernel.org
......
......@@ -111,6 +111,7 @@
#define INTEL_FAM6_ATOM_TREMONT_D 0x86 /* Jacobsville */
#define INTEL_FAM6_ATOM_TREMONT 0x96 /* Elkhart Lake */
#define INTEL_FAM6_ATOM_TREMONT_L 0x9C /* Jasper Lake */
/* Xeon Phi */
......
......@@ -241,6 +241,7 @@ config ACPI_CPU_FREQ_PSS
config ACPI_PROCESSOR_CSTATE
def_bool y
depends on ACPI_PROCESSOR
depends on IA64 || X86
config ACPI_PROCESSOR_IDLE
......
......@@ -705,3 +705,185 @@ void __init acpi_processor_init(void)
acpi_scan_add_handler_with_hotplug(&processor_handler, "processor");
acpi_scan_add_handler(&processor_container_handler);
}
#ifdef CONFIG_ACPI_PROCESSOR_CSTATE
/**
* acpi_processor_claim_cst_control - Request _CST control from the platform.
*/
bool acpi_processor_claim_cst_control(void)
{
static bool cst_control_claimed;
acpi_status status;
if (!acpi_gbl_FADT.cst_control || cst_control_claimed)
return true;
status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
acpi_gbl_FADT.cst_control, 8);
if (ACPI_FAILURE(status)) {
pr_warn("ACPI: Failed to claim processor _CST control\n");
return false;
}
cst_control_claimed = true;
return true;
}
EXPORT_SYMBOL_GPL(acpi_processor_claim_cst_control);
/**
* acpi_processor_evaluate_cst - Evaluate the processor _CST control method.
* @handle: ACPI handle of the processor object containing the _CST.
* @cpu: The numeric ID of the target CPU.
* @info: Object write the C-states information into.
*
* Extract the C-state information for the given CPU from the output of the _CST
* control method under the corresponding ACPI processor object (or processor
* device object) and populate @info with it.
*
* If any ACPI_ADR_SPACE_FIXED_HARDWARE C-states are found, invoke
* acpi_processor_ffh_cstate_probe() to verify them and update the
* cpu_cstate_entry data for @cpu.
*/
int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu,
struct acpi_processor_power *info)
{
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *cst;
acpi_status status;
u64 count;
int last_index = 0;
int i, ret = 0;
status = acpi_evaluate_object(handle, "_CST", NULL, &buffer);
if (ACPI_FAILURE(status)) {
acpi_handle_debug(handle, "No _CST\n");
return -ENODEV;
}
cst = buffer.pointer;
/* There must be at least 2 elements. */
if (!cst || cst->type != ACPI_TYPE_PACKAGE || cst->package.count < 2) {
acpi_handle_warn(handle, "Invalid _CST output\n");
ret = -EFAULT;
goto end;
}
count = cst->package.elements[0].integer.value;
/* Validate the number of C-states. */
if (count < 1 || count != cst->package.count - 1) {
acpi_handle_warn(handle, "Inconsistent _CST data\n");
ret = -EFAULT;
goto end;
}
for (i = 1; i <= count; i++) {
union acpi_object *element;
union acpi_object *obj;
struct acpi_power_register *reg;
struct acpi_processor_cx cx;
/*
* If there is not enough space for all C-states, skip the
* excess ones and log a warning.
*/
if (last_index >= ACPI_PROCESSOR_MAX_POWER - 1) {
acpi_handle_warn(handle,
"No room for more idle states (limit: %d)\n",
ACPI_PROCESSOR_MAX_POWER - 1);
break;
}
memset(&cx, 0, sizeof(cx));
element = &cst->package.elements[i];
if (element->type != ACPI_TYPE_PACKAGE)
continue;
if (element->package.count != 4)
continue;
obj = &element->package.elements[0];
if (obj->type != ACPI_TYPE_BUFFER)
continue;
reg = (struct acpi_power_register *)obj->buffer.pointer;
obj = &element->package.elements[1];
if (obj->type != ACPI_TYPE_INTEGER)
continue;
cx.type = obj->integer.value;
/*
* There are known cases in which the _CST output does not
* contain C1, so if the type of the first state found is not
* C1, leave an empty slot for C1 to be filled in later.
*/
if (i == 1 && cx.type != ACPI_STATE_C1)
last_index = 1;
cx.address = reg->address;
cx.index = last_index + 1;
if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
if (!acpi_processor_ffh_cstate_probe(cpu, &cx, reg)) {
/*
* In the majority of cases _CST describes C1 as
* a FIXED_HARDWARE C-state, but if the command
* line forbids using MWAIT, use CSTATE_HALT for
* C1 regardless.
*/
if (cx.type == ACPI_STATE_C1 &&
boot_option_idle_override == IDLE_NOMWAIT) {
cx.entry_method = ACPI_CSTATE_HALT;
snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT");
} else {
cx.entry_method = ACPI_CSTATE_FFH;
}
} else if (cx.type == ACPI_STATE_C1) {
/*
* In the special case of C1, FIXED_HARDWARE can
* be handled by executing the HLT instruction.
*/
cx.entry_method = ACPI_CSTATE_HALT;
snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT");
} else {
continue;
}
} else if (reg->space_id == ACPI_ADR_SPACE_SYSTEM_IO) {
cx.entry_method = ACPI_CSTATE_SYSTEMIO;
snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI IOPORT 0x%x",
cx.address);
} else {
continue;
}
if (cx.type == ACPI_STATE_C1)
cx.valid = 1;
obj = &element->package.elements[2];
if (obj->type != ACPI_TYPE_INTEGER)
continue;
cx.latency = obj->integer.value;
obj = &element->package.elements[3];
if (obj->type != ACPI_TYPE_INTEGER)
continue;
memcpy(&info->states[++last_index], &cx, sizeof(cx));
}
acpi_handle_info(handle, "Found %d idle states\n", last_index);
info->count = last_index;
end:
kfree(buffer.pointer);
return ret;
}
EXPORT_SYMBOL_GPL(acpi_processor_evaluate_cst);
#endif /* CONFIG_ACPI_PROCESSOR_CSTATE */
......@@ -299,164 +299,24 @@ static int acpi_processor_get_power_info_default(struct acpi_processor *pr)
static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
{
acpi_status status;
u64 count;
int current_count;
int i, ret = 0;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
union acpi_object *cst;
int ret;
if (nocst)
return -ENODEV;
current_count = 0;
status = acpi_evaluate_object(pr->handle, "_CST", NULL, &buffer);
if (ACPI_FAILURE(status)) {
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "No _CST, giving up\n"));
return -ENODEV;
}
cst = buffer.pointer;
/* There must be at least 2 elements */
if (!cst || (cst->type != ACPI_TYPE_PACKAGE) || cst->package.count < 2) {
pr_err("not enough elements in _CST\n");
ret = -EFAULT;
goto end;
}
count = cst->package.elements[0].integer.value;
/* Validate number of power states. */
if (count < 1 || count != cst->package.count - 1) {
pr_err("count given by _CST is not valid\n");
ret = -EFAULT;
goto end;
}
/* Tell driver that at least _CST is supported. */
pr->flags.has_cst = 1;
for (i = 1; i <= count; i++) {
union acpi_object *element;
union acpi_object *obj;
struct acpi_power_register *reg;
struct acpi_processor_cx cx;
memset(&cx, 0, sizeof(cx));
element = &(cst->package.elements[i]);
if (element->type != ACPI_TYPE_PACKAGE)
continue;
if (element->package.count != 4)
continue;
obj = &(element->package.elements[0]);
if (obj->type != ACPI_TYPE_BUFFER)
continue;
reg = (struct acpi_power_register *)obj->buffer.pointer;
if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_IO &&
(reg->space_id != ACPI_ADR_SPACE_FIXED_HARDWARE))
continue;
/* There should be an easy way to extract an integer... */
obj = &(element->package.elements[1]);
if (obj->type != ACPI_TYPE_INTEGER)
continue;
cx.type = obj->integer.value;
/*
* Some buggy BIOSes won't list C1 in _CST -
* Let acpi_processor_get_power_info_default() handle them later
*/
if (i == 1 && cx.type != ACPI_STATE_C1)
current_count++;
cx.address = reg->address;
cx.index = current_count + 1;
cx.entry_method = ACPI_CSTATE_SYSTEMIO;
if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
if (acpi_processor_ffh_cstate_probe
(pr->id, &cx, reg) == 0) {
cx.entry_method = ACPI_CSTATE_FFH;
} else if (cx.type == ACPI_STATE_C1) {
/*
* C1 is a special case where FIXED_HARDWARE
* can be handled in non-MWAIT way as well.
* In that case, save this _CST entry info.
* Otherwise, ignore this info and continue.
*/
cx.entry_method = ACPI_CSTATE_HALT;
snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT");
} else {
continue;
}
if (cx.type == ACPI_STATE_C1 &&
(boot_option_idle_override == IDLE_NOMWAIT)) {
/*
* In most cases the C1 space_id obtained from
* _CST object is FIXED_HARDWARE access mode.
* But when the option of idle=halt is added,
* the entry_method type should be changed from
* CSTATE_FFH to CSTATE_HALT.
* When the option of idle=nomwait is added,
* the C1 entry_method type should be
* CSTATE_HALT.
*/
cx.entry_method = ACPI_CSTATE_HALT;
snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI HLT");
}
} else {
snprintf(cx.desc, ACPI_CX_DESC_LEN, "ACPI IOPORT 0x%x",
cx.address);
}
if (cx.type == ACPI_STATE_C1) {
cx.valid = 1;
}
obj = &(element->package.elements[2]);
if (obj->type != ACPI_TYPE_INTEGER)
continue;
cx.latency = obj->integer.value;
obj = &(element->package.elements[3]);
if (obj->type != ACPI_TYPE_INTEGER)
continue;
current_count++;
memcpy(&(pr->power.states[current_count]), &cx, sizeof(cx));
ret = acpi_processor_evaluate_cst(pr->handle, pr->id, &pr->power);
if (ret)
return ret;
/*
* We support total ACPI_PROCESSOR_MAX_POWER - 1
* (From 1 through ACPI_PROCESSOR_MAX_POWER - 1)
* It is expected that there will be at least 2 states, C1 and
* something else (C2 or C3), so fail if that is not the case.
*/
if (current_count >= (ACPI_PROCESSOR_MAX_POWER - 1)) {
pr_warn("Limiting number of power states to max (%d)\n",
ACPI_PROCESSOR_MAX_POWER);
pr_warn("Please increase ACPI_PROCESSOR_MAX_POWER if needed.\n");
break;
}
}
ACPI_DEBUG_PRINT((ACPI_DB_INFO, "Found %d power states\n",
current_count));
if (pr->power.count < 2)
return -EFAULT;
/* Validate number of power states discovered */
if (current_count < 2)
ret = -EFAULT;
end:
kfree(buffer.pointer);
return ret;
pr->flags.has_cst = 1;
return 0;
}
static void acpi_processor_power_verify_c3(struct acpi_processor *pr,
......@@ -909,7 +769,6 @@ static int acpi_processor_setup_cstates(struct acpi_processor *pr)
static inline void acpi_processor_cstate_first_run_checks(void)
{
acpi_status status;
static int first_run;
if (first_run)
......@@ -921,13 +780,10 @@ static inline void acpi_processor_cstate_first_run_checks(void)
max_cstate);
first_run++;
if (acpi_gbl_FADT.cst_control && !nocst) {
status = acpi_os_write_port(acpi_gbl_FADT.smi_command,
acpi_gbl_FADT.cst_control, 8);
if (ACPI_FAILURE(status))
ACPI_EXCEPTION((AE_INFO, status,
"Notifying BIOS of _CST ability failed"));
}
if (nocst)
return;
acpi_processor_claim_cst_control();
}
#else
......
......@@ -1006,9 +1006,11 @@ int __pm_runtime_idle(struct device *dev, int rpmflags)
int retval;
if (rpmflags & RPM_GET_PUT) {
if (!atomic_dec_and_test(&dev->power.usage_count))
if (!atomic_dec_and_test(&dev->power.usage_count)) {
trace_rpm_usage_rcuidle(dev, rpmflags);
return 0;
}
}
might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
......@@ -1038,9 +1040,11 @@ int __pm_runtime_suspend(struct device *dev, int rpmflags)
int retval;
if (rpmflags & RPM_GET_PUT) {
if (!atomic_dec_and_test(&dev->power.usage_count))
if (!atomic_dec_and_test(&dev->power.usage_count)) {
trace_rpm_usage_rcuidle(dev, rpmflags);
return 0;
}
}
might_sleep_if(!(rpmflags & RPM_ASYNC) && !dev->power.irq_safe);
......@@ -1101,6 +1105,7 @@ int pm_runtime_get_if_in_use(struct device *dev)
retval = dev->power.disable_depth > 0 ? -EINVAL :
dev->power.runtime_status == RPM_ACTIVE
&& atomic_inc_not_zero(&dev->power.usage_count);
trace_rpm_usage_rcuidle(dev, 0);
spin_unlock_irqrestore(&dev->power.lock, flags);
return retval;
}
......@@ -1434,6 +1439,8 @@ void pm_runtime_allow(struct device *dev)
dev->power.runtime_auto = true;
if (atomic_dec_and_test(&dev->power.usage_count))
rpm_idle(dev, RPM_AUTO | RPM_ASYNC);
else
trace_rpm_usage_rcuidle(dev, RPM_AUTO | RPM_ASYNC);
out:
spin_unlock_irq(&dev->power.lock);
......@@ -1501,6 +1508,8 @@ static void update_autosuspend(struct device *dev, int old_delay, int old_use)
if (!old_use || old_delay >= 0) {
atomic_inc(&dev->power.usage_count);
rpm_resume(dev, 0);
} else {
trace_rpm_usage_rcuidle(dev, 0);
}
}
......
......@@ -1125,6 +1125,9 @@ static void *wakeup_sources_stats_seq_next(struct seq_file *m,
break;
}
if (!next_ws)
print_wakeup_source_stats(m, &deleted_ws);
return next_ws;
}
......
......@@ -455,6 +455,8 @@ static unsigned int brcm_avs_cpufreq_get(unsigned int cpu)
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
struct private_data *priv = policy->driver_data;
cpufreq_cpu_put(policy);
return brcm_avs_get_frequency(priv->base);
}
......
......@@ -39,7 +39,7 @@
static struct cppc_cpudata **all_cpu_data;
struct cppc_workaround_oem_info {
char oem_id[ACPI_OEM_ID_SIZE +1];
char oem_id[ACPI_OEM_ID_SIZE + 1];
char oem_table_id[ACPI_OEM_TABLE_ID_SIZE + 1];
u32 oem_revision;
};
......@@ -93,9 +93,13 @@ static void cppc_check_hisi_workaround(void)
for (i = 0; i < ARRAY_SIZE(wa_info); i++) {
if (!memcmp(wa_info[i].oem_id, tbl->oem_id, ACPI_OEM_ID_SIZE) &&
!memcmp(wa_info[i].oem_table_id, tbl->oem_table_id, ACPI_OEM_TABLE_ID_SIZE) &&
wa_info[i].oem_revision == tbl->oem_revision)
wa_info[i].oem_revision == tbl->oem_revision) {
apply_hisi_workaround = true;
break;
}
}
acpi_put_table(tbl);
}
/* Callback function used to retrieve the max frequency from DMI */
......
......@@ -109,6 +109,7 @@ static const struct of_device_id blacklist[] __initconst = {
{ .compatible = "fsl,imx8mq", },
{ .compatible = "fsl,imx8mm", },
{ .compatible = "fsl,imx8mn", },
{ .compatible = "fsl,imx8mp", },
{ .compatible = "marvell,armadaxp", },
......
......@@ -35,7 +35,8 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev)
if (ret)
return ret;
if (of_machine_is_compatible("fsl,imx8mn"))
if (of_machine_is_compatible("fsl,imx8mn") ||
of_machine_is_compatible("fsl,imx8mp"))
speed_grade = (cell_value & IMX8MN_OCOTP_CFG3_SPEED_GRADE_MASK)
>> OCOTP_CFG3_SPEED_GRADE_SHIFT;
else
......@@ -54,7 +55,8 @@ static int imx_cpufreq_dt_probe(struct platform_device *pdev)
if (of_machine_is_compatible("fsl,imx8mm") ||
of_machine_is_compatible("fsl,imx8mq"))
speed_grade = 1;
if (of_machine_is_compatible("fsl,imx8mn"))
if (of_machine_is_compatible("fsl,imx8mn") ||
of_machine_is_compatible("fsl,imx8mp"))
speed_grade = 0xb;
}
......
......@@ -172,7 +172,7 @@ struct vid_data {
/**
* struct global_params - Global parameters, mostly tunable via sysfs.
* @no_turbo: Whether or not to use turbo P-states.
* @turbo_disabled: Whethet or not turbo P-states are available at all,
* @turbo_disabled: Whether or not turbo P-states are available at all,
* based on the MSR_IA32_MISC_ENABLE value and whether or
* not the maximum reported turbo P-state is different from
* the maximum reported non-turbo one.
......
......@@ -102,13 +102,11 @@ static struct cpufreq_driver kirkwood_cpufreq_driver = {
static int kirkwood_cpufreq_probe(struct platform_device *pdev)
{
struct device_node *np;
struct resource *res;
int err;
priv.dev = &pdev->dev;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
priv.base = devm_ioremap_resource(&pdev->dev, res);
priv.base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(priv.base))
return PTR_ERR(priv.base);
......
......@@ -144,9 +144,11 @@ static void loongson2_cpu_wait(void)
u32 cpu_freq;
spin_lock_irqsave(&loongson2_wait_lock, flags);
cpu_freq = LOONGSON_CHIPCFG(0);
LOONGSON_CHIPCFG(0) &= ~0x7; /* Put CPU into wait mode */
LOONGSON_CHIPCFG(0) = cpu_freq; /* Restore CPU state */
cpu_freq = readl(LOONGSON_CHIPCFG);
/* Put CPU into wait mode */
writel(readl(LOONGSON_CHIPCFG) & ~0x7, LOONGSON_CHIPCFG);
/* Restore CPU state */
writel(cpu_freq, LOONGSON_CHIPCFG);
spin_unlock_irqrestore(&loongson2_wait_lock, flags);
local_irq_enable();
}
......
......@@ -304,6 +304,7 @@ static int s3c2416_cpufreq_reboot_notifier_evt(struct notifier_block *this,
{
struct s3c2416_data *s3c_freq = &s3c2416_cpufreq;
int ret;
struct cpufreq_policy *policy;
mutex_lock(&cpufreq_lock);
......@@ -318,7 +319,16 @@ static int s3c2416_cpufreq_reboot_notifier_evt(struct notifier_block *this,
*/
if (s3c_freq->is_dvs) {
pr_debug("cpufreq: leave dvs on reboot\n");
ret = cpufreq_driver_target(cpufreq_cpu_get(0), FREQ_SLEEP, 0);
policy = cpufreq_cpu_get(0);
if (!policy) {
pr_debug("cpufreq: get no policy for cpu0\n");
return NOTIFY_BAD;
}
ret = cpufreq_driver_target(policy, FREQ_SLEEP, 0);
cpufreq_cpu_put(policy);
if (ret < 0)
return NOTIFY_BAD;
}
......
......@@ -555,8 +555,17 @@ static int s5pv210_cpufreq_reboot_notifier_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
int ret;
struct cpufreq_policy *policy;
policy = cpufreq_cpu_get(0);
if (!policy) {
pr_debug("cpufreq: get no policy for cpu0\n");
return NOTIFY_BAD;
}
ret = cpufreq_driver_target(policy, SLEEP_FREQ, 0);
cpufreq_cpu_put(policy);
ret = cpufreq_driver_target(cpufreq_cpu_get(0), SLEEP_FREQ, 0);
if (ret < 0)
return NOTIFY_BAD;
......
......@@ -187,7 +187,6 @@ static int tegra186_cpufreq_probe(struct platform_device *pdev)
{
struct tegra186_cpufreq_data *data;
struct tegra_bpmp *bpmp;
struct resource *res;
unsigned int i = 0, err;
data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
......@@ -205,8 +204,7 @@ static int tegra186_cpufreq_probe(struct platform_device *pdev)
if (IS_ERR(bpmp))
return PTR_ERR(bpmp);
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->regs = devm_ioremap_resource(&pdev->dev, res);
data->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(data->regs)) {
err = PTR_ERR(data->regs);
goto put_bpmp;
......
......@@ -25,7 +25,7 @@ config ARM_PSCI_CPUIDLE
config ARM_BIG_LITTLE_CPUIDLE
bool "Support for ARM big.LITTLE processors"
depends on ARCH_VEXPRESS_TC2_PM || ARCH_EXYNOS
depends on ARCH_VEXPRESS_TC2_PM || ARCH_EXYNOS || COMPILE_TEST
depends on MCPM && !ARM64
select ARM_CPU_SUSPEND
select CPU_IDLE_MULTIPLE_DRIVERS
......@@ -51,13 +51,13 @@ config ARM_HIGHBANK_CPUIDLE
config ARM_KIRKWOOD_CPUIDLE
bool "CPU Idle Driver for Marvell Kirkwood SoCs"
depends on MACH_KIRKWOOD && !ARM64
depends on (MACH_KIRKWOOD || COMPILE_TEST) && !ARM64
help
This adds the CPU Idle driver for Marvell Kirkwood SoCs.
config ARM_ZYNQ_CPUIDLE
bool "CPU Idle Driver for Xilinx Zynq processors"
depends on ARCH_ZYNQ && !ARM64
depends on (ARCH_ZYNQ || COMPILE_TEST) && !ARM64
help
Select this to enable cpuidle on Xilinx Zynq processors.
......@@ -70,19 +70,19 @@ config ARM_U8500_CPUIDLE
config ARM_AT91_CPUIDLE
bool "Cpu Idle Driver for the AT91 processors"
default y
depends on ARCH_AT91 && !ARM64
depends on (ARCH_AT91 || COMPILE_TEST) && !ARM64
help
Select this to enable cpuidle for AT91 processors.
config ARM_EXYNOS_CPUIDLE
bool "Cpu Idle Driver for the Exynos processors"
depends on ARCH_EXYNOS && !ARM64
depends on (ARCH_EXYNOS || COMPILE_TEST) && !ARM64
select ARCH_NEEDS_CPU_IDLE_COUPLED if SMP
help
Select this to enable cpuidle for Exynos processors.
config ARM_MVEBU_V7_CPUIDLE
bool "CPU Idle Driver for mvebu v7 family processors"
depends on ARCH_MVEBU && !ARM64
depends on (ARCH_MVEBU || COMPILE_TEST) && !ARM64
help
Select this to enable cpuidle on Armada 370, 38x and XP processors.
......@@ -89,6 +89,7 @@
* @coupled_cpus: mask of cpus that are part of the coupled set
* @requested_state: array of requested states for cpus in the coupled set
* @ready_waiting_counts: combined count of cpus in ready or waiting loops
* @abort_barrier: synchronisation point for abort cases
* @online_count: count of cpus that are online
* @refcnt: reference count of cpuidle devices that are using this struct
* @prevent: flag to prevent coupled idle while a cpu is hotplugging
......@@ -338,7 +339,7 @@ static void cpuidle_coupled_poke(int cpu)
/**
* cpuidle_coupled_poke_others - wake up all other cpus that may be waiting
* @dev: struct cpuidle_device for this cpu
* @this_cpu: target cpu
* @coupled: the struct coupled that contains the current cpu
*
* Calls cpuidle_coupled_poke on all other online cpus.
......@@ -355,7 +356,7 @@ static void cpuidle_coupled_poke_others(int this_cpu,
/**
* cpuidle_coupled_set_waiting - mark this cpu as in the wait loop
* @dev: struct cpuidle_device for this cpu
* @cpu: target cpu
* @coupled: the struct coupled that contains the current cpu
* @next_state: the index in drv->states of the requested state for this cpu
*
......@@ -376,7 +377,7 @@ static int cpuidle_coupled_set_waiting(int cpu,
/**
* cpuidle_coupled_set_not_waiting - mark this cpu as leaving the wait loop
* @dev: struct cpuidle_device for this cpu
* @cpu: target cpu
* @coupled: the struct coupled that contains the current cpu
*
* Removes the requested idle state for the specified cpuidle device.
......@@ -412,7 +413,7 @@ static void cpuidle_coupled_set_done(int cpu, struct cpuidle_coupled *coupled)
/**
* cpuidle_coupled_clear_pokes - spin until the poke interrupt is processed
* @cpu - this cpu
* @cpu: this cpu
*
* Turns on interrupts and spins until any outstanding poke interrupts have
* been processed and the poke bit has been cleared.
......
......@@ -37,10 +37,7 @@ static struct cpuidle_driver clps711x_idle_driver = {
static int __init clps711x_cpuidle_probe(struct platform_device *pdev)
{
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
clps711x_halt = devm_ioremap_resource(&pdev->dev, res);
clps711x_halt = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(clps711x_halt))
return PTR_ERR(clps711x_halt);
......
......@@ -55,10 +55,7 @@ static struct cpuidle_driver kirkwood_idle_driver = {
/* Initialize CPU idle by registering the idle states */
static int kirkwood_cpuidle_probe(struct platform_device *pdev)
{
struct resource *res;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
ddr_operation_base = devm_ioremap_resource(&pdev->dev, res);
ddr_operation_base = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(ddr_operation_base))
return PTR_ERR(ddr_operation_base);
......
......@@ -121,6 +121,9 @@ void cpuidle_use_deepest_state(u64 latency_limit_ns)
* cpuidle_find_deepest_state - Find the deepest available idle state.
* @drv: cpuidle driver for the given CPU.
* @dev: cpuidle device for the given CPU.
* @latency_limit_ns: Idle state exit latency limit
*
* Return: the index of the deepest available idle state.
*/
int cpuidle_find_deepest_state(struct cpuidle_driver *drv,
struct cpuidle_device *dev,
......@@ -572,10 +575,14 @@ static int __cpuidle_register_device(struct cpuidle_device *dev)
if (!try_module_get(drv->owner))
return -EINVAL;
for (i = 0; i < drv->state_count; i++)
for (i = 0; i < drv->state_count; i++) {
if (drv->states[i].flags & CPUIDLE_FLAG_UNUSABLE)
dev->states_usage[i].disable |= CPUIDLE_STATE_DISABLED_BY_DRIVER;
if (drv->states[i].flags & CPUIDLE_FLAG_OFF)
dev->states_usage[i].disable |= CPUIDLE_STATE_DISABLED_BY_USER;
}
per_cpu(cpuidle_devices, dev->cpu) = dev;
list_add(&dev->device_list, &cpuidle_detected_devices);
......
......@@ -155,8 +155,6 @@ static void __cpuidle_driver_init(struct cpuidle_driver *drv)
{
int i;
drv->refcnt = 0;
/*
* Use all possible CPUs as the default, because if the kernel boots
* with some CPUs offline and then we online one of them, the CPU
......@@ -240,9 +238,6 @@ static int __cpuidle_register_driver(struct cpuidle_driver *drv)
*/
static void __cpuidle_unregister_driver(struct cpuidle_driver *drv)
{
if (WARN_ON(drv->refcnt > 0))
return;
if (drv->bctimer) {
drv->bctimer = 0;
on_each_cpu_mask(drv->cpumask, cpuidle_setup_broadcast_timer,
......@@ -349,47 +344,6 @@ struct cpuidle_driver *cpuidle_get_cpu_driver(struct cpuidle_device *dev)
}
EXPORT_SYMBOL_GPL(cpuidle_get_cpu_driver);
/**
* cpuidle_driver_ref - get a reference to the driver.
*
* Increment the reference counter of the cpuidle driver associated with
* the current CPU.
*
* Returns a pointer to the driver, or NULL if the current CPU has no driver.
*/
struct cpuidle_driver *cpuidle_driver_ref(void)
{
struct cpuidle_driver *drv;
spin_lock(&cpuidle_driver_lock);
drv = cpuidle_get_driver();
if (drv)
drv->refcnt++;
spin_unlock(&cpuidle_driver_lock);
return drv;
}
/**
* cpuidle_driver_unref - puts down the refcount for the driver
*
* Decrement the reference counter of the cpuidle driver associated with
* the current CPU.
*/
void cpuidle_driver_unref(void)
{
struct cpuidle_driver *drv;
spin_lock(&cpuidle_driver_lock);
drv = cpuidle_get_driver();
if (drv && !WARN_ON(drv->refcnt <= 0))
drv->refcnt--;
spin_unlock(&cpuidle_driver_lock);
}
/**
* cpuidle_driver_state_disabled - Disable or enable an idle state
* @drv: cpuidle driver owning the state
......
......@@ -142,6 +142,7 @@ static struct attribute_group cpuidle_attr_group = {
/**
* cpuidle_add_interface - add CPU global sysfs attributes
* @dev: the target device
*/
int cpuidle_add_interface(struct device *dev)
{
......@@ -153,6 +154,7 @@ int cpuidle_add_interface(struct device *dev)
/**
* cpuidle_remove_interface - remove CPU global sysfs attributes
* @dev: the target device
*/
void cpuidle_remove_interface(struct device *dev)
{
......@@ -327,6 +329,14 @@ static ssize_t store_state_disable(struct cpuidle_state *state,
return size;
}
static ssize_t show_state_default_status(struct cpuidle_state *state,
struct cpuidle_state_usage *state_usage,
char *buf)
{
return sprintf(buf, "%s\n",
state->flags & CPUIDLE_FLAG_OFF ? "disabled" : "enabled");
}
define_one_state_ro(name, show_state_name);
define_one_state_ro(desc, show_state_desc);
define_one_state_ro(latency, show_state_exit_latency);
......@@ -337,6 +347,7 @@ define_one_state_ro(time, show_state_time);
define_one_state_rw(disable, show_state_disable, store_state_disable);
define_one_state_ro(above, show_state_above);
define_one_state_ro(below, show_state_below);
define_one_state_ro(default_status, show_state_default_status);
static struct attribute *cpuidle_state_default_attrs[] = {
&attr_name.attr,
......@@ -349,6 +360,7 @@ static struct attribute *cpuidle_state_default_attrs[] = {
&attr_disable.attr,
&attr_above.attr,
&attr_below.attr,
&attr_default_status.attr,
NULL
};
......@@ -615,7 +627,7 @@ static struct kobj_type ktype_driver_cpuidle = {
/**
* cpuidle_add_driver_sysfs - adds the driver name sysfs attribute
* @device: the target device
* @dev: the target device
*/
static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
{
......@@ -646,7 +658,7 @@ static int cpuidle_add_driver_sysfs(struct cpuidle_device *dev)
/**
* cpuidle_remove_driver_sysfs - removes the driver name sysfs attribute
* @device: the target device
* @dev: the target device
*/
static void cpuidle_remove_driver_sysfs(struct cpuidle_device *dev)
{
......
......@@ -77,7 +77,7 @@ config DEVFREQ_GOV_PASSIVE
comment "DEVFREQ Drivers"
config ARM_EXYNOS_BUS_DEVFREQ
tristate "ARM EXYNOS Generic Memory Bus DEVFREQ Driver"
tristate "ARM Exynos Generic Memory Bus DEVFREQ Driver"
depends on ARCH_EXYNOS || COMPILE_TEST
select DEVFREQ_GOV_SIMPLE_ONDEMAND
select DEVFREQ_GOV_PASSIVE
......@@ -91,6 +91,16 @@ config ARM_EXYNOS_BUS_DEVFREQ
and adjusts the operating frequencies and voltages with OPP support.
This does not yet operate with optimal voltages.
config ARM_IMX8M_DDRC_DEVFREQ
tristate "i.MX8M DDRC DEVFREQ Driver"
depends on (ARCH_MXC && HAVE_ARM_SMCCC) || \
(COMPILE_TEST && HAVE_ARM_SMCCC)
select DEVFREQ_GOV_SIMPLE_ONDEMAND
select DEVFREQ_GOV_USERSPACE
help
This adds the DEVFREQ driver for the i.MX8M DDR Controller. It allows
adjusting DRAM frequency.
config ARM_TEGRA_DEVFREQ
tristate "NVIDIA Tegra30/114/124/210 DEVFREQ Driver"
depends on ARCH_TEGRA_3x_SOC || ARCH_TEGRA_114_SOC || \
......@@ -115,7 +125,8 @@ config ARM_TEGRA20_DEVFREQ
config ARM_RK3399_DMC_DEVFREQ
tristate "ARM RK3399 DMC DEVFREQ Driver"
depends on ARCH_ROCKCHIP
depends on (ARCH_ROCKCHIP && HAVE_ARM_SMCCC) || \
(COMPILE_TEST && HAVE_ARM_SMCCC)
select DEVFREQ_EVENT_ROCKCHIP_DFI
select DEVFREQ_GOV_SIMPLE_ONDEMAND
select PM_DEVFREQ_EVENT
......
......@@ -9,6 +9,7 @@ obj-$(CONFIG_DEVFREQ_GOV_PASSIVE) += governor_passive.o
# DEVFREQ Drivers
obj-$(CONFIG_ARM_EXYNOS_BUS_DEVFREQ) += exynos-bus.o
obj-$(CONFIG_ARM_IMX8M_DDRC_DEVFREQ) += imx8m-ddrc.o
obj-$(CONFIG_ARM_RK3399_DMC_DEVFREQ) += rk3399_dmc.o
obj-$(CONFIG_ARM_TEGRA_DEVFREQ) += tegra30-devfreq.o
obj-$(CONFIG_ARM_TEGRA20_DEVFREQ) += tegra20-devfreq.o
......
......@@ -346,9 +346,9 @@ EXPORT_SYMBOL_GPL(devfreq_event_add_edev);
/**
* devfreq_event_remove_edev() - Remove the devfreq-event device registered.
* @dev : the devfreq-event device
* @edev : the devfreq-event device
*
* Note that this function remove the registered devfreq-event device.
* Note that this function removes the registered devfreq-event device.
*/
int devfreq_event_remove_edev(struct devfreq_event_dev *edev)
{
......
......@@ -10,6 +10,7 @@
#include <linux/kernel.h>
#include <linux/kmod.h>
#include <linux/sched.h>
#include <linux/debugfs.h>
#include <linux/errno.h>
#include <linux/err.h>
#include <linux/init.h>
......@@ -33,6 +34,7 @@
#define HZ_PER_KHZ 1000
static struct class *devfreq_class;
static struct dentry *devfreq_debugfs;
/*
* devfreq core provides delayed work based load monitoring helper
......@@ -209,10 +211,10 @@ static int set_freq_table(struct devfreq *devfreq)
int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
{
int lev, prev_lev, ret = 0;
unsigned long cur_time;
u64 cur_time;
lockdep_assert_held(&devfreq->lock);
cur_time = jiffies;
cur_time = get_jiffies_64();
/* Immediately exit if previous_freq is not initialized yet. */
if (!devfreq->previous_freq)
......@@ -224,8 +226,8 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
goto out;
}
devfreq->time_in_state[prev_lev] +=
cur_time - devfreq->last_stat_updated;
devfreq->stats.time_in_state[prev_lev] +=
cur_time - devfreq->stats.last_update;
lev = devfreq_get_freq_level(devfreq, freq);
if (lev < 0) {
......@@ -234,13 +236,13 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
}
if (lev != prev_lev) {
devfreq->trans_table[(prev_lev *
devfreq->profile->max_state) + lev]++;
devfreq->total_trans++;
devfreq->stats.trans_table[
(prev_lev * devfreq->profile->max_state) + lev]++;
devfreq->stats.total_trans++;
}
out:
devfreq->last_stat_updated = cur_time;
devfreq->stats.last_update = cur_time;
return ret;
}
EXPORT_SYMBOL(devfreq_update_status);
......@@ -535,7 +537,7 @@ void devfreq_monitor_resume(struct devfreq *devfreq)
msecs_to_jiffies(devfreq->profile->polling_ms));
out_update:
devfreq->last_stat_updated = jiffies;
devfreq->stats.last_update = get_jiffies_64();
devfreq->stop_polling = false;
if (devfreq->profile->get_cur_freq &&
......@@ -807,28 +809,29 @@ struct devfreq *devfreq_add_device(struct device *dev,
goto err_out;
}
devfreq->trans_table = devm_kzalloc(&devfreq->dev,
devfreq->stats.trans_table = devm_kzalloc(&devfreq->dev,
array3_size(sizeof(unsigned int),
devfreq->profile->max_state,
devfreq->profile->max_state),
GFP_KERNEL);
if (!devfreq->trans_table) {
if (!devfreq->stats.trans_table) {
mutex_unlock(&devfreq->lock);
err = -ENOMEM;
goto err_devfreq;
}
devfreq->time_in_state = devm_kcalloc(&devfreq->dev,
devfreq->stats.time_in_state = devm_kcalloc(&devfreq->dev,
devfreq->profile->max_state,
sizeof(unsigned long),
sizeof(*devfreq->stats.time_in_state),
GFP_KERNEL);
if (!devfreq->time_in_state) {
if (!devfreq->stats.time_in_state) {
mutex_unlock(&devfreq->lock);
err = -ENOMEM;
goto err_devfreq;
}
devfreq->last_stat_updated = jiffies;
devfreq->stats.total_trans = 0;
devfreq->stats.last_update = get_jiffies_64();
srcu_init_notifier_head(&devfreq->transition_notifier_list);
......@@ -1259,6 +1262,14 @@ int devfreq_remove_governor(struct devfreq_governor *governor)
}
EXPORT_SYMBOL(devfreq_remove_governor);
static ssize_t name_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct devfreq *devfreq = to_devfreq(dev);
return sprintf(buf, "%s\n", dev_name(devfreq->dev.parent));
}
static DEVICE_ATTR_RO(name);
static ssize_t governor_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
......@@ -1461,6 +1472,7 @@ static ssize_t min_freq_show(struct device *dev, struct device_attribute *attr,
return sprintf(buf, "%lu\n", min_freq);
}
static DEVICE_ATTR_RW(min_freq);
static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
......@@ -1501,7 +1513,6 @@ static ssize_t max_freq_store(struct device *dev, struct device_attribute *attr,
return count;
}
static DEVICE_ATTR_RW(min_freq);
static ssize_t max_freq_show(struct device *dev, struct device_attribute *attr,
char *buf)
......@@ -1580,18 +1591,47 @@ static ssize_t trans_stat_show(struct device *dev,
devfreq->profile->freq_table[i]);
for (j = 0; j < max_state; j++)
len += sprintf(buf + len, "%10u",
devfreq->trans_table[(i * max_state) + j]);
len += sprintf(buf + len, "%10u\n",
jiffies_to_msecs(devfreq->time_in_state[i]));
devfreq->stats.trans_table[(i * max_state) + j]);
len += sprintf(buf + len, "%10llu\n", (u64)
jiffies64_to_msecs(devfreq->stats.time_in_state[i]));
}
len += sprintf(buf + len, "Total transition : %u\n",
devfreq->total_trans);
devfreq->stats.total_trans);
return len;
}
static DEVICE_ATTR_RO(trans_stat);
static ssize_t trans_stat_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct devfreq *df = to_devfreq(dev);
int err, value;
if (df->profile->max_state == 0)
return count;
err = kstrtoint(buf, 10, &value);
if (err || value != 0)
return -EINVAL;
mutex_lock(&df->lock);
memset(df->stats.time_in_state, 0, (df->profile->max_state *
sizeof(*df->stats.time_in_state)));
memset(df->stats.trans_table, 0, array3_size(sizeof(unsigned int),
df->profile->max_state,
df->profile->max_state));
df->stats.total_trans = 0;
df->stats.last_update = get_jiffies_64();
mutex_unlock(&df->lock);
return count;
}
static DEVICE_ATTR_RW(trans_stat);
static struct attribute *devfreq_attrs[] = {
&dev_attr_name.attr,
&dev_attr_governor.attr,
&dev_attr_available_governors.attr,
&dev_attr_cur_freq.attr,
......@@ -1605,6 +1645,81 @@ static struct attribute *devfreq_attrs[] = {
};
ATTRIBUTE_GROUPS(devfreq);
/**
* devfreq_summary_show() - Show the summary of the devfreq devices
* @s: seq_file instance to show the summary of devfreq devices
* @data: not used
*
* Show the summary of the devfreq devices via 'devfreq_summary' debugfs file.
* It helps that user can know the detailed information of the devfreq devices.
*
* Return 0 always because it shows the information without any data change.
*/
static int devfreq_summary_show(struct seq_file *s, void *data)
{
struct devfreq *devfreq;
struct devfreq *p_devfreq = NULL;
unsigned long cur_freq, min_freq, max_freq;
unsigned int polling_ms;
seq_printf(s, "%-30s %-10s %-10s %-15s %10s %12s %12s %12s\n",
"dev_name",
"dev",
"parent_dev",
"governor",
"polling_ms",
"cur_freq_Hz",
"min_freq_Hz",
"max_freq_Hz");
seq_printf(s, "%30s %10s %10s %15s %10s %12s %12s %12s\n",
"------------------------------",
"----------",
"----------",
"---------------",
"----------",
"------------",
"------------",
"------------");
mutex_lock(&devfreq_list_lock);
list_for_each_entry_reverse(devfreq, &devfreq_list, node) {
#if IS_ENABLED(CONFIG_DEVFREQ_GOV_PASSIVE)
if (!strncmp(devfreq->governor_name, DEVFREQ_GOV_PASSIVE,
DEVFREQ_NAME_LEN)) {
struct devfreq_passive_data *data = devfreq->data;
if (data)
p_devfreq = data->parent;
} else {
p_devfreq = NULL;
}
#endif
mutex_lock(&devfreq->lock);
cur_freq = devfreq->previous_freq,
get_freq_range(devfreq, &min_freq, &max_freq);
polling_ms = devfreq->profile->polling_ms,
mutex_unlock(&devfreq->lock);
seq_printf(s,
"%-30s %-10s %-10s %-15s %10d %12ld %12ld %12ld\n",
dev_name(devfreq->dev.parent),
dev_name(&devfreq->dev),
p_devfreq ? dev_name(&p_devfreq->dev) : "null",
devfreq->governor_name,
polling_ms,
cur_freq,
min_freq,
max_freq);
}
mutex_unlock(&devfreq_list_lock);
return 0;
}
DEFINE_SHOW_ATTRIBUTE(devfreq_summary);
static int __init devfreq_init(void)
{
devfreq_class = class_create(THIS_MODULE, "devfreq");
......@@ -1621,6 +1736,11 @@ static int __init devfreq_init(void)
}
devfreq_class->dev_groups = devfreq_groups;
devfreq_debugfs = debugfs_create_dir("devfreq", NULL);
debugfs_create_file("devfreq_summary", 0444,
devfreq_debugfs, NULL,
&devfreq_summary_fops);
return 0;
}
subsys_initcall(devfreq_init);
......@@ -1814,7 +1934,7 @@ static void devm_devfreq_notifier_release(struct device *dev, void *res)
/**
* devm_devfreq_register_notifier()
- Resource-managed devfreq_register_notifier()
* - Resource-managed devfreq_register_notifier()
* @dev: The devfreq user device. (parent of devfreq)
* @devfreq: The devfreq object.
* @nb: The notifier block to be unregistered.
......@@ -1850,7 +1970,7 @@ EXPORT_SYMBOL(devm_devfreq_register_notifier);
/**
* devm_devfreq_unregister_notifier()
- Resource-managed devfreq_unregister_notifier()
* - Resource-managed devfreq_unregister_notifier()
* @dev: The devfreq user device. (parent of devfreq)
* @devfreq: The devfreq object.
* @nb: The notifier block to be unregistered.
......
......@@ -15,7 +15,7 @@ menuconfig PM_DEVFREQ_EVENT
if PM_DEVFREQ_EVENT
config DEVFREQ_EVENT_EXYNOS_NOCP
tristate "EXYNOS NoC (Network On Chip) Probe DEVFREQ event Driver"
tristate "Exynos NoC (Network On Chip) Probe DEVFREQ event Driver"
depends on ARCH_EXYNOS || COMPILE_TEST
select PM_OPP
select REGMAP_MMIO
......@@ -24,7 +24,7 @@ config DEVFREQ_EVENT_EXYNOS_NOCP
(Network on Chip) Probe counters to measure the bandwidth of AXI bus.
config DEVFREQ_EVENT_EXYNOS_PPMU
tristate "EXYNOS PPMU (Platform Performance Monitoring Unit) DEVFREQ event Driver"
tristate "Exynos PPMU (Platform Performance Monitoring Unit) DEVFREQ event Driver"
depends on ARCH_EXYNOS || COMPILE_TEST
select PM_OPP
help
......@@ -34,7 +34,7 @@ config DEVFREQ_EVENT_EXYNOS_PPMU
config DEVFREQ_EVENT_ROCKCHIP_DFI
tristate "ROCKCHIP DFI DEVFREQ event Driver"
depends on ARCH_ROCKCHIP
depends on ARCH_ROCKCHIP || COMPILE_TEST
help
This add the devfreq-event driver for Rockchip SoC. It provides DFI
(DDR Monitor Module) driver to count ddr load.
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* exynos-nocp.c - EXYNOS NoC (Network On Chip) Probe support
* exynos-nocp.c - Exynos NoC (Network On Chip) Probe support
*
* Copyright (c) 2016 Samsung Electronics Co., Ltd.
* Author : Chanwoo Choi <cw00.choi@samsung.com>
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* exynos-nocp.h - EXYNOS NoC (Network on Chip) Probe header file
* exynos-nocp.h - Exynos NoC (Network on Chip) Probe header file
*
* Copyright (c) 2016 Samsung Electronics Co., Ltd.
* Author : Chanwoo Choi <cw00.choi@samsung.com>
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* exynos_ppmu.c - EXYNOS PPMU (Platform Performance Monitoring Unit) support
* exynos_ppmu.c - Exynos PPMU (Platform Performance Monitoring Unit) support
*
* Copyright (c) 2014-2015 Samsung Electronics Co., Ltd.
* Author : Chanwoo Choi <cw00.choi@samsung.com>
......@@ -101,17 +101,22 @@ static struct __exynos_ppmu_events {
PPMU_EVENT(dmc1_1),
};
static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev)
static int __exynos_ppmu_find_ppmu_id(const char *edev_name)
{
int i;
for (i = 0; i < ARRAY_SIZE(ppmu_events); i++)
if (!strcmp(edev->desc->name, ppmu_events[i].name))
if (!strcmp(edev_name, ppmu_events[i].name))
return ppmu_events[i].id;
return -EINVAL;
}
static int exynos_ppmu_find_ppmu_id(struct devfreq_event_dev *edev)
{
return __exynos_ppmu_find_ppmu_id(edev->desc->name);
}
/*
* The devfreq-event ops structure for PPMU v1.1
*/
......@@ -556,13 +561,11 @@ static int of_get_devfreq_events(struct device_node *np,
* use default if not.
*/
if (info->ppmu_type == EXYNOS_TYPE_PPMU_V2) {
struct devfreq_event_dev edev;
int id;
/* Not all registers take the same value for
* read+write data count.
*/
edev.desc = &desc[j];
id = exynos_ppmu_find_ppmu_id(&edev);
id = __exynos_ppmu_find_ppmu_id(desc[j].name);
switch (id) {
case PPMU_PMNCNT0:
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* exynos_ppmu.h - EXYNOS PPMU header file
* exynos_ppmu.h - Exynos PPMU header file
*
* Copyright (c) 2015 Samsung Electronics Co., Ltd.
* Author : Chanwoo Choi <cw00.choi@samsung.com>
......
......@@ -177,7 +177,6 @@ static int rockchip_dfi_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rockchip_dfi *data;
struct resource *res;
struct devfreq_event_desc *desc;
struct device_node *np = pdev->dev.of_node, *node;
......@@ -185,8 +184,7 @@ static int rockchip_dfi_probe(struct platform_device *pdev)
if (!data)
return -ENOMEM;
res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
data->regs = devm_ioremap_resource(&pdev->dev, res);
data->regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(data->regs))
return PTR_ERR(data->regs);
......@@ -200,6 +198,7 @@ static int rockchip_dfi_probe(struct platform_device *pdev)
node = of_parse_phandle(np, "rockchip,pmu", 0);
if (node) {
data->regmap_pmu = syscon_node_to_regmap(node);
of_node_put(node);
if (IS_ERR(data->regmap_pmu))
return PTR_ERR(data->regmap_pmu);
}
......
......@@ -15,11 +15,10 @@
#include <linux/device.h>
#include <linux/export.h>
#include <linux/module.h>
#include <linux/of_device.h>
#include <linux/of.h>
#include <linux/pm_opp.h>
#include <linux/platform_device.h>
#include <linux/regulator/consumer.h>
#include <linux/slab.h>
#define DEFAULT_SATURATION_RATIO 40
......@@ -127,6 +126,7 @@ static int exynos_bus_get_dev_status(struct device *dev,
ret = exynos_bus_get_event(bus, &edata);
if (ret < 0) {
dev_err(dev, "failed to get event from devfreq-event devices\n");
stat->total_time = stat->busy_time = 0;
goto err;
}
......@@ -287,52 +287,12 @@ static int exynos_bus_parse_of(struct device_node *np,
return ret;
}
static int exynos_bus_probe(struct platform_device *pdev)
static int exynos_bus_profile_init(struct exynos_bus *bus,
struct devfreq_dev_profile *profile)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node, *node;
struct devfreq_dev_profile *profile;
struct device *dev = bus->dev;
struct devfreq_simple_ondemand_data *ondemand_data;
struct devfreq_passive_data *passive_data;
struct devfreq *parent_devfreq;
struct exynos_bus *bus;
int ret, max_state;
unsigned long min_freq, max_freq;
bool passive = false;
if (!np) {
dev_err(dev, "failed to find devicetree node\n");
return -EINVAL;
}
bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
if (!bus)
return -ENOMEM;
mutex_init(&bus->lock);
bus->dev = &pdev->dev;
platform_set_drvdata(pdev, bus);
profile = devm_kzalloc(dev, sizeof(*profile), GFP_KERNEL);
if (!profile)
return -ENOMEM;
node = of_parse_phandle(dev->of_node, "devfreq", 0);
if (node) {
of_node_put(node);
passive = true;
} else {
ret = exynos_bus_parent_parse_of(np, bus);
if (ret < 0)
return ret;
}
/* Parse the device-tree to get the resource information */
ret = exynos_bus_parse_of(np, bus);
if (ret < 0)
goto err_reg;
if (passive)
goto passive;
int ret;
/* Initialize the struct profile and governor data for parent device */
profile->polling_ms = 50;
......@@ -341,10 +301,9 @@ static int exynos_bus_probe(struct platform_device *pdev)
profile->exit = exynos_bus_exit;
ondemand_data = devm_kzalloc(dev, sizeof(*ondemand_data), GFP_KERNEL);
if (!ondemand_data) {
ret = -ENOMEM;
goto err;
}
if (!ondemand_data)
return -ENOMEM;
ondemand_data->upthreshold = 40;
ondemand_data->downdifferential = 5;
......@@ -354,15 +313,14 @@ static int exynos_bus_probe(struct platform_device *pdev)
ondemand_data);
if (IS_ERR(bus->devfreq)) {
dev_err(dev, "failed to add devfreq device\n");
ret = PTR_ERR(bus->devfreq);
goto err;
return PTR_ERR(bus->devfreq);
}
/* Register opp_notifier to catch the change of OPP */
ret = devm_devfreq_register_opp_notifier(dev, bus->devfreq);
if (ret < 0) {
dev_err(dev, "failed to register opp notifier\n");
goto err;
return ret;
}
/*
......@@ -372,33 +330,44 @@ static int exynos_bus_probe(struct platform_device *pdev)
ret = exynos_bus_enable_edev(bus);
if (ret < 0) {
dev_err(dev, "failed to enable devfreq-event devices\n");
goto err;
return ret;
}
ret = exynos_bus_set_event(bus);
if (ret < 0) {
dev_err(dev, "failed to set event to devfreq-event devices\n");
goto err;
goto err_edev;
}
goto out;
passive:
return 0;
err_edev:
if (exynos_bus_disable_edev(bus))
dev_warn(dev, "failed to disable the devfreq-event devices\n");
return ret;
}
static int exynos_bus_profile_init_passive(struct exynos_bus *bus,
struct devfreq_dev_profile *profile)
{
struct device *dev = bus->dev;
struct devfreq_passive_data *passive_data;
struct devfreq *parent_devfreq;
/* Initialize the struct profile and governor data for passive device */
profile->target = exynos_bus_target;
profile->exit = exynos_bus_passive_exit;
/* Get the instance of parent devfreq device */
parent_devfreq = devfreq_get_devfreq_by_phandle(dev, 0);
if (IS_ERR(parent_devfreq)) {
ret = -EPROBE_DEFER;
goto err;
}
if (IS_ERR(parent_devfreq))
return -EPROBE_DEFER;
passive_data = devm_kzalloc(dev, sizeof(*passive_data), GFP_KERNEL);
if (!passive_data) {
ret = -ENOMEM;
goto err;
}
if (!passive_data)
return -ENOMEM;
passive_data->parent = parent_devfreq;
/* Add devfreq device for exynos bus with passive governor */
......@@ -407,11 +376,61 @@ static int exynos_bus_probe(struct platform_device *pdev)
if (IS_ERR(bus->devfreq)) {
dev_err(dev,
"failed to add devfreq dev with passive governor\n");
ret = PTR_ERR(bus->devfreq);
goto err;
return PTR_ERR(bus->devfreq);
}
return 0;
}
static int exynos_bus_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node, *node;
struct devfreq_dev_profile *profile;
struct exynos_bus *bus;
int ret, max_state;
unsigned long min_freq, max_freq;
bool passive = false;
if (!np) {
dev_err(dev, "failed to find devicetree node\n");
return -EINVAL;
}
out:
bus = devm_kzalloc(&pdev->dev, sizeof(*bus), GFP_KERNEL);
if (!bus)
return -ENOMEM;
mutex_init(&bus->lock);
bus->dev = &pdev->dev;
platform_set_drvdata(pdev, bus);
profile = devm_kzalloc(dev, sizeof(*profile), GFP_KERNEL);
if (!profile)
return -ENOMEM;
node = of_parse_phandle(dev->of_node, "devfreq", 0);
if (node) {
of_node_put(node);
passive = true;
} else {
ret = exynos_bus_parent_parse_of(np, bus);
if (ret < 0)
return ret;
}
/* Parse the device-tree to get the resource information */
ret = exynos_bus_parse_of(np, bus);
if (ret < 0)
goto err_reg;
if (passive)
ret = exynos_bus_profile_init_passive(bus, profile);
else
ret = exynos_bus_profile_init(bus, profile);
if (ret < 0)
goto err;
max_state = bus->devfreq->profile->max_state;
min_freq = (bus->devfreq->profile->freq_table[0] / 1000);
max_freq = (bus->devfreq->profile->freq_table[max_state - 1] / 1000);
......
This diff is collapsed.
......@@ -364,7 +364,8 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
if (res.a0) {
dev_err(dev, "Failed to set dram param: %ld\n",
res.a0);
return -EINVAL;
ret = -EINVAL;
goto err_edev;
}
}
}
......@@ -372,8 +373,11 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
node = of_parse_phandle(np, "rockchip,pmu", 0);
if (node) {
data->regmap_pmu = syscon_node_to_regmap(node);
if (IS_ERR(data->regmap_pmu))
return PTR_ERR(data->regmap_pmu);
of_node_put(node);
if (IS_ERR(data->regmap_pmu)) {
ret = PTR_ERR(data->regmap_pmu);
goto err_edev;
}
}
regmap_read(data->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val);
......@@ -391,7 +395,8 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
data->odt_dis_freq = data->timing.lpddr4_odt_dis_freq;
break;
default:
return -EINVAL;
ret = -EINVAL;
goto err_edev;
};
arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, 0, 0,
......@@ -425,7 +430,8 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
*/
if (dev_pm_opp_of_add_table(dev)) {
dev_err(dev, "Invalid operating-points in device tree.\n");
return -EINVAL;
ret = -EINVAL;
goto err_edev;
}
of_property_read_u32(np, "upthreshold",
......@@ -465,6 +471,9 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
err_free_opp:
dev_pm_opp_of_remove_table(&pdev->dev);
err_edev:
devfreq_event_disable_edev(data->edev);
return ret;
}
......
This diff is collapsed.
......@@ -988,7 +988,6 @@ static struct opp_table *_allocate_opp_table(struct device *dev, int index)
BLOCKING_INIT_NOTIFIER_HEAD(&opp_table->head);
INIT_LIST_HEAD(&opp_table->opp_list);
kref_init(&opp_table->kref);
kref_init(&opp_table->list_kref);
/* Secure the device table modification */
list_add(&opp_table->node, &opp_tables);
......@@ -1072,33 +1071,6 @@ static void _opp_table_kref_release(struct kref *kref)
mutex_unlock(&opp_table_lock);
}
void _opp_remove_all_static(struct opp_table *opp_table)
{
struct dev_pm_opp *opp, *tmp;
list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) {
if (!opp->dynamic)
dev_pm_opp_put(opp);
}
opp_table->parsed_static_opps = false;
}
static void _opp_table_list_kref_release(struct kref *kref)
{
struct opp_table *opp_table = container_of(kref, struct opp_table,
list_kref);
_opp_remove_all_static(opp_table);
mutex_unlock(&opp_table_lock);
}
void _put_opp_list_kref(struct opp_table *opp_table)
{
kref_put_mutex(&opp_table->list_kref, _opp_table_list_kref_release,
&opp_table_lock);
}
void dev_pm_opp_put_opp_table(struct opp_table *opp_table)
{
kref_put_mutex(&opp_table->kref, _opp_table_kref_release,
......@@ -1202,6 +1174,24 @@ void dev_pm_opp_remove(struct device *dev, unsigned long freq)
}
EXPORT_SYMBOL_GPL(dev_pm_opp_remove);
void _opp_remove_all_static(struct opp_table *opp_table)
{
struct dev_pm_opp *opp, *tmp;
mutex_lock(&opp_table->lock);
if (!opp_table->parsed_static_opps || --opp_table->parsed_static_opps)
goto unlock;
list_for_each_entry_safe(opp, tmp, &opp_table->opp_list, node) {
if (!opp->dynamic)
dev_pm_opp_put_unlocked(opp);
}
unlock:
mutex_unlock(&opp_table->lock);
}
/**
* dev_pm_opp_remove_all_dynamic() - Remove all dynamically created OPPs
* @dev: device for which we do this operation
......@@ -2276,7 +2266,7 @@ void _dev_pm_opp_find_and_remove_table(struct device *dev)
return;
}
_put_opp_list_kref(opp_table);
_opp_remove_all_static(opp_table);
/* Drop reference taken by _find_opp_table() */
dev_pm_opp_put_opp_table(opp_table);
......
......@@ -658,17 +658,15 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
struct dev_pm_opp *opp;
/* OPP table is already initialized for the device */
mutex_lock(&opp_table->lock);
if (opp_table->parsed_static_opps) {
kref_get(&opp_table->list_kref);
opp_table->parsed_static_opps++;
mutex_unlock(&opp_table->lock);
return 0;
}
/*
* Re-initialize list_kref every time we add static OPPs to the OPP
* table as the reference count may be 0 after the last tie static OPPs
* were removed.
*/
kref_init(&opp_table->list_kref);
opp_table->parsed_static_opps = 1;
mutex_unlock(&opp_table->lock);
/* We have opp-table node now, iterate over it and add OPPs */
for_each_available_child_of_node(opp_table->np, np) {
......@@ -678,15 +676,17 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
dev_err(dev, "%s: Failed to add OPP, %d\n", __func__,
ret);
of_node_put(np);
return ret;
goto remove_static_opp;
} else if (opp) {
count++;
}
}
/* There should be one of more OPP defined */
if (WARN_ON(!count))
return -ENOENT;
if (WARN_ON(!count)) {
ret = -ENOENT;
goto remove_static_opp;
}
list_for_each_entry(opp, &opp_table->opp_list, node)
pstate_count += !!opp->pstate;
......@@ -695,15 +695,19 @@ static int _of_add_opp_table_v2(struct device *dev, struct opp_table *opp_table)
if (pstate_count && pstate_count != count) {
dev_err(dev, "Not all nodes have performance state set (%d: %d)\n",
count, pstate_count);
return -ENOENT;
ret = -ENOENT;
goto remove_static_opp;
}
if (pstate_count)
opp_table->genpd_performance_state = true;
opp_table->parsed_static_opps = true;
return 0;
remove_static_opp:
_opp_remove_all_static(opp_table);
return ret;
}
/* Initializes OPP tables based on old-deprecated bindings */
......@@ -738,6 +742,7 @@ static int _of_add_opp_table_v1(struct device *dev, struct opp_table *opp_table)
if (ret) {
dev_err(dev, "%s: Failed to add OPP %ld (%d)\n",
__func__, freq, ret);
_opp_remove_all_static(opp_table);
return ret;
}
nr -= 2;
......
......@@ -127,11 +127,10 @@ enum opp_table_access {
* @dev_list: list of devices that share these OPPs
* @opp_list: table of opps
* @kref: for reference count of the table.
* @list_kref: for reference count of the OPP list.
* @lock: mutex protecting the opp_list and dev_list.
* @np: struct device_node pointer for opp's DT node.
* @clock_latency_ns_max: Max clock latency in nanoseconds.
* @parsed_static_opps: True if OPPs are initialized from DT.
* @parsed_static_opps: Count of devices for which OPPs are initialized from DT.
* @shared_opp: OPP is shared between multiple devices.
* @suspend_opp: Pointer to OPP to be used during device suspend.
* @genpd_virt_dev_lock: Mutex protecting the genpd virtual device pointers.
......@@ -167,7 +166,6 @@ struct opp_table {
struct list_head dev_list;
struct list_head opp_list;
struct kref kref;
struct kref list_kref;
struct mutex lock;
struct device_node *np;
......@@ -176,7 +174,7 @@ struct opp_table {
/* For backward compatibility with v1 bindings */
unsigned int voltage_tolerance_v1;
bool parsed_static_opps;
unsigned int parsed_static_opps;
enum opp_table_access shared_opp;
struct dev_pm_opp *suspend_opp;
......
......@@ -12,6 +12,22 @@ menuconfig POWER_AVS
Say Y here to enable Adaptive Voltage Scaling class support.
config QCOM_CPR
tristate "QCOM Core Power Reduction (CPR) support"
depends on POWER_AVS
select PM_OPP
select REGMAP
help
Say Y here to enable support for the CPR hardware found on Qualcomm
SoCs like QCS404.
This driver populates CPU OPPs tables and makes adjustments to the
tables based on feedback from the CPR hardware. If you want to do
CPUfrequency scaling say Y here.
To compile this driver as a module, choose M here: the module will
be called qcom-cpr
config ROCKCHIP_IODOMAIN
tristate "Rockchip IO domain support"
depends on POWER_AVS && ARCH_ROCKCHIP && OF
......
# SPDX-License-Identifier: GPL-2.0-only
obj-$(CONFIG_POWER_AVS_OMAP) += smartreflex.o
obj-$(CONFIG_QCOM_CPR) += qcom-cpr.o
obj-$(CONFIG_ROCKCHIP_IODOMAIN) += rockchip-io-domain.o
This diff is collapsed.
......@@ -980,6 +980,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = {
INTEL_CPU_FAM6(ICELAKE_D, rapl_defaults_hsw_server),
INTEL_CPU_FAM6(COMETLAKE_L, rapl_defaults_core),
INTEL_CPU_FAM6(COMETLAKE, rapl_defaults_core),
INTEL_CPU_FAM6(TIGERLAKE_L, rapl_defaults_core),
INTEL_CPU_FAM6(ATOM_SILVERMONT, rapl_defaults_byt),
INTEL_CPU_FAM6(ATOM_AIRMONT, rapl_defaults_cht),
......@@ -989,6 +990,7 @@ static const struct x86_cpu_id rapl_ids[] __initconst = {
INTEL_CPU_FAM6(ATOM_GOLDMONT_PLUS, rapl_defaults_core),
INTEL_CPU_FAM6(ATOM_GOLDMONT_D, rapl_defaults_core),
INTEL_CPU_FAM6(ATOM_TREMONT_D, rapl_defaults_core),
INTEL_CPU_FAM6(ATOM_TREMONT_L, rapl_defaults_core),
INTEL_CPU_FAM6(XEON_PHI_KNL, rapl_defaults_hsw_server),
INTEL_CPU_FAM6(XEON_PHI_KNM, rapl_defaults_hsw_server),
......
......@@ -279,6 +279,21 @@ static inline bool invalid_phys_cpuid(phys_cpuid_t phys_id)
/* Validate the processor object's proc_id */
bool acpi_duplicate_processor_id(int proc_id);
/* Processor _CTS control */
struct acpi_processor_power;
#ifdef CONFIG_ACPI_PROCESSOR_CSTATE
bool acpi_processor_claim_cst_control(void);
int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu,
struct acpi_processor_power *info);
#else
static inline bool acpi_processor_claim_cst_control(void) { return false; }
static inline int acpi_processor_evaluate_cst(acpi_handle handle, u32 cpu,
struct acpi_processor_power *info)
{
return -ENODEV;
}
#endif
#ifdef CONFIG_ACPI_HOTPLUG_CPU
/* Arch dependent functions for cpu hotplug support */
......
......@@ -77,6 +77,7 @@ struct cpuidle_state {
#define CPUIDLE_FLAG_COUPLED BIT(1) /* state applies to multiple cpus */
#define CPUIDLE_FLAG_TIMER_STOP BIT(2) /* timer is stopped on this state */
#define CPUIDLE_FLAG_UNUSABLE BIT(3) /* avoid using this state */
#define CPUIDLE_FLAG_OFF BIT(4) /* disable this state by default */
struct cpuidle_device_kobj;
struct cpuidle_state_kobj;
......@@ -115,7 +116,6 @@ DECLARE_PER_CPU(struct cpuidle_device, cpuidle_dev);
struct cpuidle_driver {
const char *name;
struct module *owner;
int refcnt;
/* used by the cpuidle framework to setup the broadcast timer */
unsigned int bctimer:1;
......@@ -147,8 +147,6 @@ extern u64 cpuidle_poll_time(struct cpuidle_driver *drv,
extern int cpuidle_register_driver(struct cpuidle_driver *drv);
extern struct cpuidle_driver *cpuidle_get_driver(void);
extern struct cpuidle_driver *cpuidle_driver_ref(void);
extern void cpuidle_driver_unref(void);
extern void cpuidle_driver_state_disabled(struct cpuidle_driver *drv, int idx,
bool disable);
extern void cpuidle_unregister_driver(struct cpuidle_driver *drv);
......@@ -186,8 +184,6 @@ static inline u64 cpuidle_poll_time(struct cpuidle_driver *drv,
static inline int cpuidle_register_driver(struct cpuidle_driver *drv)
{return -ENODEV; }
static inline struct cpuidle_driver *cpuidle_get_driver(void) {return NULL; }
static inline struct cpuidle_driver *cpuidle_driver_ref(void) {return NULL; }
static inline void cpuidle_driver_unref(void) {}
static inline void cpuidle_driver_state_disabled(struct cpuidle_driver *drv,
int idx, bool disable) { }
static inline void cpuidle_unregister_driver(struct cpuidle_driver *drv) { }
......
......@@ -107,6 +107,20 @@ struct devfreq_dev_profile {
unsigned int max_state;
};
/**
* struct devfreq_stats - Statistics of devfreq device behavior
* @total_trans: Number of devfreq transitions.
* @trans_table: Statistics of devfreq transitions.
* @time_in_state: Statistics of devfreq states.
* @last_update: The last time stats were updated.
*/
struct devfreq_stats {
unsigned int total_trans;
unsigned int *trans_table;
u64 *time_in_state;
u64 last_update;
};
/**
* struct devfreq - Device devfreq structure
* @node: list node - contains the devices with devfreq that have been
......@@ -122,6 +136,7 @@ struct devfreq_dev_profile {
* devfreq.nb to the corresponding register notifier call chain.
* @work: delayed work for load monitoring.
* @previous_freq: previously configured frequency value.
* @last_status: devfreq user device info, performance statistics
* @data: Private data of the governor. The devfreq framework does not
* touch this.
* @user_min_freq_req: PM QoS minimum frequency request from user (via sysfs)
......@@ -132,15 +147,12 @@ struct devfreq_dev_profile {
* @suspend_freq: frequency of a device set during suspend phase.
* @resume_freq: frequency of a device set in resume phase.
* @suspend_count: suspend requests counter for a device.
* @total_trans: Number of devfreq transitions
* @trans_table: Statistics of devfreq transitions
* @time_in_state: Statistics of devfreq states
* @last_stat_updated: The last time stat updated
* @stats: Statistics of devfreq device behavior
* @transition_notifier_list: list head of DEVFREQ_TRANSITION_NOTIFIER notifier
* @nb_min: Notifier block for DEV_PM_QOS_MIN_FREQUENCY
* @nb_max: Notifier block for DEV_PM_QOS_MAX_FREQUENCY
*
* This structure stores the devfreq information for a give device.
* This structure stores the devfreq information for a given device.
*
* Note that when a governor accesses entries in struct devfreq in its
* functions except for the context of callbacks defined in struct
......@@ -174,11 +186,8 @@ struct devfreq {
unsigned long resume_freq;
atomic_t suspend_count;
/* information for device frequency transition */
unsigned int total_trans;
unsigned int *trans_table;
unsigned long *time_in_state;
unsigned long last_stat_updated;
/* information for device frequency transitions */
struct devfreq_stats stats;
struct srcu_notifier_head transition_notifier_list;
......
......@@ -329,6 +329,7 @@ extern void arch_suspend_disable_irqs(void);
extern void arch_suspend_enable_irqs(void);
extern int pm_suspend(suspend_state_t state);
extern bool sync_on_suspend_enabled;
#else /* !CONFIG_SUSPEND */
#define suspend_valid_only_mem NULL
......@@ -342,6 +343,7 @@ static inline bool pm_suspend_default_s2idle(void) { return false; }
static inline void suspend_set_ops(const struct platform_suspend_ops *ops) {}
static inline int pm_suspend(suspend_state_t state) { return -ENOSYS; }
static inline bool sync_on_suspend_enabled(void) { return true; }
static inline bool idle_should_enter_s2idle(void) { return false; }
static inline void __init pm_states_init(void) {}
static inline void s2idle_set_ops(const struct platform_s2idle_ops *ops) {}
......
......@@ -74,6 +74,12 @@ DEFINE_EVENT(rpm_internal, rpm_idle,
TP_ARGS(dev, flags)
);
DEFINE_EVENT(rpm_internal, rpm_usage,
TP_PROTO(struct device *dev, int flags),
TP_ARGS(dev, flags)
);
TRACE_EVENT(rpm_return_int,
TP_PROTO(struct device *dev, unsigned long ip, int ret),
......
......@@ -27,7 +27,10 @@ config SUSPEND_SKIP_SYNC
Skip the kernel sys_sync() before freezing user processes.
Some systems prefer not to pay this cost on every invocation
of suspend, or they are content with invoking sync() from
user-space before invoking suspend. Say Y if that's your case.
user-space before invoking suspend. There's a run-time switch
at '/sys/power/sync_on_suspend' to configure this behaviour.
This setting changes the default for the run-tim switch. Say Y
to change the default to disable the kernel sys_sync().
config HIBERNATE_CALLBACKS
bool
......
......@@ -9,7 +9,7 @@
* Copyright (C) 2012 Bojan Smojver <bojan@rexursive.com>
*/
#define pr_fmt(fmt) "PM: " fmt
#define pr_fmt(fmt) "PM: hibernation: " fmt
#include <linux/export.h>
#include <linux/suspend.h>
......@@ -106,7 +106,7 @@ EXPORT_SYMBOL(system_entering_hibernation);
#ifdef CONFIG_PM_DEBUG
static void hibernation_debug_sleep(void)
{
pr_info("hibernation debug: Waiting for 5 seconds.\n");
pr_info("debug: Waiting for 5 seconds.\n");
mdelay(5000);
}
......@@ -277,7 +277,7 @@ static int create_image(int platform_mode)
error = dpm_suspend_end(PMSG_FREEZE);
if (error) {
pr_err("Some devices failed to power down, aborting hibernation\n");
pr_err("Some devices failed to power down, aborting\n");
return error;
}
......@@ -295,7 +295,7 @@ static int create_image(int platform_mode)
error = syscore_suspend();
if (error) {
pr_err("Some system devices failed to power down, aborting hibernation\n");
pr_err("Some system devices failed to power down, aborting\n");
goto Enable_irqs;
}
......@@ -310,7 +310,7 @@ static int create_image(int platform_mode)
restore_processor_state();
trace_suspend_resume(TPS("machine_suspend"), PM_EVENT_HIBERNATE, false);
if (error)
pr_err("Error %d creating hibernation image\n", error);
pr_err("Error %d creating image\n", error);
if (!in_suspend) {
events_check_enabled = false;
......@@ -680,7 +680,7 @@ static int load_image_and_restore(void)
if (!error)
hibernation_restore(flags & SF_PLATFORM_MODE);
pr_err("Failed to load hibernation image, recovering.\n");
pr_err("Failed to load image, recovering.\n");
swsusp_free();
free_basic_memory_bitmaps();
Unlock:
......@@ -743,7 +743,7 @@ int hibernate(void)
else
flags |= SF_CRC32_MODE;
pm_pr_dbg("Writing image.\n");
pm_pr_dbg("Writing hibernation image.\n");
error = swsusp_write(flags);
swsusp_free();
if (!error) {
......@@ -755,7 +755,7 @@ int hibernate(void)
in_suspend = 0;
pm_restore_gfp_mask();
} else {
pm_pr_dbg("Image restored successfully.\n");
pm_pr_dbg("Hibernation image restored successfully.\n");
}
Free_bitmaps:
......@@ -894,7 +894,7 @@ static int software_resume(void)
goto Close_Finish;
}
pm_pr_dbg("Preparing processes for restore.\n");
pm_pr_dbg("Preparing processes for hibernation restore.\n");
error = freeze_processes();
if (error)
goto Close_Finish;
......@@ -903,7 +903,7 @@ static int software_resume(void)
Finish:
__pm_notifier_call_chain(PM_POST_RESTORE, nr_calls, NULL);
pm_restore_console();
pr_info("resume from hibernation failed (%d)\n", error);
pr_info("resume failed (%d)\n", error);
atomic_inc(&snapshot_device_available);
/* For success case, the suspend path will release the lock */
Unlock:
......@@ -1068,7 +1068,8 @@ static ssize_t resume_store(struct kobject *kobj, struct kobj_attribute *attr,
lock_system_sleep();
swsusp_resume_device = res;
unlock_system_sleep();
pm_pr_dbg("Configured resume from disk to %u\n", swsusp_resume_device);
pm_pr_dbg("Configured hibernation resume from disk to %u\n",
swsusp_resume_device);
noresume = 0;
software_resume();
return n;
......
......@@ -190,6 +190,38 @@ static ssize_t mem_sleep_store(struct kobject *kobj, struct kobj_attribute *attr
}
power_attr(mem_sleep);
/*
* sync_on_suspend: invoke ksys_sync_helper() before suspend.
*
* show() returns whether ksys_sync_helper() is invoked before suspend.
* store() accepts 0 or 1. 0 disables ksys_sync_helper() and 1 enables it.
*/
bool sync_on_suspend_enabled = !IS_ENABLED(CONFIG_SUSPEND_SKIP_SYNC);
static ssize_t sync_on_suspend_show(struct kobject *kobj,
struct kobj_attribute *attr, char *buf)
{
return sprintf(buf, "%d\n", sync_on_suspend_enabled);
}
static ssize_t sync_on_suspend_store(struct kobject *kobj,
struct kobj_attribute *attr,
const char *buf, size_t n)
{
unsigned long val;
if (kstrtoul(buf, 10, &val))
return -EINVAL;
if (val > 1)
return -EINVAL;
sync_on_suspend_enabled = !!val;
return n;
}
power_attr(sync_on_suspend);
#endif /* CONFIG_SUSPEND */
#ifdef CONFIG_PM_SLEEP_DEBUG
......@@ -855,6 +887,7 @@ static struct attribute * g[] = {
&wakeup_count_attr.attr,
#ifdef CONFIG_SUSPEND
&mem_sleep_attr.attr,
&sync_on_suspend_attr.attr,
#endif
#ifdef CONFIG_PM_AUTOSLEEP
&autosleep_attr.attr,
......
......@@ -8,7 +8,7 @@
* Copyright (C) 2006 Rafael J. Wysocki <rjw@sisk.pl>
*/
#define pr_fmt(fmt) "PM: " fmt
#define pr_fmt(fmt) "PM: hibernation: " fmt
#include <linux/version.h>
#include <linux/module.h>
......@@ -1566,9 +1566,7 @@ static unsigned long preallocate_image_highmem(unsigned long nr_pages)
*/
static unsigned long __fraction(u64 x, u64 multiplier, u64 base)
{
x *= multiplier;
do_div(x, base);
return (unsigned long)x;
return div64_u64(x * multiplier, base);
}
static unsigned long preallocate_highmem_fraction(unsigned long nr_pages,
......@@ -1705,16 +1703,20 @@ int hibernate_preallocate_memory(void)
ktime_t start, stop;
int error;
pr_info("Preallocating image memory... ");
pr_info("Preallocating image memory\n");
start = ktime_get();
error = memory_bm_create(&orig_bm, GFP_IMAGE, PG_ANY);
if (error)
if (error) {
pr_err("Cannot allocate original bitmap\n");
goto err_out;
}
error = memory_bm_create(&copy_bm, GFP_IMAGE, PG_ANY);
if (error)
if (error) {
pr_err("Cannot allocate copy bitmap\n");
goto err_out;
}
alloc_normal = 0;
alloc_highmem = 0;
......@@ -1804,8 +1806,11 @@ int hibernate_preallocate_memory(void)
alloc -= pages;
pages += pages_highmem;
pages_highmem = preallocate_image_highmem(alloc);
if (pages_highmem < alloc)
if (pages_highmem < alloc) {
pr_err("Image allocation is %lu pages short\n",
alloc - pages_highmem);
goto err_out;
}
pages += pages_highmem;
/*
* size is the desired number of saveable pages to leave in
......@@ -1836,13 +1841,12 @@ int hibernate_preallocate_memory(void)
out:
stop = ktime_get();
pr_cont("done (allocated %lu pages)\n", pages);
pr_info("Allocated %lu pages for snapshot\n", pages);
swsusp_show_speed(start, stop, pages, "Allocated");
return 0;
err_out:
pr_cont("\n");
swsusp_free();
return -ENOMEM;
}
......@@ -1976,7 +1980,7 @@ asmlinkage __visible int swsusp_save(void)
{
unsigned int nr_pages, nr_highmem;
pr_info("Creating hibernation image:\n");
pr_info("Creating image:\n");
drain_local_pages(NULL);
nr_pages = count_data_pages();
......@@ -2010,7 +2014,7 @@ asmlinkage __visible int swsusp_save(void)
nr_copy_pages = nr_pages;
nr_meta_pages = DIV_ROUND_UP(nr_pages * sizeof(long), PAGE_SIZE);
pr_info("Hibernation image created (%d pages copied)\n", nr_pages);
pr_info("Image created (%d pages copied)\n", nr_pages);
return 0;
}
......
......@@ -564,7 +564,7 @@ static int enter_state(suspend_state_t state)
if (state == PM_SUSPEND_TO_IDLE)
s2idle_begin();
if (!IS_ENABLED(CONFIG_SUSPEND_SKIP_SYNC)) {
if (sync_on_suspend_enabled) {
trace_suspend_resume(TPS("sync_filesystems"), 0, true);
ksys_sync_helper();
trace_suspend_resume(TPS("sync_filesystems"), 0, false);
......
......@@ -70,7 +70,7 @@ static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state)
static char info_test[] __initdata =
KERN_INFO "PM: test RTC wakeup from '%s' suspend\n";
unsigned long now;
time64_t now;
struct rtc_wkalrm alm;
int status;
......@@ -81,10 +81,10 @@ static void __init test_wakealarm(struct rtc_device *rtc, suspend_state_t state)
printk(err_readtime, dev_name(&rtc->dev), status);
return;
}
rtc_tm_to_time(&alm.time, &now);
now = rtc_tm_to_time64(&alm.time);
memset(&alm, 0, sizeof alm);
rtc_time_to_tm(now + TEST_SUSPEND_SECONDS, &alm.time);
rtc_time64_to_tm(now + TEST_SUSPEND_SECONDS, &alm.time);
alm.enabled = true;
status = rtc_set_alarm(rtc, &alm);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment