Merge branches 'thermal-powerclamp', 'thermal-int340x' and 'thermal-docs'

Merge powerclamp thermal driver changes, int340x thermal driver changes
and thermal documentation changes for 5.18-rc1:

 - Don't use bitmap_weight() in end_power_clamp() in the powerclamp
   driver (Yury Norov).

 - Update the OS policy capabilities handshake in the int340x thermal
   driver (Srinivas Pandruvada).

 - Increase the policies bitmap size in int340x (Srinivas Pandruvada).

 - Replace acpi_bus_get_device() with acpi_fetch_acpi_dev() in the
   int340x thermal driver (Rafael Wysocki).

 - Check for NULL after calling kmemdup() in int340x (Jiasheng Jiang).

 - Add Intel Dynamic Power and Thermal Framework (DPTF) kernel interface
   documentation (Srinivas Pandruvada).

 - Fix bullet list warning in the thermal documentation (Randy Dunlap).

* thermal-powerclamp:
  thermal: intel_powerclamp: don't use bitmap_weight() in end_power_clamp()

* thermal-int340x:
  thermal: int340x: Update OS policy capability handshake
  thermal: int340x: Increase bitmap size
  thermal: Replace acpi_bus_get_device()
  thermal: int340x: Check for NULL after calling kmemdup()

* thermal-docs:
  Documentation: thermal: DPTF Documentation
  thermal: fix Documentation bullet list warning
This commit is contained in:
Rafael J. Wysocki 2022-03-18 18:53:02 +01:00
commit 2d6fc1455f
6 changed files with 387 additions and 73 deletions

View file

@ -203,7 +203,7 @@ Description:
- for generic ACPI: should be "Fan", "Processor" or "LCD"
- for memory controller device on intel_menlow platform:
should be "Memory controller".
should be "Memory controller".
RO, Required

View file

@ -17,3 +17,4 @@ Thermal
intel_powerclamp
nouveau_thermal
x86_pkg_temperature_thermal
intel_dptf

View file

@ -0,0 +1,272 @@
.. SPDX-License-Identifier: GPL-2.0
===============================================================
Intel(R) Dynamic Platform and Thermal Framework Sysfs Interface
===============================================================
:Copyright: |copy| 2022 Intel Corporation
:Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Introduction
------------
Intel(R) Dynamic Platform and Thermal Framework (DPTF) is a platform
level hardware/software solution for power and thermal management.
As a container for multiple power/thermal technologies, DPTF provides
a coordinated approach for different policies to effect the hardware
state of a system.
Since it is a platform level framework, this has several components.
Some parts of the technology is implemented in the firmware and uses
ACPI and PCI devices to expose various features for monitoring and
control. Linux has a set of kernel drivers exposing hardware interface
to user space. This allows user space thermal solutions like
"Linux Thermal Daemon" to read platform specific thermal and power
tables to deliver adequate performance while keeping the system under
thermal limits.
DPTF ACPI Drivers interface
----------------------------
:file:`/sys/bus/platform/devices/<N>/uuids`, where <N>
=INT3400|INTC1040|INTC1041|INTC10A0
``available_uuids`` (RO)
A set of UUIDs strings presenting available policies
which should be notified to the firmware when the
user space can support those policies.
UUID strings:
"42A441D6-AE6A-462b-A84B-4A8CE79027D3" : Passive 1
"3A95C389-E4B8-4629-A526-C52C88626BAE" : Active
"97C68AE7-15FA-499c-B8C9-5DA81D606E0A" : Critical
"63BE270F-1C11-48FD-A6F7-3AF253FF3E2D" : Adaptive performance
"5349962F-71E6-431D-9AE8-0A635B710AEE" : Emergency call
"9E04115A-AE87-4D1C-9500-0F3E340BFE75" : Passive 2
"F5A35014-C209-46A4-993A-EB56DE7530A1" : Power Boss
"6ED722A7-9240-48A5-B479-31EEF723D7CF" : Virtual Sensor
"16CAF1B7-DD38-40ED-B1C1-1B8A1913D531" : Cooling mode
"BE84BABF-C4D4-403D-B495-3128FD44dAC1" : HDC
``current_uuid`` (RW)
User space can write strings from available UUIDs, one at a
time.
:file:`/sys/bus/platform/devices/<N>/`, where <N>
=INT3400|INTC1040|INTC1041|INTC10A0
``imok`` (WO)
User space daemon write 1 to respond to firmware event
for sending keep alive notification. User space receives
THERMAL_EVENT_KEEP_ALIVE kobject uevent notification when
firmware calls for user space to respond with imok ACPI
method.
``odvp*`` (RO)
Firmware thermal status variable values. Thermal tables
calls for different processing based on these variable
values.
``data_vault`` (RO)
Binary thermal table. Refer to
https:/github.com/intel/thermal_daemon for decoding
thermal table.
ACPI Thermal Relationship table interface
------------------------------------------
:file:`/dev/acpi_thermal_rel`
This device provides IOCTL interface to read standard ACPI
thermal relationship tables via ACPI methods _TRT and _ART.
These IOCTLs are defined in
drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.h
IOCTLs:
ACPI_THERMAL_GET_TRT_LEN: Get length of TRT table
ACPI_THERMAL_GET_ART_LEN: Get length of ART table
ACPI_THERMAL_GET_TRT_COUNT: Number of records in TRT table
ACPI_THERMAL_GET_ART_COUNT: Number of records in ART table
ACPI_THERMAL_GET_TRT: Read binary TRT table, length to read is
provided via argument to ioctl().
ACPI_THERMAL_GET_ART: Read binary ART table, length to read is
provided via argument to ioctl().
DPTF ACPI Sensor drivers
-------------------------
DPTF Sensor drivers are presented as standard thermal sysfs thermal_zone.
DPTF ACPI Cooling drivers
--------------------------
DPTF cooling drivers are presented as standard thermal sysfs cooling_device.
DPTF Processor thermal PCI Driver interface
--------------------------------------------
:file:`/sys/bus/pci/devices/0000\:00\:04.0/power_limits/`
Refer to Documentation/power/powercap/powercap.rst for powercap
ABI.
``power_limit_0_max_uw`` (RO)
Maximum powercap sysfs constraint_0_power_limit_uw for Intel RAPL
``power_limit_0_step_uw`` (RO)
Power limit increment/decrements for Intel RAPL constraint 0 power limit
``power_limit_0_min_uw`` (RO)
Minimum powercap sysfs constraint_0_power_limit_uw for Intel RAPL
``power_limit_0_tmin_us`` (RO)
Minimum powercap sysfs constraint_0_time_window_us for Intel RAPL
``power_limit_0_tmax_us`` (RO)
Maximum powercap sysfs constraint_0_time_window_us for Intel RAPL
``power_limit_1_max_uw`` (RO)
Maximum powercap sysfs constraint_1_power_limit_uw for Intel RAPL
``power_limit_1_step_uw`` (RO)
Power limit increment/decrements for Intel RAPL constraint 1 power limit
``power_limit_1_min_uw`` (RO)
Minimum powercap sysfs constraint_1_power_limit_uw for Intel RAPL
``power_limit_1_tmin_us`` (RO)
Minimum powercap sysfs constraint_1_time_window_us for Intel RAPL
``power_limit_1_tmax_us`` (RO)
Maximum powercap sysfs constraint_1_time_window_us for Intel RAPL
:file:`/sys/bus/pci/devices/0000\:00\:04.0/`
``tcc_offset_degree_celsius`` (RW)
TCC offset from the critical temperature where hardware will throttle
CPU.
:file:`/sys/bus/pci/devices/0000\:00\:04.0/workload_request`
``workload_available_types`` (RO)
Available workload types. User space can specify one of the workload type
it is currently executing via workload_type. For example: idle, bursty,
sustained etc.
``workload_type`` (RW)
User space can specify any one of the available workload type using
this interface.
DPTF Processor thermal RFIM interface
--------------------------------------------
RFIM interface allows adjustment of FIVR (Fully Integrated Voltage Regulator)
and DDR (Double Data Rate)frequencies to avoid RF interference with WiFi and 5G.
Switching voltage regulators (VR) generate radiated EMI or RFI at the
fundamental frequency and its harmonics. Some harmonics may interfere
with very sensitive wireless receivers such as Wi-Fi and cellular that
are integrated into host systems like notebook PCs. One of mitigation
methods is requesting SOC integrated VR (IVR) switching frequency to a
small % and shift away the switching noise harmonic interference from
radio channels. OEM or ODMs can use the driver to control SOC IVR
operation within the range where it does not impact IVR performance.
DRAM devices of DDR IO interface and their power plane can generate EMI
at the data rates. Similar to IVR control mechanism, Intel offers a
mechanism by which DDR data rates can be changed if several conditions
are met: there is strong RFI interference because of DDR; CPU power
management has no other restriction in changing DDR data rates;
PC ODMs enable this feature (real time DDR RFI Mitigation referred to as
DDR-RFIM) for Wi-Fi from BIOS.
FIVR attributes
:file:`/sys/bus/pci/devices/0000\:00\:04.0/fivr/`
``vco_ref_code_lo`` (RW)
The VCO reference code is an 11-bit field and controls the FIVR
switching frequency. This is the 3-bit LSB field.
``vco_ref_code_hi`` (RW)
The VCO reference code is an 11-bit field and controls the FIVR
switching frequency. This is the 8-bit MSB field.
``spread_spectrum_pct`` (RW)
Set the FIVR spread spectrum clocking percentage
``spread_spectrum_clk_enable`` (RW)
Enable/disable of the FIVR spread spectrum clocking feature
``rfi_vco_ref_code`` (RW)
This field is a read only status register which reflects the
current FIVR switching frequency
``fivr_fffc_rev`` (RW)
This field indicated the revision of the FIVR HW.
DVFS attributes
:file:`/sys/bus/pci/devices/0000\:00\:04.0/dvfs/`
``rfi_restriction_run_busy`` (RW)
Request the restriction of specific DDR data rate and set this
value 1. Self reset to 0 after operation.
``rfi_restriction_err_code`` (RW)
0 :Request is accepted, 1:Feature disabled,
2: the request restricts more points than it is allowed
``rfi_restriction_data_rate_Delta`` (RW)
Restricted DDR data rate for RFI protection: Lower Limit
``rfi_restriction_data_rate_Base`` (RW)
Restricted DDR data rate for RFI protection: Upper Limit
``ddr_data_rate_point_0`` (RO)
DDR data rate selection 1st point
``ddr_data_rate_point_1`` (RO)
DDR data rate selection 2nd point
``ddr_data_rate_point_2`` (RO)
DDR data rate selection 3rd point
``ddr_data_rate_point_3`` (RO)
DDR data rate selection 4th point
``rfi_disable (RW)``
Disable DDR rate change feature
DPTF Power supply and Battery Interface
----------------------------------------
Refer to Documentation/ABI/testing/sysfs-platform-dptf
DPTF Fan Control
----------------------------------------
Refer to Documentation/admin-guide/acpi/fan_performance_states.rst

View file

@ -72,7 +72,6 @@ int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trtp,
int i;
int nr_bad_entries = 0;
struct trt *trts;
struct acpi_device *adev;
union acpi_object *p;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_buffer element = { 0, NULL };
@ -112,12 +111,10 @@ int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trtp,
if (!create_dev)
continue;
result = acpi_bus_get_device(trt->source, &adev);
if (result)
if (!acpi_fetch_acpi_dev(trt->source))
pr_warn("Failed to get source ACPI device\n");
result = acpi_bus_get_device(trt->target, &adev);
if (result)
if (!acpi_fetch_acpi_dev(trt->target))
pr_warn("Failed to get target ACPI device\n");
}
@ -149,7 +146,6 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp,
int i;
int nr_bad_entries = 0;
struct art *arts;
struct acpi_device *adev;
union acpi_object *p;
struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
struct acpi_buffer element = { 0, NULL };
@ -191,16 +187,11 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp,
if (!create_dev)
continue;
if (art->source) {
result = acpi_bus_get_device(art->source, &adev);
if (result)
pr_warn("Failed to get source ACPI device\n");
}
if (art->target) {
result = acpi_bus_get_device(art->target, &adev);
if (result)
pr_warn("Failed to get target ACPI device\n");
}
if (!acpi_fetch_acpi_dev(art->source))
pr_warn("Failed to get source ACPI device\n");
if (!acpi_fetch_acpi_dev(art->target))
pr_warn("Failed to get target ACPI device\n");
}
*artp = arts;

View file

@ -17,8 +17,8 @@
#define INT3400_KEEP_ALIVE 0xA0
enum int3400_thermal_uuid {
INT3400_THERMAL_ACTIVE = 0,
INT3400_THERMAL_PASSIVE_1,
INT3400_THERMAL_ACTIVE,
INT3400_THERMAL_CRITICAL,
INT3400_THERMAL_ADAPTIVE_PERFORMANCE,
INT3400_THERMAL_EMERGENCY_CALL_MODE,
@ -31,8 +31,8 @@ enum int3400_thermal_uuid {
};
static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
"42A441D6-AE6A-462b-A84B-4A8CE79027D3",
"3A95C389-E4B8-4629-A526-C52C88626BAE",
"42A441D6-AE6A-462b-A84B-4A8CE79027D3",
"97C68AE7-15FA-499c-B8C9-5DA81D606E0A",
"63BE270F-1C11-48FD-A6F7-3AF253FF3E2D",
"5349962F-71E6-431D-9AE8-0A635B710AEE",
@ -53,12 +53,13 @@ struct int3400_thermal_priv {
struct art *arts;
int trt_count;
struct trt *trts;
u8 uuid_bitmap;
u32 uuid_bitmap;
int rel_misc_dev_res;
int current_uuid_index;
char *data_vault;
int odvp_count;
int *odvp;
u32 os_uuid_mask;
struct odvp_attr *odvp_attrs;
};
@ -142,12 +143,55 @@ static ssize_t current_uuid_show(struct device *dev,
struct device_attribute *devattr, char *buf)
{
struct int3400_thermal_priv *priv = dev_get_drvdata(dev);
int i, length = 0;
if (priv->current_uuid_index == -1)
return sprintf(buf, "INVALID\n");
if (priv->current_uuid_index > 0)
return sprintf(buf, "%s\n",
int3400_thermal_uuids[priv->current_uuid_index]);
return sprintf(buf, "%s\n",
int3400_thermal_uuids[priv->current_uuid_index]);
for (i = 0; i <= INT3400_THERMAL_CRITICAL; i++) {
if (priv->os_uuid_mask & BIT(i))
length += scnprintf(&buf[length],
PAGE_SIZE - length,
"%s\n",
int3400_thermal_uuids[i]);
}
if (length)
return length;
return sprintf(buf, "INVALID\n");
}
static int int3400_thermal_run_osc(acpi_handle handle, char *uuid_str, int *enable)
{
u32 ret, buf[2];
acpi_status status;
int result = 0;
struct acpi_osc_context context = {
.uuid_str = NULL,
.rev = 1,
.cap.length = 8,
};
context.uuid_str = uuid_str;
buf[OSC_QUERY_DWORD] = 0;
buf[OSC_SUPPORT_DWORD] = *enable;
context.cap.pointer = buf;
status = acpi_run_osc(handle, &context);
if (ACPI_SUCCESS(status)) {
ret = *((u32 *)(context.ret.pointer + 4));
if (ret != *enable)
result = -EPERM;
} else
result = -EPERM;
kfree(context.ret.pointer);
return result;
}
static ssize_t current_uuid_store(struct device *dev,
@ -164,16 +208,47 @@ static ssize_t current_uuid_store(struct device *dev,
* If we have a list of supported UUIDs, make sure
* this one is supported.
*/
if (priv->uuid_bitmap &&
!(priv->uuid_bitmap & (1 << i)))
if (priv->uuid_bitmap & BIT(i)) {
priv->current_uuid_index = i;
return count;
}
/*
* There is support of only 3 policies via the new
* _OSC to inform OS capability:
* INT3400_THERMAL_ACTIVE
* INT3400_THERMAL_PASSIVE_1
* INT3400_THERMAL_CRITICAL
*/
if (i > INT3400_THERMAL_CRITICAL)
return -EINVAL;
priv->current_uuid_index = i;
return count;
priv->os_uuid_mask |= BIT(i);
break;
}
}
return -EINVAL;
if (priv->os_uuid_mask) {
int cap, ret;
/*
* Capability bits:
* Bit 0: set to 1 to indicate DPTF is active
* Bi1 1: set to 1 to active cooling is supported by user space daemon
* Bit 2: set to 1 to passive cooling is supported by user space daemon
* Bit 3: set to 1 to critical trip is handled by user space daemon
*/
cap = ((priv->os_uuid_mask << 1) | 0x01);
ret = int3400_thermal_run_osc(priv->adev->handle,
"b23ba85d-c8b7-3542-88de-8de2ffcfd698",
&cap);
if (ret)
return ret;
}
return count;
}
static DEVICE_ATTR_RW(current_uuid);
@ -236,41 +311,6 @@ static int int3400_thermal_get_uuids(struct int3400_thermal_priv *priv)
return result;
}
static int int3400_thermal_run_osc(acpi_handle handle,
enum int3400_thermal_uuid uuid, bool enable)
{
u32 ret, buf[2];
acpi_status status;
int result = 0;
struct acpi_osc_context context = {
.uuid_str = NULL,
.rev = 1,
.cap.length = 8,
};
if (uuid < 0 || uuid >= INT3400_THERMAL_MAXIMUM_UUID)
return -EINVAL;
context.uuid_str = int3400_thermal_uuids[uuid];
buf[OSC_QUERY_DWORD] = 0;
buf[OSC_SUPPORT_DWORD] = enable;
context.cap.pointer = buf;
status = acpi_run_osc(handle, &context);
if (ACPI_SUCCESS(status)) {
ret = *((u32 *)(context.ret.pointer + 4));
if (ret != enable)
result = -EPERM;
} else
result = -EPERM;
kfree(context.ret.pointer);
return result;
}
static ssize_t odvp_show(struct kobject *kobj, struct kobj_attribute *attr,
char *buf)
{
@ -426,10 +466,18 @@ static int int3400_thermal_change_mode(struct thermal_zone_device *thermal,
if (!priv)
return -EINVAL;
if (mode != thermal->mode)
if (mode != thermal->mode) {
int enabled;
if (priv->current_uuid_index < 0 ||
priv->current_uuid_index >= INT3400_THERMAL_MAXIMUM_UUID)
return -EINVAL;
enabled = (mode == THERMAL_DEVICE_ENABLED);
result = int3400_thermal_run_osc(priv->adev->handle,
priv->current_uuid_index,
mode == THERMAL_DEVICE_ENABLED);
int3400_thermal_uuids[priv->current_uuid_index],
&enabled);
}
evaluate_odvp(priv);
@ -468,6 +516,11 @@ static void int3400_setup_gddv(struct int3400_thermal_priv *priv)
priv->data_vault = kmemdup(obj->package.elements[0].buffer.pointer,
obj->package.elements[0].buffer.length,
GFP_KERNEL);
if (!priv->data_vault) {
kfree(buffer.pointer);
return;
}
bin_attr_data_vault.private = priv->data_vault;
bin_attr_data_vault.size = obj->package.elements[0].buffer.length;
kfree(buffer.pointer);

View file

@ -556,12 +556,9 @@ static void end_power_clamp(void)
* stop faster.
*/
clamping = false;
if (bitmap_weight(cpu_clamping_mask, num_possible_cpus())) {
for_each_set_bit(i, cpu_clamping_mask, num_possible_cpus()) {
pr_debug("clamping worker for cpu %d alive, destroy\n",
i);
stop_power_clamp_worker(i);
}
for_each_set_bit(i, cpu_clamping_mask, num_possible_cpus()) {
pr_debug("clamping worker for cpu %d alive, destroy\n", i);
stop_power_clamp_worker(i);
}
}