Merge 4ac4677fdb ("Merge tag 'thermal-6.7-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm") into android-mainline
Steps on the way to 6.7-rc1 Change-Id: Idbab09f3a801a616fefab4abf9bb392f3bde8f69 Signed-off-by: Greg Kroah-Hartman <gregkh@google.com>
This commit is contained in:
@@ -44,6 +44,8 @@ properties:
|
||||
|
||||
local-mac-address: true
|
||||
mac-address: true
|
||||
nvmem-cells: true
|
||||
nvmem-cell-names: true
|
||||
|
||||
required:
|
||||
- compatible
|
||||
|
||||
@@ -18,7 +18,9 @@ allOf:
|
||||
properties:
|
||||
compatible:
|
||||
items:
|
||||
- const: fsl,imx8qxp-sc-thermal
|
||||
- enum:
|
||||
- fsl,imx8dxl-sc-thermal
|
||||
- fsl,imx8qxp-sc-thermal
|
||||
- const: fsl,imx-sc-thermal
|
||||
|
||||
'#thermal-sensor-cells':
|
||||
|
||||
@@ -60,6 +60,9 @@ properties:
|
||||
clocks:
|
||||
maxItems: 1
|
||||
|
||||
"#thermal-sensor-cells":
|
||||
const: 0
|
||||
|
||||
required:
|
||||
- compatible
|
||||
- interrupts
|
||||
@@ -67,6 +70,9 @@ required:
|
||||
- nvmem-cells
|
||||
- nvmem-cell-names
|
||||
|
||||
allOf:
|
||||
- $ref: thermal-sensor.yaml#
|
||||
|
||||
additionalProperties: false
|
||||
|
||||
examples:
|
||||
@@ -104,5 +110,6 @@ examples:
|
||||
nvmem-cells = <&tempmon_calib>, <&tempmon_temp_grade>;
|
||||
nvmem-cell-names = "calib", "temp_grade";
|
||||
clocks = <&clks IMX6SX_CLK_PLL3_USB_OTG>;
|
||||
#thermal-sensor-cells = <0>;
|
||||
};
|
||||
};
|
||||
|
||||
@@ -18,6 +18,7 @@ description: |
|
||||
properties:
|
||||
compatible:
|
||||
enum:
|
||||
- mediatek,mt7988-lvts-ap
|
||||
- mediatek,mt8192-lvts-ap
|
||||
- mediatek,mt8192-lvts-mcu
|
||||
- mediatek,mt8195-lvts-ap
|
||||
|
||||
@@ -68,7 +68,12 @@ properties:
|
||||
patternProperties:
|
||||
"^(light|heavy|oc1)$":
|
||||
type: object
|
||||
additionalProperties: false
|
||||
|
||||
properties:
|
||||
"#cooling-cells":
|
||||
const: 2
|
||||
|
||||
nvidia,priority:
|
||||
$ref: /schemas/types.yaml#/definitions/uint32
|
||||
minimum: 1
|
||||
|
||||
@@ -51,6 +51,7 @@ properties:
|
||||
- qcom,msm8996-tsens
|
||||
- qcom,msm8998-tsens
|
||||
- qcom,qcm2290-tsens
|
||||
- qcom,sa8775p-tsens
|
||||
- qcom,sc7180-tsens
|
||||
- qcom,sc7280-tsens
|
||||
- qcom,sc8180x-tsens
|
||||
|
||||
@@ -8,7 +8,7 @@ $schema: http://devicetree.org/meta-schemas/base.yaml#
|
||||
title: Thermal zone
|
||||
|
||||
maintainers:
|
||||
- Amit Kucheria <amitk@kernel.org>
|
||||
- Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||
|
||||
description: |
|
||||
Thermal management is achieved in devicetree by describing the sensor hardware
|
||||
|
||||
@@ -36,7 +36,9 @@ properties:
|
||||
- fsl,imxrt1170-gpt
|
||||
- const: fsl,imx6dl-gpt
|
||||
- items:
|
||||
- const: fsl,imx6ul-gpt
|
||||
- enum:
|
||||
- fsl,imx6ul-gpt
|
||||
- fsl,imx7d-gpt
|
||||
- const: fsl,imx6sx-gpt
|
||||
|
||||
reg:
|
||||
|
||||
@@ -164,6 +164,16 @@ ABI.
|
||||
``power_limit_1_tmax_us`` (RO)
|
||||
Maximum powercap sysfs constraint_1_time_window_us for Intel RAPL
|
||||
|
||||
``power_floor_status`` (RO)
|
||||
When set to 1, the power floor of the system in the current
|
||||
configuration has been reached. It needs to be reconfigured to allow
|
||||
power to be reduced any further.
|
||||
|
||||
``power_floor_enable`` (RW)
|
||||
When set to 1, enable reading and notification of the power floor
|
||||
status. Notifications are triggered for the power_floor_status
|
||||
attribute value changes.
|
||||
|
||||
:file:`/sys/bus/pci/devices/0000\:00\:04.0/`
|
||||
|
||||
``tcc_offset_degree_celsius`` (RW)
|
||||
@@ -315,3 +325,57 @@ DPTF Fan Control
|
||||
----------------------------------------
|
||||
|
||||
Refer to Documentation/admin-guide/acpi/fan_performance_states.rst
|
||||
|
||||
Workload Type Hints
|
||||
----------------------------------------
|
||||
|
||||
The firmware in Meteor Lake processor generation is capable of identifying
|
||||
workload type and passing hints regarding it to the OS. A special sysfs
|
||||
interface is provided to allow user space to obtain workload type hints from
|
||||
the firmware and control the rate at which they are provided.
|
||||
|
||||
User space can poll attribute "workload_type_index" for the current hint or
|
||||
can receive a notification whenever the value of this attribute is updated.
|
||||
|
||||
file:`/sys/bus/pci/devices/0000:00:04.0/workload_hint/`
|
||||
Segment 0, bus 0, device 4, function 0 is reserved for the processor thermal
|
||||
device on all Intel client processors. So, the above path doesn't change
|
||||
based on the processor generation.
|
||||
|
||||
``workload_hint_enable`` (RW)
|
||||
Enable firmware to send workload type hints to user space.
|
||||
|
||||
``notification_delay_ms`` (RW)
|
||||
Minimum delay in milliseconds before firmware will notify OS. This is
|
||||
for the rate control of notifications. This delay is between changing
|
||||
the workload type prediction in the firmware and notifying the OS about
|
||||
the change. The default delay is 1024 ms. The delay of 0 is invalid.
|
||||
The delay is rounded up to the nearest power of 2 to simplify firmware
|
||||
programming of the delay value. The read of notification_delay_ms
|
||||
attribute shows the effective value used.
|
||||
|
||||
``workload_type_index`` (RO)
|
||||
Predicted workload type index. User space can get notification of
|
||||
change via existing sysfs attribute change notification mechanism.
|
||||
|
||||
The supported index values and their meaning for the Meteor Lake
|
||||
processor generation are as follows:
|
||||
|
||||
0 - Idle: System performs no tasks, power and idle residency are
|
||||
consistently low for long periods of time.
|
||||
|
||||
1 – Battery Life: Power is relatively low, but the processor may
|
||||
still be actively performing a task, such as video playback for
|
||||
a long period of time.
|
||||
|
||||
2 – Sustained: Power level that is relatively high for a long period
|
||||
of time, with very few to no periods of idleness, which will
|
||||
eventually exhaust RAPL Power Limit 1 and 2.
|
||||
|
||||
3 – Bursty: Consumes a relatively constant average amount of power, but
|
||||
periods of relative idleness are interrupted by bursts of
|
||||
activity. The bursts are relatively short and the periods of
|
||||
relative idleness between them typically prevent RAPL Power
|
||||
Limit 1 from being exhausted.
|
||||
|
||||
4 – Unknown: Can't classify.
|
||||
|
||||
+1
-1
@@ -21409,8 +21409,8 @@ F: drivers/media/radio/radio-raremono.c
|
||||
THERMAL
|
||||
M: Rafael J. Wysocki <rafael@kernel.org>
|
||||
M: Daniel Lezcano <daniel.lezcano@linaro.org>
|
||||
R: Amit Kucheria <amitk@kernel.org>
|
||||
R: Zhang Rui <rui.zhang@intel.com>
|
||||
R: Lukasz Luba <lukasz.luba@arm.com>
|
||||
L: linux-pm@vger.kernel.org
|
||||
S: Supported
|
||||
Q: https://patchwork.kernel.org/project/linux-pm/list/
|
||||
|
||||
+423
-446
File diff suppressed because it is too large
Load Diff
@@ -291,11 +291,11 @@ static int amlogic_thermal_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int amlogic_thermal_remove(struct platform_device *pdev)
|
||||
static void amlogic_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct amlogic_thermal *data = platform_get_drvdata(pdev);
|
||||
|
||||
return amlogic_thermal_disable(data);
|
||||
amlogic_thermal_disable(data);
|
||||
}
|
||||
|
||||
static int __maybe_unused amlogic_thermal_suspend(struct device *dev)
|
||||
@@ -321,8 +321,8 @@ static struct platform_driver amlogic_thermal_driver = {
|
||||
.pm = &amlogic_thermal_pm_ops,
|
||||
.of_match_table = of_amlogic_thermal_match,
|
||||
},
|
||||
.probe = amlogic_thermal_probe,
|
||||
.remove = amlogic_thermal_remove,
|
||||
.probe = amlogic_thermal_probe,
|
||||
.remove_new = amlogic_thermal_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(amlogic_thermal_driver);
|
||||
|
||||
@@ -965,19 +965,17 @@ static int armada_thermal_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int armada_thermal_exit(struct platform_device *pdev)
|
||||
static void armada_thermal_exit(struct platform_device *pdev)
|
||||
{
|
||||
struct armada_drvdata *drvdata = platform_get_drvdata(pdev);
|
||||
|
||||
if (drvdata->type == LEGACY)
|
||||
thermal_zone_device_unregister(drvdata->data.tz);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver armada_thermal_driver = {
|
||||
.probe = armada_thermal_probe,
|
||||
.remove = armada_thermal_exit,
|
||||
.remove_new = armada_thermal_exit,
|
||||
.driver = {
|
||||
.name = "armada_thermal",
|
||||
.of_match_table = armada_thermal_id_table,
|
||||
|
||||
@@ -282,19 +282,17 @@ err_clk:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int bcm2835_thermal_remove(struct platform_device *pdev)
|
||||
static void bcm2835_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct bcm2835_thermal_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
debugfs_remove_recursive(data->debugfsdir);
|
||||
clk_disable_unprepare(data->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver bcm2835_thermal_driver = {
|
||||
.probe = bcm2835_thermal_probe,
|
||||
.remove = bcm2835_thermal_remove,
|
||||
.remove_new = bcm2835_thermal_remove,
|
||||
.driver = {
|
||||
.name = "bcm2835_thermal",
|
||||
.of_match_table = bcm2835_thermal_of_match_table,
|
||||
|
||||
@@ -65,13 +65,11 @@ static int ns_thermal_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ns_thermal_remove(struct platform_device *pdev)
|
||||
static void ns_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
void __iomem *pvtmon = platform_get_drvdata(pdev);
|
||||
|
||||
iounmap(pvtmon);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id ns_thermal_of_match[] = {
|
||||
@@ -82,7 +80,7 @@ MODULE_DEVICE_TABLE(of, ns_thermal_of_match);
|
||||
|
||||
static struct platform_driver ns_thermal_driver = {
|
||||
.probe = ns_thermal_probe,
|
||||
.remove = ns_thermal_remove,
|
||||
.remove_new = ns_thermal_remove,
|
||||
.driver = {
|
||||
.name = "ns-thermal",
|
||||
.of_match_table = ns_thermal_of_match,
|
||||
|
||||
@@ -239,19 +239,18 @@ err:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int da9062_thermal_remove(struct platform_device *pdev)
|
||||
static void da9062_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct da9062_thermal *thermal = platform_get_drvdata(pdev);
|
||||
|
||||
free_irq(thermal->irq, thermal);
|
||||
cancel_delayed_work_sync(&thermal->work);
|
||||
thermal_zone_device_unregister(thermal->zone);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver da9062_thermal_driver = {
|
||||
.probe = da9062_thermal_probe,
|
||||
.remove = da9062_thermal_remove,
|
||||
.remove_new = da9062_thermal_remove,
|
||||
.driver = {
|
||||
.name = "da9062-thermal",
|
||||
.of_match_table = da9062_compatible_reg_id_table,
|
||||
|
||||
@@ -158,21 +158,19 @@ static int dove_thermal_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dove_thermal_exit(struct platform_device *pdev)
|
||||
static void dove_thermal_exit(struct platform_device *pdev)
|
||||
{
|
||||
struct thermal_zone_device *dove_thermal =
|
||||
platform_get_drvdata(pdev);
|
||||
|
||||
thermal_zone_device_unregister(dove_thermal);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_DEVICE_TABLE(of, dove_thermal_id_table);
|
||||
|
||||
static struct platform_driver dove_thermal_driver = {
|
||||
.probe = dove_thermal_probe,
|
||||
.remove = dove_thermal_exit,
|
||||
.remove_new = dove_thermal_exit,
|
||||
.driver = {
|
||||
.name = "dove_thermal",
|
||||
.of_match_table = dove_thermal_id_table,
|
||||
|
||||
@@ -13,28 +13,22 @@
|
||||
|
||||
#include "thermal_core.h"
|
||||
|
||||
static int thermal_zone_trip_update(struct thermal_zone_device *tz, int trip_id)
|
||||
static int thermal_zone_trip_update(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip)
|
||||
{
|
||||
struct thermal_trip trip;
|
||||
int trip_index = thermal_zone_trip_id(tz, trip);
|
||||
struct thermal_instance *instance;
|
||||
int ret;
|
||||
|
||||
ret = __thermal_zone_get_trip(tz, trip_id, &trip);
|
||||
if (ret) {
|
||||
pr_warn_once("Failed to retrieve trip point %d\n", trip_id);
|
||||
return ret;
|
||||
}
|
||||
|
||||
if (!trip.hysteresis)
|
||||
if (!trip->hysteresis)
|
||||
dev_info_once(&tz->device,
|
||||
"Zero hysteresis value for thermal zone %s\n", tz->type);
|
||||
|
||||
dev_dbg(&tz->device, "Trip%d[temp=%d]:temp=%d:hyst=%d\n",
|
||||
trip_id, trip.temperature, tz->temperature,
|
||||
trip.hysteresis);
|
||||
trip_index, trip->temperature, tz->temperature,
|
||||
trip->hysteresis);
|
||||
|
||||
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
|
||||
if (instance->trip != trip_id)
|
||||
if (instance->trip != trip)
|
||||
continue;
|
||||
|
||||
/* in case fan is in initial state, switch the fan off */
|
||||
@@ -52,10 +46,10 @@ static int thermal_zone_trip_update(struct thermal_zone_device *tz, int trip_id)
|
||||
* enable fan when temperature exceeds trip_temp and disable
|
||||
* the fan in case it falls below trip_temp minus hysteresis
|
||||
*/
|
||||
if (instance->target == 0 && tz->temperature >= trip.temperature)
|
||||
if (instance->target == 0 && tz->temperature >= trip->temperature)
|
||||
instance->target = 1;
|
||||
else if (instance->target == 1 &&
|
||||
tz->temperature <= trip.temperature - trip.hysteresis)
|
||||
tz->temperature <= trip->temperature - trip->hysteresis)
|
||||
instance->target = 0;
|
||||
|
||||
dev_dbg(&instance->cdev->device, "target=%d\n",
|
||||
@@ -96,7 +90,8 @@ static int thermal_zone_trip_update(struct thermal_zone_device *tz, int trip_id)
|
||||
* (trip_temp - hyst) so that the fan gets turned off again.
|
||||
*
|
||||
*/
|
||||
static int bang_bang_control(struct thermal_zone_device *tz, int trip)
|
||||
static int bang_bang_control(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip)
|
||||
{
|
||||
struct thermal_instance *instance;
|
||||
int ret;
|
||||
|
||||
@@ -15,29 +15,27 @@
|
||||
|
||||
#include "thermal_core.h"
|
||||
|
||||
/**
|
||||
* get_trip_level: - obtains the current trip level for a zone
|
||||
* @tz: thermal zone device
|
||||
*/
|
||||
static int get_trip_level(struct thermal_zone_device *tz)
|
||||
{
|
||||
struct thermal_trip trip;
|
||||
int count;
|
||||
const struct thermal_trip *trip, *level_trip = NULL;
|
||||
int trip_level;
|
||||
|
||||
for (count = 0; count < tz->num_trips; count++) {
|
||||
__thermal_zone_get_trip(tz, count, &trip);
|
||||
if (tz->temperature < trip.temperature)
|
||||
for_each_trip(tz, trip) {
|
||||
if (trip->temperature >= tz->temperature)
|
||||
break;
|
||||
|
||||
level_trip = trip;
|
||||
}
|
||||
|
||||
/*
|
||||
* count > 0 only if temperature is greater than first trip
|
||||
* point, in which case, trip_point = count - 1
|
||||
*/
|
||||
if (count > 0)
|
||||
trace_thermal_zone_trip(tz, count - 1, trip.type);
|
||||
/* Bail out if the temperature is not greater than any trips. */
|
||||
if (!level_trip)
|
||||
return 0;
|
||||
|
||||
return count;
|
||||
trip_level = thermal_zone_trip_id(tz, level_trip);
|
||||
|
||||
trace_thermal_zone_trip(tz, trip_level, level_trip->type);
|
||||
|
||||
return trip_level;
|
||||
}
|
||||
|
||||
static long get_target_state(struct thermal_zone_device *tz,
|
||||
@@ -49,7 +47,7 @@ static long get_target_state(struct thermal_zone_device *tz,
|
||||
/**
|
||||
* fair_share_throttle - throttles devices associated with the given zone
|
||||
* @tz: thermal_zone_device
|
||||
* @trip: trip point index
|
||||
* @trip: trip point
|
||||
*
|
||||
* Throttling Logic: This uses three parameters to calculate the new
|
||||
* throttle state of the cooling devices associated with the given zone.
|
||||
@@ -65,7 +63,8 @@ static long get_target_state(struct thermal_zone_device *tz,
|
||||
* (Heavily assumes the trip points are in ascending order)
|
||||
* new_state of cooling device = P3 * P2 * P1
|
||||
*/
|
||||
static int fair_share_throttle(struct thermal_zone_device *tz, int trip)
|
||||
static int fair_share_throttle(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip)
|
||||
{
|
||||
struct thermal_instance *instance;
|
||||
int total_weight = 0;
|
||||
|
||||
@@ -16,8 +16,6 @@
|
||||
|
||||
#include "thermal_core.h"
|
||||
|
||||
#define INVALID_TRIP -1
|
||||
|
||||
#define FRAC_BITS 10
|
||||
#define int_to_frac(x) ((x) << FRAC_BITS)
|
||||
#define frac_to_int(x) ((x) >> FRAC_BITS)
|
||||
@@ -55,23 +53,23 @@ static inline s64 div_frac(s64 x, s64 y)
|
||||
* @err_integral: accumulated error in the PID controller.
|
||||
* @prev_err: error in the previous iteration of the PID controller.
|
||||
* Used to calculate the derivative term.
|
||||
* @sustainable_power: Sustainable power (heat) that this thermal zone can
|
||||
* dissipate
|
||||
* @trip_switch_on: first passive trip point of the thermal zone. The
|
||||
* governor switches on when this trip point is crossed.
|
||||
* If the thermal zone only has one passive trip point,
|
||||
* @trip_switch_on should be INVALID_TRIP.
|
||||
* @trip_switch_on should be NULL.
|
||||
* @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;
|
||||
s64 err_integral;
|
||||
s32 prev_err;
|
||||
int trip_switch_on;
|
||||
int trip_max_desired_temperature;
|
||||
u32 sustainable_power;
|
||||
const struct thermal_trip *trip_switch_on;
|
||||
const struct thermal_trip *trip_max_desired_temperature;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -114,24 +112,22 @@ static u32 estimate_sustainable_power(struct thermal_zone_device *tz)
|
||||
* estimate_pid_constants() - Estimate the constants for the PID controller
|
||||
* @tz: thermal zone for which to estimate the constants
|
||||
* @sustainable_power: sustainable power for the thermal zone
|
||||
* @trip_switch_on: trip point number for the switch on temperature
|
||||
* @trip_switch_on: trip point for the switch on temperature
|
||||
* @control_temp: target temperature for the power allocator governor
|
||||
*
|
||||
* This function is used to update the estimation of the PID
|
||||
* controller constants in struct thermal_zone_parameters.
|
||||
*/
|
||||
static void estimate_pid_constants(struct thermal_zone_device *tz,
|
||||
u32 sustainable_power, int trip_switch_on,
|
||||
u32 sustainable_power,
|
||||
const struct thermal_trip *trip_switch_on,
|
||||
int control_temp)
|
||||
{
|
||||
struct thermal_trip trip;
|
||||
u32 temperature_threshold = control_temp;
|
||||
int ret;
|
||||
s32 k_i;
|
||||
|
||||
ret = __thermal_zone_get_trip(tz, trip_switch_on, &trip);
|
||||
if (!ret)
|
||||
temperature_threshold -= trip.temperature;
|
||||
if (trip_switch_on)
|
||||
temperature_threshold -= trip_switch_on->temperature;
|
||||
|
||||
/*
|
||||
* estimate_pid_constants() tries to find appropriate default
|
||||
@@ -383,12 +379,13 @@ static int allocate_power(struct thermal_zone_device *tz,
|
||||
{
|
||||
struct thermal_instance *instance;
|
||||
struct power_allocator_params *params = tz->governor_data;
|
||||
const struct thermal_trip *trip_max_desired_temperature =
|
||||
params->trip_max_desired_temperature;
|
||||
u32 *req_power, *max_power, *granted_power, *extra_actor_power;
|
||||
u32 *weighted_req_power;
|
||||
u32 total_req_power, max_allocatable_power, total_weighted_req_power;
|
||||
u32 total_granted_power, power_range;
|
||||
int i, num_actors, total_weight, ret = 0;
|
||||
int trip_max_desired_temperature = params->trip_max_desired_temperature;
|
||||
|
||||
num_actors = 0;
|
||||
total_weight = 0;
|
||||
@@ -493,7 +490,7 @@ static int allocate_power(struct thermal_zone_device *tz,
|
||||
}
|
||||
|
||||
/**
|
||||
* get_governor_trips() - get the number of the two trip points that are key for this governor
|
||||
* get_governor_trips() - get the two trip points that are key for this governor
|
||||
* @tz: thermal zone to operate on
|
||||
* @params: pointer to private data for this governor
|
||||
*
|
||||
@@ -510,46 +507,36 @@ static int allocate_power(struct thermal_zone_device *tz,
|
||||
static void get_governor_trips(struct thermal_zone_device *tz,
|
||||
struct power_allocator_params *params)
|
||||
{
|
||||
int i, last_active, last_passive;
|
||||
bool found_first_passive;
|
||||
const struct thermal_trip *first_passive = NULL;
|
||||
const struct thermal_trip *last_passive = NULL;
|
||||
const struct thermal_trip *last_active = NULL;
|
||||
const struct thermal_trip *trip;
|
||||
|
||||
found_first_passive = false;
|
||||
last_active = INVALID_TRIP;
|
||||
last_passive = INVALID_TRIP;
|
||||
|
||||
for (i = 0; i < tz->num_trips; i++) {
|
||||
struct thermal_trip trip;
|
||||
int ret;
|
||||
|
||||
ret = __thermal_zone_get_trip(tz, i, &trip);
|
||||
if (ret) {
|
||||
dev_warn(&tz->device,
|
||||
"Failed to get trip point %d type: %d\n", i,
|
||||
ret);
|
||||
continue;
|
||||
}
|
||||
|
||||
if (trip.type == THERMAL_TRIP_PASSIVE) {
|
||||
if (!found_first_passive) {
|
||||
params->trip_switch_on = i;
|
||||
found_first_passive = true;
|
||||
} else {
|
||||
last_passive = i;
|
||||
for_each_trip(tz, trip) {
|
||||
switch (trip->type) {
|
||||
case THERMAL_TRIP_PASSIVE:
|
||||
if (!first_passive) {
|
||||
first_passive = trip;
|
||||
break;
|
||||
}
|
||||
} else if (trip.type == THERMAL_TRIP_ACTIVE) {
|
||||
last_active = i;
|
||||
} else {
|
||||
last_passive = trip;
|
||||
break;
|
||||
case THERMAL_TRIP_ACTIVE:
|
||||
last_active = trip;
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (last_passive != INVALID_TRIP) {
|
||||
if (last_passive) {
|
||||
params->trip_switch_on = first_passive;
|
||||
params->trip_max_desired_temperature = last_passive;
|
||||
} else if (found_first_passive) {
|
||||
params->trip_max_desired_temperature = params->trip_switch_on;
|
||||
params->trip_switch_on = INVALID_TRIP;
|
||||
} else if (first_passive) {
|
||||
params->trip_switch_on = NULL;
|
||||
params->trip_max_desired_temperature = first_passive;
|
||||
} else {
|
||||
params->trip_switch_on = INVALID_TRIP;
|
||||
params->trip_switch_on = NULL;
|
||||
params->trip_max_desired_temperature = last_active;
|
||||
}
|
||||
}
|
||||
@@ -569,7 +556,7 @@ static void allow_maximum_power(struct thermal_zone_device *tz, bool update)
|
||||
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
|
||||
struct thermal_cooling_device *cdev = instance->cdev;
|
||||
|
||||
if ((instance->trip != params->trip_max_desired_temperature) ||
|
||||
if (instance->trip != params->trip_max_desired_temperature ||
|
||||
(!cdev_is_power_actor(instance->cdev)))
|
||||
continue;
|
||||
|
||||
@@ -631,7 +618,6 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
|
||||
{
|
||||
int ret;
|
||||
struct power_allocator_params *params;
|
||||
struct thermal_trip trip;
|
||||
|
||||
ret = check_power_actors(tz);
|
||||
if (ret)
|
||||
@@ -656,13 +642,11 @@ static int power_allocator_bind(struct thermal_zone_device *tz)
|
||||
|
||||
get_governor_trips(tz, params);
|
||||
|
||||
if (tz->num_trips > 0) {
|
||||
ret = __thermal_zone_get_trip(tz, params->trip_max_desired_temperature,
|
||||
&trip);
|
||||
if (!ret)
|
||||
estimate_pid_constants(tz, tz->tzp->sustainable_power,
|
||||
params->trip_switch_on,
|
||||
trip.temperature);
|
||||
if (params->trip_max_desired_temperature) {
|
||||
int temp = params->trip_max_desired_temperature->temperature;
|
||||
|
||||
estimate_pid_constants(tz, tz->tzp->sustainable_power,
|
||||
params->trip_switch_on, temp);
|
||||
}
|
||||
|
||||
reset_pid_controller(params);
|
||||
@@ -692,11 +676,10 @@ static void power_allocator_unbind(struct thermal_zone_device *tz)
|
||||
tz->governor_data = NULL;
|
||||
}
|
||||
|
||||
static int power_allocator_throttle(struct thermal_zone_device *tz, int trip_id)
|
||||
static int power_allocator_throttle(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip)
|
||||
{
|
||||
struct power_allocator_params *params = tz->governor_data;
|
||||
struct thermal_trip trip;
|
||||
int ret;
|
||||
bool update;
|
||||
|
||||
lockdep_assert_held(&tz->lock);
|
||||
@@ -705,12 +688,12 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip_id)
|
||||
* We get called for every trip point but we only need to do
|
||||
* our calculations once
|
||||
*/
|
||||
if (trip_id != params->trip_max_desired_temperature)
|
||||
if (trip != params->trip_max_desired_temperature)
|
||||
return 0;
|
||||
|
||||
ret = __thermal_zone_get_trip(tz, params->trip_switch_on, &trip);
|
||||
if (!ret && (tz->temperature < trip.temperature)) {
|
||||
update = (tz->last_temperature >= trip.temperature);
|
||||
trip = params->trip_switch_on;
|
||||
if (trip && tz->temperature < trip->temperature) {
|
||||
update = tz->last_temperature >= trip->temperature;
|
||||
tz->passive = 0;
|
||||
reset_pid_controller(params);
|
||||
allow_maximum_power(tz, update);
|
||||
@@ -719,14 +702,7 @@ static int power_allocator_throttle(struct thermal_zone_device *tz, int trip_id)
|
||||
|
||||
tz->passive = 1;
|
||||
|
||||
ret = __thermal_zone_get_trip(tz, params->trip_max_desired_temperature, &trip);
|
||||
if (ret) {
|
||||
dev_warn(&tz->device, "Failed to get the maximum desired temperature: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
|
||||
return allocate_power(tz, trip.temperature);
|
||||
return allocate_power(tz, params->trip_max_desired_temperature->temperature);
|
||||
}
|
||||
|
||||
static struct thermal_governor thermal_gov_power_allocator = {
|
||||
|
||||
@@ -68,39 +68,27 @@ static unsigned long get_target_state(struct thermal_instance *instance,
|
||||
return next_target;
|
||||
}
|
||||
|
||||
static void update_passive_instance(struct thermal_zone_device *tz,
|
||||
enum thermal_trip_type type, int value)
|
||||
{
|
||||
/*
|
||||
* If value is +1, activate a passive instance.
|
||||
* If value is -1, deactivate a passive instance.
|
||||
*/
|
||||
if (type == THERMAL_TRIP_PASSIVE)
|
||||
tz->passive += value;
|
||||
}
|
||||
|
||||
static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip_id)
|
||||
static void thermal_zone_trip_update(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip)
|
||||
{
|
||||
int trip_id = thermal_zone_trip_id(tz, trip);
|
||||
enum thermal_trend trend;
|
||||
struct thermal_instance *instance;
|
||||
struct thermal_trip trip;
|
||||
bool throttle = false;
|
||||
int old_target;
|
||||
|
||||
__thermal_zone_get_trip(tz, trip_id, &trip);
|
||||
trend = get_tz_trend(tz, trip);
|
||||
|
||||
trend = get_tz_trend(tz, trip_id);
|
||||
|
||||
if (tz->temperature >= trip.temperature) {
|
||||
if (tz->temperature >= trip->temperature) {
|
||||
throttle = true;
|
||||
trace_thermal_zone_trip(tz, trip_id, trip.type);
|
||||
trace_thermal_zone_trip(tz, trip_id, trip->type);
|
||||
}
|
||||
|
||||
dev_dbg(&tz->device, "Trip%d[type=%d,temp=%d]:trend=%d,throttle=%d\n",
|
||||
trip_id, trip.type, trip.temperature, trend, throttle);
|
||||
trip_id, trip->type, trip->temperature, trend, throttle);
|
||||
|
||||
list_for_each_entry(instance, &tz->thermal_instances, tz_node) {
|
||||
if (instance->trip != trip_id)
|
||||
if (instance->trip != trip)
|
||||
continue;
|
||||
|
||||
old_target = instance->target;
|
||||
@@ -111,14 +99,17 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip_id
|
||||
if (instance->initialized && old_target == instance->target)
|
||||
continue;
|
||||
|
||||
/* Activate a passive thermal instance */
|
||||
if (old_target == THERMAL_NO_TARGET &&
|
||||
instance->target != THERMAL_NO_TARGET)
|
||||
update_passive_instance(tz, trip.type, 1);
|
||||
/* Deactivate a passive thermal instance */
|
||||
else if (old_target != THERMAL_NO_TARGET &&
|
||||
instance->target == THERMAL_NO_TARGET)
|
||||
update_passive_instance(tz, trip.type, -1);
|
||||
instance->target != THERMAL_NO_TARGET) {
|
||||
/* Activate a passive thermal instance */
|
||||
if (trip->type == THERMAL_TRIP_PASSIVE)
|
||||
tz->passive++;
|
||||
} else if (old_target != THERMAL_NO_TARGET &&
|
||||
instance->target == THERMAL_NO_TARGET) {
|
||||
/* Deactivate a passive thermal instance */
|
||||
if (trip->type == THERMAL_TRIP_PASSIVE)
|
||||
tz->passive--;
|
||||
}
|
||||
|
||||
instance->initialized = true;
|
||||
mutex_lock(&instance->cdev->lock);
|
||||
@@ -130,7 +121,7 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip_id
|
||||
/**
|
||||
* step_wise_throttle - throttles devices associated with the given zone
|
||||
* @tz: thermal_zone_device
|
||||
* @trip: trip point index
|
||||
* @trip: trip point
|
||||
*
|
||||
* Throttling Logic: This uses the trend of the thermal zone to throttle.
|
||||
* If the thermal zone is 'heating up' this throttles all the cooling
|
||||
@@ -138,7 +129,8 @@ static void thermal_zone_trip_update(struct thermal_zone_device *tz, int trip_id
|
||||
* step. If the zone is 'cooling down' it brings back the performance of
|
||||
* the devices by one step.
|
||||
*/
|
||||
static int step_wise_throttle(struct thermal_zone_device *tz, int trip)
|
||||
static int step_wise_throttle(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip)
|
||||
{
|
||||
struct thermal_instance *instance;
|
||||
|
||||
|
||||
@@ -25,11 +25,12 @@ static int user_space_bind(struct thermal_zone_device *tz)
|
||||
/**
|
||||
* notify_user_space - Notifies user space about thermal events
|
||||
* @tz: thermal_zone_device
|
||||
* @trip: trip point index
|
||||
* @trip: trip point
|
||||
*
|
||||
* This function notifies the user space through UEvents.
|
||||
*/
|
||||
static int notify_user_space(struct thermal_zone_device *tz, int trip)
|
||||
static int notify_user_space(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip)
|
||||
{
|
||||
char *thermal_prop[5];
|
||||
int i;
|
||||
@@ -38,7 +39,8 @@ static int notify_user_space(struct thermal_zone_device *tz, int trip)
|
||||
|
||||
thermal_prop[0] = kasprintf(GFP_KERNEL, "NAME=%s", tz->type);
|
||||
thermal_prop[1] = kasprintf(GFP_KERNEL, "TEMP=%d", tz->temperature);
|
||||
thermal_prop[2] = kasprintf(GFP_KERNEL, "TRIP=%d", trip);
|
||||
thermal_prop[2] = kasprintf(GFP_KERNEL, "TRIP=%d",
|
||||
thermal_zone_trip_id(tz, trip));
|
||||
thermal_prop[3] = kasprintf(GFP_KERNEL, "EVENT=%d", tz->notify_event);
|
||||
thermal_prop[4] = NULL;
|
||||
kobject_uevent_env(&tz->device.kobj, KOBJ_CHANGE, thermal_prop);
|
||||
|
||||
@@ -597,7 +597,7 @@ static int hisi_thermal_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hisi_thermal_remove(struct platform_device *pdev)
|
||||
static void hisi_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct hisi_thermal_data *data = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
@@ -608,8 +608,6 @@ static int hisi_thermal_remove(struct platform_device *pdev)
|
||||
hisi_thermal_toggle_sensor(sensor, false);
|
||||
data->ops->disable_sensor(sensor);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int hisi_thermal_suspend(struct device *dev)
|
||||
@@ -644,7 +642,7 @@ static struct platform_driver hisi_thermal_driver = {
|
||||
.of_match_table = of_hisi_thermal_match,
|
||||
},
|
||||
.probe = hisi_thermal_probe,
|
||||
.remove = hisi_thermal_remove,
|
||||
.remove_new = hisi_thermal_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(hisi_thermal_driver);
|
||||
|
||||
@@ -78,7 +78,7 @@
|
||||
struct thermal_soc_data {
|
||||
u32 num_sensors;
|
||||
u32 version;
|
||||
int (*get_temp)(void *, int *);
|
||||
int (*get_temp)(void *data, int *temp);
|
||||
};
|
||||
|
||||
struct tmu_sensor {
|
||||
@@ -363,7 +363,7 @@ disable_clk:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx8mm_tmu_remove(struct platform_device *pdev)
|
||||
static void imx8mm_tmu_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct imx8mm_tmu *tmu = platform_get_drvdata(pdev);
|
||||
|
||||
@@ -372,8 +372,6 @@ static int imx8mm_tmu_remove(struct platform_device *pdev)
|
||||
|
||||
clk_disable_unprepare(tmu->clk);
|
||||
platform_set_drvdata(pdev, NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct thermal_soc_data imx8mm_tmu_data = {
|
||||
@@ -401,7 +399,7 @@ static struct platform_driver imx8mm_tmu = {
|
||||
.of_match_table = imx8mm_tmu_table,
|
||||
},
|
||||
.probe = imx8mm_tmu_probe,
|
||||
.remove = imx8mm_tmu_remove,
|
||||
.remove_new = imx8mm_tmu_remove,
|
||||
};
|
||||
module_platform_driver(imx8mm_tmu);
|
||||
|
||||
|
||||
@@ -771,7 +771,7 @@ legacy_cleanup:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int imx_thermal_remove(struct platform_device *pdev)
|
||||
static void imx_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct imx_thermal_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
@@ -780,8 +780,6 @@ static int imx_thermal_remove(struct platform_device *pdev)
|
||||
|
||||
thermal_zone_device_unregister(data->tz);
|
||||
imx_thermal_unregister_legacy_cooling(data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused imx_thermal_suspend(struct device *dev)
|
||||
@@ -880,7 +878,7 @@ static struct platform_driver imx_thermal = {
|
||||
.of_match_table = of_imx_thermal_match,
|
||||
},
|
||||
.probe = imx_thermal_probe,
|
||||
.remove = imx_thermal_remove,
|
||||
.remove_new = imx_thermal_remove,
|
||||
};
|
||||
module_platform_driver(imx_thermal);
|
||||
|
||||
|
||||
@@ -10,5 +10,8 @@ obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_device_pci.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_INT340X_THERMAL) += processor_thermal_wt_req.o
|
||||
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_wt_hint.o
|
||||
obj-$(CONFIG_INT340X_THERMAL) += processor_thermal_power_floor.o
|
||||
obj-$(CONFIG_INT3406_THERMAL) += int3406_thermal.o
|
||||
obj-$(CONFIG_ACPI_THERMAL_REL) += acpi_thermal_rel.o
|
||||
|
||||
@@ -674,7 +674,7 @@ free_priv:
|
||||
return result;
|
||||
}
|
||||
|
||||
static int int3400_thermal_remove(struct platform_device *pdev)
|
||||
static void int3400_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct int3400_thermal_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
@@ -698,7 +698,6 @@ static int int3400_thermal_remove(struct platform_device *pdev)
|
||||
kfree(priv->trts);
|
||||
kfree(priv->arts);
|
||||
kfree(priv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id int3400_thermal_match[] = {
|
||||
@@ -714,7 +713,7 @@ MODULE_DEVICE_TABLE(acpi, int3400_thermal_match);
|
||||
|
||||
static struct platform_driver int3400_thermal_driver = {
|
||||
.probe = int3400_thermal_probe,
|
||||
.remove = int3400_thermal_remove,
|
||||
.remove_new = int3400_thermal_remove,
|
||||
.driver = {
|
||||
.name = "int3400 thermal",
|
||||
.acpi_match_table = ACPI_PTR(int3400_thermal_match),
|
||||
|
||||
@@ -36,11 +36,9 @@ static int int3401_add(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int int3401_remove(struct platform_device *pdev)
|
||||
static void int3401_remove(struct platform_device *pdev)
|
||||
{
|
||||
proc_thermal_remove(platform_get_drvdata(pdev));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@@ -62,7 +60,7 @@ static SIMPLE_DEV_PM_OPS(int3401_proc_thermal_pm, int3401_thermal_suspend,
|
||||
|
||||
static struct platform_driver int3401_driver = {
|
||||
.probe = int3401_add,
|
||||
.remove = int3401_remove,
|
||||
.remove_new = int3401_remove,
|
||||
.driver = {
|
||||
.name = "int3401 thermal",
|
||||
.acpi_match_table = int3401_device_ids,
|
||||
|
||||
@@ -71,15 +71,13 @@ static int int3402_thermal_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int int3402_thermal_remove(struct platform_device *pdev)
|
||||
static void int3402_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct int3402_thermal_data *d = platform_get_drvdata(pdev);
|
||||
|
||||
acpi_remove_notify_handler(d->handle,
|
||||
ACPI_DEVICE_NOTIFY, int3402_notify);
|
||||
int340x_thermal_zone_remove(d->int340x_zone);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id int3402_thermal_match[] = {
|
||||
@@ -91,7 +89,7 @@ MODULE_DEVICE_TABLE(acpi, int3402_thermal_match);
|
||||
|
||||
static struct platform_driver int3402_thermal_driver = {
|
||||
.probe = int3402_thermal_probe,
|
||||
.remove = int3402_thermal_remove,
|
||||
.remove_new = int3402_thermal_remove,
|
||||
.driver = {
|
||||
.name = "int3402 thermal",
|
||||
.acpi_match_table = int3402_thermal_match,
|
||||
|
||||
@@ -262,7 +262,7 @@ err:
|
||||
return result;
|
||||
}
|
||||
|
||||
static int int3403_remove(struct platform_device *pdev)
|
||||
static void int3403_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct int3403_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
@@ -277,8 +277,6 @@ static int int3403_remove(struct platform_device *pdev)
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id int3403_device_ids[] = {
|
||||
@@ -293,7 +291,7 @@ MODULE_DEVICE_TABLE(acpi, int3403_device_ids);
|
||||
|
||||
static struct platform_driver int3403_driver = {
|
||||
.probe = int3403_add,
|
||||
.remove = int3403_remove,
|
||||
.remove_new = int3403_remove,
|
||||
.driver = {
|
||||
.name = "int3403 thermal",
|
||||
.acpi_match_table = int3403_device_ids,
|
||||
|
||||
@@ -178,13 +178,12 @@ err:
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
static int int3406_thermal_remove(struct platform_device *pdev)
|
||||
static void int3406_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct int3406_thermal_data *d = platform_get_drvdata(pdev);
|
||||
|
||||
thermal_cooling_device_unregister(d->cooling_dev);
|
||||
kfree(d->br);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct acpi_device_id int3406_thermal_match[] = {
|
||||
@@ -196,7 +195,7 @@ MODULE_DEVICE_TABLE(acpi, int3406_thermal_match);
|
||||
|
||||
static struct platform_driver int3406_thermal_driver = {
|
||||
.probe = int3406_thermal_probe,
|
||||
.remove = int3406_thermal_remove,
|
||||
.remove_new = int3406_thermal_remove,
|
||||
.driver = {
|
||||
.name = "int3406 thermal",
|
||||
.acpi_match_table = int3406_thermal_match,
|
||||
|
||||
@@ -67,6 +67,16 @@ static struct thermal_zone_device_ops int340x_thermal_zone_ops = {
|
||||
.critical = int340x_thermal_critical,
|
||||
};
|
||||
|
||||
static inline void *int_to_trip_priv(int i)
|
||||
{
|
||||
return (void *)(long)i;
|
||||
}
|
||||
|
||||
static inline int trip_priv_to_int(const struct thermal_trip *trip)
|
||||
{
|
||||
return (long)trip->priv;
|
||||
}
|
||||
|
||||
static int int340x_thermal_read_trips(struct acpi_device *zone_adev,
|
||||
struct thermal_trip *zone_trips,
|
||||
int trip_cnt)
|
||||
@@ -101,6 +111,7 @@ static int int340x_thermal_read_trips(struct acpi_device *zone_adev,
|
||||
break;
|
||||
|
||||
zone_trips[trip_cnt].type = THERMAL_TRIP_ACTIVE;
|
||||
zone_trips[trip_cnt].priv = int_to_trip_priv(i);
|
||||
trip_cnt++;
|
||||
}
|
||||
|
||||
@@ -212,45 +223,40 @@ void int340x_thermal_zone_remove(struct int34x_thermal_zone *int34x_zone)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(int340x_thermal_zone_remove);
|
||||
|
||||
static int int340x_update_one_trip(struct thermal_trip *trip, void *arg)
|
||||
{
|
||||
struct acpi_device *zone_adev = arg;
|
||||
int temp, err;
|
||||
|
||||
switch (trip->type) {
|
||||
case THERMAL_TRIP_CRITICAL:
|
||||
err = thermal_acpi_critical_trip_temp(zone_adev, &temp);
|
||||
break;
|
||||
case THERMAL_TRIP_HOT:
|
||||
err = thermal_acpi_hot_trip_temp(zone_adev, &temp);
|
||||
break;
|
||||
case THERMAL_TRIP_PASSIVE:
|
||||
err = thermal_acpi_passive_trip_temp(zone_adev, &temp);
|
||||
break;
|
||||
case THERMAL_TRIP_ACTIVE:
|
||||
err = thermal_acpi_active_trip_temp(zone_adev,
|
||||
trip_priv_to_int(trip),
|
||||
&temp);
|
||||
break;
|
||||
default:
|
||||
err = -ENODEV;
|
||||
}
|
||||
if (err)
|
||||
temp = THERMAL_TEMP_INVALID;
|
||||
|
||||
trip->temperature = temp;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void int340x_thermal_update_trips(struct int34x_thermal_zone *int34x_zone)
|
||||
{
|
||||
struct acpi_device *zone_adev = int34x_zone->adev;
|
||||
struct thermal_trip *zone_trips = int34x_zone->trips;
|
||||
int trip_cnt = int34x_zone->zone->num_trips;
|
||||
int act_trip_nr = 0;
|
||||
int i;
|
||||
|
||||
mutex_lock(&int34x_zone->zone->lock);
|
||||
|
||||
for (i = int34x_zone->aux_trip_nr; i < trip_cnt; i++) {
|
||||
int temp, err;
|
||||
|
||||
switch (zone_trips[i].type) {
|
||||
case THERMAL_TRIP_CRITICAL:
|
||||
err = thermal_acpi_critical_trip_temp(zone_adev, &temp);
|
||||
break;
|
||||
case THERMAL_TRIP_HOT:
|
||||
err = thermal_acpi_hot_trip_temp(zone_adev, &temp);
|
||||
break;
|
||||
case THERMAL_TRIP_PASSIVE:
|
||||
err = thermal_acpi_passive_trip_temp(zone_adev, &temp);
|
||||
break;
|
||||
case THERMAL_TRIP_ACTIVE:
|
||||
err = thermal_acpi_active_trip_temp(zone_adev, act_trip_nr++,
|
||||
&temp);
|
||||
break;
|
||||
default:
|
||||
err = -ENODEV;
|
||||
}
|
||||
if (err) {
|
||||
zone_trips[i].temperature = THERMAL_TEMP_INVALID;
|
||||
continue;
|
||||
}
|
||||
|
||||
zone_trips[i].temperature = temp;
|
||||
}
|
||||
|
||||
mutex_unlock(&int34x_zone->zone->lock);
|
||||
thermal_zone_for_each_trip(int34x_zone->zone, int340x_update_one_trip,
|
||||
int34x_zone->adev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(int340x_thermal_update_trips);
|
||||
|
||||
|
||||
@@ -26,6 +26,48 @@ static ssize_t power_limit_##index##_##suffix##_show(struct device *dev, \
|
||||
(unsigned long)proc_dev->power_limits[index].suffix * 1000); \
|
||||
}
|
||||
|
||||
static ssize_t power_floor_status_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct proc_thermal_device *proc_dev = dev_get_drvdata(dev);
|
||||
int ret;
|
||||
|
||||
ret = proc_thermal_read_power_floor_status(proc_dev);
|
||||
|
||||
return sysfs_emit(buf, "%d\n", ret);
|
||||
}
|
||||
|
||||
static ssize_t power_floor_enable_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct proc_thermal_device *proc_dev = dev_get_drvdata(dev);
|
||||
bool ret;
|
||||
|
||||
ret = proc_thermal_power_floor_get_state(proc_dev);
|
||||
|
||||
return sysfs_emit(buf, "%d\n", ret);
|
||||
}
|
||||
|
||||
static ssize_t power_floor_enable_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
struct proc_thermal_device *proc_dev = dev_get_drvdata(dev);
|
||||
u8 state;
|
||||
int ret;
|
||||
|
||||
if (kstrtou8(buf, 0, &state))
|
||||
return -EINVAL;
|
||||
|
||||
ret = proc_thermal_power_floor_set_state(proc_dev, !!state);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
POWER_LIMIT_SHOW(0, min_uw)
|
||||
POWER_LIMIT_SHOW(0, max_uw)
|
||||
POWER_LIMIT_SHOW(0, step_uw)
|
||||
@@ -50,6 +92,9 @@ static DEVICE_ATTR_RO(power_limit_1_step_uw);
|
||||
static DEVICE_ATTR_RO(power_limit_1_tmin_us);
|
||||
static DEVICE_ATTR_RO(power_limit_1_tmax_us);
|
||||
|
||||
static DEVICE_ATTR_RO(power_floor_status);
|
||||
static DEVICE_ATTR_RW(power_floor_enable);
|
||||
|
||||
static struct attribute *power_limit_attrs[] = {
|
||||
&dev_attr_power_limit_0_min_uw.attr,
|
||||
&dev_attr_power_limit_1_min_uw.attr,
|
||||
@@ -61,12 +106,30 @@ static struct attribute *power_limit_attrs[] = {
|
||||
&dev_attr_power_limit_1_tmin_us.attr,
|
||||
&dev_attr_power_limit_0_tmax_us.attr,
|
||||
&dev_attr_power_limit_1_tmax_us.attr,
|
||||
&dev_attr_power_floor_status.attr,
|
||||
&dev_attr_power_floor_enable.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static umode_t power_limit_attr_visible(struct kobject *kobj, struct attribute *attr, int unused)
|
||||
{
|
||||
struct device *dev = kobj_to_dev(kobj);
|
||||
struct proc_thermal_device *proc_dev;
|
||||
|
||||
if (attr != &dev_attr_power_floor_status.attr && attr != &dev_attr_power_floor_enable.attr)
|
||||
return attr->mode;
|
||||
|
||||
proc_dev = dev_get_drvdata(dev);
|
||||
if (!proc_dev || !(proc_dev->mmio_feature_mask & PROC_THERMAL_FEATURE_POWER_FLOOR))
|
||||
return 0;
|
||||
|
||||
return attr->mode;
|
||||
}
|
||||
|
||||
static const struct attribute_group power_limit_attribute_group = {
|
||||
.attrs = power_limit_attrs,
|
||||
.name = "power_limits"
|
||||
.name = "power_limits",
|
||||
.is_visible = power_limit_attr_visible,
|
||||
};
|
||||
|
||||
static ssize_t tcc_offset_degree_celsius_show(struct device *dev,
|
||||
@@ -346,12 +409,18 @@ int proc_thermal_mmio_add(struct pci_dev *pdev,
|
||||
}
|
||||
}
|
||||
|
||||
if (feature_mask & PROC_THERMAL_FEATURE_MBOX) {
|
||||
ret = proc_thermal_mbox_add(pdev, proc_priv);
|
||||
if (feature_mask & PROC_THERMAL_FEATURE_WT_REQ) {
|
||||
ret = proc_thermal_wt_req_add(pdev, proc_priv);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add MBOX interface\n");
|
||||
goto err_rem_rfim;
|
||||
}
|
||||
} else if (feature_mask & PROC_THERMAL_FEATURE_WT_HINT) {
|
||||
ret = proc_thermal_wt_hint_add(pdev, proc_priv);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "failed to add WT Hint\n");
|
||||
goto err_rem_rfim;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
@@ -374,12 +443,18 @@ void proc_thermal_mmio_remove(struct pci_dev *pdev, struct proc_thermal_device *
|
||||
proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_DVFS)
|
||||
proc_thermal_rfim_remove(pdev);
|
||||
|
||||
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_MBOX)
|
||||
proc_thermal_mbox_remove(pdev);
|
||||
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_POWER_FLOOR)
|
||||
proc_thermal_power_floor_set_state(proc_priv, false);
|
||||
|
||||
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_WT_REQ)
|
||||
proc_thermal_wt_req_remove(pdev);
|
||||
else if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_WT_HINT)
|
||||
proc_thermal_wt_hint_remove(pdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(proc_thermal_mmio_remove);
|
||||
|
||||
MODULE_IMPORT_NS(INTEL_TCC);
|
||||
MODULE_IMPORT_NS(INT340X_THERMAL);
|
||||
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
|
||||
MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
#include <linux/intel_rapl.h>
|
||||
|
||||
#define PCI_DEVICE_ID_INTEL_ADL_THERMAL 0x461d
|
||||
#define PCI_DEVICE_ID_INTEL_ARL_S_THERMAL 0xAD03
|
||||
#define PCI_DEVICE_ID_INTEL_BDW_THERMAL 0x1603
|
||||
#define PCI_DEVICE_ID_INTEL_BSW_THERMAL 0x22DC
|
||||
|
||||
@@ -59,8 +60,10 @@ struct rapl_mmio_regs {
|
||||
#define PROC_THERMAL_FEATURE_RAPL 0x01
|
||||
#define PROC_THERMAL_FEATURE_FIVR 0x02
|
||||
#define PROC_THERMAL_FEATURE_DVFS 0x04
|
||||
#define PROC_THERMAL_FEATURE_MBOX 0x08
|
||||
#define PROC_THERMAL_FEATURE_WT_REQ 0x08
|
||||
#define PROC_THERMAL_FEATURE_DLVR 0x10
|
||||
#define PROC_THERMAL_FEATURE_WT_HINT 0x20
|
||||
#define PROC_THERMAL_FEATURE_POWER_FLOOR 0x40
|
||||
|
||||
#if IS_ENABLED(CONFIG_PROC_THERMAL_MMIO_RAPL)
|
||||
int proc_thermal_rapl_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
|
||||
@@ -80,13 +83,37 @@ static void __maybe_unused proc_thermal_rapl_remove(void)
|
||||
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);
|
||||
int proc_thermal_wt_req_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
|
||||
void proc_thermal_wt_req_remove(struct pci_dev *pdev);
|
||||
|
||||
#define MBOX_CMD_WORKLOAD_TYPE_READ 0x0E
|
||||
#define MBOX_CMD_WORKLOAD_TYPE_WRITE 0x0F
|
||||
|
||||
#define MBOX_DATA_BIT_AC_DC 30
|
||||
#define MBOX_DATA_BIT_VALID 31
|
||||
|
||||
#define SOC_WT_RES_INT_STATUS_OFFSET 0x5B18
|
||||
#define SOC_WT_RES_INT_STATUS_MASK GENMASK_ULL(3, 2)
|
||||
|
||||
int proc_thermal_read_power_floor_status(struct proc_thermal_device *proc_priv);
|
||||
int proc_thermal_power_floor_set_state(struct proc_thermal_device *proc_priv, bool enable);
|
||||
bool proc_thermal_power_floor_get_state(struct proc_thermal_device *proc_priv);
|
||||
void proc_thermal_power_floor_intr_callback(struct pci_dev *pdev,
|
||||
struct proc_thermal_device *proc_priv);
|
||||
bool proc_thermal_check_power_floor_intr(struct proc_thermal_device *proc_priv);
|
||||
|
||||
int processor_thermal_send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp);
|
||||
int processor_thermal_send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data);
|
||||
int processor_thermal_mbox_interrupt_config(struct pci_dev *pdev, bool enable, int enable_bit,
|
||||
int time_window);
|
||||
int proc_thermal_add(struct device *dev, struct proc_thermal_device *priv);
|
||||
void proc_thermal_remove(struct proc_thermal_device *proc_priv);
|
||||
|
||||
int proc_thermal_wt_hint_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
|
||||
void proc_thermal_wt_hint_remove(struct pci_dev *pdev);
|
||||
void proc_thermal_wt_intr_callback(struct pci_dev *pdev, struct proc_thermal_device *proc_priv);
|
||||
bool proc_thermal_check_wt_intr(struct proc_thermal_device *proc_priv);
|
||||
|
||||
int proc_thermal_suspend(struct device *dev);
|
||||
int proc_thermal_resume(struct device *dev);
|
||||
int proc_thermal_mmio_add(struct pci_dev *pdev,
|
||||
|
||||
@@ -15,6 +15,11 @@
|
||||
|
||||
#define DRV_NAME "proc_thermal_pci"
|
||||
|
||||
static bool use_msi;
|
||||
module_param(use_msi, bool, 0644);
|
||||
MODULE_PARM_DESC(use_msi,
|
||||
"Use PCI MSI based interrupts for processor thermal device.");
|
||||
|
||||
struct proc_thermal_pci {
|
||||
struct pci_dev *pdev;
|
||||
struct proc_thermal_device *proc_priv;
|
||||
@@ -117,20 +122,64 @@ static void pkg_thermal_schedule_work(struct delayed_work *work)
|
||||
schedule_delayed_work(work, ms);
|
||||
}
|
||||
|
||||
static void proc_thermal_clear_soc_int_status(struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
u64 status;
|
||||
|
||||
if (!(proc_priv->mmio_feature_mask &
|
||||
(PROC_THERMAL_FEATURE_WT_HINT | PROC_THERMAL_FEATURE_POWER_FLOOR)))
|
||||
return;
|
||||
|
||||
status = readq(proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET);
|
||||
writeq(status & ~SOC_WT_RES_INT_STATUS_MASK,
|
||||
proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET);
|
||||
}
|
||||
|
||||
static irqreturn_t proc_thermal_irq_thread_handler(int irq, void *devid)
|
||||
{
|
||||
struct proc_thermal_pci *pci_info = devid;
|
||||
|
||||
proc_thermal_wt_intr_callback(pci_info->pdev, pci_info->proc_priv);
|
||||
proc_thermal_power_floor_intr_callback(pci_info->pdev, pci_info->proc_priv);
|
||||
proc_thermal_clear_soc_int_status(pci_info->proc_priv);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
}
|
||||
|
||||
static irqreturn_t proc_thermal_irq_handler(int irq, void *devid)
|
||||
{
|
||||
struct proc_thermal_pci *pci_info = devid;
|
||||
struct proc_thermal_device *proc_priv;
|
||||
int ret = IRQ_HANDLED;
|
||||
u32 status;
|
||||
|
||||
proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_INT_STATUS_0, &status);
|
||||
proc_priv = pci_info->proc_priv;
|
||||
|
||||
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_WT_HINT) {
|
||||
if (proc_thermal_check_wt_intr(pci_info->proc_priv))
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
if (proc_priv->mmio_feature_mask & PROC_THERMAL_FEATURE_POWER_FLOOR) {
|
||||
if (proc_thermal_check_power_floor_intr(pci_info->proc_priv))
|
||||
ret = IRQ_WAKE_THREAD;
|
||||
}
|
||||
|
||||
/*
|
||||
* Since now there are two sources of interrupts: one from thermal threshold
|
||||
* and another from workload hint, add a check if there was really a threshold
|
||||
* interrupt before scheduling work function for thermal threshold.
|
||||
*/
|
||||
proc_thermal_mmio_read(pci_info, PROC_THERMAL_MMIO_INT_STATUS_0, &status);
|
||||
if (status) {
|
||||
/* Disable enable interrupt flag */
|
||||
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
|
||||
pkg_thermal_schedule_work(&pci_info->work);
|
||||
}
|
||||
|
||||
/* Disable enable interrupt flag */
|
||||
proc_thermal_mmio_write(pci_info, PROC_THERMAL_MMIO_INT_ENABLE_0, 0);
|
||||
pci_write_config_byte(pci_info->pdev, 0xdc, 0x01);
|
||||
|
||||
pkg_thermal_schedule_work(&pci_info->work);
|
||||
|
||||
return IRQ_HANDLED;
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int sys_get_curr_temp(struct thermal_zone_device *tzd, int *temp)
|
||||
@@ -203,6 +252,7 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
|
||||
struct proc_thermal_device *proc_priv;
|
||||
struct proc_thermal_pci *pci_info;
|
||||
int irq_flag = 0, irq, ret;
|
||||
bool msi_irq = false;
|
||||
|
||||
proc_priv = devm_kzalloc(&pdev->dev, sizeof(*proc_priv), GFP_KERNEL);
|
||||
if (!proc_priv)
|
||||
@@ -223,19 +273,19 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
|
||||
|
||||
INIT_DELAYED_WORK(&pci_info->work, proc_thermal_threshold_work_fn);
|
||||
|
||||
ret = proc_thermal_add(&pdev->dev, proc_priv);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "error: proc_thermal_add, will continue\n");
|
||||
pci_info->no_legacy = 1;
|
||||
}
|
||||
|
||||
proc_priv->priv_data = pci_info;
|
||||
pci_info->proc_priv = proc_priv;
|
||||
pci_set_drvdata(pdev, proc_priv);
|
||||
|
||||
ret = proc_thermal_mmio_add(pdev, proc_priv, id->driver_data);
|
||||
if (ret)
|
||||
goto err_ret_thermal;
|
||||
return ret;
|
||||
|
||||
ret = proc_thermal_add(&pdev->dev, proc_priv);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "error: proc_thermal_add, will continue\n");
|
||||
pci_info->no_legacy = 1;
|
||||
}
|
||||
|
||||
psv_trip.temperature = get_trip_temp(pci_info);
|
||||
|
||||
@@ -245,21 +295,26 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
|
||||
&tzone_params, 0, 0);
|
||||
if (IS_ERR(pci_info->tzone)) {
|
||||
ret = PTR_ERR(pci_info->tzone);
|
||||
goto err_ret_mmio;
|
||||
goto err_del_legacy;
|
||||
}
|
||||
|
||||
/* request and enable interrupt */
|
||||
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to allocate vectors!\n");
|
||||
goto err_ret_tzone;
|
||||
}
|
||||
if (!pdev->msi_enabled && !pdev->msix_enabled)
|
||||
if (use_msi && (pdev->msi_enabled || pdev->msix_enabled)) {
|
||||
/* request and enable interrupt */
|
||||
ret = pci_alloc_irq_vectors(pdev, 1, 1, PCI_IRQ_ALL_TYPES);
|
||||
if (ret < 0) {
|
||||
dev_err(&pdev->dev, "Failed to allocate vectors!\n");
|
||||
goto err_ret_tzone;
|
||||
}
|
||||
|
||||
irq = pci_irq_vector(pdev, 0);
|
||||
msi_irq = true;
|
||||
} else {
|
||||
irq_flag = IRQF_SHARED;
|
||||
irq = pdev->irq;
|
||||
}
|
||||
|
||||
irq = pci_irq_vector(pdev, 0);
|
||||
ret = devm_request_threaded_irq(&pdev->dev, irq,
|
||||
proc_thermal_irq_handler, NULL,
|
||||
proc_thermal_irq_handler, proc_thermal_irq_thread_handler,
|
||||
irq_flag, KBUILD_MODNAME, pci_info);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "Request IRQ %d failed\n", pdev->irq);
|
||||
@@ -273,14 +328,14 @@ static int proc_thermal_pci_probe(struct pci_dev *pdev, const struct pci_device_
|
||||
return 0;
|
||||
|
||||
err_free_vectors:
|
||||
pci_free_irq_vectors(pdev);
|
||||
if (msi_irq)
|
||||
pci_free_irq_vectors(pdev);
|
||||
err_ret_tzone:
|
||||
thermal_zone_device_unregister(pci_info->tzone);
|
||||
err_ret_mmio:
|
||||
proc_thermal_mmio_remove(pdev, proc_priv);
|
||||
err_ret_thermal:
|
||||
err_del_legacy:
|
||||
if (!pci_info->no_legacy)
|
||||
proc_thermal_remove(proc_priv);
|
||||
proc_thermal_mmio_remove(pdev, proc_priv);
|
||||
pci_disable_device(pdev);
|
||||
|
||||
return ret;
|
||||
@@ -350,9 +405,15 @@ static SIMPLE_DEV_PM_OPS(proc_thermal_pci_pm, proc_thermal_pci_suspend,
|
||||
proc_thermal_pci_resume);
|
||||
|
||||
static const struct pci_device_id proc_thermal_pci_ids[] = {
|
||||
{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) },
|
||||
{ PCI_DEVICE_DATA(INTEL, MTLP_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX | PROC_THERMAL_FEATURE_DLVR) },
|
||||
{ PCI_DEVICE_DATA(INTEL, RPL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_MBOX) },
|
||||
{ PCI_DEVICE_DATA(INTEL, ADL_THERMAL, PROC_THERMAL_FEATURE_RAPL |
|
||||
PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_WT_REQ) },
|
||||
{ PCI_DEVICE_DATA(INTEL, MTLP_THERMAL, PROC_THERMAL_FEATURE_RAPL |
|
||||
PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_DLVR |
|
||||
PROC_THERMAL_FEATURE_WT_HINT | PROC_THERMAL_FEATURE_POWER_FLOOR) },
|
||||
{ PCI_DEVICE_DATA(INTEL, ARL_S_THERMAL, PROC_THERMAL_FEATURE_RAPL |
|
||||
PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_DLVR | PROC_THERMAL_FEATURE_WT_HINT) },
|
||||
{ PCI_DEVICE_DATA(INTEL, RPL_THERMAL, PROC_THERMAL_FEATURE_RAPL |
|
||||
PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_DVFS | PROC_THERMAL_FEATURE_WT_REQ) },
|
||||
{ },
|
||||
};
|
||||
|
||||
@@ -368,6 +429,8 @@ static struct pci_driver proc_thermal_pci_driver = {
|
||||
|
||||
module_pci_driver(proc_thermal_pci_driver);
|
||||
|
||||
MODULE_IMPORT_NS(INT340X_THERMAL);
|
||||
|
||||
MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>");
|
||||
MODULE_DESCRIPTION("Processor Thermal Reporting Device Driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -137,7 +137,8 @@ static const struct pci_device_id proc_thermal_pci_ids[] = {
|
||||
{ PCI_DEVICE_DATA(INTEL, ICL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
|
||||
{ PCI_DEVICE_DATA(INTEL, JSL_THERMAL, 0) },
|
||||
{ PCI_DEVICE_DATA(INTEL, SKL_THERMAL, PROC_THERMAL_FEATURE_RAPL) },
|
||||
{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL | PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_MBOX) },
|
||||
{ PCI_DEVICE_DATA(INTEL, TGL_THERMAL, PROC_THERMAL_FEATURE_RAPL |
|
||||
PROC_THERMAL_FEATURE_FIVR | PROC_THERMAL_FEATURE_WT_REQ) },
|
||||
{ },
|
||||
};
|
||||
|
||||
|
||||
@@ -10,18 +10,12 @@
|
||||
#include <linux/io-64-nonatomic-lo-hi.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 wait_for_mbox_ready(struct proc_thermal_device *proc_priv)
|
||||
@@ -51,23 +45,16 @@ static int send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data)
|
||||
int ret;
|
||||
|
||||
proc_priv = pci_get_drvdata(pdev);
|
||||
|
||||
mutex_lock(&mbox_lock);
|
||||
|
||||
ret = wait_for_mbox_ready(proc_priv);
|
||||
if (ret)
|
||||
goto unlock_mbox;
|
||||
return ret;
|
||||
|
||||
writel(data, (proc_priv->mmio_base + MBOX_OFFSET_DATA));
|
||||
/* Write command register */
|
||||
reg_data = BIT_ULL(MBOX_BUSY_BIT) | id;
|
||||
writel(reg_data, (proc_priv->mmio_base + MBOX_OFFSET_INTERFACE));
|
||||
|
||||
ret = wait_for_mbox_ready(proc_priv);
|
||||
|
||||
unlock_mbox:
|
||||
mutex_unlock(&mbox_lock);
|
||||
return ret;
|
||||
return wait_for_mbox_ready(proc_priv);
|
||||
}
|
||||
|
||||
static int send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp)
|
||||
@@ -77,12 +64,9 @@ static int send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp)
|
||||
int ret;
|
||||
|
||||
proc_priv = pci_get_drvdata(pdev);
|
||||
|
||||
mutex_lock(&mbox_lock);
|
||||
|
||||
ret = wait_for_mbox_ready(proc_priv);
|
||||
if (ret)
|
||||
goto unlock_mbox;
|
||||
return ret;
|
||||
|
||||
/* Write command register */
|
||||
reg_data = BIT_ULL(MBOX_BUSY_BIT) | id;
|
||||
@@ -90,152 +74,85 @@ static int send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp)
|
||||
|
||||
ret = wait_for_mbox_ready(proc_priv);
|
||||
if (ret)
|
||||
goto unlock_mbox;
|
||||
return ret;
|
||||
|
||||
if (id == MBOX_CMD_WORKLOAD_TYPE_READ)
|
||||
*resp = readl(proc_priv->mmio_base + MBOX_OFFSET_DATA);
|
||||
else
|
||||
*resp = readq(proc_priv->mmio_base + MBOX_OFFSET_DATA);
|
||||
|
||||
unlock_mbox:
|
||||
mutex_unlock(&mbox_lock);
|
||||
return ret;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int processor_thermal_send_mbox_read_cmd(struct pci_dev *pdev, u16 id, u64 *resp)
|
||||
{
|
||||
return send_mbox_read_cmd(pdev, id, resp);
|
||||
int ret;
|
||||
|
||||
mutex_lock(&mbox_lock);
|
||||
ret = send_mbox_read_cmd(pdev, id, resp);
|
||||
mutex_unlock(&mbox_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_read_cmd, INT340X_THERMAL);
|
||||
|
||||
int processor_thermal_send_mbox_write_cmd(struct pci_dev *pdev, u16 id, u32 data)
|
||||
{
|
||||
return send_mbox_write_cmd(pdev, id, data);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_write_cmd, INT340X_THERMAL);
|
||||
int 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");
|
||||
mutex_lock(&mbox_lock);
|
||||
ret = send_mbox_write_cmd(pdev, id, data);
|
||||
mutex_unlock(&mbox_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(processor_thermal_send_mbox_write_cmd, INT340X_THERMAL);
|
||||
|
||||
static DEVICE_ATTR_RO(workload_available_types);
|
||||
#define MBOX_CAMARILLO_RD_INTR_CONFIG 0x1E
|
||||
#define MBOX_CAMARILLO_WR_INTR_CONFIG 0x1F
|
||||
#define WLT_TW_MASK GENMASK_ULL(30, 24)
|
||||
#define SOC_PREDICTION_TW_SHIFT 24
|
||||
|
||||
static ssize_t workload_type_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t count)
|
||||
int processor_thermal_mbox_interrupt_config(struct pci_dev *pdev, bool enable,
|
||||
int enable_bit, int time_window)
|
||||
{
|
||||
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_write_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_WRITE, data);
|
||||
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);
|
||||
u64 cmd_resp;
|
||||
u64 data;
|
||||
int ret;
|
||||
|
||||
ret = send_mbox_read_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, &cmd_resp);
|
||||
if (!pdev)
|
||||
return -ENODEV;
|
||||
|
||||
mutex_lock(&mbox_lock);
|
||||
|
||||
/* Do read modify write for MBOX_CAMARILLO_RD_INTR_CONFIG */
|
||||
|
||||
ret = send_mbox_read_cmd(pdev, MBOX_CAMARILLO_RD_INTR_CONFIG, &data);
|
||||
if (ret) {
|
||||
dev_err(&pdev->dev, "MBOX_CAMARILLO_RD_INTR_CONFIG failed\n");
|
||||
goto unlock;
|
||||
}
|
||||
|
||||
if (time_window >= 0) {
|
||||
data &= ~WLT_TW_MASK;
|
||||
|
||||
/* Program notification delay */
|
||||
data |= ((u64)time_window << SOC_PREDICTION_TW_SHIFT) & WLT_TW_MASK;
|
||||
}
|
||||
|
||||
if (enable)
|
||||
data |= BIT(enable_bit);
|
||||
else
|
||||
data &= ~BIT(enable_bit);
|
||||
|
||||
ret = send_mbox_write_cmd(pdev, MBOX_CAMARILLO_WR_INTR_CONFIG, data);
|
||||
if (ret)
|
||||
return false;
|
||||
dev_err(&pdev->dev, "MBOX_CAMARILLO_WR_INTR_CONFIG failed\n");
|
||||
|
||||
cmd_resp &= 0xff;
|
||||
unlock:
|
||||
mutex_unlock(&mbox_lock);
|
||||
|
||||
if (cmd_resp > ARRAY_SIZE(workload_types) - 1)
|
||||
return -EINVAL;
|
||||
|
||||
return sprintf(buf, "%s\n", workload_types[cmd_resp]);
|
||||
return ret;
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
u64 cmd_resp;
|
||||
int ret;
|
||||
|
||||
/* Check if there is a mailbox support, if fails return success */
|
||||
ret = send_mbox_read_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, &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);
|
||||
EXPORT_SYMBOL_NS_GPL(processor_thermal_mbox_interrupt_config, INT340X_THERMAL);
|
||||
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* Processor thermal device module for registering and processing
|
||||
* power floor. When the hardware reduces the power to the minimum
|
||||
* possible, the power floor is notified via an interrupt.
|
||||
*
|
||||
* Operation:
|
||||
* When user space enables power floor reporting:
|
||||
* - Use mailbox to:
|
||||
* Enable processor thermal device interrupt
|
||||
*
|
||||
* - Current status of power floor is read from offset 0x5B18
|
||||
* bit 39.
|
||||
*
|
||||
* Two interface functions are provided to call when there is a
|
||||
* thermal device interrupt:
|
||||
* - proc_thermal_power_floor_intr():
|
||||
* Check if the interrupt is for change in power floor.
|
||||
* Called from interrupt context.
|
||||
*
|
||||
* - proc_thermal_power_floor_intr_callback():
|
||||
* Callback for interrupt processing in thread context. This involves
|
||||
* sending notification to user space that there is a change in the
|
||||
* power floor status.
|
||||
*
|
||||
* Copyright (c) 2023, Intel Corporation.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include "processor_thermal_device.h"
|
||||
|
||||
#define SOC_POWER_FLOOR_STATUS BIT(39)
|
||||
#define SOC_POWER_FLOOR_SHIFT 39
|
||||
|
||||
#define SOC_POWER_FLOOR_INT_ENABLE_BIT 31
|
||||
#define SOC_POWER_FLOOR_INT_ACTIVE BIT(3)
|
||||
|
||||
int proc_thermal_read_power_floor_status(struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
u64 status = 0;
|
||||
|
||||
status = readq(proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET);
|
||||
return (status & SOC_POWER_FLOOR_STATUS) >> SOC_POWER_FLOOR_SHIFT;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(proc_thermal_read_power_floor_status, INT340X_THERMAL);
|
||||
|
||||
static bool enable_state;
|
||||
static DEFINE_MUTEX(pf_lock);
|
||||
|
||||
int proc_thermal_power_floor_set_state(struct proc_thermal_device *proc_priv, bool enable)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
mutex_lock(&pf_lock);
|
||||
if (enable_state == enable)
|
||||
goto pf_unlock;
|
||||
|
||||
/*
|
||||
* Time window parameter is not applicable to power floor interrupt configuration.
|
||||
* Hence use -1 for time window.
|
||||
*/
|
||||
ret = processor_thermal_mbox_interrupt_config(to_pci_dev(proc_priv->dev), enable,
|
||||
SOC_POWER_FLOOR_INT_ENABLE_BIT, -1);
|
||||
if (!ret)
|
||||
enable_state = enable;
|
||||
|
||||
pf_unlock:
|
||||
mutex_unlock(&pf_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_set_state, INT340X_THERMAL);
|
||||
|
||||
bool proc_thermal_power_floor_get_state(struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
return enable_state;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_get_state, INT340X_THERMAL);
|
||||
|
||||
/**
|
||||
* proc_thermal_check_power_floor_intr() - Check power floor interrupt.
|
||||
* @proc_priv: Processor thermal device instance.
|
||||
*
|
||||
* Callback to check if the interrupt for power floor is active.
|
||||
*
|
||||
* Context: Called from interrupt context.
|
||||
*
|
||||
* Return: true if power floor is active, false when not active.
|
||||
*/
|
||||
bool proc_thermal_check_power_floor_intr(struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
u64 int_status;
|
||||
|
||||
int_status = readq(proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET);
|
||||
return !!(int_status & SOC_POWER_FLOOR_INT_ACTIVE);
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(proc_thermal_check_power_floor_intr, INT340X_THERMAL);
|
||||
|
||||
/**
|
||||
* proc_thermal_power_floor_intr_callback() - Process power floor notification
|
||||
* @pdev: PCI device instance
|
||||
* @proc_priv: Processor thermal device instance.
|
||||
*
|
||||
* Check if the power floor interrupt is active, if active send notification to
|
||||
* user space for the attribute "power_limits", so that user can read the attribute
|
||||
* and take action.
|
||||
*
|
||||
* Context: Called from interrupt thread context.
|
||||
*
|
||||
* Return: None.
|
||||
*/
|
||||
void proc_thermal_power_floor_intr_callback(struct pci_dev *pdev,
|
||||
struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
u64 status;
|
||||
|
||||
status = readq(proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET);
|
||||
if (!(status & SOC_POWER_FLOOR_INT_ACTIVE))
|
||||
return;
|
||||
|
||||
sysfs_notify(&pdev->dev.kobj, "power_limits", "power_floor_status");
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(proc_thermal_power_floor_intr_callback, INT340X_THERMAL);
|
||||
|
||||
MODULE_IMPORT_NS(INT340X_THERMAL);
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,255 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* processor thermal device interface for reading workload type hints
|
||||
* from the user space. The hints are provided by the firmware.
|
||||
*
|
||||
* Operation:
|
||||
* When user space enables workload type prediction:
|
||||
* - Use mailbox to:
|
||||
* Configure notification delay
|
||||
* Enable processor thermal device interrupt
|
||||
*
|
||||
* - The predicted workload type can be read from MMIO:
|
||||
* Offset 0x5B18 shows if there was an interrupt
|
||||
* active for change in workload type and also
|
||||
* predicted workload type.
|
||||
*
|
||||
* Two interface functions are provided to call when there is a
|
||||
* thermal device interrupt:
|
||||
* - proc_thermal_check_wt_intr():
|
||||
* Check if the interrupt is for change in workload type. Called from
|
||||
* interrupt context.
|
||||
*
|
||||
* - proc_thermal_wt_intr_callback():
|
||||
* Callback for interrupt processing in thread context. This involves
|
||||
* sending notification to user space that there is a change in the
|
||||
* workload type.
|
||||
*
|
||||
* Copyright (c) 2023, Intel Corporation.
|
||||
*/
|
||||
|
||||
#include <linux/bitfield.h>
|
||||
#include <linux/pci.h>
|
||||
#include "processor_thermal_device.h"
|
||||
|
||||
#define SOC_WT GENMASK_ULL(47, 40)
|
||||
|
||||
#define SOC_WT_PREDICTION_INT_ENABLE_BIT 23
|
||||
|
||||
#define SOC_WT_PREDICTION_INT_ACTIVE BIT(2)
|
||||
|
||||
/*
|
||||
* Closest possible to 1 Second is 1024 ms with programmed time delay
|
||||
* of 0x0A.
|
||||
*/
|
||||
static u8 notify_delay = 0x0A;
|
||||
static u16 notify_delay_ms = 1024;
|
||||
|
||||
static DEFINE_MUTEX(wt_lock);
|
||||
static u8 wt_enable;
|
||||
|
||||
/* Show current predicted workload type index */
|
||||
static ssize_t workload_type_index_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
struct proc_thermal_device *proc_priv;
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
u64 status = 0;
|
||||
int wt;
|
||||
|
||||
mutex_lock(&wt_lock);
|
||||
if (!wt_enable) {
|
||||
mutex_unlock(&wt_lock);
|
||||
return -ENODATA;
|
||||
}
|
||||
|
||||
proc_priv = pci_get_drvdata(pdev);
|
||||
|
||||
status = readq(proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET);
|
||||
|
||||
mutex_unlock(&wt_lock);
|
||||
|
||||
wt = FIELD_GET(SOC_WT, status);
|
||||
|
||||
return sysfs_emit(buf, "%d\n", wt);
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RO(workload_type_index);
|
||||
|
||||
static ssize_t workload_hint_enable_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%d\n", wt_enable);
|
||||
}
|
||||
|
||||
static ssize_t workload_hint_enable_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
u8 mode;
|
||||
int ret;
|
||||
|
||||
if (kstrtou8(buf, 10, &mode) || mode > 1)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&wt_lock);
|
||||
|
||||
if (mode)
|
||||
ret = processor_thermal_mbox_interrupt_config(pdev, true,
|
||||
SOC_WT_PREDICTION_INT_ENABLE_BIT,
|
||||
notify_delay);
|
||||
else
|
||||
ret = processor_thermal_mbox_interrupt_config(pdev, false,
|
||||
SOC_WT_PREDICTION_INT_ENABLE_BIT, 0);
|
||||
|
||||
if (ret)
|
||||
goto ret_enable_store;
|
||||
|
||||
ret = size;
|
||||
wt_enable = mode;
|
||||
|
||||
ret_enable_store:
|
||||
mutex_unlock(&wt_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(workload_hint_enable);
|
||||
|
||||
static ssize_t notification_delay_ms_show(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
char *buf)
|
||||
{
|
||||
return sysfs_emit(buf, "%u\n", notify_delay_ms);
|
||||
}
|
||||
|
||||
static ssize_t notification_delay_ms_store(struct device *dev,
|
||||
struct device_attribute *attr,
|
||||
const char *buf, size_t size)
|
||||
{
|
||||
struct pci_dev *pdev = to_pci_dev(dev);
|
||||
u16 new_tw;
|
||||
int ret;
|
||||
u8 tm;
|
||||
|
||||
/*
|
||||
* Time window register value:
|
||||
* Formula: (1 + x/4) * power(2,y)
|
||||
* x = 2 msbs, that is [30:29] y = 5 [28:24]
|
||||
* in INTR_CONFIG register.
|
||||
* The result will be in milli seconds.
|
||||
* Here, just keep x = 0, and just change y.
|
||||
* First round up the user value to power of 2 and
|
||||
* then take log2, to get "y" value to program.
|
||||
*/
|
||||
ret = kstrtou16(buf, 10, &new_tw);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!new_tw)
|
||||
return -EINVAL;
|
||||
|
||||
new_tw = roundup_pow_of_two(new_tw);
|
||||
tm = ilog2(new_tw);
|
||||
if (tm > 31)
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&wt_lock);
|
||||
|
||||
/* If the workload hint was already enabled, then update with the new delay */
|
||||
if (wt_enable)
|
||||
ret = processor_thermal_mbox_interrupt_config(pdev, true,
|
||||
SOC_WT_PREDICTION_INT_ENABLE_BIT,
|
||||
tm);
|
||||
|
||||
if (!ret) {
|
||||
ret = size;
|
||||
notify_delay = tm;
|
||||
notify_delay_ms = new_tw;
|
||||
}
|
||||
|
||||
mutex_unlock(&wt_lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static DEVICE_ATTR_RW(notification_delay_ms);
|
||||
|
||||
static struct attribute *workload_hint_attrs[] = {
|
||||
&dev_attr_workload_type_index.attr,
|
||||
&dev_attr_workload_hint_enable.attr,
|
||||
&dev_attr_notification_delay_ms.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
static const struct attribute_group workload_hint_attribute_group = {
|
||||
.attrs = workload_hint_attrs,
|
||||
.name = "workload_hint"
|
||||
};
|
||||
|
||||
/*
|
||||
* Callback to check if the interrupt for prediction is active.
|
||||
* Caution: Called from the interrupt context.
|
||||
*/
|
||||
bool proc_thermal_check_wt_intr(struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
u64 int_status;
|
||||
|
||||
int_status = readq(proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET);
|
||||
if (int_status & SOC_WT_PREDICTION_INT_ACTIVE)
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(proc_thermal_check_wt_intr, INT340X_THERMAL);
|
||||
|
||||
/* Callback to notify user space */
|
||||
void proc_thermal_wt_intr_callback(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
u64 status;
|
||||
|
||||
status = readq(proc_priv->mmio_base + SOC_WT_RES_INT_STATUS_OFFSET);
|
||||
if (!(status & SOC_WT_PREDICTION_INT_ACTIVE))
|
||||
return;
|
||||
|
||||
sysfs_notify(&pdev->dev.kobj, "workload_hint", "workload_type_index");
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(proc_thermal_wt_intr_callback, INT340X_THERMAL);
|
||||
|
||||
static bool workload_hint_created;
|
||||
|
||||
int proc_thermal_wt_hint_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = sysfs_create_group(&pdev->dev.kobj, &workload_hint_attribute_group);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
workload_hint_created = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(proc_thermal_wt_hint_add, INT340X_THERMAL);
|
||||
|
||||
void proc_thermal_wt_hint_remove(struct pci_dev *pdev)
|
||||
{
|
||||
mutex_lock(&wt_lock);
|
||||
if (wt_enable)
|
||||
processor_thermal_mbox_interrupt_config(pdev, false,
|
||||
SOC_WT_PREDICTION_INT_ENABLE_BIT,
|
||||
0);
|
||||
mutex_unlock(&wt_lock);
|
||||
|
||||
if (workload_hint_created)
|
||||
sysfs_remove_group(&pdev->dev.kobj, &workload_hint_attribute_group);
|
||||
|
||||
workload_hint_created = false;
|
||||
}
|
||||
EXPORT_SYMBOL_NS_GPL(proc_thermal_wt_hint_remove, INT340X_THERMAL);
|
||||
|
||||
MODULE_IMPORT_NS(INT340X_THERMAL);
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -0,0 +1,136 @@
|
||||
// SPDX-License-Identifier: GPL-2.0-only
|
||||
/*
|
||||
* processor thermal device for Workload type hints
|
||||
* update from user space
|
||||
*
|
||||
* Copyright (c) 2020-2023, Intel Corporation.
|
||||
*/
|
||||
|
||||
#include <linux/pci.h>
|
||||
#include "processor_thermal_device.h"
|
||||
|
||||
/* 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 = processor_thermal_send_mbox_write_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_WRITE, data);
|
||||
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);
|
||||
u64 cmd_resp;
|
||||
int ret;
|
||||
|
||||
ret = processor_thermal_send_mbox_read_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, &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_wt_req_add(struct pci_dev *pdev, struct proc_thermal_device *proc_priv)
|
||||
{
|
||||
u64 cmd_resp;
|
||||
int ret;
|
||||
|
||||
/* Check if there is a mailbox support, if fails return success */
|
||||
ret = processor_thermal_send_mbox_read_cmd(pdev, MBOX_CMD_WORKLOAD_TYPE_READ, &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_wt_req_add);
|
||||
|
||||
void proc_thermal_wt_req_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_wt_req_remove);
|
||||
|
||||
MODULE_IMPORT_NS(INT340X_THERMAL);
|
||||
MODULE_LICENSE("GPL");
|
||||
@@ -256,7 +256,7 @@ skip_limit_set:
|
||||
|
||||
static const struct kernel_param_ops max_idle_ops = {
|
||||
.set = max_idle_set,
|
||||
.get = param_get_int,
|
||||
.get = param_get_byte,
|
||||
};
|
||||
|
||||
module_param_cb(max_idle, &max_idle_ops, &max_idle, 0644);
|
||||
|
||||
@@ -235,12 +235,10 @@ err_alloc:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int k3_bandgap_remove(struct platform_device *pdev)
|
||||
static void k3_bandgap_remove(struct platform_device *pdev)
|
||||
{
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id of_k3_bandgap_match[] = {
|
||||
@@ -253,7 +251,7 @@ MODULE_DEVICE_TABLE(of, of_k3_bandgap_match);
|
||||
|
||||
static struct platform_driver k3_bandgap_sensor_driver = {
|
||||
.probe = k3_bandgap_probe,
|
||||
.remove = k3_bandgap_remove,
|
||||
.remove_new = k3_bandgap_remove,
|
||||
.driver = {
|
||||
.name = "k3-soc-thermal",
|
||||
.of_match_table = of_k3_bandgap_match,
|
||||
|
||||
@@ -521,12 +521,10 @@ err_alloc:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int k3_j72xx_bandgap_remove(struct platform_device *pdev)
|
||||
static void k3_j72xx_bandgap_remove(struct platform_device *pdev)
|
||||
{
|
||||
pm_runtime_put_sync(&pdev->dev);
|
||||
pm_runtime_disable(&pdev->dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct k3_j72xx_bandgap_data k3_j72xx_bandgap_j721e_data = {
|
||||
@@ -552,7 +550,7 @@ MODULE_DEVICE_TABLE(of, of_k3_j72xx_bandgap_match);
|
||||
|
||||
static struct platform_driver k3_j72xx_bandgap_sensor_driver = {
|
||||
.probe = k3_j72xx_bandgap_probe,
|
||||
.remove = k3_j72xx_bandgap_remove,
|
||||
.remove_new = k3_j72xx_bandgap_remove,
|
||||
.driver = {
|
||||
.name = "k3-j72xx-soc-thermal",
|
||||
.of_match_table = of_k3_j72xx_bandgap_match,
|
||||
|
||||
@@ -90,21 +90,19 @@ static int kirkwood_thermal_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int kirkwood_thermal_exit(struct platform_device *pdev)
|
||||
static void kirkwood_thermal_exit(struct platform_device *pdev)
|
||||
{
|
||||
struct thermal_zone_device *kirkwood_thermal =
|
||||
platform_get_drvdata(pdev);
|
||||
|
||||
thermal_zone_device_unregister(kirkwood_thermal);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
MODULE_DEVICE_TABLE(of, kirkwood_thermal_id_table);
|
||||
|
||||
static struct platform_driver kirkwood_thermal_driver = {
|
||||
.probe = kirkwood_thermal_probe,
|
||||
.remove = kirkwood_thermal_exit,
|
||||
.remove_new = kirkwood_thermal_exit,
|
||||
.driver = {
|
||||
.name = "kirkwood_thermal",
|
||||
.of_match_table = kirkwood_thermal_id_table,
|
||||
|
||||
@@ -114,12 +114,8 @@ static int max77620_thermal_probe(struct platform_device *pdev)
|
||||
|
||||
mtherm->tz_device = devm_thermal_of_zone_register(&pdev->dev, 0,
|
||||
mtherm, &max77620_thermal_ops);
|
||||
if (IS_ERR(mtherm->tz_device)) {
|
||||
ret = PTR_ERR(mtherm->tz_device);
|
||||
dev_err(&pdev->dev, "Failed to register thermal zone: %d\n",
|
||||
ret);
|
||||
return ret;
|
||||
}
|
||||
if (IS_ERR(mtherm->tz_device))
|
||||
return PTR_ERR(mtherm->tz_device);
|
||||
|
||||
ret = devm_request_threaded_irq(&pdev->dev, mtherm->irq_tjalarm1, NULL,
|
||||
max77620_thermal_irq,
|
||||
|
||||
@@ -1267,7 +1267,7 @@ static int mtk_thermal_probe(struct platform_device *pdev)
|
||||
|
||||
mtk_thermal_turn_on_buffer(mt, apmixed_base);
|
||||
|
||||
if (mt->conf->version != MTK_THERMAL_V2)
|
||||
if (mt->conf->version != MTK_THERMAL_V1)
|
||||
mtk_thermal_release_periodic_ts(mt, auxadc_base);
|
||||
|
||||
if (mt->conf->version == MTK_THERMAL_V1)
|
||||
|
||||
@@ -80,8 +80,10 @@
|
||||
#define LVTS_SENSOR_MAX 4
|
||||
#define LVTS_GOLDEN_TEMP_MAX 62
|
||||
#define LVTS_GOLDEN_TEMP_DEFAULT 50
|
||||
#define LVTS_COEFF_A -250460
|
||||
#define LVTS_COEFF_B 250460
|
||||
#define LVTS_COEFF_A_MT8195 -250460
|
||||
#define LVTS_COEFF_B_MT8195 250460
|
||||
#define LVTS_COEFF_A_MT7988 -204650
|
||||
#define LVTS_COEFF_B_MT7988 204650
|
||||
|
||||
#define LVTS_MSR_IMMEDIATE_MODE 0
|
||||
#define LVTS_MSR_FILTERED_MODE 1
|
||||
@@ -89,12 +91,14 @@
|
||||
#define LVTS_MSR_READ_TIMEOUT_US 400
|
||||
#define LVTS_MSR_READ_WAIT_US (LVTS_MSR_READ_TIMEOUT_US / 2)
|
||||
|
||||
#define LVTS_HW_SHUTDOWN_MT7988 105000
|
||||
#define LVTS_HW_SHUTDOWN_MT8192 105000
|
||||
#define LVTS_HW_SHUTDOWN_MT8195 105000
|
||||
|
||||
#define LVTS_MINIMUM_THRESHOLD 20000
|
||||
|
||||
static int golden_temp = LVTS_GOLDEN_TEMP_DEFAULT;
|
||||
static int coeff_b = LVTS_COEFF_B;
|
||||
static int golden_temp_offset;
|
||||
|
||||
struct lvts_sensor_data {
|
||||
int dt_id;
|
||||
@@ -112,6 +116,8 @@ struct lvts_ctrl_data {
|
||||
struct lvts_data {
|
||||
const struct lvts_ctrl_data *lvts_ctrl;
|
||||
int num_lvts_ctrl;
|
||||
int temp_factor;
|
||||
int temp_offset;
|
||||
};
|
||||
|
||||
struct lvts_sensor {
|
||||
@@ -126,6 +132,7 @@ struct lvts_sensor {
|
||||
|
||||
struct lvts_ctrl {
|
||||
struct lvts_sensor sensors[LVTS_SENSOR_MAX];
|
||||
const struct lvts_data *lvts_data;
|
||||
u32 calibration[LVTS_SENSOR_MAX];
|
||||
u32 hw_tshut_raw_temp;
|
||||
int num_lvts_sensor;
|
||||
@@ -213,7 +220,7 @@ static int lvts_debugfs_init(struct device *dev, struct lvts_domain *lvts_td)
|
||||
|
||||
sprintf(name, "controller%d", i);
|
||||
dentry = debugfs_create_dir(name, lvts_td->dom_dentry);
|
||||
if (!dentry)
|
||||
if (IS_ERR(dentry))
|
||||
continue;
|
||||
|
||||
regset = devm_kzalloc(dev, sizeof(*regset), GFP_KERNEL);
|
||||
@@ -247,21 +254,21 @@ static void lvts_debugfs_exit(struct lvts_domain *lvts_td) { }
|
||||
|
||||
#endif
|
||||
|
||||
static int lvts_raw_to_temp(u32 raw_temp)
|
||||
static int lvts_raw_to_temp(u32 raw_temp, int temp_factor)
|
||||
{
|
||||
int temperature;
|
||||
|
||||
temperature = ((s64)(raw_temp & 0xFFFF) * LVTS_COEFF_A) >> 14;
|
||||
temperature += coeff_b;
|
||||
temperature = ((s64)(raw_temp & 0xFFFF) * temp_factor) >> 14;
|
||||
temperature += golden_temp_offset;
|
||||
|
||||
return temperature;
|
||||
}
|
||||
|
||||
static u32 lvts_temp_to_raw(int temperature)
|
||||
static u32 lvts_temp_to_raw(int temperature, int temp_factor)
|
||||
{
|
||||
u32 raw_temp = ((s64)(coeff_b - temperature)) << 14;
|
||||
u32 raw_temp = ((s64)(golden_temp_offset - temperature)) << 14;
|
||||
|
||||
raw_temp = div_s64(raw_temp, -LVTS_COEFF_A);
|
||||
raw_temp = div_s64(raw_temp, -temp_factor);
|
||||
|
||||
return raw_temp;
|
||||
}
|
||||
@@ -269,6 +276,9 @@ static u32 lvts_temp_to_raw(int temperature)
|
||||
static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
{
|
||||
struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
|
||||
struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl,
|
||||
sensors[lvts_sensor->id]);
|
||||
const struct lvts_data *lvts_data = lvts_ctrl->lvts_data;
|
||||
void __iomem *msr = lvts_sensor->msr;
|
||||
u32 value;
|
||||
int rc;
|
||||
@@ -301,7 +311,7 @@ static int lvts_get_temp(struct thermal_zone_device *tz, int *temp)
|
||||
if (rc)
|
||||
return -EAGAIN;
|
||||
|
||||
*temp = lvts_raw_to_temp(value & 0xFFFF);
|
||||
*temp = lvts_raw_to_temp(value & 0xFFFF, lvts_data->temp_factor);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -348,10 +358,13 @@ static bool lvts_should_update_thresh(struct lvts_ctrl *lvts_ctrl, int high)
|
||||
static int lvts_set_trips(struct thermal_zone_device *tz, int low, int high)
|
||||
{
|
||||
struct lvts_sensor *lvts_sensor = thermal_zone_device_priv(tz);
|
||||
struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl, sensors[lvts_sensor->id]);
|
||||
struct lvts_ctrl *lvts_ctrl = container_of(lvts_sensor, struct lvts_ctrl,
|
||||
sensors[lvts_sensor->id]);
|
||||
const struct lvts_data *lvts_data = lvts_ctrl->lvts_data;
|
||||
void __iomem *base = lvts_sensor->base;
|
||||
u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD);
|
||||
u32 raw_high = lvts_temp_to_raw(high);
|
||||
u32 raw_low = lvts_temp_to_raw(low != -INT_MAX ? low : LVTS_MINIMUM_THRESHOLD,
|
||||
lvts_data->temp_factor);
|
||||
u32 raw_high = lvts_temp_to_raw(high, lvts_data->temp_factor);
|
||||
bool should_update_thresh;
|
||||
|
||||
lvts_sensor->low_thresh = low;
|
||||
@@ -603,7 +616,34 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
|
||||
* The efuse blob values follows the sensor enumeration per thermal
|
||||
* controller. The decoding of the stream is as follow:
|
||||
*
|
||||
* stream index map for MCU Domain :
|
||||
* MT8192 :
|
||||
* Stream index map for MCU Domain mt8192 :
|
||||
*
|
||||
* <-----mcu-tc#0-----> <-----sensor#0-----> <-----sensor#1----->
|
||||
* 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09 | 0x0A | 0x0B
|
||||
*
|
||||
* <-----sensor#2-----> <-----sensor#3----->
|
||||
* 0x0C | 0x0D | 0x0E | 0x0F | 0x10 | 0x11 | 0x12 | 0x13
|
||||
*
|
||||
* <-----sensor#4-----> <-----sensor#5-----> <-----sensor#6-----> <-----sensor#7----->
|
||||
* 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0x1B | 0x1C | 0x1D | 0x1E | 0x1F | 0x20 | 0x21 | 0x22 | 0x23
|
||||
*
|
||||
* Stream index map for AP Domain mt8192 :
|
||||
*
|
||||
* <-----sensor#0-----> <-----sensor#1----->
|
||||
* 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2A | 0x2B
|
||||
*
|
||||
* <-----sensor#2-----> <-----sensor#3----->
|
||||
* 0x2C | 0x2D | 0x2E | 0x2F | 0x30 | 0x31 | 0x32 | 0x33
|
||||
*
|
||||
* <-----sensor#4-----> <-----sensor#5----->
|
||||
* 0x34 | 0x35 | 0x36 | 0x37 | 0x38 | 0x39 | 0x3A | 0x3B
|
||||
*
|
||||
* <-----sensor#6-----> <-----sensor#7-----> <-----sensor#8----->
|
||||
* 0x3C | 0x3D | 0x3E | 0x3F | 0x40 | 0x41 | 0x42 | 0x43 | 0x44 | 0x45 | 0x46 | 0x47
|
||||
*
|
||||
* MT8195 :
|
||||
* Stream index map for MCU Domain mt8195 :
|
||||
*
|
||||
* <-----mcu-tc#0-----> <-----sensor#0-----> <-----sensor#1----->
|
||||
* 0x01 | 0x02 | 0x03 | 0x04 | 0x05 | 0x06 | 0x07 | 0x08 | 0x09
|
||||
@@ -614,7 +654,7 @@ static int lvts_sensor_init(struct device *dev, struct lvts_ctrl *lvts_ctrl,
|
||||
* <-----mcu-tc#2-----> <-----sensor#4-----> <-----sensor#5-----> <-----sensor#6-----> <-----sensor#7----->
|
||||
* 0x13 | 0x14 | 0x15 | 0x16 | 0x17 | 0x18 | 0x19 | 0x1A | 0x1B | 0x1C | 0x1D | 0x1E | 0x1F | 0x20 | 0x21
|
||||
*
|
||||
* stream index map for AP Domain :
|
||||
* Stream index map for AP Domain mt8195 :
|
||||
*
|
||||
* <-----ap--tc#0-----> <-----sensor#0-----> <-----sensor#1----->
|
||||
* 0x22 | 0x23 | 0x24 | 0x25 | 0x26 | 0x27 | 0x28 | 0x29 | 0x2A
|
||||
@@ -692,7 +732,7 @@ static int lvts_calibration_read(struct device *dev, struct lvts_domain *lvts_td
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lvts_golden_temp_init(struct device *dev, u32 *value)
|
||||
static int lvts_golden_temp_init(struct device *dev, u32 *value, int temp_offset)
|
||||
{
|
||||
u32 gt;
|
||||
|
||||
@@ -701,7 +741,7 @@ static int lvts_golden_temp_init(struct device *dev, u32 *value)
|
||||
if (gt && gt < LVTS_GOLDEN_TEMP_MAX)
|
||||
golden_temp = gt;
|
||||
|
||||
coeff_b = golden_temp * 500 + LVTS_COEFF_B;
|
||||
golden_temp_offset = golden_temp * 500 + temp_offset;
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -724,7 +764,7 @@ static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td,
|
||||
* The golden temp information is contained in the first chunk
|
||||
* of efuse data.
|
||||
*/
|
||||
ret = lvts_golden_temp_init(dev, (u32 *)lvts_td->calib);
|
||||
ret = lvts_golden_temp_init(dev, (u32 *)lvts_td->calib, lvts_data->temp_offset);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
@@ -735,6 +775,7 @@ static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td,
|
||||
for (i = 0; i < lvts_data->num_lvts_ctrl; i++) {
|
||||
|
||||
lvts_ctrl[i].base = lvts_td->base + lvts_data->lvts_ctrl[i].offset;
|
||||
lvts_ctrl[i].lvts_data = lvts_data;
|
||||
|
||||
ret = lvts_sensor_init(dev, &lvts_ctrl[i],
|
||||
&lvts_data->lvts_ctrl[i]);
|
||||
@@ -758,7 +799,8 @@ static int lvts_ctrl_init(struct device *dev, struct lvts_domain *lvts_td,
|
||||
* after initializing the calibration.
|
||||
*/
|
||||
lvts_ctrl[i].hw_tshut_raw_temp =
|
||||
lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp);
|
||||
lvts_temp_to_raw(lvts_data->lvts_ctrl[i].hw_tshut_temp,
|
||||
lvts_data->temp_factor);
|
||||
|
||||
lvts_ctrl[i].low_thresh = INT_MIN;
|
||||
lvts_ctrl[i].high_thresh = INT_MIN;
|
||||
@@ -1223,6 +1265,8 @@ static int lvts_probe(struct platform_device *pdev)
|
||||
if (irq < 0)
|
||||
return irq;
|
||||
|
||||
golden_temp_offset = lvts_data->temp_offset;
|
||||
|
||||
ret = lvts_domain_init(dev, lvts_td, lvts_data);
|
||||
if (ret)
|
||||
return dev_err_probe(dev, ret, "Failed to initialize the lvts domain\n");
|
||||
@@ -1241,7 +1285,7 @@ static int lvts_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lvts_remove(struct platform_device *pdev)
|
||||
static void lvts_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct lvts_domain *lvts_td;
|
||||
int i;
|
||||
@@ -1252,10 +1296,149 @@ static int lvts_remove(struct platform_device *pdev)
|
||||
lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false);
|
||||
|
||||
lvts_debugfs_exit(lvts_td);
|
||||
}
|
||||
|
||||
static const struct lvts_ctrl_data mt7988_lvts_ap_data_ctrl[] = {
|
||||
{
|
||||
.cal_offset = { 0x00, 0x04, 0x08, 0x0c },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT7988_CPU_0 },
|
||||
{ .dt_id = MT7988_CPU_1 },
|
||||
{ .dt_id = MT7988_ETH2P5G_0 },
|
||||
{ .dt_id = MT7988_ETH2P5G_1 }
|
||||
},
|
||||
.num_lvts_sensor = 4,
|
||||
.offset = 0x0,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT7988,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x14, 0x18, 0x1c, 0x20 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT7988_TOPS_0},
|
||||
{ .dt_id = MT7988_TOPS_1},
|
||||
{ .dt_id = MT7988_ETHWARP_0},
|
||||
{ .dt_id = MT7988_ETHWARP_1}
|
||||
},
|
||||
.num_lvts_sensor = 4,
|
||||
.offset = 0x100,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT7988,
|
||||
}
|
||||
};
|
||||
|
||||
static int lvts_suspend(struct device *dev)
|
||||
{
|
||||
struct lvts_domain *lvts_td;
|
||||
int i;
|
||||
|
||||
lvts_td = dev_get_drvdata(dev);
|
||||
|
||||
for (i = 0; i < lvts_td->num_lvts_ctrl; i++)
|
||||
lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], false);
|
||||
|
||||
clk_disable_unprepare(lvts_td->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int lvts_resume(struct device *dev)
|
||||
{
|
||||
struct lvts_domain *lvts_td;
|
||||
int i, ret;
|
||||
|
||||
lvts_td = dev_get_drvdata(dev);
|
||||
|
||||
ret = clk_prepare_enable(lvts_td->clk);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
for (i = 0; i < lvts_td->num_lvts_ctrl; i++)
|
||||
lvts_ctrl_set_enable(&lvts_td->lvts_ctrl[i], true);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct lvts_ctrl_data mt8192_lvts_mcu_data_ctrl[] = {
|
||||
{
|
||||
.cal_offset = { 0x04, 0x08 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8192_MCU_BIG_CPU0 },
|
||||
{ .dt_id = MT8192_MCU_BIG_CPU1 }
|
||||
},
|
||||
.num_lvts_sensor = 2,
|
||||
.offset = 0x0,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
|
||||
.mode = LVTS_MSR_FILTERED_MODE,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x0c, 0x10 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8192_MCU_BIG_CPU2 },
|
||||
{ .dt_id = MT8192_MCU_BIG_CPU3 }
|
||||
},
|
||||
.num_lvts_sensor = 2,
|
||||
.offset = 0x100,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
|
||||
.mode = LVTS_MSR_FILTERED_MODE,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x14, 0x18, 0x1c, 0x20 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8192_MCU_LITTLE_CPU0 },
|
||||
{ .dt_id = MT8192_MCU_LITTLE_CPU1 },
|
||||
{ .dt_id = MT8192_MCU_LITTLE_CPU2 },
|
||||
{ .dt_id = MT8192_MCU_LITTLE_CPU3 }
|
||||
},
|
||||
.num_lvts_sensor = 4,
|
||||
.offset = 0x200,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
|
||||
.mode = LVTS_MSR_FILTERED_MODE,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct lvts_ctrl_data mt8192_lvts_ap_data_ctrl[] = {
|
||||
{
|
||||
.cal_offset = { 0x24, 0x28 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8192_AP_VPU0 },
|
||||
{ .dt_id = MT8192_AP_VPU1 }
|
||||
},
|
||||
.num_lvts_sensor = 2,
|
||||
.offset = 0x0,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x2c, 0x30 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8192_AP_GPU0 },
|
||||
{ .dt_id = MT8192_AP_GPU1 }
|
||||
},
|
||||
.num_lvts_sensor = 2,
|
||||
.offset = 0x100,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x34, 0x38 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8192_AP_INFRA },
|
||||
{ .dt_id = MT8192_AP_CAM },
|
||||
},
|
||||
.num_lvts_sensor = 2,
|
||||
.offset = 0x200,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
|
||||
},
|
||||
{
|
||||
.cal_offset = { 0x3c, 0x40, 0x44 },
|
||||
.lvts_sensor = {
|
||||
{ .dt_id = MT8192_AP_MD0 },
|
||||
{ .dt_id = MT8192_AP_MD1 },
|
||||
{ .dt_id = MT8192_AP_MD2 }
|
||||
},
|
||||
.num_lvts_sensor = 3,
|
||||
.offset = 0x300,
|
||||
.hw_tshut_temp = LVTS_HW_SHUTDOWN_MT8192,
|
||||
}
|
||||
};
|
||||
|
||||
static const struct lvts_ctrl_data mt8195_lvts_mcu_data_ctrl[] = {
|
||||
{
|
||||
.cal_offset = { 0x04, 0x07 },
|
||||
@@ -1335,29 +1518,58 @@ static const struct lvts_ctrl_data mt8195_lvts_ap_data_ctrl[] = {
|
||||
}
|
||||
};
|
||||
|
||||
static const struct lvts_data mt7988_lvts_ap_data = {
|
||||
.lvts_ctrl = mt7988_lvts_ap_data_ctrl,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt7988_lvts_ap_data_ctrl),
|
||||
.temp_factor = LVTS_COEFF_A_MT7988,
|
||||
.temp_offset = LVTS_COEFF_B_MT7988,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8192_lvts_mcu_data = {
|
||||
.lvts_ctrl = mt8192_lvts_mcu_data_ctrl,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8192_lvts_mcu_data_ctrl),
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8192_lvts_ap_data = {
|
||||
.lvts_ctrl = mt8192_lvts_ap_data_ctrl,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8192_lvts_ap_data_ctrl),
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8195_lvts_mcu_data = {
|
||||
.lvts_ctrl = mt8195_lvts_mcu_data_ctrl,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_mcu_data_ctrl),
|
||||
.temp_factor = LVTS_COEFF_A_MT8195,
|
||||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
};
|
||||
|
||||
static const struct lvts_data mt8195_lvts_ap_data = {
|
||||
.lvts_ctrl = mt8195_lvts_ap_data_ctrl,
|
||||
.num_lvts_ctrl = ARRAY_SIZE(mt8195_lvts_ap_data_ctrl),
|
||||
.temp_factor = LVTS_COEFF_A_MT8195,
|
||||
.temp_offset = LVTS_COEFF_B_MT8195,
|
||||
};
|
||||
|
||||
static const struct of_device_id lvts_of_match[] = {
|
||||
{ .compatible = "mediatek,mt7988-lvts-ap", .data = &mt7988_lvts_ap_data },
|
||||
{ .compatible = "mediatek,mt8192-lvts-mcu", .data = &mt8192_lvts_mcu_data },
|
||||
{ .compatible = "mediatek,mt8192-lvts-ap", .data = &mt8192_lvts_ap_data },
|
||||
{ .compatible = "mediatek,mt8195-lvts-mcu", .data = &mt8195_lvts_mcu_data },
|
||||
{ .compatible = "mediatek,mt8195-lvts-ap", .data = &mt8195_lvts_ap_data },
|
||||
{},
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, lvts_of_match);
|
||||
|
||||
static const struct dev_pm_ops lvts_pm_ops = {
|
||||
NOIRQ_SYSTEM_SLEEP_PM_OPS(lvts_suspend, lvts_resume)
|
||||
};
|
||||
|
||||
static struct platform_driver lvts_driver = {
|
||||
.probe = lvts_probe,
|
||||
.remove = lvts_remove,
|
||||
.remove_new = lvts_remove,
|
||||
.driver = {
|
||||
.name = "mtk-lvts-thermal",
|
||||
.of_match_table = lvts_of_match,
|
||||
.pm = &lvts_pm_ops,
|
||||
},
|
||||
};
|
||||
module_platform_driver(lvts_driver);
|
||||
|
||||
@@ -325,12 +325,6 @@ static const struct reg_field tsens_v0_1_regfields[MAX_REGFIELDS] = {
|
||||
[TRDY] = REG_FIELD(TM_TRDY_OFF, 0, 0),
|
||||
};
|
||||
|
||||
static const struct tsens_ops ops_v0_1 = {
|
||||
.init = init_common,
|
||||
.calibrate = tsens_calibrate_common,
|
||||
.get_temp = get_temp_common,
|
||||
};
|
||||
|
||||
static const struct tsens_ops ops_8226 = {
|
||||
.init = init_8226,
|
||||
.calibrate = tsens_calibrate_common,
|
||||
|
||||
@@ -1319,7 +1319,7 @@ static int tsens_probe(struct platform_device *pdev)
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int tsens_remove(struct platform_device *pdev)
|
||||
static void tsens_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tsens_priv *priv = platform_get_drvdata(pdev);
|
||||
|
||||
@@ -1327,13 +1327,11 @@ static int tsens_remove(struct platform_device *pdev)
|
||||
tsens_disable_irq(priv);
|
||||
if (priv->ops->disable)
|
||||
priv->ops->disable(priv);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver tsens_driver = {
|
||||
.probe = tsens_probe,
|
||||
.remove = tsens_remove,
|
||||
.remove_new = tsens_remove,
|
||||
.driver = {
|
||||
.name = "qcom-tsens",
|
||||
.pm = &tsens_pm_ops,
|
||||
|
||||
@@ -432,14 +432,12 @@ static const struct of_device_id rcar_gen3_thermal_dt_ids[] = {
|
||||
};
|
||||
MODULE_DEVICE_TABLE(of, rcar_gen3_thermal_dt_ids);
|
||||
|
||||
static int rcar_gen3_thermal_remove(struct platform_device *pdev)
|
||||
static void rcar_gen3_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct device *dev = &pdev->dev;
|
||||
|
||||
pm_runtime_put(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void rcar_gen3_hwmon_action(void *data)
|
||||
@@ -594,7 +592,7 @@ static struct platform_driver rcar_gen3_thermal_driver = {
|
||||
.of_match_table = rcar_gen3_thermal_dt_ids,
|
||||
},
|
||||
.probe = rcar_gen3_thermal_probe,
|
||||
.remove = rcar_gen3_thermal_remove,
|
||||
.remove_new = rcar_gen3_thermal_remove,
|
||||
};
|
||||
module_platform_driver(rcar_gen3_thermal_driver);
|
||||
|
||||
|
||||
@@ -371,7 +371,7 @@ static irqreturn_t rcar_thermal_irq(int irq, void *data)
|
||||
/*
|
||||
* platform functions
|
||||
*/
|
||||
static int rcar_thermal_remove(struct platform_device *pdev)
|
||||
static void rcar_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rcar_thermal_common *common = platform_get_drvdata(pdev);
|
||||
struct device *dev = &pdev->dev;
|
||||
@@ -388,8 +388,6 @@ static int rcar_thermal_remove(struct platform_device *pdev)
|
||||
|
||||
pm_runtime_put(dev);
|
||||
pm_runtime_disable(dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rcar_thermal_probe(struct platform_device *pdev)
|
||||
@@ -581,7 +579,7 @@ static struct platform_driver rcar_thermal_driver = {
|
||||
.of_match_table = rcar_thermal_dt_ids,
|
||||
},
|
||||
.probe = rcar_thermal_probe,
|
||||
.remove = rcar_thermal_remove,
|
||||
.remove_new = rcar_thermal_remove,
|
||||
};
|
||||
module_platform_driver(rcar_thermal_driver);
|
||||
|
||||
|
||||
@@ -1601,7 +1601,7 @@ static int rockchip_thermal_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rockchip_thermal_remove(struct platform_device *pdev)
|
||||
static void rockchip_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rockchip_thermal_data *thermal = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
@@ -1614,8 +1614,6 @@ static int rockchip_thermal_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
thermal->chip->control(thermal->regs, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused rockchip_thermal_suspend(struct device *dev)
|
||||
@@ -1691,7 +1689,7 @@ static struct platform_driver rockchip_thermal_driver = {
|
||||
.of_match_table = of_rockchip_thermal_match,
|
||||
},
|
||||
.probe = rockchip_thermal_probe,
|
||||
.remove = rockchip_thermal_remove,
|
||||
.remove_new = rockchip_thermal_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(rockchip_thermal_driver);
|
||||
|
||||
@@ -150,14 +150,12 @@ static void rzg2l_thermal_reset_assert_pm_disable_put(struct platform_device *pd
|
||||
reset_control_assert(priv->rstc);
|
||||
}
|
||||
|
||||
static int rzg2l_thermal_remove(struct platform_device *pdev)
|
||||
static void rzg2l_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct rzg2l_thermal_priv *priv = dev_get_drvdata(&pdev->dev);
|
||||
|
||||
thermal_remove_hwmon_sysfs(priv->zone);
|
||||
rzg2l_thermal_reset_assert_pm_disable_put(pdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int rzg2l_thermal_probe(struct platform_device *pdev)
|
||||
@@ -242,7 +240,7 @@ static struct platform_driver rzg2l_thermal_driver = {
|
||||
.of_match_table = rzg2l_thermal_dt_ids,
|
||||
},
|
||||
.probe = rzg2l_thermal_probe,
|
||||
.remove = rzg2l_thermal_remove,
|
||||
.remove_new = rzg2l_thermal_remove,
|
||||
};
|
||||
module_platform_driver(rzg2l_thermal_driver);
|
||||
|
||||
|
||||
@@ -1124,7 +1124,7 @@ err_sensor:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int exynos_tmu_remove(struct platform_device *pdev)
|
||||
static void exynos_tmu_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct exynos_tmu_data *data = platform_get_drvdata(pdev);
|
||||
|
||||
@@ -1137,8 +1137,6 @@ static int exynos_tmu_remove(struct platform_device *pdev)
|
||||
|
||||
if (!IS_ERR(data->regulator))
|
||||
regulator_disable(data->regulator);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@@ -1173,7 +1171,7 @@ static struct platform_driver exynos_tmu_driver = {
|
||||
.of_match_table = exynos_tmu_match,
|
||||
},
|
||||
.probe = exynos_tmu_probe,
|
||||
.remove = exynos_tmu_remove,
|
||||
.remove_new = exynos_tmu_remove,
|
||||
};
|
||||
|
||||
module_platform_driver(exynos_tmu_driver);
|
||||
|
||||
@@ -150,7 +150,7 @@ disable_clk:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int spear_thermal_exit(struct platform_device *pdev)
|
||||
static void spear_thermal_exit(struct platform_device *pdev)
|
||||
{
|
||||
unsigned int actual_mask = 0;
|
||||
struct thermal_zone_device *spear_thermal = platform_get_drvdata(pdev);
|
||||
@@ -163,8 +163,6 @@ static int spear_thermal_exit(struct platform_device *pdev)
|
||||
writel_relaxed(actual_mask & ~stdev->flags, stdev->thermal_base);
|
||||
|
||||
clk_disable(stdev->clk);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id spear_thermal_id_table[] = {
|
||||
@@ -175,7 +173,7 @@ MODULE_DEVICE_TABLE(of, spear_thermal_id_table);
|
||||
|
||||
static struct platform_driver spear_thermal_driver = {
|
||||
.probe = spear_thermal_probe,
|
||||
.remove = spear_thermal_exit,
|
||||
.remove_new = spear_thermal_exit,
|
||||
.driver = {
|
||||
.name = "spear_thermal",
|
||||
.pm = &spear_thermal_pm_ops,
|
||||
|
||||
@@ -516,7 +516,7 @@ disable_clk:
|
||||
}
|
||||
#endif
|
||||
|
||||
static int sprd_thm_remove(struct platform_device *pdev)
|
||||
static void sprd_thm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct sprd_thermal_data *thm = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
@@ -528,7 +528,6 @@ static int sprd_thm_remove(struct platform_device *pdev)
|
||||
}
|
||||
|
||||
clk_disable_unprepare(thm->clk);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id sprd_thermal_of_match[] = {
|
||||
@@ -543,7 +542,7 @@ static const struct dev_pm_ops sprd_thermal_pm_ops = {
|
||||
|
||||
static struct platform_driver sprd_thermal_driver = {
|
||||
.probe = sprd_thm_probe,
|
||||
.remove = sprd_thm_remove,
|
||||
.remove_new = sprd_thm_remove,
|
||||
.driver = {
|
||||
.name = "sprd-thermal",
|
||||
.pm = &sprd_thermal_pm_ops,
|
||||
|
||||
@@ -569,14 +569,12 @@ err_tz:
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int stm_thermal_remove(struct platform_device *pdev)
|
||||
static void stm_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct stm_thermal_sensor *sensor = platform_get_drvdata(pdev);
|
||||
|
||||
stm_thermal_sensor_off(sensor);
|
||||
thermal_remove_hwmon_sysfs(sensor->th_dev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static struct platform_driver stm_thermal_driver = {
|
||||
@@ -586,7 +584,7 @@ static struct platform_driver stm_thermal_driver = {
|
||||
.of_match_table = stm_thermal_of_match,
|
||||
},
|
||||
.probe = stm_thermal_probe,
|
||||
.remove = stm_thermal_remove,
|
||||
.remove_new = stm_thermal_remove,
|
||||
};
|
||||
module_platform_driver(stm_thermal_driver);
|
||||
|
||||
|
||||
@@ -2219,15 +2219,13 @@ disable_clocks:
|
||||
return err;
|
||||
}
|
||||
|
||||
static int tegra_soctherm_remove(struct platform_device *pdev)
|
||||
static void tegra_soctherm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_soctherm *tegra = platform_get_drvdata(pdev);
|
||||
|
||||
debugfs_remove_recursive(tegra->debugfs_dir);
|
||||
|
||||
soctherm_clk_enable(pdev, false);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int __maybe_unused soctherm_suspend(struct device *dev)
|
||||
@@ -2274,7 +2272,7 @@ static SIMPLE_DEV_PM_OPS(tegra_soctherm_pm, soctherm_suspend, soctherm_resume);
|
||||
|
||||
static struct platform_driver tegra_soctherm_driver = {
|
||||
.probe = tegra_soctherm_probe,
|
||||
.remove = tegra_soctherm_remove,
|
||||
.remove_new = tegra_soctherm_remove,
|
||||
.driver = {
|
||||
.name = "tegra_soctherm",
|
||||
.pm = &tegra_soctherm_pm,
|
||||
|
||||
@@ -300,13 +300,11 @@ static int tegra_bpmp_thermal_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int tegra_bpmp_thermal_remove(struct platform_device *pdev)
|
||||
static void tegra_bpmp_thermal_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct tegra_bpmp_thermal *tegra = platform_get_drvdata(pdev);
|
||||
|
||||
tegra_bpmp_free_mrq(tegra->bpmp, MRQ_THERMAL, tegra);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct of_device_id tegra_bpmp_thermal_of_match[] = {
|
||||
@@ -317,7 +315,7 @@ MODULE_DEVICE_TABLE(of, tegra_bpmp_thermal_of_match);
|
||||
|
||||
static struct platform_driver tegra_bpmp_thermal_driver = {
|
||||
.probe = tegra_bpmp_thermal_probe,
|
||||
.remove = tegra_bpmp_thermal_remove,
|
||||
.remove_new = tegra_bpmp_thermal_remove,
|
||||
.driver = {
|
||||
.name = "tegra-bpmp-thermal",
|
||||
.of_match_table = tegra_bpmp_thermal_of_match,
|
||||
|
||||
@@ -8,8 +8,7 @@
|
||||
*/
|
||||
#include <linux/acpi.h>
|
||||
#include <linux/units.h>
|
||||
|
||||
#include "thermal_core.h"
|
||||
#include <linux/thermal.h>
|
||||
|
||||
/*
|
||||
* Minimum temperature for full military grade is 218°K (-55°C) and
|
||||
|
||||
@@ -307,7 +307,8 @@ static void monitor_thermal_zone(struct thermal_zone_device *tz)
|
||||
thermal_zone_device_set_polling(tz, tz->polling_delay_jiffies);
|
||||
}
|
||||
|
||||
static void handle_non_critical_trips(struct thermal_zone_device *tz, int trip)
|
||||
static void handle_non_critical_trips(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip)
|
||||
{
|
||||
tz->governor ? tz->governor->throttle(tz, trip) :
|
||||
def_governor->throttle(tz, trip);
|
||||
@@ -329,48 +330,43 @@ void thermal_zone_device_critical(struct thermal_zone_device *tz)
|
||||
EXPORT_SYMBOL(thermal_zone_device_critical);
|
||||
|
||||
static void handle_critical_trips(struct thermal_zone_device *tz,
|
||||
int trip, int trip_temp, enum thermal_trip_type trip_type)
|
||||
const struct thermal_trip *trip)
|
||||
{
|
||||
/* If we have not crossed the trip_temp, we do not care. */
|
||||
if (trip_temp <= 0 || tz->temperature < trip_temp)
|
||||
if (trip->temperature <= 0 || tz->temperature < trip->temperature)
|
||||
return;
|
||||
|
||||
trace_thermal_zone_trip(tz, trip, trip_type);
|
||||
trace_thermal_zone_trip(tz, thermal_zone_trip_id(tz, trip), trip->type);
|
||||
|
||||
if (trip_type == THERMAL_TRIP_HOT && tz->ops->hot)
|
||||
tz->ops->hot(tz);
|
||||
else if (trip_type == THERMAL_TRIP_CRITICAL)
|
||||
if (trip->type == THERMAL_TRIP_CRITICAL)
|
||||
tz->ops->critical(tz);
|
||||
else if (tz->ops->hot)
|
||||
tz->ops->hot(tz);
|
||||
}
|
||||
|
||||
static void handle_thermal_trip(struct thermal_zone_device *tz, int trip_id)
|
||||
static void handle_thermal_trip(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip)
|
||||
{
|
||||
struct thermal_trip trip;
|
||||
|
||||
/* Ignore disabled trip points */
|
||||
if (test_bit(trip_id, &tz->trips_disabled))
|
||||
return;
|
||||
|
||||
__thermal_zone_get_trip(tz, trip_id, &trip);
|
||||
|
||||
if (trip.temperature == THERMAL_TEMP_INVALID)
|
||||
if (trip->temperature == THERMAL_TEMP_INVALID)
|
||||
return;
|
||||
|
||||
if (tz->last_temperature != THERMAL_TEMP_INVALID) {
|
||||
if (tz->last_temperature < trip.temperature &&
|
||||
tz->temperature >= trip.temperature)
|
||||
thermal_notify_tz_trip_up(tz->id, trip_id,
|
||||
if (tz->last_temperature < trip->temperature &&
|
||||
tz->temperature >= trip->temperature)
|
||||
thermal_notify_tz_trip_up(tz->id,
|
||||
thermal_zone_trip_id(tz, trip),
|
||||
tz->temperature);
|
||||
if (tz->last_temperature >= trip.temperature &&
|
||||
tz->temperature < (trip.temperature - trip.hysteresis))
|
||||
thermal_notify_tz_trip_down(tz->id, trip_id,
|
||||
if (tz->last_temperature >= trip->temperature &&
|
||||
tz->temperature < trip->temperature - trip->hysteresis)
|
||||
thermal_notify_tz_trip_down(tz->id,
|
||||
thermal_zone_trip_id(tz, trip),
|
||||
tz->temperature);
|
||||
}
|
||||
|
||||
if (trip.type == THERMAL_TRIP_CRITICAL || trip.type == THERMAL_TRIP_HOT)
|
||||
handle_critical_trips(tz, trip_id, trip.temperature, trip.type);
|
||||
if (trip->type == THERMAL_TRIP_CRITICAL || trip->type == THERMAL_TRIP_HOT)
|
||||
handle_critical_trips(tz, trip);
|
||||
else
|
||||
handle_non_critical_trips(tz, trip_id);
|
||||
handle_non_critical_trips(tz, trip);
|
||||
}
|
||||
|
||||
static void update_temperature(struct thermal_zone_device *tz)
|
||||
@@ -407,7 +403,7 @@ static void thermal_zone_device_init(struct thermal_zone_device *tz)
|
||||
void __thermal_zone_device_update(struct thermal_zone_device *tz,
|
||||
enum thermal_notify_event event)
|
||||
{
|
||||
int count;
|
||||
const struct thermal_trip *trip;
|
||||
|
||||
if (atomic_read(&in_suspend))
|
||||
return;
|
||||
@@ -426,8 +422,8 @@ void __thermal_zone_device_update(struct thermal_zone_device *tz,
|
||||
|
||||
tz->notify_event = event;
|
||||
|
||||
for (count = 0; count < tz->num_trips; count++)
|
||||
handle_thermal_trip(tz, count);
|
||||
for_each_trip(tz, trip)
|
||||
handle_thermal_trip(tz, trip);
|
||||
|
||||
monitor_thermal_zone(tz);
|
||||
}
|
||||
@@ -499,25 +495,6 @@ void thermal_zone_device_update(struct thermal_zone_device *tz,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_device_update);
|
||||
|
||||
/**
|
||||
* thermal_zone_device_exec - Run a callback under the zone lock.
|
||||
* @tz: Thermal zone.
|
||||
* @cb: Callback to run.
|
||||
* @data: Data to pass to the callback.
|
||||
*/
|
||||
void thermal_zone_device_exec(struct thermal_zone_device *tz,
|
||||
void (*cb)(struct thermal_zone_device *,
|
||||
unsigned long),
|
||||
unsigned long data)
|
||||
{
|
||||
mutex_lock(&tz->lock);
|
||||
|
||||
cb(tz, data);
|
||||
|
||||
mutex_unlock(&tz->lock);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_device_exec);
|
||||
|
||||
static void thermal_zone_device_check(struct work_struct *work)
|
||||
{
|
||||
struct thermal_zone_device *tz = container_of(work, struct
|
||||
@@ -604,10 +581,9 @@ struct thermal_zone_device *thermal_zone_get_by_id(int id)
|
||||
*/
|
||||
|
||||
/**
|
||||
* thermal_zone_bind_cooling_device() - bind a cooling device to a thermal zone
|
||||
* thermal_bind_cdev_to_trip - bind a cooling device to a thermal zone
|
||||
* @tz: pointer to struct thermal_zone_device
|
||||
* @trip: indicates which trip point the cooling devices is
|
||||
* associated with in this thermal zone.
|
||||
* @trip: trip point the cooling devices is associated with in this zone.
|
||||
* @cdev: pointer to struct thermal_cooling_device
|
||||
* @upper: the Maximum cooling state for this trip point.
|
||||
* THERMAL_NO_LIMIT means no upper limit,
|
||||
@@ -625,8 +601,8 @@ struct thermal_zone_device *thermal_zone_get_by_id(int id)
|
||||
*
|
||||
* Return: 0 on success, the proper error value otherwise.
|
||||
*/
|
||||
int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
|
||||
int trip,
|
||||
int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip,
|
||||
struct thermal_cooling_device *cdev,
|
||||
unsigned long upper, unsigned long lower,
|
||||
unsigned int weight)
|
||||
@@ -638,9 +614,6 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
|
||||
bool upper_no_limit;
|
||||
int result;
|
||||
|
||||
if (trip >= tz->num_trips || trip < 0)
|
||||
return -EINVAL;
|
||||
|
||||
list_for_each_entry(pos1, &thermal_tz_list, node) {
|
||||
if (pos1 == tz)
|
||||
break;
|
||||
@@ -689,7 +662,8 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
|
||||
if (result)
|
||||
goto release_ida;
|
||||
|
||||
sprintf(dev->attr_name, "cdev%d_trip_point", dev->id);
|
||||
snprintf(dev->attr_name, sizeof(dev->attr_name), "cdev%d_trip_point",
|
||||
dev->id);
|
||||
sysfs_attr_init(&dev->attr.attr);
|
||||
dev->attr.attr.name = dev->attr_name;
|
||||
dev->attr.attr.mode = 0444;
|
||||
@@ -698,7 +672,8 @@ int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
|
||||
if (result)
|
||||
goto remove_symbol_link;
|
||||
|
||||
sprintf(dev->weight_attr_name, "cdev%d_weight", dev->id);
|
||||
snprintf(dev->weight_attr_name, sizeof(dev->weight_attr_name),
|
||||
"cdev%d_weight", dev->id);
|
||||
sysfs_attr_init(&dev->weight_attr.attr);
|
||||
dev->weight_attr.attr.name = dev->weight_attr_name;
|
||||
dev->weight_attr.attr.mode = S_IWUSR | S_IRUGO;
|
||||
@@ -737,14 +712,26 @@ free_mem:
|
||||
kfree(dev);
|
||||
return result;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_bind_cdev_to_trip);
|
||||
|
||||
int thermal_zone_bind_cooling_device(struct thermal_zone_device *tz,
|
||||
int trip_index,
|
||||
struct thermal_cooling_device *cdev,
|
||||
unsigned long upper, unsigned long lower,
|
||||
unsigned int weight)
|
||||
{
|
||||
if (trip_index < 0 || trip_index >= tz->num_trips)
|
||||
return -EINVAL;
|
||||
|
||||
return thermal_bind_cdev_to_trip(tz, &tz->trips[trip_index], cdev,
|
||||
upper, lower, weight);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_bind_cooling_device);
|
||||
|
||||
/**
|
||||
* thermal_zone_unbind_cooling_device() - unbind a cooling device from a
|
||||
* thermal zone.
|
||||
* thermal_unbind_cdev_from_trip - unbind a cooling device from a thermal zone.
|
||||
* @tz: pointer to a struct thermal_zone_device.
|
||||
* @trip: indicates which trip point the cooling devices is
|
||||
* associated with in this thermal zone.
|
||||
* @trip: trip point the cooling devices is associated with in this zone.
|
||||
* @cdev: pointer to a struct thermal_cooling_device.
|
||||
*
|
||||
* This interface function unbind a thermal cooling device from the certain
|
||||
@@ -753,9 +740,9 @@ EXPORT_SYMBOL_GPL(thermal_zone_bind_cooling_device);
|
||||
*
|
||||
* Return: 0 on success, the proper error value otherwise.
|
||||
*/
|
||||
int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
|
||||
int trip,
|
||||
struct thermal_cooling_device *cdev)
|
||||
int thermal_unbind_cdev_from_trip(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip,
|
||||
struct thermal_cooling_device *cdev)
|
||||
{
|
||||
struct thermal_instance *pos, *next;
|
||||
|
||||
@@ -783,6 +770,17 @@ unbind:
|
||||
kfree(pos);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_unbind_cdev_from_trip);
|
||||
|
||||
int thermal_zone_unbind_cooling_device(struct thermal_zone_device *tz,
|
||||
int trip_index,
|
||||
struct thermal_cooling_device *cdev)
|
||||
{
|
||||
if (trip_index < 0 || trip_index >= tz->num_trips)
|
||||
return -EINVAL;
|
||||
|
||||
return thermal_unbind_cdev_from_trip(tz, &tz->trips[trip_index], cdev);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_unbind_cooling_device);
|
||||
|
||||
static void thermal_release(struct device *dev)
|
||||
@@ -1231,7 +1229,6 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t
|
||||
struct thermal_zone_device *tz;
|
||||
int id;
|
||||
int result;
|
||||
int count;
|
||||
struct thermal_governor *governor;
|
||||
|
||||
if (!type || strlen(type) == 0) {
|
||||
@@ -1328,14 +1325,6 @@ thermal_zone_device_register_with_trips(const char *type, struct thermal_trip *t
|
||||
if (result)
|
||||
goto release_device;
|
||||
|
||||
for (count = 0; count < num_trips; count++) {
|
||||
struct thermal_trip trip;
|
||||
|
||||
result = thermal_zone_get_trip(tz, count, &trip);
|
||||
if (result || !trip.temperature)
|
||||
set_bit(count, &tz->trips_disabled);
|
||||
}
|
||||
|
||||
/* Update 'this' zone's governor information */
|
||||
mutex_lock(&thermal_governor_lock);
|
||||
|
||||
|
||||
@@ -70,7 +70,7 @@ static inline bool cdev_is_power_actor(struct thermal_cooling_device *cdev)
|
||||
void thermal_cdev_update(struct thermal_cooling_device *);
|
||||
void __thermal_cdev_update(struct thermal_cooling_device *cdev);
|
||||
|
||||
int get_tz_trend(struct thermal_zone_device *tz, int trip_index);
|
||||
int get_tz_trend(struct thermal_zone_device *tz, const struct thermal_trip *trip);
|
||||
|
||||
struct thermal_instance *
|
||||
get_thermal_instance(struct thermal_zone_device *tz,
|
||||
@@ -87,7 +87,7 @@ struct thermal_instance {
|
||||
char name[THERMAL_NAME_LENGTH];
|
||||
struct thermal_zone_device *tz;
|
||||
struct thermal_cooling_device *cdev;
|
||||
int trip;
|
||||
const struct thermal_trip *trip;
|
||||
bool initialized;
|
||||
unsigned long upper; /* Highest cooling state for this trip point */
|
||||
unsigned long lower; /* Lowest cooling state for this trip point */
|
||||
@@ -116,9 +116,14 @@ void __thermal_zone_device_update(struct thermal_zone_device *tz,
|
||||
enum thermal_notify_event event);
|
||||
|
||||
/* Helpers */
|
||||
#define for_each_trip(__tz, __trip) \
|
||||
for (__trip = __tz->trips; __trip - __tz->trips < __tz->num_trips; __trip++)
|
||||
|
||||
void __thermal_zone_set_trips(struct thermal_zone_device *tz);
|
||||
int __thermal_zone_get_trip(struct thermal_zone_device *tz, int trip_id,
|
||||
struct thermal_trip *trip);
|
||||
int thermal_zone_trip_id(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip);
|
||||
int __thermal_zone_get_temp(struct thermal_zone_device *tz, int *temp);
|
||||
|
||||
/* sysfs I/F */
|
||||
|
||||
@@ -22,9 +22,8 @@
|
||||
#include "thermal_core.h"
|
||||
#include "thermal_trace.h"
|
||||
|
||||
int get_tz_trend(struct thermal_zone_device *tz, int trip_index)
|
||||
int get_tz_trend(struct thermal_zone_device *tz, const struct thermal_trip *trip)
|
||||
{
|
||||
struct thermal_trip *trip = tz->trips ? &tz->trips[trip_index] : NULL;
|
||||
enum thermal_trend trend;
|
||||
|
||||
if (tz->emul_temperature || !tz->ops->get_trend ||
|
||||
@@ -42,14 +41,17 @@ int get_tz_trend(struct thermal_zone_device *tz, int trip_index)
|
||||
|
||||
struct thermal_instance *
|
||||
get_thermal_instance(struct thermal_zone_device *tz,
|
||||
struct thermal_cooling_device *cdev, int trip)
|
||||
struct thermal_cooling_device *cdev, int trip_index)
|
||||
{
|
||||
struct thermal_instance *pos = NULL;
|
||||
struct thermal_instance *target_instance = NULL;
|
||||
const struct thermal_trip *trip;
|
||||
|
||||
mutex_lock(&tz->lock);
|
||||
mutex_lock(&cdev->lock);
|
||||
|
||||
trip = &tz->trips[trip_index];
|
||||
|
||||
list_for_each_entry(pos, &tz->thermal_instances, tz_node) {
|
||||
if (pos->tz == tz && pos->trip == trip && pos->cdev == cdev) {
|
||||
target_instance = pos;
|
||||
|
||||
@@ -943,7 +943,8 @@ trip_point_show(struct device *dev, struct device_attribute *attr, char *buf)
|
||||
instance =
|
||||
container_of(attr, struct thermal_instance, attr);
|
||||
|
||||
return sprintf(buf, "%d\n", instance->trip);
|
||||
return sprintf(buf, "%d\n",
|
||||
thermal_zone_trip_id(instance->tz, instance->trip));
|
||||
}
|
||||
|
||||
ssize_t
|
||||
|
||||
@@ -13,15 +13,11 @@ int for_each_thermal_trip(struct thermal_zone_device *tz,
|
||||
int (*cb)(struct thermal_trip *, void *),
|
||||
void *data)
|
||||
{
|
||||
int i, ret;
|
||||
struct thermal_trip *trip;
|
||||
int ret;
|
||||
|
||||
lockdep_assert_held(&tz->lock);
|
||||
|
||||
if (!tz->trips)
|
||||
return -ENODATA;
|
||||
|
||||
for (i = 0; i < tz->num_trips; i++) {
|
||||
ret = cb(&tz->trips[i], data);
|
||||
for_each_trip(tz, trip) {
|
||||
ret = cb(trip, data);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
@@ -30,6 +26,20 @@ int for_each_thermal_trip(struct thermal_zone_device *tz,
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(for_each_thermal_trip);
|
||||
|
||||
int thermal_zone_for_each_trip(struct thermal_zone_device *tz,
|
||||
int (*cb)(struct thermal_trip *, void *),
|
||||
void *data)
|
||||
{
|
||||
int ret;
|
||||
|
||||
mutex_lock(&tz->lock);
|
||||
ret = for_each_thermal_trip(tz, cb, data);
|
||||
mutex_unlock(&tz->lock);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(thermal_zone_for_each_trip);
|
||||
|
||||
int thermal_zone_get_num_trips(struct thermal_zone_device *tz)
|
||||
{
|
||||
return tz->num_trips;
|
||||
@@ -55,6 +65,7 @@ void __thermal_zone_set_trips(struct thermal_zone_device *tz)
|
||||
{
|
||||
struct thermal_trip trip;
|
||||
int low = -INT_MAX, high = INT_MAX;
|
||||
bool same_trip = false;
|
||||
int i, ret;
|
||||
|
||||
lockdep_assert_held(&tz->lock);
|
||||
@@ -63,6 +74,7 @@ void __thermal_zone_set_trips(struct thermal_zone_device *tz)
|
||||
return;
|
||||
|
||||
for (i = 0; i < tz->num_trips; i++) {
|
||||
bool low_set = false;
|
||||
int trip_low;
|
||||
|
||||
ret = __thermal_zone_get_trip(tz, i , &trip);
|
||||
@@ -71,18 +83,31 @@ void __thermal_zone_set_trips(struct thermal_zone_device *tz)
|
||||
|
||||
trip_low = trip.temperature - trip.hysteresis;
|
||||
|
||||
if (trip_low < tz->temperature && trip_low > low)
|
||||
if (trip_low < tz->temperature && trip_low > low) {
|
||||
low = trip_low;
|
||||
low_set = true;
|
||||
same_trip = false;
|
||||
}
|
||||
|
||||
if (trip.temperature > tz->temperature &&
|
||||
trip.temperature < high)
|
||||
trip.temperature < high) {
|
||||
high = trip.temperature;
|
||||
same_trip = low_set;
|
||||
}
|
||||
}
|
||||
|
||||
/* No need to change trip points */
|
||||
if (tz->prev_low_trip == low && tz->prev_high_trip == high)
|
||||
return;
|
||||
|
||||
/*
|
||||
* If "high" and "low" are the same, skip the change unless this is the
|
||||
* first time.
|
||||
*/
|
||||
if (same_trip && (tz->prev_low_trip != -INT_MAX ||
|
||||
tz->prev_high_trip != INT_MAX))
|
||||
return;
|
||||
|
||||
tz->prev_low_trip = low;
|
||||
tz->prev_high_trip = high;
|
||||
|
||||
@@ -160,3 +185,13 @@ int thermal_zone_set_trip(struct thermal_zone_device *tz, int trip_id,
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int thermal_zone_trip_id(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip)
|
||||
{
|
||||
/*
|
||||
* Assume the trip to be located within the bounds of the thermal
|
||||
* zone's trips[] table.
|
||||
*/
|
||||
return trip - tz->trips;
|
||||
}
|
||||
|
||||
@@ -1069,7 +1069,7 @@ free_irqs:
|
||||
}
|
||||
|
||||
static
|
||||
int ti_bandgap_remove(struct platform_device *pdev)
|
||||
void ti_bandgap_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct ti_bandgap *bgp = platform_get_drvdata(pdev);
|
||||
int i;
|
||||
@@ -1098,8 +1098,6 @@ int ti_bandgap_remove(struct platform_device *pdev)
|
||||
|
||||
if (TI_BANDGAP_HAS(bgp, TSHUT))
|
||||
free_irq(gpiod_to_irq(bgp->tshut_gpiod), NULL);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PM_SLEEP
|
||||
@@ -1283,7 +1281,7 @@ MODULE_DEVICE_TABLE(of, of_ti_bandgap_match);
|
||||
|
||||
static struct platform_driver ti_bandgap_sensor_driver = {
|
||||
.probe = ti_bandgap_probe,
|
||||
.remove = ti_bandgap_remove,
|
||||
.remove_new = ti_bandgap_remove,
|
||||
.driver = {
|
||||
.name = "ti-soc-thermal",
|
||||
.pm = DEV_PM_OPS,
|
||||
|
||||
@@ -317,14 +317,12 @@ static int uniphier_tm_probe(struct platform_device *pdev)
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int uniphier_tm_remove(struct platform_device *pdev)
|
||||
static void uniphier_tm_remove(struct platform_device *pdev)
|
||||
{
|
||||
struct uniphier_tm_dev *tdev = platform_get_drvdata(pdev);
|
||||
|
||||
/* disable sensor */
|
||||
uniphier_tm_disable_sensor(tdev);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct uniphier_tm_soc_data uniphier_pxs2_tm_data = {
|
||||
@@ -362,7 +360,7 @@ MODULE_DEVICE_TABLE(of, uniphier_tm_dt_ids);
|
||||
|
||||
static struct platform_driver uniphier_tm_driver = {
|
||||
.probe = uniphier_tm_probe,
|
||||
.remove = uniphier_tm_remove,
|
||||
.remove_new = uniphier_tm_remove,
|
||||
.driver = {
|
||||
.name = "uniphier-thermal",
|
||||
.of_match_table = uniphier_tm_dt_ids,
|
||||
|
||||
@@ -7,6 +7,15 @@
|
||||
#ifndef __MEDIATEK_LVTS_DT_H
|
||||
#define __MEDIATEK_LVTS_DT_H
|
||||
|
||||
#define MT7988_CPU_0 0
|
||||
#define MT7988_CPU_1 1
|
||||
#define MT7988_ETH2P5G_0 2
|
||||
#define MT7988_ETH2P5G_1 3
|
||||
#define MT7988_TOPS_0 4
|
||||
#define MT7988_TOPS_1 5
|
||||
#define MT7988_ETHWARP_0 6
|
||||
#define MT7988_ETHWARP_1 7
|
||||
|
||||
#define MT8195_MCU_BIG_CPU0 0
|
||||
#define MT8195_MCU_BIG_CPU1 1
|
||||
#define MT8195_MCU_BIG_CPU2 2
|
||||
@@ -26,4 +35,23 @@
|
||||
#define MT8195_AP_CAM0 15
|
||||
#define MT8195_AP_CAM1 16
|
||||
|
||||
#define MT8192_MCU_BIG_CPU0 0
|
||||
#define MT8192_MCU_BIG_CPU1 1
|
||||
#define MT8192_MCU_BIG_CPU2 2
|
||||
#define MT8192_MCU_BIG_CPU3 3
|
||||
#define MT8192_MCU_LITTLE_CPU0 4
|
||||
#define MT8192_MCU_LITTLE_CPU1 5
|
||||
#define MT8192_MCU_LITTLE_CPU2 6
|
||||
#define MT8192_MCU_LITTLE_CPU3 7
|
||||
|
||||
#define MT8192_AP_VPU0 8
|
||||
#define MT8192_AP_VPU1 9
|
||||
#define MT8192_AP_GPU0 10
|
||||
#define MT8192_AP_GPU1 11
|
||||
#define MT8192_AP_INFRA 12
|
||||
#define MT8192_AP_CAM 13
|
||||
#define MT8192_AP_MD0 14
|
||||
#define MT8192_AP_MD1 15
|
||||
#define MT8192_AP_MD2 16
|
||||
|
||||
#endif /* __MEDIATEK_LVTS_DT_H */
|
||||
|
||||
+13
-7
@@ -122,7 +122,6 @@ struct thermal_cooling_device {
|
||||
* @devdata: private pointer for device private data
|
||||
* @trips: an array of struct thermal_trip
|
||||
* @num_trips: number of trip points the thermal zone supports
|
||||
* @trips_disabled; bitmap for disabled trips
|
||||
* @passive_delay_jiffies: number of jiffies to wait between polls when
|
||||
* performing passive cooling.
|
||||
* @polling_delay_jiffies: number of jiffies to wait between polls when
|
||||
@@ -163,7 +162,6 @@ struct thermal_zone_device {
|
||||
void *devdata;
|
||||
struct thermal_trip *trips;
|
||||
int num_trips;
|
||||
unsigned long trips_disabled; /* bitmap for disabled trips */
|
||||
unsigned long passive_delay_jiffies;
|
||||
unsigned long polling_delay_jiffies;
|
||||
int temperature;
|
||||
@@ -201,7 +199,8 @@ struct thermal_governor {
|
||||
char name[THERMAL_NAME_LENGTH];
|
||||
int (*bind_to_tz)(struct thermal_zone_device *tz);
|
||||
void (*unbind_from_tz)(struct thermal_zone_device *tz);
|
||||
int (*throttle)(struct thermal_zone_device *tz, int trip);
|
||||
int (*throttle)(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip);
|
||||
struct list_head governor_list;
|
||||
};
|
||||
|
||||
@@ -288,6 +287,9 @@ int thermal_zone_set_trip(struct thermal_zone_device *tz, int trip_id,
|
||||
int for_each_thermal_trip(struct thermal_zone_device *tz,
|
||||
int (*cb)(struct thermal_trip *, void *),
|
||||
void *data);
|
||||
int thermal_zone_for_each_trip(struct thermal_zone_device *tz,
|
||||
int (*cb)(struct thermal_trip *, void *),
|
||||
void *data);
|
||||
int thermal_zone_get_num_trips(struct thermal_zone_device *tz);
|
||||
|
||||
int thermal_zone_get_crit_temp(struct thermal_zone_device *tz, int *temp);
|
||||
@@ -322,18 +324,22 @@ const char *thermal_zone_device_type(struct thermal_zone_device *tzd);
|
||||
int thermal_zone_device_id(struct thermal_zone_device *tzd);
|
||||
struct device *thermal_zone_device(struct thermal_zone_device *tzd);
|
||||
|
||||
int thermal_bind_cdev_to_trip(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip,
|
||||
struct thermal_cooling_device *cdev,
|
||||
unsigned long upper, unsigned long lower,
|
||||
unsigned int weight);
|
||||
int thermal_zone_bind_cooling_device(struct thermal_zone_device *, int,
|
||||
struct thermal_cooling_device *,
|
||||
unsigned long, unsigned long,
|
||||
unsigned int);
|
||||
int thermal_unbind_cdev_from_trip(struct thermal_zone_device *tz,
|
||||
const struct thermal_trip *trip,
|
||||
struct thermal_cooling_device *cdev);
|
||||
int thermal_zone_unbind_cooling_device(struct thermal_zone_device *, int,
|
||||
struct thermal_cooling_device *);
|
||||
void thermal_zone_device_update(struct thermal_zone_device *,
|
||||
enum thermal_notify_event);
|
||||
void thermal_zone_device_exec(struct thermal_zone_device *tz,
|
||||
void (*cb)(struct thermal_zone_device *,
|
||||
unsigned long),
|
||||
unsigned long data);
|
||||
|
||||
struct thermal_cooling_device *thermal_cooling_device_register(const char *,
|
||||
void *, const struct thermal_cooling_device_ops *);
|
||||
|
||||
@@ -85,6 +85,8 @@ TARGETS += syscall_user_dispatch
|
||||
TARGETS += sysctl
|
||||
TARGETS += tc-testing
|
||||
TARGETS += tdx
|
||||
TARGETS += thermal/intel/power_floor
|
||||
TARGETS += thermal/intel/workload_hint
|
||||
TARGETS += timens
|
||||
ifneq (1, $(quicktest))
|
||||
TARGETS += timers
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
ifndef CROSS_COMPILE
|
||||
uname_M := $(shell uname -m 2>/dev/null || echo not)
|
||||
ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/)
|
||||
|
||||
ifeq ($(ARCH),x86)
|
||||
TEST_GEN_PROGS := power_floor_test
|
||||
|
||||
include ../../../lib.mk
|
||||
|
||||
endif
|
||||
endif
|
||||
@@ -0,0 +1,108 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define POWER_FLOOR_ENABLE_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/power_limits/power_floor_enable"
|
||||
#define POWER_FLOOR_STATUS_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/power_limits/power_floor_status"
|
||||
|
||||
void power_floor_exit(int signum)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/* Disable feature via sysfs knob */
|
||||
|
||||
fd = open(POWER_FLOOR_ENABLE_ATTRIBUTE, O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror("Unable to open power floor enable file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (write(fd, "0\n", 2) < 0) {
|
||||
perror("Can' disable power floor notifications\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Disabled power floor notifications\n");
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct pollfd ufd;
|
||||
char status_str[3];
|
||||
int fd, ret;
|
||||
|
||||
if (signal(SIGINT, power_floor_exit) == SIG_IGN)
|
||||
signal(SIGINT, SIG_IGN);
|
||||
if (signal(SIGHUP, power_floor_exit) == SIG_IGN)
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
if (signal(SIGTERM, power_floor_exit) == SIG_IGN)
|
||||
signal(SIGTERM, SIG_IGN);
|
||||
|
||||
/* Enable feature via sysfs knob */
|
||||
fd = open(POWER_FLOOR_ENABLE_ATTRIBUTE, O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror("Unable to open power floor enable file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (write(fd, "1\n", 2) < 0) {
|
||||
perror("Can' enable power floor notifications\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
printf("Enabled power floor notifications\n");
|
||||
|
||||
while (1) {
|
||||
fd = open(POWER_FLOOR_STATUS_ATTRIBUTE, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("Unable to power floor status file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((lseek(fd, 0L, SEEK_SET)) < 0) {
|
||||
fprintf(stderr, "Failed to set pointer to beginning\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (read(fd, status_str, sizeof(status_str)) < 0) {
|
||||
fprintf(stderr, "Failed to read from:%s\n",
|
||||
POWER_FLOOR_STATUS_ATTRIBUTE);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ufd.fd = fd;
|
||||
ufd.events = POLLPRI;
|
||||
|
||||
ret = poll(&ufd, 1, -1);
|
||||
if (ret < 0) {
|
||||
perror("poll error");
|
||||
exit(1);
|
||||
} else if (ret == 0) {
|
||||
printf("Poll Timeout\n");
|
||||
} else {
|
||||
if ((lseek(fd, 0L, SEEK_SET)) < 0) {
|
||||
fprintf(stderr, "Failed to set pointer to beginning\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (read(fd, status_str, sizeof(status_str)) < 0)
|
||||
exit(0);
|
||||
|
||||
printf("power floor status: %s\n", status_str);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
# SPDX-License-Identifier: GPL-2.0
|
||||
ifndef CROSS_COMPILE
|
||||
uname_M := $(shell uname -m 2>/dev/null || echo not)
|
||||
ARCH ?= $(shell echo $(uname_M) | sed -e s/i.86/x86/ -e s/x86_64/x86/)
|
||||
|
||||
ifeq ($(ARCH),x86)
|
||||
TEST_GEN_PROGS := workload_hint_test
|
||||
|
||||
include ../../../lib.mk
|
||||
|
||||
endif
|
||||
endif
|
||||
@@ -0,0 +1,157 @@
|
||||
// SPDX-License-Identifier: GPL-2.0
|
||||
|
||||
#define _GNU_SOURCE
|
||||
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#include <fcntl.h>
|
||||
#include <poll.h>
|
||||
#include <signal.h>
|
||||
|
||||
#define WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/notification_delay_ms"
|
||||
#define WORKLOAD_ENABLE_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_hint_enable"
|
||||
#define WORKLOAD_TYPE_INDEX_ATTRIBUTE "/sys/bus/pci/devices/0000:00:04.0/workload_hint/workload_type_index"
|
||||
|
||||
static const char * const workload_types[] = {
|
||||
"idle",
|
||||
"battery_life",
|
||||
"sustained",
|
||||
"bursty",
|
||||
NULL
|
||||
};
|
||||
|
||||
#define WORKLOAD_TYPE_MAX_INDEX 3
|
||||
|
||||
void workload_hint_exit(int signum)
|
||||
{
|
||||
int fd;
|
||||
|
||||
/* Disable feature via sysfs knob */
|
||||
|
||||
fd = open(WORKLOAD_ENABLE_ATTRIBUTE, O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror("Unable to open workload type feature enable file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (write(fd, "0\n", 2) < 0) {
|
||||
perror("Can' disable workload hints\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Disabled workload type prediction\n");
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
struct pollfd ufd;
|
||||
char index_str[4];
|
||||
int fd, ret, index;
|
||||
char delay_str[64];
|
||||
int delay = 0;
|
||||
|
||||
printf("Usage: workload_hint_test [notification delay in milli seconds]\n");
|
||||
|
||||
if (argc > 1) {
|
||||
ret = sscanf(argv[1], "%d", &delay);
|
||||
if (ret < 0) {
|
||||
printf("Invalid delay\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
printf("Setting notification delay to %d ms\n", delay);
|
||||
if (delay < 0)
|
||||
exit(1);
|
||||
|
||||
sprintf(delay_str, "%s\n", argv[1]);
|
||||
|
||||
sprintf(delay_str, "%s\n", argv[1]);
|
||||
fd = open(WORKLOAD_NOTIFICATION_DELAY_ATTRIBUTE, O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror("Unable to open workload notification delay\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (write(fd, delay_str, strlen(delay_str)) < 0) {
|
||||
perror("Can't set delay\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
|
||||
if (signal(SIGINT, workload_hint_exit) == SIG_IGN)
|
||||
signal(SIGINT, SIG_IGN);
|
||||
if (signal(SIGHUP, workload_hint_exit) == SIG_IGN)
|
||||
signal(SIGHUP, SIG_IGN);
|
||||
if (signal(SIGTERM, workload_hint_exit) == SIG_IGN)
|
||||
signal(SIGTERM, SIG_IGN);
|
||||
|
||||
/* Enable feature via sysfs knob */
|
||||
fd = open(WORKLOAD_ENABLE_ATTRIBUTE, O_RDWR);
|
||||
if (fd < 0) {
|
||||
perror("Unable to open workload type feature enable file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (write(fd, "1\n", 2) < 0) {
|
||||
perror("Can' enable workload hints\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
|
||||
printf("Enabled workload type prediction\n");
|
||||
|
||||
while (1) {
|
||||
fd = open(WORKLOAD_TYPE_INDEX_ATTRIBUTE, O_RDONLY);
|
||||
if (fd < 0) {
|
||||
perror("Unable to open workload type file\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if ((lseek(fd, 0L, SEEK_SET)) < 0) {
|
||||
fprintf(stderr, "Failed to set pointer to beginning\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (read(fd, index_str, sizeof(index_str)) < 0) {
|
||||
fprintf(stderr, "Failed to read from:%s\n",
|
||||
WORKLOAD_TYPE_INDEX_ATTRIBUTE);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
ufd.fd = fd;
|
||||
ufd.events = POLLPRI;
|
||||
|
||||
ret = poll(&ufd, 1, -1);
|
||||
if (ret < 0) {
|
||||
perror("poll error");
|
||||
exit(1);
|
||||
} else if (ret == 0) {
|
||||
printf("Poll Timeout\n");
|
||||
} else {
|
||||
if ((lseek(fd, 0L, SEEK_SET)) < 0) {
|
||||
fprintf(stderr, "Failed to set pointer to beginning\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
if (read(fd, index_str, sizeof(index_str)) < 0)
|
||||
exit(0);
|
||||
|
||||
ret = sscanf(index_str, "%d", &index);
|
||||
if (ret < 0)
|
||||
break;
|
||||
if (index > WORKLOAD_TYPE_MAX_INDEX)
|
||||
printf("Invalid workload type index\n");
|
||||
else
|
||||
printf("workload type:%s\n", workload_types[index]);
|
||||
}
|
||||
|
||||
close(fd);
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,6 @@
|
||||
#include "log.h"
|
||||
|
||||
static int epfd = -1;
|
||||
static unsigned short nrhandler;
|
||||
static sig_atomic_t exit_mainloop;
|
||||
|
||||
struct mainloop_data {
|
||||
@@ -18,8 +17,6 @@ struct mainloop_data {
|
||||
int fd;
|
||||
};
|
||||
|
||||
static struct mainloop_data **mds;
|
||||
|
||||
#define MAX_EVENTS 10
|
||||
|
||||
int mainloop(unsigned int timeout)
|
||||
@@ -61,13 +58,6 @@ int mainloop_add(int fd, mainloop_callback_t cb, void *data)
|
||||
|
||||
struct mainloop_data *md;
|
||||
|
||||
if (fd >= nrhandler) {
|
||||
mds = realloc(mds, sizeof(*mds) * (fd + 1));
|
||||
if (!mds)
|
||||
return -1;
|
||||
nrhandler = fd + 1;
|
||||
}
|
||||
|
||||
md = malloc(sizeof(*md));
|
||||
if (!md)
|
||||
return -1;
|
||||
@@ -76,7 +66,6 @@ int mainloop_add(int fd, mainloop_callback_t cb, void *data)
|
||||
md->cb = cb;
|
||||
md->fd = fd;
|
||||
|
||||
mds[fd] = md;
|
||||
ev.data.ptr = md;
|
||||
|
||||
if (epoll_ctl(epfd, EPOLL_CTL_ADD, fd, &ev) < 0) {
|
||||
@@ -89,14 +78,9 @@ int mainloop_add(int fd, mainloop_callback_t cb, void *data)
|
||||
|
||||
int mainloop_del(int fd)
|
||||
{
|
||||
if (fd >= nrhandler)
|
||||
return -1;
|
||||
|
||||
if (epoll_ctl(epfd, EPOLL_CTL_DEL, fd, NULL) < 0)
|
||||
return -1;
|
||||
|
||||
free(mds[fd]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user