Commit b109bc72 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'thermal-v5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux

Pull thermal updates from Daniel Lezcano:

 - Add upper and lower limits clamps for the cooling device state in the
   power allocator governor (Michael Kao)

 - Add upper and lower limits support for the power allocator governor
   (Lukasz Luba)

 - Optimize conditions testing for the trip points (Bernard Zhao)

 - Replace spin_lock_irqsave by spin_lock in hard IRQ on the rcar driver
   (Tian Tao)

 - Add MT8516 dt-bindings and device reset optional support (Fabien
   Parent)

 - Add a quiescent period to cool down the PCH when entering S0iX
   (Sumeet Pawnikar)

 - Use bitmap API instead of re-inventing the wheel on sun8i (Yangtao
   Li)

 - Remove useless NULL check in the hwmon driver (Bernard Zhao)

 - Update the current state in the cpufreq cooling device only if the
   frequency change is effective (Zhuguangqing)

 - Improve the schema validation for the rcar DT bindings (Geert
   Uytterhoeven)

 - Fix the user time unit in the documentation (Viresh Kumar)

 - Add PCI ids for Lewisburg PCH (Andres Freund)

 - Add hwmon support on amlogic (Martin Blumenstingl)

 - Fix build failure for PCH entering on in S0iX (Randy Dunlap)

 - Improve the k_* coefficient for the power allocator governor (Lukasz
   Luba)

 - Fix missing const on a sysfs attribute (Rikard Falkeborn)

 - Remove broken interrupt support on rcar to be replaced by a new one
   (Niklas Söderlund)

 - Improve the error code handling at init time on imx8mm (Fabio
   Estevam)

 - Compute interval validity once instead at each temperature reading
   iteration on acerhdf (Daniel Lezcano)

 - Add r8a779a0 support (Niklas Söderlund)

 - Add PCI ids for AlderLake PCH and mmio refactoring (Srinivas
   Pandruvada)

 - Add RFIM and mailbox support on int340x (Srinivas Pandruvada)

 - Use macro for temperature calculation on PCH (Sumeet Pawnikar)

 - Simplify return conditions at probe time on Broadcom (Zheng Yongjun)

 - Fix workload name on PCH (Srinivas Pandruvada)

 - Migrate the devfreq cooling device code to the energy model API
   (Lukasz Luba)

 - Emit a warning if the thermal_zone_device_update is called without
   the .get_temp() ops (Daniel Lezcano)

 - Add critical and hot ops for the thermal zone (Daniel Lezcano)

 - Remove notification usage when critical is reached on rcar (Daniel
   Lezcano)

 - Fix devfreq build when ENERGY_MODEL is not set (Lukasz Luba)

* tag 'thermal-v5.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/thermal/linux: (45 commits)
  thermal/drivers/devfreq_cooling: Fix the build when !ENERGY_MODEL
  thermal/drivers/rcar: Remove notification usage
  thermal/core: Add critical and hot ops
  thermal/core: Emit a warning if the thermal zone is updated without ops
  drm/panfrost: Register devfreq cooling and attempt to add Energy Model
  thermal: devfreq_cooling: remove old power model and use EM
  thermal: devfreq_cooling: add new registration functions with Energy Model
  thermal: devfreq_cooling: use a copy of device status
  thermal: devfreq_cooling: change tracing function and arguments
  thermal: int340x: processor_thermal: Correct workload type name
  thermal: broadcom: simplify the return expression of bcm2711_thermal_probe()
  thermal: intel: pch: use macro for temperature calculation
  thermal: int340x: processor_thermal: Add mailbox driver
  thermal: int340x: processor_thermal: Add RFIM driver
  thermal: int340x: processor_thermal: Add AlderLake PCI device id
  thermal: int340x: processor_thermal: Refactor MMIO interface
  thermal: rcar_gen3_thermal: Add r8a779a0 support
  dt-bindings: thermal: rcar-gen3-thermal: Add r8a779a0 support
  platform/x86/drivers/acerhdf: Check the interval value when it is set
  platform/x86/drivers/acerhdf: Use module_param_cb to set/get polling interval
  ...
parents ee249d30 4401117b
......@@ -14,18 +14,19 @@ Required properties:
- "mediatek,mt2712-thermal" : For MT2712 family of SoCs
- "mediatek,mt7622-thermal" : For MT7622 SoC
- "mediatek,mt8183-thermal" : For MT8183 family of SoCs
- "mediatek,mt8516-thermal", "mediatek,mt2701-thermal : For MT8516 family of SoCs
- reg: Address range of the thermal controller
- interrupts: IRQ for the thermal controller
- clocks, clock-names: Clocks needed for the thermal controller. required
clocks are:
"therm": Main clock needed for register access
"auxadc": The AUXADC clock
- resets: Reference to the reset controller controlling the thermal controller.
- mediatek,auxadc: A phandle to the AUXADC which the thermal controller uses
- mediatek,apmixedsys: A phandle to the APMIXEDSYS controller.
- #thermal-sensor-cells : Should be 0. See Documentation/devicetree/bindings/thermal/thermal-sensor.yaml for a description.
Optional properties:
- resets: Reference to the reset controller controlling the thermal controller.
- nvmem-cells: A phandle to the calibration data provided by a nvmem device. If
unspecified default values shall be used.
- nvmem-cell-names: Should be "calibration-data"
......
......@@ -26,13 +26,16 @@ properties:
- renesas,r8a77961-thermal # R-Car M3-W+
- renesas,r8a77965-thermal # R-Car M3-N
- renesas,r8a77980-thermal # R-Car V3H
- renesas,r8a779a0-thermal # R-Car V3U
reg:
minItems: 2
maxItems: 3
maxItems: 4
items:
- description: TSC1 registers
- description: TSC2 registers
- description: TSC3 registers
- description: TSC4 registers
interrupts:
items:
......@@ -55,12 +58,22 @@ properties:
required:
- compatible
- reg
- interrupts
- clocks
- power-domains
- resets
- "#thermal-sensor-cells"
if:
not:
properties:
compatible:
contains:
enum:
- renesas,r8a779a0-thermal
then:
required:
- interrupts
additionalProperties: false
examples:
......
......@@ -62,25 +62,35 @@ properties:
"#thermal-sensor-cells":
const: 0
if:
properties:
compatible:
contains:
enum:
- renesas,thermal-r8a73a4 # R-Mobile APE6
- renesas,thermal-r8a7779 # R-Car H1
then:
required:
- compatible
- reg
else:
required:
- compatible
- reg
- interrupts
- clocks
- power-domains
- resets
required:
- compatible
- reg
allOf:
- if:
not:
properties:
compatible:
contains:
enum:
- renesas,thermal-r8a73a4 # R-Mobile APE6
- renesas,thermal-r8a7779 # R-Car H1
then:
required:
- resets
- '#thermal-sensor-cells'
- if:
not:
properties:
compatible:
contains:
const: renesas,thermal-r8a7779 # R-Car H1
then:
required:
- interrupts
- clocks
- power-domains
additionalProperties: false
......
......@@ -654,8 +654,7 @@ stats/time_in_state_ms:
The amount of time spent by the cooling device in various cooling
states. The output will have "<state> <time>" pair in each line, which
will mean this cooling device spent <time> msec of time at <state>.
Output will have one line for each of the supported states. usertime
units here is 10mS (similar to other time exported in /proc).
Output will have one line for each of the supported states.
RO, Required
......
......@@ -138,7 +138,7 @@ int panfrost_devfreq_init(struct panfrost_device *pfdev)
}
pfdevfreq->devfreq = devfreq;
cooling = of_devfreq_cooling_register(dev->of_node, devfreq);
cooling = devfreq_cooling_em_register(devfreq, NULL);
if (IS_ERR(cooling))
DRM_DEV_INFO(dev, "Failed to register cooling device\n");
else
......
......@@ -84,8 +84,6 @@ static struct platform_device *acerhdf_dev;
module_param(kernelmode, uint, 0);
MODULE_PARM_DESC(kernelmode, "Kernel mode fan control on / off");
module_param(interval, uint, 0600);
MODULE_PARM_DESC(interval, "Polling interval of temperature check");
module_param(fanon, uint, 0600);
MODULE_PARM_DESC(fanon, "Turn the fan on above this temperature");
module_param(fanoff, uint, 0600);
......@@ -336,7 +334,10 @@ static void acerhdf_check_param(struct thermal_zone_device *thermal)
}
if (verbose)
pr_notice("interval changed to: %d\n", interval);
thermal->polling_delay = interval*1000;
if (thermal)
thermal->polling_delay = interval*1000;
prev_interval = interval;
}
}
......@@ -351,8 +352,6 @@ static int acerhdf_get_ec_temp(struct thermal_zone_device *thermal, int *t)
{
int temp, err = 0;
acerhdf_check_param(thermal);
err = acerhdf_get_temp(&temp);
if (err)
return err;
......@@ -824,3 +823,24 @@ MODULE_ALIAS("dmi:*:*Acer*:pnExtensa*5420*:");
module_init(acerhdf_init);
module_exit(acerhdf_exit);
static int interval_set_uint(const char *val, const struct kernel_param *kp)
{
int ret;
ret = param_set_uint(val, kp);
if (ret)
return ret;
acerhdf_check_param(thz_dev);
return 0;
}
static const struct kernel_param_ops interval_ops = {
.set = interval_set_uint,
.get = param_get_uint,
};
module_param_cb(interval, &interval_ops, &interval, 0600);
MODULE_PARM_DESC(interval, "Polling interval of temperature check");
......@@ -29,6 +29,7 @@
#include <linux/thermal.h>
#include "thermal_core.h"
#include "thermal_hwmon.h"
#define TSENSOR_CFG_REG1 0x4
#define TSENSOR_CFG_REG1_RSET_VBG BIT(12)
......@@ -287,6 +288,9 @@ static int amlogic_thermal_probe(struct platform_device *pdev)
return ret;
}
if (devm_thermal_add_hwmon_sysfs(pdata->tzd))
dev_warn(&pdev->dev, "Failed to add hwmon sysfs attributes\n");
ret = amlogic_thermal_initialize(pdata);
if (ret)
return ret;
......
......@@ -102,11 +102,7 @@ static int bcm2711_thermal_probe(struct platform_device *pdev)
priv->thermal = thermal;
thermal->tzp->no_hwmon = false;
ret = thermal_add_hwmon_sysfs(thermal);
if (ret)
return ret;
return 0;
return thermal_add_hwmon_sysfs(thermal);
}
static struct platform_driver bcm2711_thermal_driver = {
......
......@@ -438,13 +438,11 @@ static int cpufreq_set_cur_state(struct thermal_cooling_device *cdev,
if (cpufreq_cdev->cpufreq_state == state)
return 0;
cpufreq_cdev->cpufreq_state = state;
frequency = get_state_freq(cpufreq_cdev, state);
ret = freq_qos_update_request(&cpufreq_cdev->qos_req, frequency);
if (ret > 0) {
cpufreq_cdev->cpufreq_state = state;
cpus = cpufreq_cdev->policy->cpus;
max_capacity = arch_scale_cpu_capacity(cpumask_first(cpus));
capacity = frequency * max_capacity;
......
This diff is collapsed.
......@@ -63,6 +63,8 @@ static inline s64 div_frac(s64 x, s64 y)
* @trip_max_desired_temperature: last passive trip point of the thermal
* zone. The temperature we are
* controlling for.
* @sustainable_power: Sustainable power (heat) that this thermal zone can
* dissipate
*/
struct power_allocator_params {
bool allocated_tzp;
......@@ -70,6 +72,7 @@ struct power_allocator_params {
s32 prev_err;
int trip_switch_on;
int trip_max_desired_temperature;
u32 sustainable_power;
};
/**
......@@ -96,7 +99,10 @@ static u32 estimate_sustainable_power(struct thermal_zone_device *tz)
if (instance->trip != params->trip_max_desired_temperature)
continue;
if (power_actor_get_min_power(cdev, &min_power))
if (!cdev_is_power_actor(cdev))
continue;
if (cdev->ops->state2power(cdev, instance->upper, &min_power))
continue;
sustainable_power += min_power;
......@@ -111,26 +117,18 @@ static u32 estimate_sustainable_power(struct thermal_zone_device *tz)
* @sustainable_power: sustainable power for the thermal zone
* @trip_switch_on: trip point number for the switch on temperature
* @control_temp: target temperature for the power allocator governor
* @force: whether to force the update of the constants
*
* This function is used to update the estimation of the PID
* controller constants in struct thermal_zone_parameters.
* Sustainable power is provided in case it was estimated. The
* estimated sustainable_power should not be stored in the
* thermal_zone_parameters so it has to be passed explicitly to this
* function.
*
* If @force is not set, the values in the thermal zone's parameters
* are preserved if they are not zero. If @force is set, the values
* in thermal zone's parameters are overwritten.
*/
static void estimate_pid_constants(struct thermal_zone_device *tz,
u32 sustainable_power, int trip_switch_on,
int control_temp, bool force)
int control_temp)
{
int ret;
int switch_on_temp;
u32 temperature_threshold;
s32 k_i;
ret = tz->ops->get_trip_temp(tz, trip_switch_on, &switch_on_temp);
if (ret)
......@@ -148,22 +146,56 @@ static void estimate_pid_constants(struct thermal_zone_device *tz,
if (!temperature_threshold)
return;
if (!tz->tzp->k_po || force)
tz->tzp->k_po = int_to_frac(sustainable_power) /
temperature_threshold;
tz->tzp->k_po = int_to_frac(sustainable_power) /
temperature_threshold;
tz->tzp->k_pu = int_to_frac(2 * sustainable_power) /
temperature_threshold;
if (!tz->tzp->k_pu || force)
tz->tzp->k_pu = int_to_frac(2 * sustainable_power) /
temperature_threshold;
k_i = tz->tzp->k_pu / 10;
tz->tzp->k_i = k_i > 0 ? k_i : 1;
if (!tz->tzp->k_i || force)
tz->tzp->k_i = int_to_frac(10) / 1000;
/*
* The default for k_d and integral_cutoff is 0, so we can
* leave them as they are.
*/
}
/**
* get_sustainable_power() - Get the right sustainable power
* @tz: thermal zone for which to estimate the constants
* @params: parameters for the power allocator governor
* @control_temp: target temperature for the power allocator governor
*
* This function is used for getting the proper sustainable power value based
* on variables which might be updated by the user sysfs interface. If that
* happen the new value is going to be estimated and updated. It is also used
* after thermal zone binding, where the initial values where set to 0.
*/
static u32 get_sustainable_power(struct thermal_zone_device *tz,
struct power_allocator_params *params,
int control_temp)
{
u32 sustainable_power;
if (!tz->tzp->sustainable_power)
sustainable_power = estimate_sustainable_power(tz);
else
sustainable_power = tz->tzp->sustainable_power;
/* Check if it's init value 0 or there was update via sysfs */
if (sustainable_power != params->sustainable_power) {
estimate_pid_constants(tz, sustainable_power,
params->trip_switch_on, control_temp);
/* Do the estimation only once and make available in sysfs */
tz->tzp->sustainable_power = sustainable_power;
params->sustainable_power = sustainable_power;
}
return sustainable_power;
}
/**
* pid_controller() - PID controller
* @tz: thermal zone we are operating in
......@@ -193,14 +225,7 @@ static u32 pid_controller(struct thermal_zone_device *tz,
max_power_frac = int_to_frac(max_allocatable_power);
if (tz->tzp->sustainable_power) {
sustainable_power = tz->tzp->sustainable_power;
} else {
sustainable_power = estimate_sustainable_power(tz);
estimate_pid_constants(tz, sustainable_power,
params->trip_switch_on, control_temp,
true);
}
sustainable_power = get_sustainable_power(tz, params, control_temp);
err = control_temp - tz->temperature;
err = int_to_frac(err);
......@@ -251,6 +276,38 @@ static u32 pid_controller(struct thermal_zone_device *tz,
return power_range;
}
/**
* power_actor_set_power() - limit the maximum power a cooling device consumes
* @cdev: pointer to &thermal_cooling_device
* @instance: thermal instance to update
* @power: the power in milliwatts
*
* Set the cooling device to consume at most @power milliwatts. The limit is
* expected to be a cap at the maximum power consumption.
*
* Return: 0 on success, -EINVAL if the cooling device does not
* implement the power actor API or -E* for other failures.
*/
static int
power_actor_set_power(struct thermal_cooling_device *cdev,
struct thermal_instance *instance, u32 power)
{
unsigned long state;
int ret;
ret = cdev->ops->power2state(cdev, power, &state);
if (ret)
return ret;
instance->target = clamp_val(state, instance->lower, instance->upper);
mutex_lock(&cdev->lock);
cdev->updated = false;
mutex_unlock(&cdev->lock);
thermal_cdev_update(cdev);
return 0;
}
/**
* divvy_up_power() - divvy the allocated power between the actors
* @req_power: each actor's requested power
......@@ -398,7 +455,8 @@ static int allocate_power(struct thermal_zone_device *tz,
weighted_req_power[i] = frac_to_int(weight * req_power[i]);
if (power_actor_get_max_power(cdev, &max_power[i]))
if (cdev->ops->state2power(cdev, instance->lower,
&max_power[i]))
continue;
total_req_power += req_power[i];
......@@ -572,7 +630,7 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
if (!ret)
estimate_pid_constants(tz, tz->tzp->sustainable_power,
params->trip_switch_on,
control_temp, false);
control_temp);
}
reset_pid_controller(params);
......
......@@ -166,10 +166,11 @@ static int imx8mm_tmu_probe(struct platform_device *pdev)
&tmu->sensors[i],
&tmu_tz_ops);
if (IS_ERR(tmu->sensors[i].tzd)) {
ret = PTR_ERR(tmu->sensors[i].tzd);
dev_err(&pdev->dev,
"failed to register thermal zone sensor[%d]: %d\n",
i, ret);
return PTR_ERR(tmu->sensors[i].tzd);
goto disable_clk;
}
tmu->sensors[i].hw_id = i;
}
......@@ -184,6 +185,10 @@ static int imx8mm_tmu_probe(struct platform_device *pdev)
imx8mm_tmu_enable(tmu, true);
return 0;
disable_clk:
clk_disable_unprepare(tmu->clk);
return ret;
}
static int imx8mm_tmu_remove(struct platform_device *pdev)
......
......@@ -10,6 +10,7 @@ config INT340X_THERMAL
select ACPI_THERMAL_REL
select ACPI_FAN
select INTEL_SOC_DTS_IOSF_CORE
select PROC_THERMAL_MMIO_RAPL if X86_64 && POWERCAP
help
Newer laptops and tablets that use ACPI may have thermal sensors and
other devices with thermal control capabilities outside the core
......@@ -41,9 +42,6 @@ config INT3406_THERMAL
power consumed by display device.
config PROC_THERMAL_MMIO_RAPL
bool
depends on 64BIT
depends on POWERCAP
tristate
select INTEL_RAPL_CORE
default y
endif
......@@ -4,5 +4,8 @@ obj-$(CONFIG_INT340X_THERMAL) += int340x_thermal_zone.o
obj-$(CONFIG_INT340X_THERMAL) += int3402_thermal.o
obj-$(CONFIG_INT340X_THERMAL) += int3403_thermal.o
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device.o
obj-$(CONFIG_PROC_THERMAL_MMIO_RAPL) += processor_thermal_rapl.o
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_rfim.o
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_mbox.o
obj-$(CONFIG_INT3406_THERMAL) += int3406_thermal.o
obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* processor_thermal_device.h
* Copyright (c) 2020, Intel Corporation.
*/
#ifndef __PROCESSOR_THERMAL_DEVICE_H__
#define __PROCESSOR_THERMAL_DEVICE_H__
#include <linux/intel_rapl.h>
#define PCI_DEVICE_ID_INTEL_ADL_THERMAL 0x461d
#define PCI_DEVICE_ID_INTEL_BDW_THERMAL 0x1603
#define PCI_DEVICE_ID_INTEL_BSW_THERMAL 0x22DC
#define PCI_DEVICE_ID_INTEL_BXT0_THERMAL 0x0A8C
#define PCI_DEVICE_ID_INTEL_BXT1_THERMAL 0x1A8C
#define PCI_DEVICE_ID_INTEL_BXTX_THERMAL 0x4A8C
#define PCI_DEVICE_ID_INTEL_BXTP_THERMAL 0x5A8C
#define PCI_DEVICE_ID_INTEL_CNL_THERMAL 0x5a03
#define PCI_DEVICE_ID_INTEL_CFL_THERMAL 0x3E83
#define PCI_DEVICE_ID_INTEL_GLK_THERMAL 0x318C
#define PCI_DEVICE_ID_INTEL_HSB_THERMAL 0x0A03
#define PCI_DEVICE_ID_INTEL_ICL_THERMAL 0x8a03
#define PCI_DEVICE_ID_INTEL_JSL_THERMAL 0x4E03
#define PCI_DEVICE_ID_INTEL_SKL_THERMAL 0x1903
#define PCI_DEVICE_ID_INTEL_TGL_THERMAL 0x9A03
struct power_config {
u32 index;
u32 min_uw;
u32 max_uw;
u32 tmin_us;
u32 tmax_us;
u32 step_uw;
};
struct proc_thermal_device {
struct device *dev;
struct acpi_device *adev;
struct power_config power_limits[2];
struct int34x_thermal_zone *int340x_zone;
struct intel_soc_dts_sensors *soc_dts;
u32 mmio_feature_mask;
void __iomem *mmio_base;
};
struct rapl_mmio_regs {
u64 reg_unit;
u64 regs[RAPL_DOMAIN_MAX][RAPL_DOMAIN_REG_MAX];
int limits[RAPL_DOMAIN_MAX];
};
#define PROC_THERMAL_FEATURE_NONE 0x00
#define PROC_THERMAL_FEATURE_RAPL 0x01
#define PROC_THERMAL_FEATURE_FIVR 0x02
#define PROC_THERMAL_FEATURE_DVFS 0x04
#define PROC_THERMAL_FEATURE_MBOX 0x08
#if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
void proc_thermal_rapl_remove(void);
#else
static int __maybe_unused proc_thermal_rapl_add(struct pci_dev *pdev,
struct proc_thermal_device *proc_priv)
{
return 0;
}
static void __maybe_unused proc_thermal_rapl_remove(void)
{
}
#endif
int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
void proc_thermal_rfim_remove(struct pci_dev *pdev);
int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
void proc_thermal_mbox_remove(struct pci_dev *pdev);
#endif
// SPDX-License-Identifier: GPL-2.0-only
/*
* processor thermal device mailbox driver for Workload type hints
* Copyright (c) 2020, Intel Corporation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "processor_thermal_device.h"
#define MBOX_CMD_WORKLOAD_TYPE_READ 0x0E
#define MBOX_CMD_WORKLOAD_TYPE_WRITE 0x0F
#define MBOX_OFFSET_DATA 0x5810
#define MBOX_OFFSET_INTERFACE 0x5818
#define MBOX_BUSY_BIT 31
#define MBOX_RETRY_COUNT 100
#define MBOX_DATA_BIT_VALID 31
#define MBOX_DATA_BIT_AC_DC 30
static DEFINE_MUTEX(mbox_lock);
static int send_mbox_cmd(struct pci_dev *pdev, u8 cmd_id, u32 cmd_data, u8 *cmd_resp)
{
struct proc_thermal_device *proc_priv;
u32 retries, data;
int ret;
mutex_lock(&mbox_lock);
proc_priv = pci_get_drvdata(pdev);
/* Poll for rb bit == 0 */
retries = MBOX_RETRY_COUNT;
do {
data = readl((void __iomem *) (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE));
if (data & BIT_ULL(MBOX_BUSY_BIT)) {
ret = -EBUSY;
continue;
}
ret = 0;
break;
} while (--retries);
if (ret)
goto unlock_mbox;
if (cmd_id == MBOX_CMD_WORKLOAD_TYPE_WRITE)
writel(cmd_data, (void __iomem *) ((proc_priv->mmio_base + MBOX_OFFSET_DATA)));
/* Write command register */
data = BIT_ULL(MBOX_BUSY_BIT) | cmd_id;
writel(data, (void __iomem *) ((proc_priv->mmio_base + MBOX_OFFSET_INTERFACE)));
/* Poll for rb bit == 0 */
retries = MBOX_RETRY_COUNT;
do {
data = readl((void __iomem *) (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE));
if (data & BIT_ULL(MBOX_BUSY_BIT)) {
ret = -EBUSY;
continue;
}
if (data) {
ret = -ENXIO;
goto unlock_mbox;
}
if (cmd_id == MBOX_CMD_WORKLOAD_TYPE_READ) {
data = readl((void __iomem *) (proc_priv->mmio_base + MBOX_OFFSET_DATA));
*cmd_resp = data & 0xff;
}
ret = 0;
break;
} while (--retries);
unlock_mbox:
mutex_unlock(&mbox_lock);
return ret;
}
/* List of workload types */
static const char * const workload_types[] = {
"none",
"idle",
"semi_active",
"bursty",
"sustained",
"battery_life",
NULL
};
static ssize_t workload_available_types_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
int i = 0;
int ret = 0;
while (workload_types[i] != NULL)
ret += sprintf(&buf[ret], "%s ", workload_types[i++]);
ret += sprintf(&buf[ret], "\n");
return ret;
}
static DEVICE_ATTR_RO(workload_available_types);
static ssize_t workload_type_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct pci_dev *pdev = to_pci_dev(dev);
char str_preference[15];
u32 data = 0;
ssize_t ret;
ret = sscanf(buf, "%14s", str_preference);
if (ret != 1)
return -EINVAL;
ret = match_string(workload_types, -1, str_preference);
if (ret < 0)
return ret;
ret &= 0xff;
if (ret)
data = BIT(MBOX_DATA_BIT_VALID) | BIT(MBOX_DATA_BIT_AC_DC);
data |= ret;
ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_WRITE, data, NULL);
if (ret)
return false;
return count;
}
static ssize_t workload_type_show(struct device *dev,
struct device_attribute *attr,
char *buf)
{
struct pci_dev *pdev = to_pci_dev(dev);
u8 cmd_resp;
int ret;
ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, 0, &cmd_resp);
if (ret)
return false;
cmd_resp &= 0xff;
if (cmd_resp > ARRAY_SIZE(workload_types) - 1)
return -EINVAL;
return sprintf(buf, "%s\n", workload_types[cmd_resp]);
}
static DEVICE_ATTR_RW(workload_type);
static struct attribute *workload_req_attrs[] = {
&dev_attr_workload_available_types.attr,
&dev_attr_workload_type.attr,
NULL
};
static const struct attribute_group workload_req_attribute_group = {
.attrs = workload_req_attrs,
.name = "workload_request"
};
static bool workload_req_created;
int proc_thermal_mbox_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
{
u8 cmd_resp;
int ret;
/* Check if there is a mailbox support, if fails return success */
ret = send_mbox_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, 0, &cmd_resp);
if (ret)
return 0;
ret = sysfs_create_group(&pdev->dev.kobj, &workload_req_attribute_group);
if (ret)
return ret;
workload_req_created = true;
return 0;
}
EXPORT_SYMBOL_GPL(proc_thermal_mbox_add);
void proc_thermal_mbox_remove(struct pci_dev *pdev)
{
if (workload_req_created)
sysfs_remove_group(&pdev->dev.kobj, &workload_req_attribute_group);
workload_req_created = false;
}
EXPORT_SYMBOL_GPL(proc_thermal_mbox_remove);
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0-only
/*
* processor thermal device RFIM control
* Copyright (c) 2020, Intel Corporation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "processor_thermal_device.h"
static struct rapl_if_priv rapl_mmio_priv;
static const struct rapl_mmio_regs rapl_mmio_default = {
.reg_unit = 0x5938,
.regs[RAPL_DOMAIN_PACKAGE] = { 0x59a0, 0x593c, 0x58f0, 0, 0x5930},
.regs[RAPL_DOMAIN_DRAM] = { 0x58e0, 0x58e8, 0x58ec, 0, 0},
.limits[RAPL_DOMAIN_PACKAGE] = 2,
.limits[RAPL_DOMAIN_DRAM] = 2,
};
static int rapl_mmio_cpu_online(unsigned int cpu)
{
struct rapl_package *rp;
/* mmio rapl supports package 0 only for now */
if (topology_physical_package_id(cpu))
return 0;
rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
if (!rp) {
rp = rapl_add_package(cpu, &rapl_mmio_priv);
if (IS_ERR(rp))
return PTR_ERR(rp);
}
cpumask_set_cpu(cpu, &rp->cpumask);
return 0;
}
static int rapl_mmio_cpu_down_prep(unsigned int cpu)
{
struct rapl_package *rp;
int lead_cpu;
rp = rapl_find_package_domain(cpu, &rapl_mmio_priv);
if (!rp)
return 0;
cpumask_clear_cpu(cpu, &rp->cpumask);
lead_cpu = cpumask_first(&rp->cpumask);
if (lead_cpu >= nr_cpu_ids)
rapl_remove_package(rp);
else if (rp->lead_cpu == cpu)
rp->lead_cpu = lead_cpu;
return 0;
}
static int rapl_mmio_read_raw(int cpu, struct reg_action *ra)
{
if (!ra->reg)
return -EINVAL;
ra->value = readq((void __iomem *)ra->reg);
ra->value &= ra->mask;
return 0;
}
static int rapl_mmio_write_raw(int cpu, struct reg_action *ra)
{
u64 val;
if (!ra->reg)
return -EINVAL;
val = readq((void __iomem *)ra->reg);
val &= ~ra->mask;
val |= ra->value;
writeq(val, (void __iomem *)ra->reg);
return 0;
}
int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
{
const struct rapl_mmio_regs *rapl_regs = &rapl_mmio_default;
enum rapl_domain_reg_id reg;
enum rapl_domain_type domain;
int ret;
if (!rapl_regs)
return 0;
for (domain = RAPL_DOMAIN_PACKAGE; domain < RAPL_DOMAIN_MAX; domain++) {
for (reg = RAPL_DOMAIN_REG_LIMIT; reg < RAPL_DOMAIN_REG_MAX; reg++)
if (rapl_regs->regs[domain][reg])
rapl_mmio_priv.regs[domain][reg] =
(u64)proc_priv->mmio_base +
rapl_regs->regs[domain][reg];
rapl_mmio_priv.limits[domain] = rapl_regs->limits[domain];
}
rapl_mmio_priv.reg_unit = (u64)proc_priv->mmio_base + rapl_regs->reg_unit;
rapl_mmio_priv.read_raw = rapl_mmio_read_raw;
rapl_mmio_priv.write_raw = rapl_mmio_write_raw;
rapl_mmio_priv.control_type = powercap_register_control_type(NULL, "intel-rapl-mmio", NULL);
if (IS_ERR(rapl_mmio_priv.control_type)) {
pr_debug("failed to register powercap control_type.\n");
return PTR_ERR(rapl_mmio_priv.control_type);
}
ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "powercap/rapl:online",
rapl_mmio_cpu_online, rapl_mmio_cpu_down_prep);
if (ret < 0) {
powercap_unregister_control_type(rapl_mmio_priv.control_type);
rapl_mmio_priv.control_type = NULL;
return ret;
}
rapl_mmio_priv.pcap_rapl_online = ret;
return 0;
}
EXPORT_SYMBOL_GPL(proc_thermal_rapl_add);
void proc_thermal_rapl_remove(void)
{
if (IS_ERR_OR_NULL(rapl_mmio_priv.control_type))
return;
cpuhp_remove_state(rapl_mmio_priv.pcap_rapl_online);
powercap_unregister_control_type(rapl_mmio_priv.control_type);
}
EXPORT_SYMBOL_GPL(proc_thermal_rapl_remove);
MODULE_LICENSE("GPL v2");
// SPDX-License-Identifier: GPL-2.0-only
/*
* processor thermal device RFIM control
* Copyright (c) 2020, Intel Corporation.
*/
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/pci.h>
#include "processor_thermal_device.h"
struct mmio_reg {
int read_only;
u32 offset;
int bits;
u16 mask;
u16 shift;
};
/* These will represent sysfs attribute names */
static const char * const fivr_strings[] = {
"vco_ref_code_lo",
"vco_ref_code_hi",
"spread_spectrum_pct",
"spread_spectrum_clk_enable",
"rfi_vco_ref_code",
"fivr_fffc_rev",
NULL
};
static const struct mmio_reg tgl_fivr_mmio_regs[] = {
{ 0, 0x5A18, 3, 0x7, 12}, /* vco_ref_code_lo */
{ 0, 0x5A18, 8, 0xFF, 16}, /* vco_ref_code_hi */
{ 0, 0x5A08, 8, 0xFF, 0}, /* spread_spectrum_pct */
{ 0, 0x5A08, 1, 0x1, 8}, /* spread_spectrum_clk_enable */
{ 1, 0x5A10, 12, 0xFFF, 0}, /* rfi_vco_ref_code */
{ 1, 0x5A14, 2, 0x3, 1}, /* fivr_fffc_rev */
};
/* These will represent sysfs attribute names */
static const char * const dvfs_strings[] = {
"rfi_restriction_run_busy",
"rfi_restriction_err_code",
"rfi_restriction_data_rate",
"rfi_restriction_data_rate_base",
"ddr_data_rate_point_0",
"ddr_data_rate_point_1",
"ddr_data_rate_point_2",
"ddr_data_rate_point_3",
"rfi_disable",
NULL
};
static const struct mmio_reg adl_dvfs_mmio_regs[] = {
{ 0, 0x5A38, 1, 0x1, 31}, /* rfi_restriction_run_busy */
{ 0, 0x5A38, 7, 0x7F, 24}, /* rfi_restriction_err_code */
{ 0, 0x5A38, 8, 0xFF, 16}, /* rfi_restriction_data_rate */
{ 0, 0x5A38, 16, 0xFFFF, 0}, /* rfi_restriction_data_rate_base */
{ 0, 0x5A30, 10, 0x3FF, 0}, /* ddr_data_rate_point_0 */
{ 0, 0x5A30, 10, 0x3FF, 10}, /* ddr_data_rate_point_1 */
{ 0, 0x5A30, 10, 0x3FF, 20}, /* ddr_data_rate_point_2 */
{ 0, 0x5A30, 10, 0x3FF, 30}, /* ddr_data_rate_point_3 */
{ 0, 0x5A40, 1, 0x1, 0}, /* rfi_disable */
};
#define RFIM_SHOW(suffix, table)\
static ssize_t suffix##_show(struct device *dev,\
struct device_attribute *attr,\
char *buf)\
{\
struct proc_thermal_device *proc_priv;\
struct pci_dev *pdev = to_pci_dev(dev);\
const struct mmio_reg *mmio_regs;\
const char **match_strs;\
u32 reg_val;\
int ret;\
\
proc_priv = pci_get_drvdata(pdev);\
if (table) {\
match_strs = (const char **)dvfs_strings;\
mmio_regs = adl_dvfs_mmio_regs;\
} else { \
match_strs = (const char **)fivr_strings;\
mmio_regs = tgl_fivr_mmio_regs;\
} \
\
ret = match_string(match_strs, -1, attr->attr.name);\
if (ret < 0)\
return ret;\
reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
ret = (reg_val >> mmio_regs[ret].shift) & mmio_regs[ret].mask;\
return sprintf(buf, "%u\n", ret);\
}
#define RFIM_STORE(suffix, table)\
static ssize_t suffix##_store(struct device *dev,\
struct device_attribute *attr,\
const char *buf, size_t count)\
{\
struct proc_thermal_device *proc_priv;\
struct pci_dev *pdev = to_pci_dev(dev);\
unsigned int input;\
const char **match_strs;\
const struct mmio_reg *mmio_regs;\
int ret, err;\
u32 reg_val;\
u32 mask;\
\
proc_priv = pci_get_drvdata(pdev);\
if (table) {\
match_strs = (const char **)dvfs_strings;\
mmio_regs = adl_dvfs_mmio_regs;\
} else { \
match_strs = (const char **)fivr_strings;\
mmio_regs = tgl_fivr_mmio_regs;\
} \
\
ret = match_string(match_strs, -1, attr->attr.name);\
if (ret < 0)\
return ret;\
if (mmio_regs[ret].read_only)\
return -EPERM;\
err = kstrtouint(buf, 10, &input);\
if (err)\
return err;\
mask = GENMASK(mmio_regs[ret].shift + mmio_regs[ret].bits - 1, mmio_regs[ret].shift);\
reg_val = readl((void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
reg_val &= ~mask;\
reg_val |= (input << mmio_regs[ret].shift);\
writel(reg_val, (void __iomem *) (proc_priv->mmio_base + mmio_regs[ret].offset));\
return count;\
}
RFIM_SHOW(vco_ref_code_lo, 0)
RFIM_SHOW(vco_ref_code_hi, 0)
RFIM_SHOW(spread_spectrum_pct, 0)
RFIM_SHOW(spread_spectrum_clk_enable, 0)
RFIM_SHOW(rfi_vco_ref_code, 0)
RFIM_SHOW(fivr_fffc_rev, 0)
RFIM_STORE(vco_ref_code_lo, 0)
RFIM_STORE(vco_ref_code_hi, 0)
RFIM_STORE(spread_spectrum_pct, 0)
RFIM_STORE(spread_spectrum_clk_enable, 0)
RFIM_STORE(rfi_vco_ref_code, 0)
RFIM_STORE(fivr_fffc_rev, 0)
static DEVICE_ATTR_RW(vco_ref_code_lo);
static DEVICE_ATTR_RW(vco_ref_code_hi);
static DEVICE_ATTR_RW(spread_spectrum_pct);
static DEVICE_ATTR_RW(spread_spectrum_clk_enable);
static DEVICE_ATTR_RW(rfi_vco_ref_code);
static DEVICE_ATTR_RW(fivr_fffc_rev);
static struct attribute *fivr_attrs[] = {
&dev_attr_vco_ref_code_lo.attr,
&dev_attr_vco_ref_code_hi.attr,
&dev_attr_spread_spectrum_pct.attr,
&dev_attr_spread_spectrum_clk_enable.attr,
&dev_attr_rfi_vco_ref_code.attr,
&dev_attr_fivr_fffc_rev.attr,
NULL
};
static const struct attribute_group fivr_attribute_group = {
.attrs = fivr_attrs,
.name = "fivr"
};
RFIM_SHOW(rfi_restriction_run_busy, 1)
RFIM_SHOW(rfi_restriction_err_code, 1)
RFIM_SHOW(rfi_restriction_data_rate, 1)
RFIM_SHOW(ddr_data_rate_point_0, 1)
RFIM_SHOW(ddr_data_rate_point_1, 1)
RFIM_SHOW(ddr_data_rate_point_2, 1)
RFIM_SHOW(ddr_data_rate_point_3, 1)
RFIM_SHOW(rfi_disable, 1)
RFIM_STORE(rfi_restriction_run_busy, 1)
RFIM_STORE(rfi_restriction_err_code, 1)
RFIM_STORE(rfi_restriction_data_rate, 1)
RFIM_STORE(rfi_disable, 1)
static DEVICE_ATTR_RW(rfi_restriction_run_busy);
static DEVICE_ATTR_RW(rfi_restriction_err_code);
static DEVICE_ATTR_RW(rfi_restriction_data_rate);
static DEVICE_ATTR_RO(ddr_data_rate_point_0);
static DEVICE_ATTR_RO(ddr_data_rate_point_1);
static DEVICE_ATTR_RO(ddr_data_rate_point_2);
static DEVICE_ATTR_RO(ddr_data_rate_point_3);
static DEVICE_ATTR_RW(rfi_disable);
static struct attribute *dvfs_attrs[] = {
&dev_attr_rfi_restriction_run_busy.attr,
&dev_attr_rfi_restriction_err_code.attr,
&dev_attr_rfi_restriction_data_rate.attr,
&dev_attr_ddr_data_rate_point_0.attr,
&dev_attr_ddr_data_rate_point_1.attr,
&dev_attr_ddr_data_rate_point_2.attr,
&dev_attr_ddr_data_rate_point_3.attr,
&dev_attr_rfi_disable.attr,
NULL
};
static const struct attribute_group dvfs_attribute_group = {
.attrs = dvfs_attrs,
.name = "dvfs"
};
int proc_thermal_rfim_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
{
int ret;
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {
ret = sysfs_create_group(&pdev->dev.kobj, &fivr_attribute_group);
if (ret)
return ret;
}
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS) {
ret = sysfs_create_group(&pdev->dev.kobj, &dvfs_attribute_group);
if (ret && proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR) {
sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
return ret;
}
}
return 0;
}
EXPORT_SYMBOL_GPL(proc_thermal_rfim_add);
void proc_thermal_rfim_remove(struct pci_dev *pdev)
{
struct proc_thermal_device *proc_priv = pci_get_drvdata(pdev);
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_FIVR)
sysfs_remove_group(&pdev->dev.kobj, &fivr_attribute_group);
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
sysfs_remove_group(&pdev->dev.kobj, &dvfs_attribute_group);
}
EXPORT_SYMBOL_GPL(proc_thermal_rfim_remove);
MODULE_LICENSE("GPL v2");
......@@ -7,14 +7,16 @@
* Tushar Dave <tushar.n.dave@intel.com>
*/
#include <linux/acpi.h>
#include <linux/delay.h>
#include <linux/module.h>
#include <linux/types.h>
#include <linux/init.h>
#include <linux/pci.h>
#include <linux/acpi.h>
#include <linux/pm.h>
#include <linux/suspend.h>
#include <linux/thermal.h>
#include <linux/types.h>
#include <linux/units.h>
#include <linux/pm.h>
/* Intel PCH thermal Device IDs */
#define PCH_THERMAL_DID_HSW_1 0x9C24 /* Haswell PCH */
......@@ -26,6 +28,7 @@
#define PCH_THERMAL_DID_CNL_H 0xA379 /* CNL-H PCH */
#define PCH_THERMAL_DID_CNL_LP 0x02F9 /* CNL-LP PCH */
#define PCH_THERMAL_DID_CML_H 0X06F9 /* CML-H PCH */
#define PCH_THERMAL_DID_LWB 0xA1B1 /* Lewisburg PCH */
/* Wildcat Point-LP PCH Thermal registers */
#define WPT_TEMP 0x0000 /* Temperature */
......@@ -35,6 +38,7 @@
#define WPT_TSREL 0x0A /* Thermal Sensor Report Enable and Lock */
#define WPT_TSMIC 0x0C /* Thermal Sensor SMI Control */
#define WPT_CTT 0x0010 /* Catastrophic Trip Point */
#define WPT_TSPM 0x001C /* Thermal Sensor Power Management */
#define WPT_TAHV 0x0014 /* Thermal Alert High Value */
#define WPT_TALV 0x0018 /* Thermal Alert Low Value */
#define WPT_TL 0x00000040 /* Throttle Value */
......@@ -55,6 +59,22 @@
#define WPT_TL_T1L 0x1ff00000 /* T1 Level */
#define WPT_TL_TTEN 0x20000000 /* TT Enable */
/* Resolution of 1/2 degree C and an offset of -50C */
#define PCH_TEMP_OFFSET (-50)
#define GET_WPT_TEMP(x) ((x) * MILLIDEGREE_PER_DEGREE / 2 + WPT_TEMP_OFFSET)
#define WPT_TEMP_OFFSET (PCH_TEMP_OFFSET * MILLIDEGREE_PER_DEGREE)
#define GET_PCH_TEMP(x) (((x) / 2) + PCH_TEMP_OFFSET)
/* Amount of time for each cooling delay, 100ms by default for now */
static unsigned int delay_timeout = 100;
module_param(delay_timeout, int, 0644);
MODULE_PARM_DESC(delay_timeout, "amount of time delay for each iteration.");
/* Number of iterations for cooling delay, 10 counts by default for now */
static unsigned int delay_cnt = 10;
module_param(delay_cnt, int, 0644);
MODULE_PARM_DESC(delay_cnt, "total number of iterations for time delay.");
static char driver_name[] = "Intel PCH thermal driver";
struct pch_thermal_device {
......@@ -147,8 +167,7 @@ static int pch_wpt_init(struct pch_thermal_device *ptd, int *nr_trips)
trip_temp = readw(ptd->hw_base + WPT_CTT);
trip_temp &= 0x1FF;
if (trip_temp) {
/* Resolution of 1/2 degree C and an offset of -50C */
ptd->crt_temp = trip_temp * 1000 / 2 - 50000;
ptd->crt_temp = GET_WPT_TEMP(trip_temp);
ptd->crt_trip_id = 0;
++(*nr_trips);
}
......@@ -157,8 +176,7 @@ static int pch_wpt_init(struct pch_thermal_device *ptd, int *nr_trips)
trip_temp = readw(ptd->hw_base + WPT_PHL);
trip_temp &= 0x1FF;
if (trip_temp) {
/* Resolution of 1/2 degree C and an offset of -50C */
ptd->hot_temp = trip_temp * 1000 / 2 - 50000;
ptd->hot_temp = GET_WPT_TEMP(trip_temp);
ptd->hot_trip_id = *nr_trips;
++(*nr_trips);
}
......@@ -170,12 +188,7 @@ static int pch_wpt_init(struct pch_thermal_device *ptd, int *nr_trips)
static int pch_wpt_get_temp(struct pch_thermal_device *ptd, int *temp)
{
u16 wpt_temp;
wpt_temp = WPT_TEMP_TSR & readw(ptd->hw_base + WPT_TEMP);
/* Resolution of 1/2 degree C and an offset of -50C */
*temp = (wpt_temp * 1000 / 2 - 50000);
*temp = GET_WPT_TEMP(WPT_TEMP_TSR & readw(ptd->hw_base + WPT_TEMP));
return 0;
}
......@@ -183,13 +196,62 @@ static int pch_wpt_get_temp(struct pch_thermal_device *ptd, int *temp)
static int pch_wpt_suspend(struct pch_thermal_device *ptd)
{
u8 tsel;
u8 pch_delay_cnt = 1;
u16 pch_thr_temp, pch_cur_temp;
if (ptd->bios_enabled)
/* Shutdown the thermal sensor if it is not enabled by BIOS */
if (!ptd->bios_enabled) {
tsel = readb(ptd->hw_base + WPT_TSEL);
writeb(tsel & 0xFE, ptd->hw_base + WPT_TSEL);
return 0;
}
tsel = readb(ptd->hw_base + WPT_TSEL);
/* Do not check temperature if it is not a S0ix capable platform */
#ifdef CONFIG_ACPI
if (!(acpi_gbl_FADT.flags & ACPI_FADT_LOW_POWER_S0))
return 0;
#else
return 0;
#endif
/* Do not check temperature if it is not s2idle */
if (pm_suspend_via_firmware())
return 0;
/* Get the PCH temperature threshold value */
pch_thr_temp = GET_PCH_TEMP(WPT_TEMP_TSR & readw(ptd->hw_base + WPT_TSPM));
/* Get the PCH current temperature value */
pch_cur_temp = GET_PCH_TEMP(WPT_TEMP_TSR & readw(ptd->hw_base + WPT_TEMP));
/*
* If current PCH temperature is higher than configured PCH threshold
* value, run some delay loop with sleep to let the current temperature
* go down below the threshold value which helps to allow system enter
* lower power S0ix suspend state. Even after delay loop if PCH current
* temperature stays above threshold, notify the warning message
* which helps to indentify the reason why S0ix entry was rejected.
*/
while (pch_delay_cnt <= delay_cnt) {
if (pch_cur_temp <= pch_thr_temp)
break;
dev_warn(&ptd->pdev->dev,
"CPU-PCH current temp [%dC] higher than the threshold temp [%dC], sleep %d times for %d ms duration\n",
pch_cur_temp, pch_thr_temp, pch_delay_cnt, delay_timeout);
msleep(delay_timeout);
/* Read the PCH current temperature for next cycle. */
pch_cur_temp = GET_PCH_TEMP(WPT_TEMP_TSR & readw(ptd->hw_base + WPT_TEMP));
pch_delay_cnt++;
}
writeb(tsel & 0xFE, ptd->hw_base + WPT_TSEL);
if (pch_cur_temp > pch_thr_temp)
dev_warn(&ptd->pdev->dev,
"CPU-PCH is hot [%dC] even after delay, continue to suspend. S0ix might fail\n",
pch_cur_temp);
else
dev_info(&ptd->pdev->dev,
"CPU-PCH is cool [%dC], continue to suspend\n", pch_cur_temp);
return 0;
}
......@@ -276,6 +338,7 @@ enum board_ids {
board_skl,
board_cnl,
board_cml,
board_lwb,
};
static const struct board_info {
......@@ -301,7 +364,11 @@ static const struct board_info {
[board_cml] = {
.name = "pch_cometlake",
.ops = &pch_dev_ops_wpt,
}
},
[board_lwb] = {
.name = "pch_lewisburg",
.ops = &pch_dev_ops_wpt,
},
};
static int intel_pch_thermal_probe(struct pci_dev *pdev,
......@@ -415,6 +482,8 @@ static const struct pci_device_id intel_pch_thermal_id[] = {
.driver_data = board_cnl, },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_CML_H),
.driver_data = board_cml, },
{ PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCH_THERMAL_DID_LWB),
.driver_data = board_lwb, },
{ 0, },
};
MODULE_DEVICE_TABLE(pci, intel_pch_thermal_id);
......
......@@ -1052,7 +1052,7 @@ static int mtk_thermal_probe(struct platform_device *pdev)
return -EINVAL;
}
ret = device_reset(&pdev->dev);
ret = device_reset_optional(&pdev->dev);
if (ret)
return ret;
......
......@@ -60,13 +60,14 @@
#define MCELSIUS(temp) ((temp) * 1000)
#define GEN3_FUSE_MASK 0xFFF
#define TSC_MAX_NUM 3
#define TSC_MAX_NUM 4
/* default THCODE values if FUSEs are missing */
static const int thcodes[TSC_MAX_NUM][3] = {
{ 3397, 2800, 2221 },
{ 3393, 2795, 2216 },
{ 3389, 2805, 2237 },
{ 3415, 2694, 2195 },
};
/* Structure for thermal temperature calculation */
......@@ -188,70 +189,10 @@ static int rcar_gen3_thermal_get_temp(void *devdata, int *temp)
return 0;
}
static int rcar_gen3_thermal_mcelsius_to_temp(struct rcar_gen3_thermal_tsc *tsc,
int mcelsius)
{
int celsius, val;
celsius = DIV_ROUND_CLOSEST(mcelsius, 1000);
if (celsius <= INT_FIXPT(tsc->tj_t))
val = celsius * tsc->coef.a1 + tsc->coef.b1;
else
val = celsius * tsc->coef.a2 + tsc->coef.b2;
return INT_FIXPT(val);
}
static int rcar_gen3_thermal_update_range(struct rcar_gen3_thermal_tsc *tsc)
{
int temperature, low, high;
rcar_gen3_thermal_get_temp(tsc, &temperature);
low = temperature - MCELSIUS(1);
high = temperature + MCELSIUS(1);
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP1,
rcar_gen3_thermal_mcelsius_to_temp(tsc, low));
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQTEMP2,
rcar_gen3_thermal_mcelsius_to_temp(tsc, high));
return 0;
}
static const struct thermal_zone_of_device_ops rcar_gen3_tz_of_ops = {
.get_temp = rcar_gen3_thermal_get_temp,
};
static void rcar_thermal_irq_set(struct rcar_gen3_thermal_priv *priv, bool on)
{
unsigned int i;
u32 val = on ? IRQ_TEMPD1 | IRQ_TEMP2 : 0;
for (i = 0; i < priv->num_tscs; i++)
rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQMSK, val);
}
static irqreturn_t rcar_gen3_thermal_irq(int irq, void *data)
{
struct rcar_gen3_thermal_priv *priv = data;
u32 status;
int i;
for (i = 0; i < priv->num_tscs; i++) {
status = rcar_gen3_thermal_read(priv->tscs[i], REG_GEN3_IRQSTR);
rcar_gen3_thermal_write(priv->tscs[i], REG_GEN3_IRQSTR, 0);
if (status) {
rcar_gen3_thermal_update_range(priv->tscs[i]);
thermal_zone_device_update(priv->tscs[i]->zone,
THERMAL_EVENT_UNSPECIFIED);
}
}
return IRQ_HANDLED;
}
static const struct soc_device_attribute r8a7795es1[] = {
{ .soc_id = "r8a7795", .revision = "ES1.*" },
{ /* sentinel */ }
......@@ -268,7 +209,6 @@ static void rcar_gen3_thermal_init_r8a7795es1(struct rcar_gen3_thermal_tsc *tsc)
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0x3F);
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2);
rcar_gen3_thermal_write(tsc, REG_GEN3_CTSR,
CTSR_PONM | CTSR_AOUT | CTSR_THBGR | CTSR_VMEN);
......@@ -294,7 +234,6 @@ static void rcar_gen3_thermal_init(struct rcar_gen3_thermal_tsc *tsc)
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQCTL, 0);
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQMSK, 0);
rcar_gen3_thermal_write(tsc, REG_GEN3_IRQEN, IRQ_TEMPD1 | IRQ_TEMP2);
reg_val = rcar_gen3_thermal_read(tsc, REG_GEN3_THCTR);
reg_val |= THCTR_THSST;
......@@ -338,6 +277,10 @@ static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
.compatible = "renesas,r8a77980-thermal",
.data = &rcar_gen3_ths_tj_1,
},
{
.compatible = "renesas,r8a779a0-thermal",
.data = &rcar_gen3_ths_tj_1,
},
{},
};
MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
......@@ -345,9 +288,6 @@ MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
static int rcar_gen3_thermal_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
rcar_thermal_irq_set(priv, false);
pm_runtime_put(dev);
pm_runtime_disable(dev);
......@@ -369,8 +309,7 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
const int *rcar_gen3_ths_tj_1 = of_device_get_match_data(dev);
struct resource *res;
struct thermal_zone_device *zone;
int ret, irq, i;
char *irqname;
int ret, i;
/* default values if FUSEs are missing */
/* TODO: Read values from hardware on supported platforms */
......@@ -386,28 +325,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
platform_set_drvdata(pdev, priv);
/*
* Request 2 (of the 3 possible) IRQs, the driver only needs to
* to trigger on the low and high trip points of the current
* temp window at this point.
*/
for (i = 0; i < 2; i++) {
irq = platform_get_irq(pdev, i);
if (irq < 0)
return irq;
irqname = devm_kasprintf(dev, GFP_KERNEL, "%s:ch%d",
dev_name(dev), i);
if (!irqname)
return -ENOMEM;
ret = devm_request_threaded_irq(dev, irq, NULL,
rcar_gen3_thermal_irq,
IRQF_ONESHOT, irqname, priv);
if (ret)
return ret;
}
pm_runtime_enable(dev);
pm_runtime_get_sync(dev);
......@@ -459,8 +376,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
if (ret < 0)
goto error_unregister;
rcar_gen3_thermal_update_range(tsc);
dev_info(dev, "TSC%d: Loaded %d trip points\n", i, ret);
}
......@@ -471,8 +386,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
goto error_unregister;
}
rcar_thermal_irq_set(priv, true);
return 0;
error_unregister:
......@@ -481,15 +394,6 @@ static int rcar_gen3_thermal_probe(struct platform_device *pdev)
return ret;
}
static int __maybe_unused rcar_gen3_thermal_suspend(struct device *dev)
{
struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
rcar_thermal_irq_set(priv, false);
return 0;
}
static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev)
{
struct rcar_gen3_thermal_priv *priv = dev_get_drvdata(dev);
......@@ -499,15 +403,12 @@ static int __maybe_unused rcar_gen3_thermal_resume(struct device *dev)
struct rcar_gen3_thermal_tsc *tsc = priv->tscs[i];
priv->thermal_init(tsc);
rcar_gen3_thermal_update_range(tsc);
}
rcar_thermal_irq_set(priv, true);
return 0;
}
static SIMPLE_DEV_PM_OPS(rcar_gen3_thermal_pm_ops, rcar_gen3_thermal_suspend,
static SIMPLE_DEV_PM_OPS(rcar_gen3_thermal_pm_ops, NULL,
rcar_gen3_thermal_resume);
static struct platform_driver rcar_gen3_thermal_driver = {
......
......@@ -323,24 +323,6 @@ static int rcar_thermal_get_trip_temp(struct thermal_zone_device *zone,
return 0;
}
static int rcar_thermal_notify(struct thermal_zone_device *zone,
int trip, enum thermal_trip_type type)
{
struct rcar_thermal_priv *priv = rcar_zone_to_priv(zone);
struct device *dev = rcar_priv_to_dev(priv);
switch (type) {
case THERMAL_TRIP_CRITICAL:
/* FIXME */
dev_warn(dev, "Thermal reached to critical temperature\n");
break;
default:
break;
}
return 0;
}
static const struct thermal_zone_of_device_ops rcar_thermal_zone_of_ops = {
.get_temp = rcar_thermal_of_get_temp,
};
......@@ -349,7 +331,6 @@ static struct thermal_zone_device_ops rcar_thermal_zone_ops = {
.get_temp = rcar_thermal_get_temp,
.get_trip_type = rcar_thermal_get_trip_type,
.get_trip_temp = rcar_thermal_get_trip_temp,
.notify = rcar_thermal_notify,
};
/*
......@@ -409,16 +390,15 @@ static irqreturn_t rcar_thermal_irq(int irq, void *data)
{
struct rcar_thermal_common *common = data;
struct rcar_thermal_priv *priv;
unsigned long flags;
u32 status, mask;
spin_lock_irqsave(&common->lock, flags);
spin_lock(&common->lock);
mask = rcar_thermal_common_read(common, INTMSK);
status = rcar_thermal_common_read(common, STR);
rcar_thermal_common_write(common, STR, 0x000F0F0F & mask);
spin_unlock_irqrestore(&common->lock, flags);
spin_unlock(&common->lock);
status = status & ~mask;
......
......@@ -8,6 +8,7 @@
* Based on the work of Josef Gajdusek <atx@atx.name>
*/
#include <linux/bitmap.h>
#include <linux/clk.h>
#include <linux/device.h>
#include <linux/interrupt.h>
......@@ -74,7 +75,7 @@ struct ths_thermal_chip {
int (*calibrate)(struct ths_device *tmdev,
u16 *caldata, int callen);
int (*init)(struct ths_device *tmdev);
int (*irq_ack)(struct ths_device *tmdev);
unsigned long (*irq_ack)(struct ths_device *tmdev);
int (*calc_temp)(struct ths_device *tmdev,
int id, int reg);
};
......@@ -146,9 +147,10 @@ static const struct regmap_config config = {
.max_register = 0xfc,
};
static int sun8i_h3_irq_ack(struct ths_device *tmdev)
static unsigned long sun8i_h3_irq_ack(struct ths_device *tmdev)
{
int i, state, ret = 0;
unsigned long irq_bitmap = 0;
int i, state;
regmap_read(tmdev->regmap, SUN8I_THS_IS, &state);
......@@ -156,16 +158,17 @@ static int sun8i_h3_irq_ack(struct ths_device *tmdev)
if (state & SUN8I_THS_DATA_IRQ_STS(i)) {
regmap_write(tmdev->regmap, SUN8I_THS_IS,
SUN8I_THS_DATA_IRQ_STS(i));
ret |= BIT(i);
bitmap_set(&irq_bitmap, i, 1);
}
}
return ret;
return irq_bitmap;
}
static int sun50i_h6_irq_ack(struct ths_device *tmdev)
static unsigned long sun50i_h6_irq_ack(struct ths_device *tmdev)
{
int i, state, ret = 0;
unsigned long irq_bitmap = 0;
int i, state;
regmap_read(tmdev->regmap, SUN50I_H6_THS_DIS, &state);
......@@ -173,24 +176,22 @@ static int sun50i_h6_irq_ack(struct ths_device *tmdev)
if (state & SUN50I_H6_THS_DATA_IRQ_STS(i)) {
regmap_write(tmdev->regmap, SUN50I_H6_THS_DIS,
SUN50I_H6_THS_DATA_IRQ_STS(i));
ret |= BIT(i);
bitmap_set(&irq_bitmap, i, 1);
}
}
return ret;
return irq_bitmap;
}
static irqreturn_t sun8i_irq_thread(int irq, void *data)
{
struct ths_device *tmdev = data;
int i, state;
state = tmdev->chip->irq_ack(tmdev);
unsigned long irq_bitmap = tmdev->chip->irq_ack(tmdev);
int i;
for (i = 0; i < tmdev->chip->sensor_num; i++) {
if (state & BIT(i))
thermal_zone_device_update(tmdev->sensor[i].tzd,
THERMAL_EVENT_UNSPECIFIED);
for_each_set_bit(i, &irq_bitmap, tmdev->chip->sensor_num) {
thermal_zone_device_update(tmdev->sensor[i].tzd,
THERMAL_EVENT_UNSPECIFIED);
}
return IRQ_HANDLED;
......
......@@ -380,6 +380,25 @@ static void thermal_emergency_poweroff(void)
msecs_to_jiffies(poweroff_delay_ms));
}
void thermal_zone_device_critical(struct thermal_zone_device *tz)
{
dev_emerg(&tz->device, "%s: critical temperature reached, "
"shutting down\n", tz->type);
mutex_lock(&poweroff_lock);
if (!power_off_triggered) {
/*
* Queue a backup emergency shutdown in the event of
* orderly_poweroff failure
*/
thermal_emergency_poweroff();
orderly_poweroff(true);
power_off_triggered = true;
}
mutex_unlock(&poweroff_lock);
}
EXPORT_SYMBOL(thermal_zone_device_critical);
static void handle_critical_trips(struct thermal_zone_device *tz,
int trip, enum thermal_trip_type trip_type)
{
......@@ -396,22 +415,10 @@ static void handle_critical_trips(struct thermal_zone_device *tz,
if (tz->ops->notify)
tz->ops->notify(tz, trip, trip_type);
if (trip_type == THERMAL_TRIP_CRITICAL) {
dev_emerg(&tz->device,
"critical temperature reached (%d C), shutting down\n",
tz->temperature / 1000);
mutex_lock(&poweroff_lock);
if (!power_off_triggered) {
/*
* Queue a backup emergency shutdown in the event of
* orderly_poweroff failure
*/
thermal_emergency_poweroff();
orderly_poweroff(true);
power_off_triggered = true;
}
mutex_unlock(&poweroff_lock);
}
if (trip_type == THERMAL_TRIP_HOT && tz->ops->hot)
tz->ops->hot(tz);
else if (trip_type == THERMAL_TRIP_CRITICAL)
tz->ops->critical(tz);
}
static void handle_thermal_trip(struct thermal_zone_device *tz, int trip)
......@@ -553,7 +560,8 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
if (atomic_read(&in_suspend))
return;
if (!tz->ops->get_temp)
if (WARN_ONCE(!tz->ops->get_temp, "'%s' must not be called without "
"'get_temp' ops set\n", __func__))
return;
update_temperature(tz);
......@@ -593,94 +601,6 @@ static void thermal_zone_device_check(struct work_struct *work)
thermal_zone_device_update(tz, THERMAL_EVENT_UNSPECIFIED);
}
/*
* Power actor section: interface to power actors to estimate power
*
* Set of functions used to interact to cooling devices that know
* how to estimate their devices power consumption.
*/
/**
* power_actor_get_max_power() - get the maximum power that a cdev can consume
* @cdev: pointer to &thermal_cooling_device
* @max_power: pointer in which to store the maximum power
*
* Calculate the maximum power consumption in milliwats that the
* cooling device can currently consume and store it in @max_power.
*
* Return: 0 on success, -EINVAL if @cdev doesn't support the
* power_actor API or -E* on other error.
*/
int power_actor_get_max_power(struct thermal_cooling_device *cdev,
u32 *max_power)
{
if (!cdev_is_power_actor(cdev))
return -EINVAL;
return cdev->ops->state2power(cdev, 0, max_power);
}
/**
* power_actor_get_min_power() - get the mainimum power that a cdev can consume
* @cdev: pointer to &thermal_cooling_device
* @min_power: pointer in which to store the minimum power
*
* Calculate the minimum power consumption in milliwatts that the
* cooling device can currently consume and store it in @min_power.
*
* Return: 0 on success, -EINVAL if @cdev doesn't support the
* power_actor API or -E* on other error.
*/
int power_actor_get_min_power(struct thermal_cooling_device *cdev,
u32 *min_power)
{
unsigned long max_state;
int ret;
if (!cdev_is_power_actor(cdev))
return -EINVAL;
ret = cdev->ops->get_max_state(cdev, &max_state);
if (ret)
return ret;
return cdev->ops->state2power(cdev, max_state, min_power);
}
/**
* power_actor_set_power() - limit the maximum power a cooling device consumes
* @cdev: pointer to &thermal_cooling_device
* @instance: thermal instance to update
* @power: the power in milliwatts
*
* Set the cooling device to consume at most @power milliwatts. The limit is
* expected to be a cap at the maximum power consumption.
*
* Return: 0 on success, -EINVAL if the cooling device does not
* implement the power actor API or -E* for other failures.
*/
int power_actor_set_power(struct thermal_cooling_device *cdev,
struct thermal_instance *instance, u32 power)
{
unsigned long state;
int ret;
if (!cdev_is_power_actor(cdev))
return -EINVAL;
ret = cdev->ops->power2state(cdev, power, &state);
if (ret)
return ret;
instance->target = state;
mutex_lock(&cdev->lock);
cdev->updated = false;
mutex_unlock(&cdev->lock);
thermal_cdev_update(cdev);
return 0;
}
void thermal_zone_device_rebind_exception(struct thermal_zone_device *tz,
const char *cdev_type, size_t size)
{
......@@ -1423,6 +1343,10 @@ thermal_zone_device_register(const char *type, int trips, int mask,
tz->id = id;
strlcpy(tz->type, type, sizeof(tz->type));
if (!ops->critical)
ops->critical = thermal_zone_device_critical;
tz->ops = ops;
tz->tzp = tzp;
tz->device.class = &thermal_class;
......@@ -1446,12 +1370,9 @@ thermal_zone_device_register(const char *type, int trips, int mask,
goto release_device;
for (count = 0; count < trips; count++) {
if (tz->ops->get_trip_type(tz, count, &trip_type))
set_bit(count, &tz->trips_disabled);
if (tz->ops->get_trip_temp(tz, count, &trip_temp))
set_bit(count, &tz->trips_disabled);
/* Check for bogus trip points */
if (trip_temp == 0)
if (tz->ops->get_trip_type(tz, count, &trip_type) ||
tz->ops->get_trip_temp(tz, count, &trip_temp) ||
!trip_temp)
set_bit(count, &tz->trips_disabled);
}
......
......@@ -65,12 +65,6 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)
cdev->ops->power2state;
}
int power_actor_get_max_power(struct thermal_cooling_device *cdev,
u32 *max_power);
int power_actor_get_min_power(struct thermal_cooling_device *cdev,
u32 *min_power);
int power_actor_set_power(struct thermal_cooling_device *cdev,
struct thermal_instance *ti, u32 power);
/**
* struct thermal_trip - representation of a point in temperature domain
* @np: pointer to struct device_node that this trip point was created from
......
......@@ -206,8 +206,7 @@ int thermal_add_hwmon_sysfs(struct thermal_zone_device *tz)
if (new_hwmon_device)
hwmon_device_unregister(hwmon->device);
free_mem:
if (new_hwmon_device)
kfree(hwmon);
kfree(hwmon);
return result;
}
......
......@@ -425,7 +425,7 @@ static struct attribute *thermal_zone_dev_attrs[] = {
NULL,
};
static struct attribute_group thermal_zone_attribute_group = {
static const struct attribute_group thermal_zone_attribute_group = {
.attrs = thermal_zone_dev_attrs,
};
......@@ -434,7 +434,7 @@ static struct attribute *thermal_zone_mode_attrs[] = {
NULL,
};
static struct attribute_group thermal_zone_mode_attribute_group = {
static const struct attribute_group thermal_zone_mode_attribute_group = {
.attrs = thermal_zone_mode_attrs,
};
......@@ -468,7 +468,7 @@ static umode_t thermal_zone_passive_is_visible(struct kobject *kobj,
return 0;
}
static struct attribute_group thermal_zone_passive_attribute_group = {
static const struct attribute_group thermal_zone_passive_attribute_group = {
.attrs = thermal_zone_passive_attrs,
.is_visible = thermal_zone_passive_is_visible,
};
......
......@@ -16,17 +16,6 @@
/**
* struct devfreq_cooling_power - Devfreq cooling power ops
* @get_static_power: Take voltage, in mV, and return the static power
* in mW. If NULL, the static power is assumed
* to be 0.
* @get_dynamic_power: Take voltage, in mV, and frequency, in HZ, and
* return the dynamic power draw in mW. If NULL,
* a simple power model is used.
* @dyn_power_coeff: Coefficient for the simple dynamic power model in
* mW/(MHz mV mV).
* If get_dynamic_power() is NULL, then the
* dynamic power is calculated as
* @dyn_power_coeff * frequency * voltage^2
* @get_real_power: When this is set, the framework uses it to ask the
* device driver for the actual power.
* Some devices have more sophisticated methods
......@@ -46,14 +35,8 @@
* max total (static + dynamic) power value for each OPP.
*/
struct devfreq_cooling_power {
unsigned long (*get_static_power)(struct devfreq *devfreq,
unsigned long voltage);
unsigned long (*get_dynamic_power)(struct devfreq *devfreq,
unsigned long freq,
unsigned long voltage);
int (*get_real_power)(struct devfreq *df, u32 *power,
unsigned long freq, unsigned long voltage);
unsigned long dyn_power_coeff;
};
#ifdef CONFIG_DEVFREQ_THERMAL
......@@ -65,6 +48,9 @@ struct thermal_cooling_device *
of_devfreq_cooling_register(struct device_node *np, struct devfreq *df);
struct thermal_cooling_device *devfreq_cooling_register(struct devfreq *df);
void devfreq_cooling_unregister(struct thermal_cooling_device *dfc);
struct thermal_cooling_device *
devfreq_cooling_em_register(struct devfreq *df,
struct devfreq_cooling_power *dfc_power);
#else /* !CONFIG_DEVFREQ_THERMAL */
......@@ -87,6 +73,13 @@ devfreq_cooling_register(struct devfreq *df)
return ERR_PTR(-EINVAL);
}
static inline struct thermal_cooling_device *
devfreq_cooling_em_register(struct devfreq *df,
struct devfreq_cooling_power *dfc_power)
{
return ERR_PTR(-EINVAL);
}
static inline void
devfreq_cooling_unregister(struct thermal_cooling_device *dfc)
{
......
......@@ -79,6 +79,8 @@ struct thermal_zone_device_ops {
enum thermal_trend *);
int (*notify) (struct thermal_zone_device *, int,
enum thermal_trip_type);
void (*hot)(struct thermal_zone_device *);
void (*critical)(struct thermal_zone_device *);
};
struct thermal_cooling_device_ops {
......@@ -399,6 +401,7 @@ void thermal_cdev_update(struct thermal_cooling_device *);
void thermal_notify_framework(struct thermal_zone_device *, int);
int thermal_zone_device_enable(struct thermal_zone_device *tz);
int thermal_zone_device_disable(struct thermal_zone_device *tz);
void thermal_zone_device_critical(struct thermal_zone_device *tz);
#else
static inline struct thermal_zone_device *thermal_zone_device_register(
const char *type, int trips, int mask, void *devdata,
......
......@@ -153,31 +153,30 @@ TRACE_EVENT(thermal_power_cpu_limit,
TRACE_EVENT(thermal_power_devfreq_get_power,
TP_PROTO(struct thermal_cooling_device *cdev,
struct devfreq_dev_status *status, unsigned long freq,
u32 dynamic_power, u32 static_power, u32 power),
u32 power),
TP_ARGS(cdev, status, freq, dynamic_power, static_power, power),
TP_ARGS(cdev, status, freq, power),
TP_STRUCT__entry(
__string(type, cdev->type )
__field(unsigned long, freq )
__field(u32, load )
__field(u32, dynamic_power )
__field(u32, static_power )
__field(u32, busy_time)
__field(u32, total_time)
__field(u32, power)
),
TP_fast_assign(
__assign_str(type, cdev->type);
__entry->freq = freq;
__entry->load = (100 * status->busy_time) / status->total_time;
__entry->dynamic_power = dynamic_power;
__entry->static_power = static_power;
__entry->busy_time = status->busy_time;
__entry->total_time = status->total_time;
__entry->power = power;
),
TP_printk("type=%s freq=%lu load=%u dynamic_power=%u static_power=%u power=%u",
TP_printk("type=%s freq=%lu load=%u power=%u",
__get_str(type), __entry->freq,
__entry->load, __entry->dynamic_power, __entry->static_power,
__entry->total_time == 0 ? 0 :
(100 * __entry->busy_time) / __entry->total_time,
__entry->power)
);
......
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