History

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

Pull thermal control updates from Rafael Wysocki: "As far as new functionality is concerned, there is a new thermal driver for the Intel Hardware Feedback Interface (HFI) along with some intel-speed-select utility changes to support it. There are also new DT compatible strings for a couple of platforms, and thermal zones on some platforms will be registered as HWmon sensors now. Apart from the above, some drivers are updated (fixes mostly) and there is a new piece of documentation for the Intel DPTF (Dynamic Power and Thermal Framework) sysfs interface. Specifics: - Add a new thermal driver for the Intel Hardware Feedback Interface (HFI) including the HFI initialization, HFI notification interrupt handling and sending CPU capabilities change messages to user space via the thermal netlink interface (Ricardo Neri, Srinivas Pandruvada, Nathan Chancellor, Randy Dunlap). - Extend the intel-speed-select utility to handle out-of-band CPU configuration changes and add support for the CPU capabilities change messages sent over the thermal netlink interface by the new HFI thermal driver to it (Srinivas Pandruvada). - Convert the DT bindings to yaml format for the Exynos platform and fix and update the MAINTAINERS file for this driver (Krzysztof Kozlowski). - Register the thermal zones as HWmon sensors for the QCom's Tsens driver and TI thermal platforms (Dmitry Baryshkov, Romain Naour). - Add the msm8953 compatible documentation in the bindings (Luca Weiss). - Add the sm8150 platform support to the QCom LMh driver's DT binding (Thara Gopinath). - Check the command result from the IPC command to the BPMP in the Tegra driver (Mikko Perttunen). - Silence the error for normal configuration where the interrupt is optionnal in the Broadcom thermal driver (Florian Fainelli). - Remove remaining dead code from the TI thermal driver (Yue Haibing). - 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)" * tag 'thermal-5.18-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm: (30 commits) thermal: int340x: Update OS policy capability handshake thermal: int340x: Increase bitmap size Documentation: thermal: DPTF Documentation MAINTAINERS: thermal: samsung: update Krzysztof Kozlowski's email thermal/drivers/ti-soc-thermal: Remove unused function ti_thermal_get_temp() thermal/drivers/brcmstb_thermal: Interrupt is optional thermal: tegra-bpmp: Handle errors in BPMP response drivers/thermal/ti-soc-thermal: Add hwmon support dt-bindings: thermal: tsens: Add msm8953 compatible dt-bindings: thermal: Add sm8150 compatible string for LMh thermal/drivers/qcom/lmh: Add support for sm8150 thermal/drivers/tsens: register thermal zones as hwmon sensors MAINTAINERS: thermal: samsung: Drop obsolete properties dt-bindings: thermal: samsung: Convert to dtschema tools/power/x86/intel-speed-select: v1.12 release tools/power/x86/intel-speed-select: HFI support tools/power/x86/intel-speed-select: OOB daemon mode thermal: intel: hfi: INTEL_HFI_THERMAL depends on NET thermal: netlink: Fix parameter type of thermal_genl_cpu_capability_event() stub thermal: Replace acpi_bus_get_device() ...

Linus Torvalds committed 4 years ago

Commit f6483722 parents 02b82b0 31035f334 files · +2026 −235Browse files

Unified · Split

34 files
  1. Documentation/ABI/testing/sysfs-class-thermal +1 −1
  2. Documentation/devicetree/bindings/thermal/exynos-thermal.txt +0 −106
  3. Documentation/devicetree/bindings/thermal/qcom-lmh.yaml +1 −0
  4. Documentation/devicetree/bindings/thermal/qcom-tsens.yaml +1 −0
  5. Documentation/devicetree/bindings/thermal/samsung,exynos-thermal.yaml +184 −0
  6. Documentation/driver-api/thermal/index.rst +1 −0
  7. Documentation/driver-api/thermal/intel_dptf.rst +272 −0
  8. Documentation/x86/index.rst +1 −0
  9. Documentation/x86/intel-hfi.rst +72 −0
  10. MAINTAINERS +4 −3
  11. arch/x86/include/asm/cpufeatures.h +1 −0
  12. arch/x86/include/asm/msr-index.h +6 −0
  13. drivers/thermal/broadcom/brcmstb_thermal.c +1 −1
  14. drivers/thermal/intel/Kconfig +14 −0
  15. drivers/thermal/intel/Makefile +1 −0
  16. drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c +7 −16
  17. drivers/thermal/intel/int340x_thermal/int3400_thermal.c +103 −50
  18. drivers/thermal/intel/intel_hfi.c +569 −0
  19. drivers/thermal/intel/intel_hfi.h +17 −0
  20. drivers/thermal/intel/intel_powerclamp.c +3 −6
  21. drivers/thermal/intel/therm_throt.c +22 −0
  22. drivers/thermal/qcom/lmh.c +35 −27
  23. drivers/thermal/qcom/tsens.c +5 −0
  24. drivers/thermal/tegra/tegra-bpmp-thermal.c +12 −1
  25. drivers/thermal/thermal_netlink.c +53 −0
  26. drivers/thermal/thermal_netlink.h +14 −0
  27. drivers/thermal/ti-soc-thermal/ti-thermal-common.c +4 −8
  28. include/uapi/linux/thermal.h +5 −1
  29. tools/power/x86/intel-speed-select/Build +1 −1
  30. tools/power/x86/intel-speed-select/Makefile +7 −3
  31. tools/power/x86/intel-speed-select/hfi-events.c +309 −0
  32. tools/power/x86/intel-speed-select/isst-config.c +43 −11
  33. tools/power/x86/intel-speed-select/isst-daemon.c +244 −0
  34. tools/power/x86/intel-speed-select/isst.h +13 −0
Documentation/ABI/testing/sysfs-class-thermal+1−1
@@ -203,7 +203,7 @@ Description: · 202 unmodified lines
203 203
204 - for generic ACPI: should be "Fan", "Processor" or "LCD"204 - for generic ACPI: should be "Fan", "Processor" or "LCD"
205 - for memory controller device on intel_menlow platform:205 - for memory controller device on intel_menlow platform:
206 should be "Memory controller".206 should be "Memory controller".
207 207
208 RO, Required208 RO, Required
209 209
Documentation/devicetree/bindings/thermal/exynos-thermal.txt+0−106
@@ -1,106 +0,0 @@
1* Exynos Thermal Management Unit (TMU)
2
3** Required properties:
4
5- compatible : One of the following:
6 "samsung,exynos3250-tmu"
7 "samsung,exynos4412-tmu"
8 "samsung,exynos4210-tmu"
9 "samsung,exynos5250-tmu"
10 "samsung,exynos5260-tmu"
11 "samsung,exynos5420-tmu" for TMU channel 0, 1 on Exynos5420
12 "samsung,exynos5420-tmu-ext-triminfo" for TMU channels 2, 3 and 4
13 Exynos5420 (Must pass triminfo base and triminfo clock)
14 "samsung,exynos5433-tmu"
15 "samsung,exynos7-tmu"
16- reg : Address range of the thermal registers. For soc's which has multiple
17 instances of TMU and some registers are shared across all TMU's like
18 interrupt related then 2 set of register has to supplied. First set
19 belongs to register set of TMU instance and second set belongs to
20 registers shared with the TMU instance.
21
22 NOTE: On Exynos5420, the TRIMINFO register is misplaced for TMU
23 channels 2, 3 and 4
24 Use "samsung,exynos5420-tmu-ext-triminfo" in cases, there is a misplaced
25 register, also provide clock to access that base.
26
27 TRIMINFO at 0x1006c000 contains data for TMU channel 3
28 TRIMINFO at 0x100a0000 contains data for TMU channel 4
29 TRIMINFO at 0x10068000 contains data for TMU channel 2
30
31- interrupts : Should contain interrupt for thermal system
32- clocks : The main clocks for TMU device
33 -- 1. operational clock for TMU channel
34 -- 2. optional clock to access the shared registers of TMU channel
35 -- 3. optional special clock for functional operation
36- clock-names : Thermal system clock name
37 -- "tmu_apbif" operational clock for current TMU channel
38 -- "tmu_triminfo_apbif" clock to access the shared triminfo register
39 for current TMU channel
40 -- "tmu_sclk" clock for functional operation of the current TMU
41 channel
42
43The Exynos TMU supports generating interrupts when reaching given
44temperature thresholds. Number of supported thermal trip points depends
45on the SoC (only first trip points defined in DT will be configured):
46 - most of SoC: 4
47 - samsung,exynos5433-tmu: 8
48 - samsung,exynos7-tmu: 8
49
50** Optional properties:
51
52- vtmu-supply: This entry is optional and provides the regulator node supplying
53 voltage to TMU. If needed this entry can be placed inside
54 board/platform specific dts file.
55
56Example 1):
57
58 tmu@100c0000 {
59 compatible = "samsung,exynos4412-tmu";
60 interrupt-parent = <&combiner>;
61 reg = <0x100C0000 0x100>;
62 interrupts = <2 4>;
63 clocks = <&clock 383>;
64 clock-names = "tmu_apbif";
65 vtmu-supply = <&tmu_regulator_node>;
66 #thermal-sensor-cells = <0>;
67 };
68
69Example 2): (In case of Exynos5420 "with misplaced TRIMINFO register")
70 tmu_cpu2: tmu@10068000 {
71 compatible = "samsung,exynos5420-tmu-ext-triminfo";
72 reg = <0x10068000 0x100>, <0x1006c000 0x4>;
73 interrupts = <0 184 0>;
74 clocks = <&clock 318>, <&clock 318>;
75 clock-names = "tmu_apbif", "tmu_triminfo_apbif";
76 #thermal-sensor-cells = <0>;
77 };
78
79 tmu_cpu3: tmu@1006c000 {
80 compatible = "samsung,exynos5420-tmu-ext-triminfo";
81 reg = <0x1006c000 0x100>, <0x100a0000 0x4>;
82 interrupts = <0 185 0>;
83 clocks = <&clock 318>, <&clock 319>;
84 clock-names = "tmu_apbif", "tmu_triminfo_apbif";
85 #thermal-sensor-cells = <0>;
86 };
87
88 tmu_gpu: tmu@100a0000 {
89 compatible = "samsung,exynos5420-tmu-ext-triminfo";
90 reg = <0x100a0000 0x100>, <0x10068000 0x4>;
91 interrupts = <0 215 0>;
92 clocks = <&clock 319>, <&clock 318>;
93 clock-names = "tmu_apbif", "tmu_triminfo_apbif";
94 #thermal-sensor-cells = <0>;
95 };
96
97Note: For multi-instance tmu each instance should have an alias correctly
98numbered in "aliases" node.
99
100Example:
101
102aliases {
103 tmuctrl0 = &tmuctrl_0;
104 tmuctrl1 = &tmuctrl_1;
105 tmuctrl2 = &tmuctrl_2;
106};
Documentation/devicetree/bindings/thermal/qcom-lmh.yaml+1−0
@@ -19,6 +19,7 @@ properties: · 18 unmodified lines
19 compatible:19 compatible:
20 enum:20 enum:
21 - qcom,sdm845-lmh21 - qcom,sdm845-lmh
22 - qcom,sm8150-lmh
22 23
23 reg:24 reg:
24 items:25 items:
Documentation/devicetree/bindings/thermal/qcom-tsens.yaml+1−0
@@ -43,6 +43,7 @@ properties: · 42 unmodified lines
43 - description: v2 of TSENS43 - description: v2 of TSENS
44 items:44 items:
45 - enum:45 - enum:
46 - qcom,msm8953-tsens
46 - qcom,msm8996-tsens47 - qcom,msm8996-tsens
47 - qcom,msm8998-tsens48 - qcom,msm8998-tsens
48 - qcom,sc7180-tsens49 - qcom,sc7180-tsens
Documentation/devicetree/bindings/thermal/samsung,exynos-thermal.yaml+184−0
@@ -0,0 +1,184 @@
1# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
2%YAML 1.2
3---
4$id: http://devicetree.org/schemas/thermal/samsung,exynos-thermal.yaml#
5$schema: http://devicetree.org/meta-schemas/core.yaml#
6
7title: Samsung Exynos SoC Thermal Management Unit (TMU)
8
9maintainers:
10 - Krzysztof Kozlowski <krzysztof.kozlowski@canonical.com>
11
12description: |
13 For multi-instance tmu each instance should have an alias correctly numbered
14 in "aliases" node.
15
16properties:
17 compatible:
18 enum:
19 - samsung,exynos3250-tmu
20 - samsung,exynos4412-tmu
21 - samsung,exynos4210-tmu
22 - samsung,exynos5250-tmu
23 - samsung,exynos5260-tmu
24 # For TMU channel 0, 1 on Exynos5420:
25 - samsung,exynos5420-tmu
26 # For TMU channels 2, 3 and 4 of Exynos5420:
27 - samsung,exynos5420-tmu-ext-triminfo
28 - samsung,exynos5433-tmu
29 - samsung,exynos7-tmu
30
31 clocks:
32 minItems: 1
33 maxItems: 3
34
35 clock-names:
36 minItems: 1
37 maxItems: 3
38
39 interrupts:
40 description: |
41 The Exynos TMU supports generating interrupts when reaching given
42 temperature thresholds. Number of supported thermal trip points depends
43 on the SoC (only first trip points defined in DT will be configured)::
44 - most of SoC: 4
45 - samsung,exynos5433-tmu: 8
46 - samsung,exynos7-tmu: 8
47 maxItems: 1
48
49 reg:
50 items:
51 - description: TMU instance registers.
52 - description: |
53 Shared TMU registers.
54
55 Note:: On Exynos5420, the TRIMINFO register is misplaced for TMU
56 channels 2, 3 and 4 Use "samsung,exynos5420-tmu-ext-triminfo" in
57 cases, there is a misplaced register, also provide clock to access
58 that base.
59 TRIMINFO at 0x1006c000 contains data for TMU channel 3
60 TRIMINFO at 0x100a0000 contains data for TMU channel 4
61 TRIMINFO at 0x10068000 contains data for TMU channel 2
62 minItems: 1
63
64 '#thermal-sensor-cells': true
65
66 vtmu-supply:
67 description: The regulator node supplying voltage to TMU.
68
69required:
70 - compatible
71 - clocks
72 - clock-names
73 - interrupts
74 - reg
75
76allOf:
77 - $ref: /schemas/thermal/thermal-sensor.yaml
78 - if:
79 properties:
80 compatible:
81 contains:
82 const: samsung,exynos5420-tmu-ext-triminfo
83 then:
84 properties:
85 clocks:
86 items:
87 - description:
88 Operational clock for TMU channel.
89 - description:
90 Optional clock to access the shared registers (e.g. TRIMINFO) of TMU
91 channel.
92 clock-names:
93 items:
94 - const: tmu_apbif
95 - const: tmu_triminfo_apbif
96 reg:
97 minItems: 2
98 maxItems: 2
99 - if:
100 properties:
101 compatible:
102 contains:
103 enum:
104 - samsung,exynos5433-tmu
105 - samsung,exynos7-tmu
106 then:
107 properties:
108 clocks:
109 items:
110 - description:
111 Operational clock for TMU channel.
112 - description:
113 Optional special clock for functional operation of TMU channel.
114 clock-names:
115 items:
116 - const: tmu_apbif
117 - const: tmu_sclk
118 reg:
119 minItems: 1
120 maxItems: 1
121
122 - if:
123 properties:
124 compatible:
125 contains:
126 enum:
127 - samsung,exynos3250-tmu
128 - samsung,exynos4412-tmu
129 - samsung,exynos4210-tmu
130 - samsung,exynos5250-tmu
131 - samsung,exynos5260-tmu
132 - samsung,exynos5420-tmu
133 then:
134 properties:
135 clocks:
136 minItems: 1
137 maxItems: 1
138 reg:
139 minItems: 1
140 maxItems: 1
141
142additionalProperties: false
143
144examples:
145 - |
146 #include <dt-bindings/clock/exynos4.h>
147
148 tmu@100c0000 {
149 compatible = "samsung,exynos4412-tmu";
150 reg = <0x100C0000 0x100>;
151 interrupt-parent = <&combiner>;
152 interrupts = <2 4>;
153 #thermal-sensor-cells = <0>;
154 clocks = <&clock CLK_TMU_APBIF>;
155 clock-names = "tmu_apbif";
156 vtmu-supply = <&ldo10_reg>;
157 };
158
159 - |
160 #include <dt-bindings/interrupt-controller/arm-gic.h>
161
162 tmu@10068000 {
163 compatible = "samsung,exynos5420-tmu-ext-triminfo";
164 reg = <0x10068000 0x100>, <0x1006c000 0x4>;
165 interrupts = <GIC_SPI 184 IRQ_TYPE_LEVEL_HIGH>;
166 #thermal-sensor-cells = <0>;
167 clocks = <&clock 318>, <&clock 318>; /* CLK_TMU */
168 clock-names = "tmu_apbif", "tmu_triminfo_apbif";
169 vtmu-supply = <&ldo7_reg>;
170 };
171
172 - |
173 #include <dt-bindings/interrupt-controller/arm-gic.h>
174
175 tmu@10060000 {
176 compatible = "samsung,exynos5433-tmu";
177 reg = <0x10060000 0x200>;
178 interrupts = <GIC_SPI 95 IRQ_TYPE_LEVEL_HIGH>;
179 #thermal-sensor-cells = <0>;
180 clocks = <&cmu_peris 3>, /* CLK_PCLK_TMU0_APBIF */
181 <&cmu_peris 35>; /* CLK_SCLK_TMU0 */
182 clock-names = "tmu_apbif", "tmu_sclk";
183 vtmu-supply = <&ldo3_reg>;
184 };
Documentation/driver-api/thermal/index.rst+1−0
@@ -17,3 +17,4 @@ Thermal · 16 unmodified lines
17 intel_powerclamp17 intel_powerclamp
18 nouveau_thermal18 nouveau_thermal
19 x86_pkg_temperature_thermal19 x86_pkg_temperature_thermal
20 intel_dptf
Documentation/driver-api/thermal/intel_dptf.rst+272−0
@@ -0,0 +1,272 @@
1.. SPDX-License-Identifier: GPL-2.0
2
3===============================================================
4Intel(R) Dynamic Platform and Thermal Framework Sysfs Interface
5===============================================================
6
7:Copyright: |copy| 2022 Intel Corporation
8
9:Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
10
11Introduction
12------------
13
14Intel(R) Dynamic Platform and Thermal Framework (DPTF) is a platform
15level hardware/software solution for power and thermal management.
16
17As a container for multiple power/thermal technologies, DPTF provides
18a coordinated approach for different policies to effect the hardware
19state of a system.
20
21Since it is a platform level framework, this has several components.
22Some parts of the technology is implemented in the firmware and uses
23ACPI and PCI devices to expose various features for monitoring and
24control. Linux has a set of kernel drivers exposing hardware interface
25to user space. This allows user space thermal solutions like
26"Linux Thermal Daemon" to read platform specific thermal and power
27tables to deliver adequate performance while keeping the system under
28thermal limits.
29
30DPTF ACPI Drivers interface
31----------------------------
32
33:file:`/sys/bus/platform/devices/<N>/uuids`, where <N>
34=INT3400|INTC1040|INTC1041|INTC10A0
35
36``available_uuids`` (RO)
37 A set of UUIDs strings presenting available policies
38 which should be notified to the firmware when the
39 user space can support those policies.
40
41 UUID strings:
42
43 "42A441D6-AE6A-462b-A84B-4A8CE79027D3" : Passive 1
44
45 "3A95C389-E4B8-4629-A526-C52C88626BAE" : Active
46
47 "97C68AE7-15FA-499c-B8C9-5DA81D606E0A" : Critical
48
49 "63BE270F-1C11-48FD-A6F7-3AF253FF3E2D" : Adaptive performance
50
51 "5349962F-71E6-431D-9AE8-0A635B710AEE" : Emergency call
52
53 "9E04115A-AE87-4D1C-9500-0F3E340BFE75" : Passive 2
54
55 "F5A35014-C209-46A4-993A-EB56DE7530A1" : Power Boss
56
57 "6ED722A7-9240-48A5-B479-31EEF723D7CF" : Virtual Sensor
58
59 "16CAF1B7-DD38-40ED-B1C1-1B8A1913D531" : Cooling mode
60
61 "BE84BABF-C4D4-403D-B495-3128FD44dAC1" : HDC
62
63``current_uuid`` (RW)
64 User space can write strings from available UUIDs, one at a
65 time.
66
67:file:`/sys/bus/platform/devices/<N>/`, where <N>
68=INT3400|INTC1040|INTC1041|INTC10A0
69
70``imok`` (WO)
71 User space daemon write 1 to respond to firmware event
72 for sending keep alive notification. User space receives
73 THERMAL_EVENT_KEEP_ALIVE kobject uevent notification when
74 firmware calls for user space to respond with imok ACPI
75 method.
76
77``odvp*`` (RO)
78 Firmware thermal status variable values. Thermal tables
79 calls for different processing based on these variable
80 values.
81
82``data_vault`` (RO)
83 Binary thermal table. Refer to
84 https:/github.com/intel/thermal_daemon for decoding
85 thermal table.
86
87
88ACPI Thermal Relationship table interface
89------------------------------------------
90
91:file:`/dev/acpi_thermal_rel`
92
93 This device provides IOCTL interface to read standard ACPI
94 thermal relationship tables via ACPI methods _TRT and _ART.
95 These IOCTLs are defined in
96 drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.h
97
98 IOCTLs:
99
100 ACPI_THERMAL_GET_TRT_LEN: Get length of TRT table
101
102 ACPI_THERMAL_GET_ART_LEN: Get length of ART table
103
104 ACPI_THERMAL_GET_TRT_COUNT: Number of records in TRT table
105
106 ACPI_THERMAL_GET_ART_COUNT: Number of records in ART table
107
108 ACPI_THERMAL_GET_TRT: Read binary TRT table, length to read is
109 provided via argument to ioctl().
110
111 ACPI_THERMAL_GET_ART: Read binary ART table, length to read is
112 provided via argument to ioctl().
113
114DPTF ACPI Sensor drivers
115-------------------------
116
117DPTF Sensor drivers are presented as standard thermal sysfs thermal_zone.
118
119
120DPTF ACPI Cooling drivers
121--------------------------
122
123DPTF cooling drivers are presented as standard thermal sysfs cooling_device.
124
125
126DPTF Processor thermal PCI Driver interface
127--------------------------------------------
128
129:file:`/sys/bus/pci/devices/0000\:00\:04.0/power_limits/`
130
131Refer to Documentation/power/powercap/powercap.rst for powercap
132ABI.
133
134``power_limit_0_max_uw`` (RO)
135 Maximum powercap sysfs constraint_0_power_limit_uw for Intel RAPL
136
137``power_limit_0_step_uw`` (RO)
138 Power limit increment/decrements for Intel RAPL constraint 0 power limit
139
140``power_limit_0_min_uw`` (RO)
141 Minimum powercap sysfs constraint_0_power_limit_uw for Intel RAPL
142
143``power_limit_0_tmin_us`` (RO)
144 Minimum powercap sysfs constraint_0_time_window_us for Intel RAPL
145
146``power_limit_0_tmax_us`` (RO)
147 Maximum powercap sysfs constraint_0_time_window_us for Intel RAPL
148
149``power_limit_1_max_uw`` (RO)
150 Maximum powercap sysfs constraint_1_power_limit_uw for Intel RAPL
151
152``power_limit_1_step_uw`` (RO)
153 Power limit increment/decrements for Intel RAPL constraint 1 power limit
154
155``power_limit_1_min_uw`` (RO)
156 Minimum powercap sysfs constraint_1_power_limit_uw for Intel RAPL
157
158``power_limit_1_tmin_us`` (RO)
159 Minimum powercap sysfs constraint_1_time_window_us for Intel RAPL
160
161``power_limit_1_tmax_us`` (RO)
162 Maximum powercap sysfs constraint_1_time_window_us for Intel RAPL
163
164:file:`/sys/bus/pci/devices/0000\:00\:04.0/`
165
166``tcc_offset_degree_celsius`` (RW)
167 TCC offset from the critical temperature where hardware will throttle
168 CPU.
169
170:file:`/sys/bus/pci/devices/0000\:00\:04.0/workload_request`
171
172``workload_available_types`` (RO)
173 Available workload types. User space can specify one of the workload type
174 it is currently executing via workload_type. For example: idle, bursty,
175 sustained etc.
176
177``workload_type`` (RW)
178 User space can specify any one of the available workload type using
179 this interface.
180
181DPTF Processor thermal RFIM interface
182--------------------------------------------
183
184RFIM interface allows adjustment of FIVR (Fully Integrated Voltage Regulator)
185and DDR (Double Data Rate)frequencies to avoid RF interference with WiFi and 5G.
186
187Switching voltage regulators (VR) generate radiated EMI or RFI at the
188fundamental frequency and its harmonics. Some harmonics may interfere
189with very sensitive wireless receivers such as Wi-Fi and cellular that
190are integrated into host systems like notebook PCs. One of mitigation
191methods is requesting SOC integrated VR (IVR) switching frequency to a
192small % and shift away the switching noise harmonic interference from
193radio channels. OEM or ODMs can use the driver to control SOC IVR
194operation within the range where it does not impact IVR performance.
195
196DRAM devices of DDR IO interface and their power plane can generate EMI
197at the data rates. Similar to IVR control mechanism, Intel offers a
198mechanism by which DDR data rates can be changed if several conditions
199are met: there is strong RFI interference because of DDR; CPU power
200management has no other restriction in changing DDR data rates;
201PC ODMs enable this feature (real time DDR RFI Mitigation referred to as
202DDR-RFIM) for Wi-Fi from BIOS.
203
204
205FIVR attributes
206
207:file:`/sys/bus/pci/devices/0000\:00\:04.0/fivr/`
208
209``vco_ref_code_lo`` (RW)
210 The VCO reference code is an 11-bit field and controls the FIVR
211 switching frequency. This is the 3-bit LSB field.
212
213``vco_ref_code_hi`` (RW)
214 The VCO reference code is an 11-bit field and controls the FIVR
215 switching frequency. This is the 8-bit MSB field.
216
217``spread_spectrum_pct`` (RW)
218 Set the FIVR spread spectrum clocking percentage
219
220``spread_spectrum_clk_enable`` (RW)
221 Enable/disable of the FIVR spread spectrum clocking feature
222
223``rfi_vco_ref_code`` (RW)
224 This field is a read only status register which reflects the
225 current FIVR switching frequency
226
227``fivr_fffc_rev`` (RW)
228 This field indicated the revision of the FIVR HW.
229
230
231DVFS attributes
232
233:file:`/sys/bus/pci/devices/0000\:00\:04.0/dvfs/`
234
235``rfi_restriction_run_busy`` (RW)
236 Request the restriction of specific DDR data rate and set this
237 value 1. Self reset to 0 after operation.
238
239``rfi_restriction_err_code`` (RW)
240 0 :Request is accepted, 1:Feature disabled,
241 2: the request restricts more points than it is allowed
242
243``rfi_restriction_data_rate_Delta`` (RW)
244 Restricted DDR data rate for RFI protection: Lower Limit
245
246``rfi_restriction_data_rate_Base`` (RW)
247 Restricted DDR data rate for RFI protection: Upper Limit
248
249``ddr_data_rate_point_0`` (RO)
250 DDR data rate selection 1st point
251
252``ddr_data_rate_point_1`` (RO)
253 DDR data rate selection 2nd point
254
255``ddr_data_rate_point_2`` (RO)
256 DDR data rate selection 3rd point
257
258``ddr_data_rate_point_3`` (RO)
259 DDR data rate selection 4th point
260
261``rfi_disable (RW)``
262 Disable DDR rate change feature
263
264DPTF Power supply and Battery Interface
265----------------------------------------
266
267Refer to Documentation/ABI/testing/sysfs-platform-dptf
268
269DPTF Fan Control
270----------------------------------------
271
272Refer to Documentation/admin-guide/acpi/fan_performance_states.rst
Documentation/x86/index.rst+1−0
@@ -21,6 +21,7 @@ x86-specific Documentation · 20 unmodified lines
21 tlb21 tlb
22 mtrr22 mtrr
23 pat23 pat
24 intel-hfi
24 intel-iommu25 intel-iommu
25 intel_txt26 intel_txt
26 amd-memory-encryption27 amd-memory-encryption
Documentation/x86/intel-hfi.rst+72−0
@@ -0,0 +1,72 @@
1.. SPDX-License-Identifier: GPL-2.0
2
3============================================================
4Hardware-Feedback Interface for scheduling on Intel Hardware
5============================================================
6
7Overview
8--------
9
10Intel has described the Hardware Feedback Interface (HFI) in the Intel 64 and
11IA-32 Architectures Software Developer's Manual (Intel SDM) Volume 3 Section
1214.6 [1]_.
13
14The HFI gives the operating system a performance and energy efficiency
15capability data for each CPU in the system. Linux can use the information from
16the HFI to influence task placement decisions.
17
18The Hardware Feedback Interface
19-------------------------------
20
21The Hardware Feedback Interface provides to the operating system information
22about the performance and energy efficiency of each CPU in the system. Each
23capability is given as a unit-less quantity in the range [0-255]. Higher values
24indicate higher capability. Energy efficiency and performance are reported in
25separate capabilities. Even though on some systems these two metrics may be
26related, they are specified as independent capabilities in the Intel SDM.
27
28These capabilities may change at runtime as a result of changes in the
29operating conditions of the system or the action of external factors. The rate
30at which these capabilities are updated is specific to each processor model. On
31some models, capabilities are set at boot time and never change. On others,
32capabilities may change every tens of milliseconds. For instance, a remote
33mechanism may be used to lower Thermal Design Power. Such change can be
34reflected in the HFI. Likewise, if the system needs to be throttled due to
35excessive heat, the HFI may reflect reduced performance on specific CPUs.
36
37The kernel or a userspace policy daemon can use these capabilities to modify
38task placement decisions. For instance, if either the performance or energy
39capabilities of a given logical processor becomes zero, it is an indication that
40the hardware recommends to the operating system to not schedule any tasks on
41that processor for performance or energy efficiency reasons, respectively.
42
43Implementation details for Linux
44--------------------------------
45
46The infrastructure to handle thermal event interrupts has two parts. In the
47Local Vector Table of a CPU's local APIC, there exists a register for the
48Thermal Monitor Register. This register controls how interrupts are delivered
49to a CPU when the thermal monitor generates and interrupt. Further details
50can be found in the Intel SDM Vol. 3 Section 10.5 [1]_.
51
52The thermal monitor may generate interrupts per CPU or per package. The HFI
53generates package-level interrupts. This monitor is configured and initialized
54via a set of machine-specific registers. Specifically, the HFI interrupt and
55status are controlled via designated bits in the IA32_PACKAGE_THERM_INTERRUPT
56and IA32_PACKAGE_THERM_STATUS registers, respectively. There exists one HFI
57table per package. Further details can be found in the Intel SDM Vol. 3
58Section 14.9 [1]_.
59
60The hardware issues an HFI interrupt after updating the HFI table and is ready
61for the operating system to consume it. CPUs receive such interrupt via the
62thermal entry in the Local APIC's Local Vector Table.
63
64When servicing such interrupt, the HFI driver parses the updated table and
65relays the update to userspace using the thermal notification framework. Given
66that there may be many HFI updates every second, the updates relayed to
67userspace are throttled at a rate of CONFIG_HZ jiffies.
68
69References
70----------
71
72.. [1] https://www.intel.com/sdm
MAINTAINERS+4−3
@@ -17143,11 +17143,12 @@ S: Supported · 17142 unmodified lines
17143F: drivers/net/ethernet/samsung/sxgbe/17143F: drivers/net/ethernet/samsung/sxgbe/
17144 17144
17145SAMSUNG THERMAL DRIVER17145SAMSUNG THERMAL DRIVER
17146M: Bartlomiej Zolnierkiewicz <b.zolnierkie@samsung.com>17146M: Bartlomiej Zolnierkiewicz <bzolnier@gmail.com>
17147M: Krzysztof Kozlowski <krzk@kernel.org>
17147L: linux-pm@vger.kernel.org17148L: linux-pm@vger.kernel.org
17148L: linux-samsung-soc@vger.kernel.org17149L: linux-samsung-soc@vger.kernel.org
17149S: Supported17150S: Maintained
17150T: git https://github.com/lmajewski/linux-samsung-thermal.git17151F: Documentation/devicetree/bindings/thermal/samsung,exynos-thermal.yaml
17151F: drivers/thermal/samsung/17152F: drivers/thermal/samsung/
17152 17153
17153SAMSUNG USB2 PHY DRIVER17154SAMSUNG USB2 PHY DRIVER
arch/x86/include/asm/cpufeatures.h+1−0
@@ -327,6 +327,7 @@ · 326 unmodified lines
327#define X86_FEATURE_HWP_ACT_WINDOW (14*32+ 9) /* HWP Activity Window */327#define X86_FEATURE_HWP_ACT_WINDOW (14*32+ 9) /* HWP Activity Window */
328#define X86_FEATURE_HWP_EPP (14*32+10) /* HWP Energy Perf. Preference */328#define X86_FEATURE_HWP_EPP (14*32+10) /* HWP Energy Perf. Preference */
329#define X86_FEATURE_HWP_PKG_REQ (14*32+11) /* HWP Package Level Request */329#define X86_FEATURE_HWP_PKG_REQ (14*32+11) /* HWP Package Level Request */
330#define X86_FEATURE_HFI (14*32+19) /* Hardware Feedback Interface */
330 331
331/* AMD SVM Feature Identification, CPUID level 0x8000000a (EDX), word 15 */332/* AMD SVM Feature Identification, CPUID level 0x8000000a (EDX), word 15 */
332#define X86_FEATURE_NPT (15*32+ 0) /* Nested Page Table support */333#define X86_FEATURE_NPT (15*32+ 0) /* Nested Page Table support */
arch/x86/include/asm/msr-index.h+6−0
@@ -705,12 +705,14 @@ · 704 unmodified lines
705 705
706#define PACKAGE_THERM_STATUS_PROCHOT (1 << 0)706#define PACKAGE_THERM_STATUS_PROCHOT (1 << 0)
707#define PACKAGE_THERM_STATUS_POWER_LIMIT (1 << 10)707#define PACKAGE_THERM_STATUS_POWER_LIMIT (1 << 10)
708#define PACKAGE_THERM_STATUS_HFI_UPDATED (1 << 26)
708 709
709#define MSR_IA32_PACKAGE_THERM_INTERRUPT 0x000001b2710#define MSR_IA32_PACKAGE_THERM_INTERRUPT 0x000001b2
710 711
711#define PACKAGE_THERM_INT_HIGH_ENABLE (1 << 0)712#define PACKAGE_THERM_INT_HIGH_ENABLE (1 << 0)
712#define PACKAGE_THERM_INT_LOW_ENABLE (1 << 1)713#define PACKAGE_THERM_INT_LOW_ENABLE (1 << 1)
713#define PACKAGE_THERM_INT_PLN_ENABLE (1 << 24)714#define PACKAGE_THERM_INT_PLN_ENABLE (1 << 24)
715#define PACKAGE_THERM_INT_HFI_ENABLE (1 << 25)
714 716
715/* Thermal Thresholds Support */717/* Thermal Thresholds Support */
716#define THERM_INT_THRESHOLD0_ENABLE (1 << 15)718#define THERM_INT_THRESHOLD0_ENABLE (1 << 15)
@@ -959,4 +961,8 @@ · 242 unmodified lines
959#define MSR_VM_IGNNE 0xc0010115961#define MSR_VM_IGNNE 0xc0010115
960#define MSR_VM_HSAVE_PA 0xc0010117962#define MSR_VM_HSAVE_PA 0xc0010117
961 963
964/* Hardware Feedback Interface */
965#define MSR_IA32_HW_FEEDBACK_PTR 0x17d0
966#define MSR_IA32_HW_FEEDBACK_CONFIG 0x17d1
967
962#endif /* _ASM_X86_MSR_INDEX_H */968#endif /* _ASM_X86_MSR_INDEX_H */
drivers/thermal/broadcom/brcmstb_thermal.c+1−1
@@ -351,7 +351,7 @@ static int brcmstb_thermal_probe(struct platform_device *pdev) · 350 unmodified lines
351 351
352 priv->thermal = thermal;352 priv->thermal = thermal;
353 353
354 irq = platform_get_irq(pdev, 0);354 irq = platform_get_irq_optional(pdev, 0);
355 if (irq >= 0) {355 if (irq >= 0) {
356 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,356 ret = devm_request_threaded_irq(&pdev->dev, irq, NULL,
357 brcmstb_tmon_irq_thread,357 brcmstb_tmon_irq_thread,
drivers/thermal/intel/Kconfig+14−0
@@ -99,3 +99,17 @@ config INTEL_MENLOW · 98 unmodified lines
99 Intel Menlow platform.99 Intel Menlow platform.
100 100
101 If unsure, say N.101 If unsure, say N.
102
103config INTEL_HFI_THERMAL
104 bool "Intel Hardware Feedback Interface"
105 depends on NET
106 depends on CPU_SUP_INTEL
107 depends on X86_THERMAL_VECTOR
108 select THERMAL_NETLINK
109 help
110 Select this option to enable the Hardware Feedback Interface. If
111 selected, hardware provides guidance to the operating system on
112 the performance and energy efficiency capabilities of each CPU.
113 These capabilities may change as a result of changes in the operating
114 conditions of the system such power and thermal limits. If selected,
115 the kernel relays updates in CPUs' capabilities to userspace.
drivers/thermal/intel/Makefile+1−0
@@ -13,3 +13,4 @@ obj-$(CONFIG_INTEL_PCH_THERMAL) += intel_pch_thermal.o · 12 unmodified lines
13obj-$(CONFIG_INTEL_TCC_COOLING) += intel_tcc_cooling.o13obj-$(CONFIG_INTEL_TCC_COOLING) += intel_tcc_cooling.o
14obj-$(CONFIG_X86_THERMAL_VECTOR) += therm_throt.o14obj-$(CONFIG_X86_THERMAL_VECTOR) += therm_throt.o
15obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o15obj-$(CONFIG_INTEL_MENLOW) += intel_menlow.o
16obj-$(CONFIG_INTEL_HFI_THERMAL) += intel_hfi.o
drivers/thermal/intel/int340x_thermal/acpi_thermal_rel.c+7−16
@@ -72,7 +72,6 @@ int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trtp, · 71 unmodified lines
72 int i;72 int i;
73 int nr_bad_entries = 0;73 int nr_bad_entries = 0;
74 struct trt *trts;74 struct trt *trts;
75 struct acpi_device *adev;
76 union acpi_object *p;75 union acpi_object *p;
77 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };76 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
78 struct acpi_buffer element = { 0, NULL };77 struct acpi_buffer element = { 0, NULL };
@@ -112,12 +111,10 @@ int acpi_parse_trt(acpi_handle handle, int *trt_count, struct trt **trtp, · 33 unmodified lines
112 if (!create_dev)111 if (!create_dev)
113 continue;112 continue;
114 113
115 result = acpi_bus_get_device(trt->source, &adev);114 if (!acpi_fetch_acpi_dev(trt->source))
116 if (result)
117 pr_warn("Failed to get source ACPI device\n");115 pr_warn("Failed to get source ACPI device\n");
118 116
119 result = acpi_bus_get_device(trt->target, &adev);117 if (!acpi_fetch_acpi_dev(trt->target))
120 if (result)
121 pr_warn("Failed to get target ACPI device\n");118 pr_warn("Failed to get target ACPI device\n");
122 }119 }
123 120
@@ -149,7 +146,6 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp, · 25 unmodified lines
149 int i;146 int i;
150 int nr_bad_entries = 0;147 int nr_bad_entries = 0;
151 struct art *arts;148 struct art *arts;
152 struct acpi_device *adev;
153 union acpi_object *p;149 union acpi_object *p;
154 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };150 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
155 struct acpi_buffer element = { 0, NULL };151 struct acpi_buffer element = { 0, NULL };
@@ -191,16 +187,11 @@ int acpi_parse_art(acpi_handle handle, int *art_count, struct art **artp, · 35 unmodified lines
191 if (!create_dev)187 if (!create_dev)
192 continue;188 continue;
193 189
194 if (art->source) {190 if (!acpi_fetch_acpi_dev(art->source))
195 result = acpi_bus_get_device(art->source, &adev);191 pr_warn("Failed to get source ACPI device\n");
196 if (result)192
197 pr_warn("Failed to get source ACPI device\n");193 if (!acpi_fetch_acpi_dev(art->target))
198 }194 pr_warn("Failed to get target ACPI device\n");
199 if (art->target) {
200 result = acpi_bus_get_device(art->target, &adev);
201 if (result)
202 pr_warn("Failed to get target ACPI device\n");
203 }
204 }195 }
205 196
206 *artp = arts;197 *artp = arts;
drivers/thermal/intel/int340x_thermal/int3400_thermal.c+103−50
@@ -17,8 +17,8 @@ · 16 unmodified lines
17#define INT3400_KEEP_ALIVE 0xA017#define INT3400_KEEP_ALIVE 0xA0
18 18
19enum int3400_thermal_uuid {19enum int3400_thermal_uuid {
20 INT3400_THERMAL_ACTIVE = 0,
20 INT3400_THERMAL_PASSIVE_1,21 INT3400_THERMAL_PASSIVE_1,
21 INT3400_THERMAL_ACTIVE,
22 INT3400_THERMAL_CRITICAL,22 INT3400_THERMAL_CRITICAL,
23 INT3400_THERMAL_ADAPTIVE_PERFORMANCE,23 INT3400_THERMAL_ADAPTIVE_PERFORMANCE,
24 INT3400_THERMAL_EMERGENCY_CALL_MODE,24 INT3400_THERMAL_EMERGENCY_CALL_MODE,
@@ -31,8 +31,8 @@ enum int3400_thermal_uuid { · 6 unmodified lines
31};31};
32 32
33static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {33static char *int3400_thermal_uuids[INT3400_THERMAL_MAXIMUM_UUID] = {
34 "42A441D6-AE6A-462b-A84B-4A8CE79027D3",
35 "3A95C389-E4B8-4629-A526-C52C88626BAE",34 "3A95C389-E4B8-4629-A526-C52C88626BAE",
35 "42A441D6-AE6A-462b-A84B-4A8CE79027D3",
36 "97C68AE7-15FA-499c-B8C9-5DA81D606E0A",36 "97C68AE7-15FA-499c-B8C9-5DA81D606E0A",
37 "63BE270F-1C11-48FD-A6F7-3AF253FF3E2D",37 "63BE270F-1C11-48FD-A6F7-3AF253FF3E2D",
38 "5349962F-71E6-431D-9AE8-0A635B710AEE",38 "5349962F-71E6-431D-9AE8-0A635B710AEE",
@@ -53,12 +53,13 @@ struct int3400_thermal_priv { · 14 unmodified lines
53 struct art *arts;53 struct art *arts;
54 int trt_count;54 int trt_count;
55 struct trt *trts;55 struct trt *trts;
56 u8 uuid_bitmap;56 u32 uuid_bitmap;
57 int rel_misc_dev_res;57 int rel_misc_dev_res;
58 int current_uuid_index;58 int current_uuid_index;
59 char *data_vault;59 char *data_vault;
60 int odvp_count;60 int odvp_count;
61 int *odvp;61 int *odvp;
62 u32 os_uuid_mask;
62 struct odvp_attr *odvp_attrs;63 struct odvp_attr *odvp_attrs;
63};64};
64 65
@@ -142,12 +143,55 @@ static ssize_t current_uuid_show(struct device *dev, · 77 unmodified lines
142 struct device_attribute *devattr, char *buf)143 struct device_attribute *devattr, char *buf)
143{144{
144 struct int3400_thermal_priv *priv = dev_get_drvdata(dev);145 struct int3400_thermal_priv *priv = dev_get_drvdata(dev);
146 int i, length = 0;
145 147
146 if (priv->current_uuid_index == -1)148 if (priv->current_uuid_index > 0)
147 return sprintf(buf, "INVALID\n");149 return sprintf(buf, "%s\n",
150 int3400_thermal_uuids[priv->current_uuid_index]);
148 151
149 return sprintf(buf, "%s\n",152 for (i = 0; i <= INT3400_THERMAL_CRITICAL; i++) {
150 int3400_thermal_uuids[priv->current_uuid_index]);153 if (priv->os_uuid_mask & BIT(i))
154 length += scnprintf(&buf[length],
155 PAGE_SIZE - length,
156 "%s\n",
157 int3400_thermal_uuids[i]);
158 }
159
160 if (length)
161 return length;
162
163 return sprintf(buf, "INVALID\n");
164}
165
166static int int3400_thermal_run_osc(acpi_handle handle, char *uuid_str, int *enable)
167{
168 u32 ret, buf[2];
169 acpi_status status;
170 int result = 0;
171 struct acpi_osc_context context = {
172 .uuid_str = NULL,
173 .rev = 1,
174 .cap.length = 8,
175 };
176
177 context.uuid_str = uuid_str;
178
179 buf[OSC_QUERY_DWORD] = 0;
180 buf[OSC_SUPPORT_DWORD] = *enable;
181
182 context.cap.pointer = buf;
183
184 status = acpi_run_osc(handle, &context);
185 if (ACPI_SUCCESS(status)) {
186 ret = *((u32 *)(context.ret.pointer + 4));
187 if (ret != *enable)
188 result = -EPERM;
189 } else
190 result = -EPERM;
191
192 kfree(context.ret.pointer);
193
194 return result;
151}195}
152 196
153static ssize_t current_uuid_store(struct device *dev,197static ssize_t current_uuid_store(struct device *dev,
@@ -164,16 +208,47 @@ static ssize_t current_uuid_store(struct device *dev, · 10 unmodified lines
164 * If we have a list of supported UUIDs, make sure208 * If we have a list of supported UUIDs, make sure
165 * this one is supported.209 * this one is supported.
166 */210 */
167 if (priv->uuid_bitmap &&211 if (priv->uuid_bitmap & BIT(i)) {
168 !(priv->uuid_bitmap & (1 << i)))212 priv->current_uuid_index = i;
213 return count;
214 }
215
216 /*
217 * There is support of only 3 policies via the new
218 * _OSC to inform OS capability:
219 * INT3400_THERMAL_ACTIVE
220 * INT3400_THERMAL_PASSIVE_1
221 * INT3400_THERMAL_CRITICAL
222 */
223
224 if (i > INT3400_THERMAL_CRITICAL)
169 return -EINVAL;225 return -EINVAL;
170 226
171 priv->current_uuid_index = i;227 priv->os_uuid_mask |= BIT(i);
172 return count;228
229 break;
173 }230 }
174 }231 }
175 232
176 return -EINVAL;233 if (priv->os_uuid_mask) {
234 int cap, ret;
235
236 /*
237 * Capability bits:
238 * Bit 0: set to 1 to indicate DPTF is active
239 * Bi1 1: set to 1 to active cooling is supported by user space daemon
240 * Bit 2: set to 1 to passive cooling is supported by user space daemon
241 * Bit 3: set to 1 to critical trip is handled by user space daemon
242 */
243 cap = ((priv->os_uuid_mask << 1) | 0x01);
244 ret = int3400_thermal_run_osc(priv->adev->handle,
245 "b23ba85d-c8b7-3542-88de-8de2ffcfd698",
246 &cap);
247 if (ret)
248 return ret;
249 }
250
251 return count;
177}252}
178 253
179static DEVICE_ATTR_RW(current_uuid);254static DEVICE_ATTR_RW(current_uuid);
@@ -236,41 +311,6 @@ end: · 56 unmodified lines
236 return result;311 return result;
237}312}
238 313
239static int int3400_thermal_run_osc(acpi_handle handle,
240 enum int3400_thermal_uuid uuid, bool enable)
241{
242 u32 ret, buf[2];
243 acpi_status status;
244 int result = 0;
245 struct acpi_osc_context context = {
246 .uuid_str = NULL,
247 .rev = 1,
248 .cap.length = 8,
249 };
250
251 if (uuid < 0 || uuid >= INT3400_THERMAL_MAXIMUM_UUID)
252 return -EINVAL;
253
254 context.uuid_str = int3400_thermal_uuids[uuid];
255
256 buf[OSC_QUERY_DWORD] = 0;
257 buf[OSC_SUPPORT_DWORD] = enable;
258
259 context.cap.pointer = buf;
260
261 status = acpi_run_osc(handle, &context);
262 if (ACPI_SUCCESS(status)) {
263 ret = *((u32 *)(context.ret.pointer + 4));
264 if (ret != enable)
265 result = -EPERM;
266 } else
267 result = -EPERM;
268
269 kfree(context.ret.pointer);
270
271 return result;
272}
273
274static ssize_t odvp_show(struct kobject *kobj, struct kobj_attribute *attr,314static ssize_t odvp_show(struct kobject *kobj, struct kobj_attribute *attr,
275 char *buf)315 char *buf)
276{316{
@@ -426,10 +466,18 @@ static int int3400_thermal_change_mode(struct thermal_zone_device *thermal, · 149 unmodified lines
426 if (!priv)466 if (!priv)
427 return -EINVAL;467 return -EINVAL;
428 468
429 if (mode != thermal->mode)469 if (mode != thermal->mode) {
470 int enabled;
471
472 if (priv->current_uuid_index < 0 ||
473 priv->current_uuid_index >= INT3400_THERMAL_MAXIMUM_UUID)
474 return -EINVAL;
475
476 enabled = (mode == THERMAL_DEVICE_ENABLED);
430 result = int3400_thermal_run_osc(priv->adev->handle,477 result = int3400_thermal_run_osc(priv->adev->handle,
431 priv->current_uuid_index,478 int3400_thermal_uuids[priv->current_uuid_index],
432 mode == THERMAL_DEVICE_ENABLED);479 &enabled);
480 }
433 481
434 482
435 evaluate_odvp(priv);483 evaluate_odvp(priv);
@@ -468,6 +516,11 @@ static void int3400_setup_gddv(struct int3400_thermal_priv *priv) · 32 unmodified lines
468 priv->data_vault = kmemdup(obj->package.elements[0].buffer.pointer,516 priv->data_vault = kmemdup(obj->package.elements[0].buffer.pointer,
469 obj->package.elements[0].buffer.length,517 obj->package.elements[0].buffer.length,
470 GFP_KERNEL);518 GFP_KERNEL);
519 if (!priv->data_vault) {
520 kfree(buffer.pointer);
521 return;
522 }
523
471 bin_attr_data_vault.private = priv->data_vault;524 bin_attr_data_vault.private = priv->data_vault;
472 bin_attr_data_vault.size = obj->package.elements[0].buffer.length;525 bin_attr_data_vault.size = obj->package.elements[0].buffer.length;
473 kfree(buffer.pointer);526 kfree(buffer.pointer);
drivers/thermal/intel/intel_hfi.c+569−0
@@ -0,0 +1,569 @@
1// SPDX-License-Identifier: GPL-2.0-only
2/*
3 * Hardware Feedback Interface Driver
4 *
5 * Copyright (c) 2021, Intel Corporation.
6 *
7 * Authors: Aubrey Li <aubrey.li@linux.intel.com>
8 * Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
9 *
10 *
11 * The Hardware Feedback Interface provides a performance and energy efficiency
12 * capability information for each CPU in the system. Depending on the processor
13 * model, hardware may periodically update these capabilities as a result of
14 * changes in the operating conditions (e.g., power limits or thermal
15 * constraints). On other processor models, there is a single HFI update
16 * at boot.
17 *
18 * This file provides functionality to process HFI updates and relay these
19 * updates to userspace.
20 */
21
22#define pr_fmt(fmt) "intel-hfi: " fmt
23
24#include <linux/bitops.h>
25#include <linux/cpufeature.h>
26#include <linux/cpumask.h>
27#include <linux/gfp.h>
28#include <linux/io.h>
29#include <linux/kernel.h>
30#include <linux/math.h>
31#include <linux/mutex.h>
32#include <linux/percpu-defs.h>
33#include <linux/printk.h>
34#include <linux/processor.h>
35#include <linux/slab.h>
36#include <linux/spinlock.h>
37#include <linux/string.h>
38#include <linux/topology.h>
39#include <linux/workqueue.h>
40
41#include <asm/msr.h>
42
43#include "../thermal_core.h"
44#include "intel_hfi.h"
45
46#define THERM_STATUS_CLEAR_PKG_MASK (BIT(1) | BIT(3) | BIT(5) | BIT(7) | \
47 BIT(9) | BIT(11) | BIT(26))
48
49/* Hardware Feedback Interface MSR configuration bits */
50#define HW_FEEDBACK_PTR_VALID_BIT BIT(0)
51#define HW_FEEDBACK_CONFIG_HFI_ENABLE_BIT BIT(0)
52
53/* CPUID detection and enumeration definitions for HFI */
54
55#define CPUID_HFI_LEAF 6
56
57union hfi_capabilities {
58 struct {
59 u8 performance:1;
60 u8 energy_efficiency:1;
61 u8 __reserved:6;
62 } split;
63 u8 bits;
64};
65
66union cpuid6_edx {
67 struct {
68 union hfi_capabilities capabilities;
69 u32 table_pages:4;
70 u32 __reserved:4;
71 s32 index:16;
72 } split;
73 u32 full;
74};
75
76/**
77 * struct hfi_cpu_data - HFI capabilities per CPU
78 * @perf_cap: Performance capability
79 * @ee_cap: Energy efficiency capability
80 *
81 * Capabilities of a logical processor in the HFI table. These capabilities are
82 * unitless.
83 */
84struct hfi_cpu_data {
85 u8 perf_cap;
86 u8 ee_cap;
87} __packed;
88
89/**
90 * struct hfi_hdr - Header of the HFI table
91 * @perf_updated: Hardware updated performance capabilities
92 * @ee_updated: Hardware updated energy efficiency capabilities
93 *
94 * Properties of the data in an HFI table.
95 */
96struct hfi_hdr {
97 u8 perf_updated;
98 u8 ee_updated;
99} __packed;
100
101/**
102 * struct hfi_instance - Representation of an HFI instance (i.e., a table)
103 * @local_table: Base of the local copy of the HFI table
104 * @timestamp: Timestamp of the last update of the local table.
105 * Located at the base of the local table.
106 * @hdr: Base address of the header of the local table
107 * @data: Base address of the data of the local table
108 * @cpus: CPUs represented in this HFI table instance
109 * @hw_table: Pointer to the HFI table of this instance
110 * @update_work: Delayed work to process HFI updates
111 * @table_lock: Lock to protect acceses to the table of this instance
112 * @event_lock: Lock to process HFI interrupts
113 *
114 * A set of parameters to parse and navigate a specific HFI table.
115 */
116struct hfi_instance {
117 union {
118 void *local_table;
119 u64 *timestamp;
120 };
121 void *hdr;
122 void *data;
123 cpumask_var_t cpus;
124 void *hw_table;
125 struct delayed_work update_work;
126 raw_spinlock_t table_lock;
127 raw_spinlock_t event_lock;
128};
129
130/**
131 * struct hfi_features - Supported HFI features
132 * @nr_table_pages: Size of the HFI table in 4KB pages
133 * @cpu_stride: Stride size to locate the capability data of a logical
134 * processor within the table (i.e., row stride)
135 * @hdr_size: Size of the table header
136 *
137 * Parameters and supported features that are common to all HFI instances
138 */
139struct hfi_features {
140 unsigned int nr_table_pages;
141 unsigned int cpu_stride;
142 unsigned int hdr_size;
143};
144
145/**
146 * struct hfi_cpu_info - Per-CPU attributes to consume HFI data
147 * @index: Row of this CPU in its HFI table
148 * @hfi_instance: Attributes of the HFI table to which this CPU belongs
149 *
150 * Parameters to link a logical processor to an HFI table and a row within it.
151 */
152struct hfi_cpu_info {
153 s16 index;
154 struct hfi_instance *hfi_instance;
155};
156
157static DEFINE_PER_CPU(struct hfi_cpu_info, hfi_cpu_info) = { .index = -1 };
158
159static int max_hfi_instances;
160static struct hfi_instance *hfi_instances;
161
162static struct hfi_features hfi_features;
163static DEFINE_MUTEX(hfi_instance_lock);
164
165static struct workqueue_struct *hfi_updates_wq;
166#define HFI_UPDATE_INTERVAL HZ
167#define HFI_MAX_THERM_NOTIFY_COUNT 16
168
169static void get_hfi_caps(struct hfi_instance *hfi_instance,
170 struct thermal_genl_cpu_caps *cpu_caps)
171{
172 int cpu, i = 0;
173
174 raw_spin_lock_irq(&hfi_instance->table_lock);
175 for_each_cpu(cpu, hfi_instance->cpus) {
176 struct hfi_cpu_data *caps;
177 s16 index;
178
179 index = per_cpu(hfi_cpu_info, cpu).index;
180 caps = hfi_instance->data + index * hfi_features.cpu_stride;
181 cpu_caps[i].cpu = cpu;
182
183 /*
184 * Scale performance and energy efficiency to
185 * the [0, 1023] interval that thermal netlink uses.
186 */
187 cpu_caps[i].performance = caps->perf_cap << 2;
188 cpu_caps[i].efficiency = caps->ee_cap << 2;
189
190 ++i;
191 }
192 raw_spin_unlock_irq(&hfi_instance->table_lock);
193}
194
195/*
196 * Call update_capabilities() when there are changes in the HFI table.
197 */
198static void update_capabilities(struct hfi_instance *hfi_instance)
199{
200 struct thermal_genl_cpu_caps *cpu_caps;
201 int i = 0, cpu_count;
202
203 /* CPUs may come online/offline while processing an HFI update. */
204 mutex_lock(&hfi_instance_lock);
205
206 cpu_count = cpumask_weight(hfi_instance->cpus);
207
208 /* No CPUs to report in this hfi_instance. */
209 if (!cpu_count)
210 goto out;
211
212 cpu_caps = kcalloc(cpu_count, sizeof(*cpu_caps), GFP_KERNEL);
213 if (!cpu_caps)
214 goto out;
215
216 get_hfi_caps(hfi_instance, cpu_caps);
217
218 if (cpu_count < HFI_MAX_THERM_NOTIFY_COUNT)
219 goto last_cmd;
220
221 /* Process complete chunks of HFI_MAX_THERM_NOTIFY_COUNT capabilities. */
222 for (i = 0;
223 (i + HFI_MAX_THERM_NOTIFY_COUNT) <= cpu_count;
224 i += HFI_MAX_THERM_NOTIFY_COUNT)
225 thermal_genl_cpu_capability_event(HFI_MAX_THERM_NOTIFY_COUNT,
226 &cpu_caps[i]);
227
228 cpu_count = cpu_count - i;
229
230last_cmd:
231 /* Process the remaining capabilities if any. */
232 if (cpu_count)
233 thermal_genl_cpu_capability_event(cpu_count, &cpu_caps[i]);
234
235 kfree(cpu_caps);
236out:
237 mutex_unlock(&hfi_instance_lock);
238}
239
240static void hfi_update_work_fn(struct work_struct *work)
241{
242 struct hfi_instance *hfi_instance;
243
244 hfi_instance = container_of(to_delayed_work(work), struct hfi_instance,
245 update_work);
246 if (!hfi_instance)
247 return;
248
249 update_capabilities(hfi_instance);
250}
251
252void intel_hfi_process_event(__u64 pkg_therm_status_msr_val)
253{
254 struct hfi_instance *hfi_instance;
255 int cpu = smp_processor_id();
256 struct hfi_cpu_info *info;
257 u64 new_timestamp;
258
259 if (!pkg_therm_status_msr_val)
260 return;
261
262 info = &per_cpu(hfi_cpu_info, cpu);
263 if (!info)
264 return;
265
266 /*
267 * A CPU is linked to its HFI instance before the thermal vector in the
268 * local APIC is unmasked. Hence, info->hfi_instance cannot be NULL
269 * when receiving an HFI event.
270 */
271 hfi_instance = info->hfi_instance;
272 if (unlikely(!hfi_instance)) {
273 pr_debug("Received event on CPU %d but instance was null", cpu);
274 return;
275 }
276
277 /*
278 * On most systems, all CPUs in the package receive a package-level
279 * thermal interrupt when there is an HFI update. It is sufficient to
280 * let a single CPU to acknowledge the update and queue work to
281 * process it. The remaining CPUs can resume their work.
282 */
283 if (!raw_spin_trylock(&hfi_instance->event_lock))
284 return;
285
286 /* Skip duplicated updates. */
287 new_timestamp = *(u64 *)hfi_instance->hw_table;
288 if (*hfi_instance->timestamp == new_timestamp) {
289 raw_spin_unlock(&hfi_instance->event_lock);
290 return;
291 }
292
293 raw_spin_lock(&hfi_instance->table_lock);
294
295 /*
296 * Copy the updated table into our local copy. This includes the new
297 * timestamp.
298 */
299 memcpy(hfi_instance->local_table, hfi_instance->hw_table,
300 hfi_features.nr_table_pages << PAGE_SHIFT);
301
302 raw_spin_unlock(&hfi_instance->table_lock);
303 raw_spin_unlock(&hfi_instance->event_lock);
304
305 /*
306 * Let hardware know that we are done reading the HFI table and it is
307 * free to update it again.
308 */
309 pkg_therm_status_msr_val &= THERM_STATUS_CLEAR_PKG_MASK &
310 ~PACKAGE_THERM_STATUS_HFI_UPDATED;
311 wrmsrl(MSR_IA32_PACKAGE_THERM_STATUS, pkg_therm_status_msr_val);
312
313 queue_delayed_work(hfi_updates_wq, &hfi_instance->update_work,
314 HFI_UPDATE_INTERVAL);
315}
316
317static void init_hfi_cpu_index(struct hfi_cpu_info *info)
318{
319 union cpuid6_edx edx;
320
321 /* Do not re-read @cpu's index if it has already been initialized. */
322 if (info->index > -1)
323 return;
324
325 edx.full = cpuid_edx(CPUID_HFI_LEAF);
326 info->index = edx.split.index;
327}
328
329/*
330 * The format of the HFI table depends on the number of capabilities that the
331 * hardware supports. Keep a data structure to navigate the table.
332 */
333static void init_hfi_instance(struct hfi_instance *hfi_instance)
334{
335 /* The HFI header is below the time-stamp. */
336 hfi_instance->hdr = hfi_instance->local_table +
337 sizeof(*hfi_instance->timestamp);
338
339 /* The HFI data starts below the header. */
340 hfi_instance->data = hfi_instance->hdr + hfi_features.hdr_size;
341}
342
343/**
344 * intel_hfi_online() - Enable HFI on @cpu
345 * @cpu: CPU in which the HFI will be enabled
346 *
347 * Enable the HFI to be used in @cpu. The HFI is enabled at the die/package
348 * level. The first CPU in the die/package to come online does the full HFI
349 * initialization. Subsequent CPUs will just link themselves to the HFI
350 * instance of their die/package.
351 *
352 * This function is called before enabling the thermal vector in the local APIC
353 * in order to ensure that @cpu has an associated HFI instance when it receives
354 * an HFI event.
355 */
356void intel_hfi_online(unsigned int cpu)
357{
358 struct hfi_instance *hfi_instance;
359 struct hfi_cpu_info *info;
360 phys_addr_t hw_table_pa;
361 u64 msr_val;
362 u16 die_id;
363
364 /* Nothing to do if hfi_instances are missing. */
365 if (!hfi_instances)
366 return;
367
368 /*
369 * Link @cpu to the HFI instance of its package/die. It does not
370 * matter whether the instance has been initialized.
371 */
372 info = &per_cpu(hfi_cpu_info, cpu);
373 die_id = topology_logical_die_id(cpu);
374 hfi_instance = info->hfi_instance;
375 if (!hfi_instance) {
376 if (die_id < 0 || die_id >= max_hfi_instances)
377 return;
378
379 hfi_instance = &hfi_instances[die_id];
380 info->hfi_instance = hfi_instance;
381 }
382
383 init_hfi_cpu_index(info);
384
385 /*
386 * Now check if the HFI instance of the package/die of @cpu has been
387 * initialized (by checking its header). In such case, all we have to
388 * do is to add @cpu to this instance's cpumask.
389 */
390 mutex_lock(&hfi_instance_lock);
391 if (hfi_instance->hdr) {
392 cpumask_set_cpu(cpu, hfi_instance->cpus);
393 goto unlock;
394 }
395
396 /*
397 * Hardware is programmed with the physical address of the first page
398 * frame of the table. Hence, the allocated memory must be page-aligned.
399 */
400 hfi_instance->hw_table = alloc_pages_exact(hfi_features.nr_table_pages,
401 GFP_KERNEL | __GFP_ZERO);
402 if (!hfi_instance->hw_table)
403 goto unlock;
404
405 hw_table_pa = virt_to_phys(hfi_instance->hw_table);
406
407 /*
408 * Allocate memory to keep a local copy of the table that
409 * hardware generates.
410 */
411 hfi_instance->local_table = kzalloc(hfi_features.nr_table_pages << PAGE_SHIFT,
412 GFP_KERNEL);
413 if (!hfi_instance->local_table)
414 goto free_hw_table;
415
416 /*
417 * Program the address of the feedback table of this die/package. On
418 * some processors, hardware remembers the old address of the HFI table
419 * even after having been reprogrammed and re-enabled. Thus, do not free
420 * the pages allocated for the table or reprogram the hardware with a
421 * new base address. Namely, program the hardware only once.
422 */
423 msr_val = hw_table_pa | HW_FEEDBACK_PTR_VALID_BIT;
424 wrmsrl(MSR_IA32_HW_FEEDBACK_PTR, msr_val);
425
426 init_hfi_instance(hfi_instance);
427
428 INIT_DELAYED_WORK(&hfi_instance->update_work, hfi_update_work_fn);
429 raw_spin_lock_init(&hfi_instance->table_lock);
430 raw_spin_lock_init(&hfi_instance->event_lock);
431
432 cpumask_set_cpu(cpu, hfi_instance->cpus);
433
434 /*
435 * Enable the hardware feedback interface and never disable it. See
436 * comment on programming the address of the table.
437 */
438 rdmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
439 msr_val |= HW_FEEDBACK_CONFIG_HFI_ENABLE_BIT;
440 wrmsrl(MSR_IA32_HW_FEEDBACK_CONFIG, msr_val);
441
442unlock:
443 mutex_unlock(&hfi_instance_lock);
444 return;
445
446free_hw_table:
447 free_pages_exact(hfi_instance->hw_table, hfi_features.nr_table_pages);
448 goto unlock;
449}
450
451/**
452 * intel_hfi_offline() - Disable HFI on @cpu
453 * @cpu: CPU in which the HFI will be disabled
454 *
455 * Remove @cpu from those covered by its HFI instance.
456 *
457 * On some processors, hardware remembers previous programming settings even
458 * after being reprogrammed. Thus, keep HFI enabled even if all CPUs in the
459 * die/package of @cpu are offline. See note in intel_hfi_online().
460 */
461void intel_hfi_offline(unsigned int cpu)
462{
463 struct hfi_cpu_info *info = &per_cpu(hfi_cpu_info, cpu);
464 struct hfi_instance *hfi_instance;
465
466 /*
467 * Check if @cpu as an associated, initialized (i.e., with a non-NULL
468 * header). Also, HFI instances are only initialized if X86_FEATURE_HFI
469 * is present.
470 */
471 hfi_instance = info->hfi_instance;
472 if (!hfi_instance)
473 return;
474
475 if (!hfi_instance->hdr)
476 return;
477
478 mutex_lock(&hfi_instance_lock);
479 cpumask_clear_cpu(cpu, hfi_instance->cpus);
480 mutex_unlock(&hfi_instance_lock);
481}
482
483static __init int hfi_parse_features(void)
484{
485 unsigned int nr_capabilities;
486 union cpuid6_edx edx;
487
488 if (!boot_cpu_has(X86_FEATURE_HFI))
489 return -ENODEV;
490
491 /*
492 * If we are here we know that CPUID_HFI_LEAF exists. Parse the
493 * supported capabilities and the size of the HFI table.
494 */
495 edx.full = cpuid_edx(CPUID_HFI_LEAF);
496
497 if (!edx.split.capabilities.split.performance) {
498 pr_debug("Performance reporting not supported! Not using HFI\n");
499 return -ENODEV;
500 }
501
502 /*
503 * The number of supported capabilities determines the number of
504 * columns in the HFI table. Exclude the reserved bits.
505 */
506 edx.split.capabilities.split.__reserved = 0;
507 nr_capabilities = hweight8(edx.split.capabilities.bits);
508
509 /* The number of 4KB pages required by the table */
510 hfi_features.nr_table_pages = edx.split.table_pages + 1;
511
512 /*
513 * The header contains change indications for each supported feature.
514 * The size of the table header is rounded up to be a multiple of 8
515 * bytes.
516 */
517 hfi_features.hdr_size = DIV_ROUND_UP(nr_capabilities, 8) * 8;
518
519 /*
520 * Data of each logical processor is also rounded up to be a multiple
521 * of 8 bytes.
522 */
523 hfi_features.cpu_stride = DIV_ROUND_UP(nr_capabilities, 8) * 8;
524
525 return 0;
526}
527
528void __init intel_hfi_init(void)
529{
530 struct hfi_instance *hfi_instance;
531 int i, j;
532
533 if (hfi_parse_features())
534 return;
535
536 /* There is one HFI instance per die/package. */
537 max_hfi_instances = topology_max_packages() *
538 topology_max_die_per_package();
539
540 /*
541 * This allocation may fail. CPU hotplug callbacks must check
542 * for a null pointer.
543 */
544 hfi_instances = kcalloc(max_hfi_instances, sizeof(*hfi_instances),
545 GFP_KERNEL);
546 if (!hfi_instances)
547 return;
548
549 for (i = 0; i < max_hfi_instances; i++) {
550 hfi_instance = &hfi_instances[i];
551 if (!zalloc_cpumask_var(&hfi_instance->cpus, GFP_KERNEL))
552 goto err_nomem;
553 }
554
555 hfi_updates_wq = create_singlethread_workqueue("hfi-updates");
556 if (!hfi_updates_wq)
557 goto err_nomem;
558
559 return;
560
561err_nomem:
562 for (j = 0; j < i; ++j) {
563 hfi_instance = &hfi_instances[j];
564 free_cpumask_var(hfi_instance->cpus);
565 }
566
567 kfree(hfi_instances);
568 hfi_instances = NULL;
569}
drivers/thermal/intel/intel_hfi.h+17−0
@@ -0,0 +1,17 @@
1/* SPDX-License-Identifier: GPL-2.0 */
2#ifndef _INTEL_HFI_H
3#define _INTEL_HFI_H
4
5#if defined(CONFIG_INTEL_HFI_THERMAL)
6void __init intel_hfi_init(void);
7void intel_hfi_online(unsigned int cpu);
8void intel_hfi_offline(unsigned int cpu);
9void intel_hfi_process_event(__u64 pkg_therm_status_msr_val);
10#else
11static inline void intel_hfi_init(void) { }
12static inline void intel_hfi_online(unsigned int cpu) { }
13static inline void intel_hfi_offline(unsigned int cpu) { }
14static inline void intel_hfi_process_event(__u64 pkg_therm_status_msr_val) { }
15#endif /* CONFIG_INTEL_HFI_THERMAL */
16
17#endif /* _INTEL_HFI_H */
drivers/thermal/intel/intel_powerclamp.c+3−6
@@ -556,12 +556,9 @@ static void end_power_clamp(void) · 555 unmodified lines
556 * stop faster.556 * stop faster.
557 */557 */
558 clamping = false;558 clamping = false;
559 if (bitmap_weight(cpu_clamping_mask, num_possible_cpus())) {559 for_each_set_bit(i, cpu_clamping_mask, num_possible_cpus()) {
560 for_each_set_bit(i, cpu_clamping_mask, num_possible_cpus()) {560 pr_debug("clamping worker for cpu %d alive, destroy\n", i);
561 pr_debug("clamping worker for cpu %d alive, destroy\n",561 stop_power_clamp_worker(i);
562 i);
563 stop_power_clamp_worker(i);
564 }
565 }562 }
566}563}
567 564
drivers/thermal/intel/therm_throt.c+22−0
@@ -32,6 +32,7 @@ · 31 unmodified lines
32#include <asm/irq.h>32#include <asm/irq.h>
33#include <asm/msr.h>33#include <asm/msr.h>
34 34
35#include "intel_hfi.h"
35#include "thermal_interrupt.h"36#include "thermal_interrupt.h"
36 37
37/* How long to wait between reporting thermal events */38/* How long to wait between reporting thermal events */
@@ -475,6 +476,13 @@ static int thermal_throttle_online(unsigned int cpu) · 437 unmodified lines
475 INIT_DELAYED_WORK(&state->package_throttle.therm_work, throttle_active_work);476 INIT_DELAYED_WORK(&state->package_throttle.therm_work, throttle_active_work);
476 INIT_DELAYED_WORK(&state->core_throttle.therm_work, throttle_active_work);477 INIT_DELAYED_WORK(&state->core_throttle.therm_work, throttle_active_work);
477 478
479 /*
480 * The first CPU coming online will enable the HFI. Usually this causes
481 * hardware to issue an HFI thermal interrupt. Such interrupt will reach
482 * the CPU once we enable the thermal vector in the local APIC.
483 */
484 intel_hfi_online(cpu);
485
478 /* Unmask the thermal vector after the above workqueues are initialized. */486 /* Unmask the thermal vector after the above workqueues are initialized. */
479 l = apic_read(APIC_LVTTHMR);487 l = apic_read(APIC_LVTTHMR);
480 apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);488 apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
@@ -492,6 +500,8 @@ static int thermal_throttle_offline(unsigned int cpu) · 11 unmodified lines
492 l = apic_read(APIC_LVTTHMR);500 l = apic_read(APIC_LVTTHMR);
493 apic_write(APIC_LVTTHMR, l | APIC_LVT_MASKED);501 apic_write(APIC_LVTTHMR, l | APIC_LVT_MASKED);
494 502
503 intel_hfi_offline(cpu);
504
495 cancel_delayed_work_sync(&state->package_throttle.therm_work);505 cancel_delayed_work_sync(&state->package_throttle.therm_work);
496 cancel_delayed_work_sync(&state->core_throttle.therm_work);506 cancel_delayed_work_sync(&state->core_throttle.therm_work);
497 507
@@ -509,6 +519,8 @@ static __init int thermal_throttle_init_device(void) · 11 unmodified lines
509 if (!atomic_read(&therm_throt_en))519 if (!atomic_read(&therm_throt_en))
510 return 0;520 return 0;
511 521
522 intel_hfi_init();
523
512 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/therm:online",524 ret = cpuhp_setup_state(CPUHP_AP_ONLINE_DYN, "x86/therm:online",
513 thermal_throttle_online,525 thermal_throttle_online,
514 thermal_throttle_offline);526 thermal_throttle_offline);
@@ -608,6 +620,10 @@ void intel_thermal_interrupt(void) · 93 unmodified lines
608 PACKAGE_THERM_STATUS_POWER_LIMIT,620 PACKAGE_THERM_STATUS_POWER_LIMIT,
609 POWER_LIMIT_EVENT,621 POWER_LIMIT_EVENT,
610 PACKAGE_LEVEL);622 PACKAGE_LEVEL);
623
624 if (this_cpu_has(X86_FEATURE_HFI))
625 intel_hfi_process_event(msr_val &
626 PACKAGE_THERM_STATUS_HFI_UPDATED);
611 }627 }
612}628}
613 629
@@ -717,6 +733,12 @@ void intel_init_thermal(struct cpuinfo_x86 *c) · 103 unmodified lines
717 wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,733 wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
718 l | (PACKAGE_THERM_INT_LOW_ENABLE734 l | (PACKAGE_THERM_INT_LOW_ENABLE
719 | PACKAGE_THERM_INT_HIGH_ENABLE), h);735 | PACKAGE_THERM_INT_HIGH_ENABLE), h);
736
737 if (cpu_has(c, X86_FEATURE_HFI)) {
738 rdmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT, l, h);
739 wrmsr(MSR_IA32_PACKAGE_THERM_INTERRUPT,
740 l | PACKAGE_THERM_INT_HFI_ENABLE, h);
741 }
720 }742 }
721 743
722 rdmsr(MSR_IA32_MISC_ENABLE, l, h);744 rdmsr(MSR_IA32_MISC_ENABLE, l, h);
drivers/thermal/qcom/lmh.c+35−27
@@ -28,6 +28,8 @@ · 27 unmodified lines
28 28
29#define LMH_REG_DCVS_INTR_CLR 0x829#define LMH_REG_DCVS_INTR_CLR 0x8
30 30
31#define LMH_ENABLE_ALGOS 1
32
31struct lmh_hw_data {33struct lmh_hw_data {
32 void __iomem *base;34 void __iomem *base;
33 struct irq_domain *domain;35 struct irq_domain *domain;
@@ -90,6 +92,7 @@ static int lmh_probe(struct platform_device *pdev) · 56 unmodified lines
90 struct device_node *cpu_node;92 struct device_node *cpu_node;
91 struct lmh_hw_data *lmh_data;93 struct lmh_hw_data *lmh_data;
92 int temp_low, temp_high, temp_arm, cpu_id, ret;94 int temp_low, temp_high, temp_arm, cpu_id, ret;
95 unsigned int enable_alg;
93 u32 node_id;96 u32 node_id;
94 97
95 lmh_data = devm_kzalloc(dev, sizeof(*lmh_data), GFP_KERNEL);98 lmh_data = devm_kzalloc(dev, sizeof(*lmh_data), GFP_KERNEL);
@@ -141,32 +144,36 @@ static int lmh_probe(struct platform_device *pdev) · 45 unmodified lines
141 if (!qcom_scm_lmh_dcvsh_available())144 if (!qcom_scm_lmh_dcvsh_available())
142 return -EINVAL;145 return -EINVAL;
143 146
144 ret = qcom_scm_lmh_dcvsh(LMH_SUB_FN_CRNT, LMH_ALGO_MODE_ENABLE, 1,147 enable_alg = (uintptr_t)of_device_get_match_data(dev);
145 LMH_NODE_DCVS, node_id, 0);148
146 if (ret)149 if (enable_alg) {
147 dev_err(dev, "Error %d enabling current subfunction\n", ret);150 ret = qcom_scm_lmh_dcvsh(LMH_SUB_FN_CRNT, LMH_ALGO_MODE_ENABLE, 1,
148 151 LMH_NODE_DCVS, node_id, 0);
149 ret = qcom_scm_lmh_dcvsh(LMH_SUB_FN_REL, LMH_ALGO_MODE_ENABLE, 1,152 if (ret)
150 LMH_NODE_DCVS, node_id, 0);153 dev_err(dev, "Error %d enabling current subfunction\n", ret);
151 if (ret)154
152 dev_err(dev, "Error %d enabling reliability subfunction\n", ret);155 ret = qcom_scm_lmh_dcvsh(LMH_SUB_FN_REL, LMH_ALGO_MODE_ENABLE, 1,
153 156 LMH_NODE_DCVS, node_id, 0);
154 ret = qcom_scm_lmh_dcvsh(LMH_SUB_FN_BCL, LMH_ALGO_MODE_ENABLE, 1,157 if (ret)
155 LMH_NODE_DCVS, node_id, 0);158 dev_err(dev, "Error %d enabling reliability subfunction\n", ret);
156 if (ret)159
157 dev_err(dev, "Error %d enabling BCL subfunction\n", ret);160 ret = qcom_scm_lmh_dcvsh(LMH_SUB_FN_BCL, LMH_ALGO_MODE_ENABLE, 1,
158 161 LMH_NODE_DCVS, node_id, 0);
159 ret = qcom_scm_lmh_dcvsh(LMH_SUB_FN_THERMAL, LMH_ALGO_MODE_ENABLE, 1,162 if (ret)
160 LMH_NODE_DCVS, node_id, 0);163 dev_err(dev, "Error %d enabling BCL subfunction\n", ret);
161 if (ret) {164
162 dev_err(dev, "Error %d enabling thermal subfunction\n", ret);165 ret = qcom_scm_lmh_dcvsh(LMH_SUB_FN_THERMAL, LMH_ALGO_MODE_ENABLE, 1,
163 return ret;166 LMH_NODE_DCVS, node_id, 0);
164 }167 if (ret) {
165 168 dev_err(dev, "Error %d enabling thermal subfunction\n", ret);
166 ret = qcom_scm_lmh_profile_change(0x1);169 return ret;
167 if (ret) {170 }
168 dev_err(dev, "Error %d changing profile\n", ret);171
169 return ret;172 ret = qcom_scm_lmh_profile_change(0x1);
173 if (ret) {
174 dev_err(dev, "Error %d changing profile\n", ret);
175 return ret;
176 }
170 }177 }
171 178
172 /* Set default thermal trips */179 /* Set default thermal trips */
@@ -213,7 +220,8 @@ static int lmh_probe(struct platform_device *pdev) · 40 unmodified lines
213}220}
214 221
215static const struct of_device_id lmh_table[] = {222static const struct of_device_id lmh_table[] = {
216 { .compatible = "qcom,sdm845-lmh", },223 { .compatible = "qcom,sdm845-lmh", .data = (void *)LMH_ENABLE_ALGOS},
224 { .compatible = "qcom,sm8150-lmh", },
217 {}225 {}
218};226};
219MODULE_DEVICE_TABLE(of, lmh_table);227MODULE_DEVICE_TABLE(of, lmh_table);
drivers/thermal/qcom/tsens.c+5−0
@@ -18,6 +18,7 @@ · 17 unmodified lines
18#include <linux/regmap.h>18#include <linux/regmap.h>
19#include <linux/slab.h>19#include <linux/slab.h>
20#include <linux/thermal.h>20#include <linux/thermal.h>
21#include "../thermal_hwmon.h"
21#include "tsens.h"22#include "tsens.h"
22 23
23/**24/**
@@ -1060,6 +1061,10 @@ static int tsens_register(struct tsens_priv *priv) · 1036 unmodified lines
1060 priv->sensor[i].tzd = tzd;1061 priv->sensor[i].tzd = tzd;
1061 if (priv->ops->enable)1062 if (priv->ops->enable)
1062 priv->ops->enable(priv, i);1063 priv->ops->enable(priv, i);
1064
1065 if (devm_thermal_add_hwmon_sysfs(tzd))
1066 dev_warn(priv->dev,
1067 "Failed to add hwmon sysfs attributes\n");
1063 }1068 }
1064 1069
1065 /* VER_0 require to set MIN and MAX THRESH1070 /* VER_0 require to set MIN and MAX THRESH
drivers/thermal/tegra/tegra-bpmp-thermal.c+12−1
@@ -52,6 +52,8 @@ static int tegra_bpmp_thermal_get_temp(void *data, int *out_temp) · 51 unmodified lines
52 err = tegra_bpmp_transfer(zone->tegra->bpmp, &msg);52 err = tegra_bpmp_transfer(zone->tegra->bpmp, &msg);
53 if (err)53 if (err)
54 return err;54 return err;
55 if (msg.rx.ret)
56 return -EINVAL;
55 57
56 *out_temp = reply.get_temp.temp;58 *out_temp = reply.get_temp.temp;
57 59
@@ -63,6 +65,7 @@ static int tegra_bpmp_thermal_set_trips(void *data, int low, int high) · 5 unmodified lines
63 struct tegra_bpmp_thermal_zone *zone = data;65 struct tegra_bpmp_thermal_zone *zone = data;
64 struct mrq_thermal_host_to_bpmp_request req;66 struct mrq_thermal_host_to_bpmp_request req;
65 struct tegra_bpmp_message msg;67 struct tegra_bpmp_message msg;
68 int err;
66 69
67 memset(&req, 0, sizeof(req));70 memset(&req, 0, sizeof(req));
68 req.type = CMD_THERMAL_SET_TRIP;71 req.type = CMD_THERMAL_SET_TRIP;
@@ -76,7 +79,13 @@ static int tegra_bpmp_thermal_set_trips(void *data, int low, int high) · 7 unmodified lines
76 msg.tx.data = &req;79 msg.tx.data = &req;
77 msg.tx.size = sizeof(req);80 msg.tx.size = sizeof(req);
78 81
79 return tegra_bpmp_transfer(zone->tegra->bpmp, &msg);82 err = tegra_bpmp_transfer(zone->tegra->bpmp, &msg);
83 if (err)
84 return err;
85 if (msg.rx.ret)
86 return -EINVAL;
87
88 return 0;
80}89}
81 90
82static void tz_device_update_work_fn(struct work_struct *work)91static void tz_device_update_work_fn(struct work_struct *work)
@@ -140,6 +149,8 @@ static int tegra_bpmp_thermal_get_num_zones(struct tegra_bpmp *bpmp, · 57 unmodified lines
140 err = tegra_bpmp_transfer(bpmp, &msg);149 err = tegra_bpmp_transfer(bpmp, &msg);
141 if (err)150 if (err)
142 return err;151 return err;
152 if (msg.rx.ret)
153 return -EINVAL;
143 154
144 *num_zones = reply.get_num_zones.num;155 *num_zones = reply.get_num_zones.num;
145 156
drivers/thermal/thermal_netlink.c+53−0
@@ -43,6 +43,11 @@ static const struct nla_policy thermal_genl_policy[THERMAL_GENL_ATTR_MAX + 1] = · 42 unmodified lines
43 [THERMAL_GENL_ATTR_CDEV_MAX_STATE] = { .type = NLA_U32 },43 [THERMAL_GENL_ATTR_CDEV_MAX_STATE] = { .type = NLA_U32 },
44 [THERMAL_GENL_ATTR_CDEV_NAME] = { .type = NLA_STRING,44 [THERMAL_GENL_ATTR_CDEV_NAME] = { .type = NLA_STRING,
45 .len = THERMAL_NAME_LENGTH },45 .len = THERMAL_NAME_LENGTH },
46 /* CPU capabilities */
47 [THERMAL_GENL_ATTR_CPU_CAPABILITY] = { .type = NLA_NESTED },
48 [THERMAL_GENL_ATTR_CPU_CAPABILITY_ID] = { .type = NLA_U32 },
49 [THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE] = { .type = NLA_U32 },
50 [THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY] = { .type = NLA_U32 },
46};51};
47 52
48struct param {53struct param {
@@ -58,6 +63,8 @@ struct param { · 9 unmodified lines
58 int temp;63 int temp;
59 int cdev_state;64 int cdev_state;
60 int cdev_max_state;65 int cdev_max_state;
66 struct thermal_genl_cpu_caps *cpu_capabilities;
67 int cpu_capabilities_count;
61};68};
62 69
63typedef int (*cb_t)(struct param *);70typedef int (*cb_t)(struct param *);
@@ -190,6 +197,42 @@ static int thermal_genl_event_gov_change(struct param *p) · 126 unmodified lines
190 return 0;197 return 0;
191}198}
192 199
200static int thermal_genl_event_cpu_capability_change(struct param *p)
201{
202 struct thermal_genl_cpu_caps *cpu_cap = p->cpu_capabilities;
203 struct sk_buff *msg = p->msg;
204 struct nlattr *start_cap;
205 int i;
206
207 start_cap = nla_nest_start(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY);
208 if (!start_cap)
209 return -EMSGSIZE;
210
211 for (i = 0; i < p->cpu_capabilities_count; ++i) {
212 if (nla_put_u32(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY_ID,
213 cpu_cap->cpu))
214 goto out_cancel_nest;
215
216 if (nla_put_u32(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE,
217 cpu_cap->performance))
218 goto out_cancel_nest;
219
220 if (nla_put_u32(msg, THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY,
221 cpu_cap->efficiency))
222 goto out_cancel_nest;
223
224 ++cpu_cap;
225 }
226
227 nla_nest_end(msg, start_cap);
228
229 return 0;
230out_cancel_nest:
231 nla_nest_cancel(msg, start_cap);
232
233 return -EMSGSIZE;
234}
235
193int thermal_genl_event_tz_delete(struct param *p)236int thermal_genl_event_tz_delete(struct param *p)
194 __attribute__((alias("thermal_genl_event_tz")));237 __attribute__((alias("thermal_genl_event_tz")));
195 238
@@ -219,6 +262,7 @@ static cb_t event_cb[] = { · 23 unmodified lines
219 [THERMAL_GENL_EVENT_CDEV_DELETE] = thermal_genl_event_cdev_delete,262 [THERMAL_GENL_EVENT_CDEV_DELETE] = thermal_genl_event_cdev_delete,
220 [THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = thermal_genl_event_cdev_state_update,263 [THERMAL_GENL_EVENT_CDEV_STATE_UPDATE] = thermal_genl_event_cdev_state_update,
221 [THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = thermal_genl_event_gov_change,264 [THERMAL_GENL_EVENT_TZ_GOV_CHANGE] = thermal_genl_event_gov_change,
265 [THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE] = thermal_genl_event_cpu_capability_change,
222};266};
223 267
224/*268/*
@@ -356,6 +400,15 @@ int thermal_notify_tz_gov_change(int tz_id, const char *name) · 131 unmodified lines
356 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_GOV_CHANGE, &p);400 return thermal_genl_send_event(THERMAL_GENL_EVENT_TZ_GOV_CHANGE, &p);
357}401}
358 402
403int thermal_genl_cpu_capability_event(int count,
404 struct thermal_genl_cpu_caps *caps)
405{
406 struct param p = { .cpu_capabilities_count = count, .cpu_capabilities = caps };
407
408 return thermal_genl_send_event(THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE, &p);
409}
410EXPORT_SYMBOL_GPL(thermal_genl_cpu_capability_event);
411
359/*************************** Command encoding ********************************/412/*************************** Command encoding ********************************/
360 413
361static int __thermal_genl_cmd_tz_get_id(struct thermal_zone_device *tz,414static int __thermal_genl_cmd_tz_get_id(struct thermal_zone_device *tz,
drivers/thermal/thermal_netlink.h+14−0
@@ -4,6 +4,12 @@ · 3 unmodified lines
4 * Author: Daniel Lezcano <daniel.lezcano@linaro.org>4 * Author: Daniel Lezcano <daniel.lezcano@linaro.org>
5 */5 */
6 6
7struct thermal_genl_cpu_caps {
8 int cpu;
9 int performance;
10 int efficiency;
11};
12
7/* Netlink notification function */13/* Netlink notification function */
8#ifdef CONFIG_THERMAL_NETLINK14#ifdef CONFIG_THERMAL_NETLINK
9int __init thermal_netlink_init(void);15int __init thermal_netlink_init(void);
@@ -23,6 +29,8 @@ int thermal_notify_cdev_add(int cdev_id, const char *name, int max_state); · 13 unmodified lines
23int thermal_notify_cdev_delete(int cdev_id);29int thermal_notify_cdev_delete(int cdev_id);
24int thermal_notify_tz_gov_change(int tz_id, const char *name);30int thermal_notify_tz_gov_change(int tz_id, const char *name);
25int thermal_genl_sampling_temp(int id, int temp);31int thermal_genl_sampling_temp(int id, int temp);
32int thermal_genl_cpu_capability_event(int count,
33 struct thermal_genl_cpu_caps *caps);
26#else34#else
27static inline int thermal_netlink_init(void)35static inline int thermal_netlink_init(void)
28{36{
@@ -101,4 +109,10 @@ static inline int thermal_genl_sampling_temp(int id, int temp) · 72 unmodified lines
101{109{
102 return 0;110 return 0;
103}111}
112
113static inline int thermal_genl_cpu_capability_event(int count, struct thermal_genl_cpu_caps *caps)
114{
115 return 0;
116}
117
104#endif /* CONFIG_THERMAL_NETLINK */118#endif /* CONFIG_THERMAL_NETLINK */
drivers/thermal/ti-soc-thermal/ti-thermal-common.c+4−8
@@ -21,6 +21,7 @@ · 20 unmodified lines
21 21
22#include "ti-thermal.h"22#include "ti-thermal.h"
23#include "ti-bandgap.h"23#include "ti-bandgap.h"
24#include "../thermal_hwmon.h"
24 25
25/* common data structures */26/* common data structures */
26struct ti_thermal_data {27struct ti_thermal_data {
@@ -106,14 +107,6 @@ static inline int __ti_thermal_get_temp(void *devdata, int *temp) · 79 unmodified lines
106 return ret;107 return ret;
107}108}
108 109
109static inline int ti_thermal_get_temp(struct thermal_zone_device *thermal,
110 int *temp)
111{
112 struct ti_thermal_data *data = thermal->devdata;
113
114 return __ti_thermal_get_temp(data, temp);
115}
116
117static int __ti_thermal_get_trend(void *p, int trip, enum thermal_trend *trend)110static int __ti_thermal_get_trend(void *p, int trip, enum thermal_trend *trend)
118{111{
119 struct ti_thermal_data *data = p;112 struct ti_thermal_data *data = p;
@@ -189,6 +182,9 @@ int ti_thermal_expose_sensor(struct ti_bandgap *bgp, int id, · 69 unmodified lines
189 ti_bandgap_set_sensor_data(bgp, id, data);182 ti_bandgap_set_sensor_data(bgp, id, data);
190 ti_bandgap_write_update_interval(bgp, data->sensor_id, interval);183 ti_bandgap_write_update_interval(bgp, data->sensor_id, interval);
191 184
185 if (devm_thermal_add_hwmon_sysfs(data->ti_thermal))
186 dev_warn(bgp->dev, "failed to add hwmon sysfs attributes\n");
187
192 return 0;188 return 0;
193}189}
194 190
include/uapi/linux/thermal.h+5−1
@@ -44,7 +44,10 @@ enum thermal_genl_attr { · 43 unmodified lines
44 THERMAL_GENL_ATTR_CDEV_MAX_STATE,44 THERMAL_GENL_ATTR_CDEV_MAX_STATE,
45 THERMAL_GENL_ATTR_CDEV_NAME,45 THERMAL_GENL_ATTR_CDEV_NAME,
46 THERMAL_GENL_ATTR_GOV_NAME,46 THERMAL_GENL_ATTR_GOV_NAME,
47 47 THERMAL_GENL_ATTR_CPU_CAPABILITY,
48 THERMAL_GENL_ATTR_CPU_CAPABILITY_ID,
49 THERMAL_GENL_ATTR_CPU_CAPABILITY_PERFORMANCE,
50 THERMAL_GENL_ATTR_CPU_CAPABILITY_EFFICIENCY,
48 __THERMAL_GENL_ATTR_MAX,51 __THERMAL_GENL_ATTR_MAX,
49};52};
50#define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1)53#define THERMAL_GENL_ATTR_MAX (__THERMAL_GENL_ATTR_MAX - 1)
@@ -71,6 +74,7 @@ enum thermal_genl_event { · 20 unmodified lines
71 THERMAL_GENL_EVENT_CDEV_DELETE, /* Cdev unbound */74 THERMAL_GENL_EVENT_CDEV_DELETE, /* Cdev unbound */
72 THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, /* Cdev state updated */75 THERMAL_GENL_EVENT_CDEV_STATE_UPDATE, /* Cdev state updated */
73 THERMAL_GENL_EVENT_TZ_GOV_CHANGE, /* Governor policy changed */76 THERMAL_GENL_EVENT_TZ_GOV_CHANGE, /* Governor policy changed */
77 THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE, /* CPU capability changed */
74 __THERMAL_GENL_EVENT_MAX,78 __THERMAL_GENL_EVENT_MAX,
75};79};
76#define THERMAL_GENL_EVENT_MAX (__THERMAL_GENL_EVENT_MAX - 1)80#define THERMAL_GENL_EVENT_MAX (__THERMAL_GENL_EVENT_MAX - 1)
tools/power/x86/intel-speed-select/Build+1−1
@@ -1 +1 @@
1intel-speed-select-y += isst-config.o isst-core.o isst-display.o1intel-speed-select-y += isst-config.o isst-core.o isst-display.o isst-daemon.o hfi-events.o
tools/power/x86/intel-speed-select/Makefile+7−3
@@ -13,8 +13,8 @@ endif · 12 unmodified lines
13# Do not use make's built-in rules13# Do not use make's built-in rules
14# (this improves performance and avoids hard-to-debug behaviour);14# (this improves performance and avoids hard-to-debug behaviour);
15MAKEFLAGS += -r15MAKEFLAGS += -r
16 16override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include -I/usr/include/libnl3
17override CFLAGS += -O2 -Wall -g -D_GNU_SOURCE -I$(OUTPUT)include17override LDFLAGS += -lnl-genl-3 -lnl-3
18 18
19ALL_TARGETS := intel-speed-select19ALL_TARGETS := intel-speed-select
20ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))20ALL_PROGRAMS := $(patsubst %,$(OUTPUT)%,$(ALL_TARGETS))
@@ -31,7 +31,11 @@ $(OUTPUT)include/linux/isst_if.h: ../../../../include/uapi/linux/isst_if.h · 10 unmodified lines
31 mkdir -p $(OUTPUT)include/linux 2>&1 || true31 mkdir -p $(OUTPUT)include/linux 2>&1 || true
32 ln -sf $(CURDIR)/../../../../include/uapi/linux/isst_if.h $@32 ln -sf $(CURDIR)/../../../../include/uapi/linux/isst_if.h $@
33 33
34prepare: $(OUTPUT)include/linux/isst_if.h34$(OUTPUT)include/linux/thermal.h: ../../../../include/uapi/linux/thermal.h
35 mkdir -p $(OUTPUT)include/linux 2>&1 || true
36 ln -sf $(CURDIR)/../../../../include/uapi/linux/thermal.h $@
37
38prepare: $(OUTPUT)include/linux/isst_if.h $(OUTPUT)include/linux/thermal.h
35 39
36ISST_IN := $(OUTPUT)intel-speed-select-in.o40ISST_IN := $(OUTPUT)intel-speed-select-in.o
37 41
tools/power/x86/intel-speed-select/hfi-events.c+309−0
@@ -0,0 +1,309 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Intel Speed Select -- Read HFI events for OOB
4 * Copyright (c) 2022 Intel Corporation.
5 */
6
7/*
8 * This file incorporates work covered by the following copyright and
9 * permission notice:
10
11 * WPA Supplicant - driver interaction with Linux nl80211/cfg80211
12 * Copyright (c) 2003-2008, Jouni Malinen <j@w1.fi>
13 *
14 * This program is free software; you can redistribute it and/or modify
15 * it under the terms of the GNU General Public License version 2 as
16 * published by the Free Software Foundation.
17 *
18 * Alternatively, this software may be distributed under the terms of
19 * BSD license.
20 *
21 * Requires
22 * libnl-genl-3-dev
23 *
24 * For Fedora/CenOS
25 * dnf install libnl3-devel
26 * For Ubuntu
27 * apt install libnl-3-dev libnl-genl-3-dev
28 */
29
30#include <stdio.h>
31#include <stdlib.h>
32#include <stdarg.h>
33#include <string.h>
34#include <unistd.h>
35#include <fcntl.h>
36#include <sys/file.h>
37#include <sys/types.h>
38#include <sys/stat.h>
39#include <errno.h>
40#include <getopt.h>
41#include <signal.h>
42#include <netlink/genl/genl.h>
43#include <netlink/genl/family.h>
44#include <netlink/genl/ctrl.h>
45
46#include <linux/thermal.h>
47#include "isst.h"
48
49struct hfi_event_data {
50 struct nl_sock *nl_handle;
51 struct nl_cb *nl_cb;
52};
53
54struct hfi_event_data drv;
55
56static int ack_handler(struct nl_msg *msg, void *arg)
57{
58 int *err = arg;
59 *err = 0;
60 return NL_STOP;
61}
62
63static int finish_handler(struct nl_msg *msg, void *arg)
64{
65 int *ret = arg;
66 *ret = 0;
67 return NL_SKIP;
68}
69
70static int error_handler(struct sockaddr_nl *nla, struct nlmsgerr *err,
71 void *arg)
72{
73 int *ret = arg;
74 *ret = err->error;
75 return NL_SKIP;
76}
77
78static int seq_check_handler(struct nl_msg *msg, void *arg)
79{
80 return NL_OK;
81}
82
83static int send_and_recv_msgs(struct hfi_event_data *drv,
84 struct nl_msg *msg,
85 int (*valid_handler)(struct nl_msg *, void *),
86 void *valid_data)
87{
88 struct nl_cb *cb;
89 int err = -ENOMEM;
90
91 cb = nl_cb_clone(drv->nl_cb);
92 if (!cb)
93 goto out;
94
95 err = nl_send_auto_complete(drv->nl_handle, msg);
96 if (err < 0)
97 goto out;
98
99 err = 1;
100
101 nl_cb_err(cb, NL_CB_CUSTOM, error_handler, &err);
102 nl_cb_set(cb, NL_CB_FINISH, NL_CB_CUSTOM, finish_handler, &err);
103 nl_cb_set(cb, NL_CB_ACK, NL_CB_CUSTOM, ack_handler, &err);
104
105 if (valid_handler)
106 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM,
107 valid_handler, valid_data);
108
109 while (err > 0)
110 nl_recvmsgs(drv->nl_handle, cb);
111 out:
112 nl_cb_put(cb);
113 nlmsg_free(msg);
114 return err;
115}
116
117struct family_data {
118 const char *group;
119 int id;
120};
121
122static int family_handler(struct nl_msg *msg, void *arg)
123{
124 struct family_data *res = arg;
125 struct nlattr *tb[CTRL_ATTR_MAX + 1];
126 struct genlmsghdr *gnlh = nlmsg_data(nlmsg_hdr(msg));
127 struct nlattr *mcgrp;
128 int i;
129
130 nla_parse(tb, CTRL_ATTR_MAX, genlmsg_attrdata(gnlh, 0),
131 genlmsg_attrlen(gnlh, 0), NULL);
132 if (!tb[CTRL_ATTR_MCAST_GROUPS])
133 return NL_SKIP;
134
135 nla_for_each_nested(mcgrp, tb[CTRL_ATTR_MCAST_GROUPS], i) {
136 struct nlattr *tb2[CTRL_ATTR_MCAST_GRP_MAX + 1];
137 nla_parse(tb2, CTRL_ATTR_MCAST_GRP_MAX, nla_data(mcgrp),
138 nla_len(mcgrp), NULL);
139 if (!tb2[CTRL_ATTR_MCAST_GRP_NAME] ||
140 !tb2[CTRL_ATTR_MCAST_GRP_ID] ||
141 strncmp(nla_data(tb2[CTRL_ATTR_MCAST_GRP_NAME]),
142 res->group,
143 nla_len(tb2[CTRL_ATTR_MCAST_GRP_NAME])) != 0)
144 continue;
145 res->id = nla_get_u32(tb2[CTRL_ATTR_MCAST_GRP_ID]);
146 break;
147 };
148
149 return 0;
150}
151
152static int nl_get_multicast_id(struct hfi_event_data *drv,
153 const char *family, const char *group)
154{
155 struct nl_msg *msg;
156 int ret = -1;
157 struct family_data res = { group, -ENOENT };
158
159 msg = nlmsg_alloc();
160 if (!msg)
161 return -ENOMEM;
162 genlmsg_put(msg, 0, 0, genl_ctrl_resolve(drv->nl_handle, "nlctrl"),
163 0, 0, CTRL_CMD_GETFAMILY, 0);
164 NLA_PUT_STRING(msg, CTRL_ATTR_FAMILY_NAME, family);
165
166 ret = send_and_recv_msgs(drv, msg, family_handler, &res);
167 msg = NULL;
168 if (ret == 0)
169 ret = res.id;
170
171nla_put_failure:
172 nlmsg_free(msg);
173 return ret;
174}
175
176struct perf_cap {
177 int cpu;
178 int perf;
179 int eff;
180};
181
182static void process_hfi_event(struct perf_cap *perf_cap)
183{
184 process_level_change(perf_cap->cpu);
185}
186
187static int handle_event(struct nl_msg *n, void *arg)
188{
189 struct nlmsghdr *nlh = nlmsg_hdr(n);
190 struct genlmsghdr *genlhdr = genlmsg_hdr(nlh);
191 struct nlattr *attrs[THERMAL_GENL_ATTR_MAX + 1];
192 int ret;
193 struct perf_cap perf_cap;
194
195 ret = genlmsg_parse(nlh, 0, attrs, THERMAL_GENL_ATTR_MAX, NULL);
196
197 debug_printf("Received event %d parse_rer:%d\n", genlhdr->cmd, ret);
198 if (genlhdr->cmd == THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE) {
199 struct nlattr *cap;
200 int j, index = 0;
201
202 debug_printf("THERMAL_GENL_EVENT_CPU_CAPABILITY_CHANGE\n");
203 nla_for_each_nested(cap, attrs[THERMAL_GENL_ATTR_CPU_CAPABILITY], j) {
204 switch (index) {
205 case 0:
206 perf_cap.cpu = nla_get_u32(cap);
207 break;
208 case 1:
209 perf_cap.perf = nla_get_u32(cap);
210 break;
211 case 2:
212 perf_cap.eff = nla_get_u32(cap);
213 break;
214 default:
215 break;
216 }
217 ++index;
218 if (index == 3) {
219 index = 0;
220 process_hfi_event(&perf_cap);
221 }
222 }
223 }
224
225 return 0;
226}
227
228static int _hfi_exit;
229
230static int check_hf_suport(void)
231{
232 unsigned int eax = 0, ebx = 0, ecx = 0, edx = 0;
233
234 __cpuid(6, eax, ebx, ecx, edx);
235 if (eax & BIT(19))
236 return 1;
237
238 return 0;
239}
240
241int hfi_main(void)
242{
243 struct nl_sock *sock;
244 struct nl_cb *cb;
245 int err = 0;
246 int mcast_id;
247 int no_block = 0;
248
249 if (!check_hf_suport()) {
250 fprintf(stderr, "CPU Doesn't support HFI\n");
251 return -1;
252 }
253
254 sock = nl_socket_alloc();
255 if (!sock) {
256 fprintf(stderr, "nl_socket_alloc failed\n");
257 return -1;
258 }
259
260 if (genl_connect(sock)) {
261 fprintf(stderr, "genl_connect(sk_event) failed\n");
262 goto free_sock;
263 }
264
265 drv.nl_handle = sock;
266 drv.nl_cb = cb = nl_cb_alloc(NL_CB_DEFAULT);
267 if (drv.nl_cb == NULL) {
268 printf("Failed to allocate netlink callbacks");
269 goto free_sock;
270 }
271
272 mcast_id = nl_get_multicast_id(&drv, THERMAL_GENL_FAMILY_NAME,
273 THERMAL_GENL_EVENT_GROUP_NAME);
274 if (mcast_id < 0) {
275 fprintf(stderr, "nl_get_multicast_id failed\n");
276 goto free_sock;
277 }
278
279 if (nl_socket_add_membership(sock, mcast_id)) {
280 fprintf(stderr, "nl_socket_add_membership failed");
281 goto free_sock;
282 }
283
284 nl_cb_set(cb, NL_CB_SEQ_CHECK, NL_CB_CUSTOM, seq_check_handler, 0);
285 nl_cb_set(cb, NL_CB_VALID, NL_CB_CUSTOM, handle_event, NULL);
286
287 if (no_block)
288 nl_socket_set_nonblocking(sock);
289
290 debug_printf("hfi is initialized\n");
291
292 while (!_hfi_exit && !err) {
293 err = nl_recvmsgs(sock, cb);
294 debug_printf("nl_recv_message err:%d\n", err);
295 }
296
297 return 0;
298
299 /* Netlink library doesn't have calls to dealloc cb or disconnect */
300free_sock:
301 nl_socket_free(sock);
302
303 return -1;
304}
305
306void hfi_exit(void)
307{
308 _hfi_exit = 1;
309}
tools/power/x86/intel-speed-select/isst-config.c+43−11
@@ -15,7 +15,8 @@ struct process_cmd_struct { · 14 unmodified lines
15 int arg;15 int arg;
16};16};
17 17
18static const char *version_str = "v1.11";18static const char *version_str = "v1.12";
19
19static const int supported_api_ver = 1;20static const int supported_api_ver = 1;
20static struct isst_if_platform_info isst_platform_info;21static struct isst_if_platform_info isst_platform_info;
21static char *progname;22static char *progname;
@@ -368,7 +369,7 @@ int get_topo_max_cpus(void) · 346 unmodified lines
368 return topo_max_cpus;369 return topo_max_cpus;
369}370}
370 371
371static void set_cpu_online_offline(int cpu, int state)372void set_cpu_online_offline(int cpu, int state)
372{373{
373 char buffer[128];374 char buffer[128];
374 int fd, ret;375 int fd, ret;
@@ -409,12 +410,10 @@ static void force_all_cpus_online(void) · 34 unmodified lines
409 unlink("/var/run/isst_cpu_topology.dat");410 unlink("/var/run/isst_cpu_topology.dat");
410}411}
411 412
412#define MAX_PACKAGE_COUNT 8413void for_each_online_package_in_set(void (*callback)(int, void *, void *,
413#define MAX_DIE_PER_PACKAGE 2414 void *, void *),
414static void for_each_online_package_in_set(void (*callback)(int, void *, void *,415 void *arg1, void *arg2, void *arg3,
415 void *, void *),416 void *arg4)
416 void *arg1, void *arg2, void *arg3,
417 void *arg4)
418{417{
419 int max_packages[MAX_PACKAGE_COUNT * MAX_PACKAGE_COUNT];418 int max_packages[MAX_PACKAGE_COUNT * MAX_PACKAGE_COUNT];
420 int pkg_index = 0, i;419 int pkg_index = 0, i;
@@ -2803,7 +2802,9 @@ static void usage(void) · 2382 unmodified lines
2803 printf("\t[-p|--pause] : Delay between two mail box commands in milliseconds\n");2802 printf("\t[-p|--pause] : Delay between two mail box commands in milliseconds\n");
2804 printf("\t[-r|--retry] : Retry count for mail box commands on failure, default 3\n");2803 printf("\t[-r|--retry] : Retry count for mail box commands on failure, default 3\n");
2805 printf("\t[-v|--version] : Print version\n");2804 printf("\t[-v|--version] : Print version\n");
2806 2805 printf("\t[-b|--oob : Start a daemon to process HFI events for perf profile change from Out of Band agent.\n");
2806 printf("\t[-n|--no-daemon : Don't run as daemon. By default --oob will turn on daemon mode\n");
2807 printf("\t[-w|--delay : Delay for reading config level state change in OOB poll mode.\n");
2807 printf("\nResult format\n");2808 printf("\nResult format\n");
2808 printf("\tResult display uses a common format for each command:\n");2809 printf("\tResult display uses a common format for each command:\n");
2809 printf("\tResults are formatted in text/JSON with\n");2810 printf("\tResults are formatted in text/JSON with\n");
@@ -2837,6 +2838,9 @@ static void cmdline(int argc, char **argv) · 27 unmodified lines
2837 int opt, force_cpus_online = 0;2838 int opt, force_cpus_online = 0;
2838 int option_index = 0;2839 int option_index = 0;
2839 int ret;2840 int ret;
2841 int oob_mode = 0;
2842 int poll_interval = -1;
2843 int no_daemon = 0;
2840 2844
2841 static struct option long_options[] = {2845 static struct option long_options[] = {
2842 { "all-cpus-online", no_argument, 0, 'a' },2846 { "all-cpus-online", no_argument, 0, 'a' },
@@ -2849,6 +2853,9 @@ static void cmdline(int argc, char **argv) · 6 unmodified lines
2849 { "out", required_argument, 0, 'o' },2853 { "out", required_argument, 0, 'o' },
2850 { "retry", required_argument, 0, 'r' },2854 { "retry", required_argument, 0, 'r' },
2851 { "version", no_argument, 0, 'v' },2855 { "version", no_argument, 0, 'v' },
2856 { "oob", no_argument, 0, 'b' },
2857 { "no-daemon", no_argument, 0, 'n' },
2858 { "poll-interval", required_argument, 0, 'w' },
2852 { 0, 0, 0, 0 }2859 { 0, 0, 0, 0 }
2853 };2860 };
2854 2861
@@ -2875,7 +2882,7 @@ static void cmdline(int argc, char **argv) · 20 unmodified lines
2875 }2882 }
2876 2883
2877 progname = argv[0];2884 progname = argv[0];
2878 while ((opt = getopt_long_only(argc, argv, "+c:df:hio:va", long_options,2885 while ((opt = getopt_long_only(argc, argv, "+c:df:hio:vabw:n", long_options,
2879 &option_index)) != -1) {2886 &option_index)) != -1) {
2880 switch (opt) {2887 switch (opt) {
2881 case 'a':2888 case 'a':
@@ -2920,12 +2927,26 @@ static void cmdline(int argc, char **argv) · 38 unmodified lines
2920 case 'v':2927 case 'v':
2921 print_version();2928 print_version();
2922 break;2929 break;
2930 case 'b':
2931 oob_mode = 1;
2932 break;
2933 case 'n':
2934 no_daemon = 1;
2935 break;
2936 case 'w':
2937 ret = strtol(optarg, &ptr, 10);
2938 if (!ret) {
2939 fprintf(stderr, "Invalid poll interval count\n");
2940 exit(0);
2941 }
2942 poll_interval = ret;
2943 break;
2923 default:2944 default:
2924 usage();2945 usage();
2925 }2946 }
2926 }2947 }
2927 2948
2928 if (optind > (argc - 2)) {2949 if (optind > (argc - 2) && !oob_mode) {
2929 usage();2950 usage();
2930 exit(0);2951 exit(0);
2931 }2952 }
@@ -2936,6 +2957,17 @@ static void cmdline(int argc, char **argv) · 4 unmodified lines
2936 set_cpu_present_cpu_mask();2957 set_cpu_present_cpu_mask();
2937 set_cpu_target_cpu_mask();2958 set_cpu_target_cpu_mask();
2938 2959
2960 if (oob_mode) {
2961 create_cpu_map();
2962 if (debug_flag)
2963 fprintf(stderr, "OOB mode is enabled in debug mode\n");
2964
2965 ret = isst_daemon(debug_flag, poll_interval, no_daemon);
2966 if (ret)
2967 fprintf(stderr, "OOB mode enable failed\n");
2968 goto out;
2969 }
2970
2939 if (!is_clx_n_platform()) {2971 if (!is_clx_n_platform()) {
2940 ret = isst_fill_platform_info();2972 ret = isst_fill_platform_info();
2941 if (ret)2973 if (ret)
tools/power/x86/intel-speed-select/isst-daemon.c+244−0
@@ -0,0 +1,244 @@
1// SPDX-License-Identifier: GPL-2.0
2/*
3 * Intel Speed Select -- Allow speed select to daemonize
4 * Copyright (c) 2022 Intel Corporation.
5 */
6
7#include <stdio.h>
8#include <stdlib.h>
9#include <stdarg.h>
10#include <string.h>
11#include <unistd.h>
12#include <fcntl.h>
13#include <sys/file.h>
14#include <sys/types.h>
15#include <sys/stat.h>
16#include <errno.h>
17#include <getopt.h>
18#include <signal.h>
19#include <time.h>
20
21#include "isst.h"
22
23static int per_package_levels_info[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE];
24static time_t per_package_levels_tm[MAX_PACKAGE_COUNT][MAX_DIE_PER_PACKAGE];
25
26static void init_levels(void)
27{
28 int i, j;
29
30 for (i = 0; i < MAX_PACKAGE_COUNT; ++i)
31 for (j = 0; j < MAX_DIE_PER_PACKAGE; ++j)
32 per_package_levels_info[i][j] = -1;
33}
34
35void process_level_change(int cpu)
36{
37 struct isst_pkg_ctdp_level_info ctdp_level;
38 int pkg_id = get_physical_package_id(cpu);
39 int die_id = get_physical_die_id(cpu);
40 struct isst_pkg_ctdp pkg_dev;
41 time_t tm;
42 int ret;
43
44 if (pkg_id >= MAX_PACKAGE_COUNT || die_id > MAX_DIE_PER_PACKAGE) {
45 debug_printf("Invalid package/die info for cpu:%d\n", cpu);
46 return;
47 }
48
49 tm = time(NULL);
50 if (tm - per_package_levels_tm[pkg_id][die_id] < 2 )
51 return;
52
53 per_package_levels_tm[pkg_id][die_id] = tm;
54
55 ret = isst_get_ctdp_levels(cpu, &pkg_dev);
56 if (ret) {
57 debug_printf("Can't get tdp levels for cpu:%d\n", cpu);
58 return;
59 }
60
61 debug_printf("Get Config level %d pkg:%d die:%d current_level:%d \n", cpu,
62 pkg_id, die_id, pkg_dev.current_level);
63
64 if (pkg_dev.locked) {
65 debug_printf("config TDP s locked \n");
66 return;
67 }
68
69 if (per_package_levels_info[pkg_id][die_id] == pkg_dev.current_level)
70 return;
71
72 debug_printf("**Config level change for cpu:%d pkg:%d die:%d from %d to %d\n",
73 cpu, pkg_id, die_id, per_package_levels_info[pkg_id][die_id],
74 pkg_dev.current_level);
75
76 per_package_levels_info[pkg_id][die_id] = pkg_dev.current_level;
77
78 ctdp_level.core_cpumask_size =
79 alloc_cpu_set(&ctdp_level.core_cpumask);
80 ret = isst_get_coremask_info(cpu, pkg_dev.current_level, &ctdp_level);
81 if (ret) {
82 free_cpu_set(ctdp_level.core_cpumask);
83 debug_printf("Can't get core_mask:%d\n", cpu);
84 return;
85 }
86
87 if (ctdp_level.cpu_count) {
88 int i, max_cpus = get_topo_max_cpus();
89 for (i = 0; i < max_cpus; ++i) {
90 if (pkg_id != get_physical_package_id(i) || die_id != get_physical_die_id(i))
91 continue;
92 if (CPU_ISSET_S(i, ctdp_level.core_cpumask_size, ctdp_level.core_cpumask)) {
93 fprintf(stderr, "online cpu %d\n", i);
94 set_cpu_online_offline(i, 1);
95 } else {
96 fprintf(stderr, "offline cpu %d\n", i);
97 set_cpu_online_offline(i, 0);
98 }
99 }
100 }
101
102 free_cpu_set(ctdp_level.core_cpumask);
103}
104
105static void _poll_for_config_change(int cpu, void *arg1, void *arg2,
106 void *arg3, void *arg4)
107{
108 process_level_change(cpu);
109}
110
111static void poll_for_config_change(void)
112{
113 for_each_online_package_in_set(_poll_for_config_change, NULL, NULL,
114 NULL, NULL);
115}
116
117static int done = 0;
118static int pid_file_handle;
119
120static void signal_handler(int sig)
121{
122 switch (sig) {
123 case SIGINT:
124 case SIGTERM:
125 done = 1;
126 hfi_exit();
127 exit(0);
128 break;
129 default:
130 break;
131 }
132}
133
134static void daemonize(char *rundir, char *pidfile)
135{
136 int pid, sid, i;
137 char str[10];
138 struct sigaction sig_actions;
139 sigset_t sig_set;
140 int ret;
141
142 if (getppid() == 1)
143 return;
144
145 sigemptyset(&sig_set);
146 sigaddset(&sig_set, SIGCHLD);
147 sigaddset(&sig_set, SIGTSTP);
148 sigaddset(&sig_set, SIGTTOU);
149 sigaddset(&sig_set, SIGTTIN);
150 sigprocmask(SIG_BLOCK, &sig_set, NULL);
151
152 sig_actions.sa_handler = signal_handler;
153 sigemptyset(&sig_actions.sa_mask);
154 sig_actions.sa_flags = 0;
155
156 sigaction(SIGHUP, &sig_actions, NULL);
157 sigaction(SIGTERM, &sig_actions, NULL);
158 sigaction(SIGINT, &sig_actions, NULL);
159
160 pid = fork();
161 if (pid < 0) {
162 /* Could not fork */
163 exit(EXIT_FAILURE);
164 }
165 if (pid > 0)
166 exit(EXIT_SUCCESS);
167
168 umask(027);
169
170 sid = setsid();
171 if (sid < 0)
172 exit(EXIT_FAILURE);
173
174 /* close all descriptors */
175 for (i = getdtablesize(); i >= 0; --i)
176 close(i);
177
178 i = open("/dev/null", O_RDWR);
179 ret = dup(i);
180 if (ret == -1)
181 exit(EXIT_FAILURE);
182
183 ret = dup(i);
184 if (ret == -1)
185 exit(EXIT_FAILURE);
186
187 ret = chdir(rundir);
188 if (ret == -1)
189 exit(EXIT_FAILURE);
190
191 pid_file_handle = open(pidfile, O_RDWR | O_CREAT, 0600);
192 if (pid_file_handle == -1) {
193 /* Couldn't open lock file */
194 exit(1);
195 }
196 /* Try to lock file */
197#ifdef LOCKF_SUPPORT
198 if (lockf(pid_file_handle, F_TLOCK, 0) == -1) {
199#else
200 if (flock(pid_file_handle, LOCK_EX|LOCK_NB) < 0) {
201#endif
202 /* Couldn't get lock on lock file */
203 fprintf(stderr, "Couldn't get lock file %d\n", getpid());
204 exit(1);
205 }
206 snprintf(str, sizeof(str), "%d\n", getpid());
207 ret = write(pid_file_handle, str, strlen(str));
208 if (ret == -1)
209 exit(EXIT_FAILURE);
210
211 close(i);
212}
213
214int isst_daemon(int debug_mode, int poll_interval, int no_daemon)
215{
216 int ret;
217
218 if (!no_daemon && poll_interval < 0 && !debug_mode) {
219 fprintf(stderr, "OOB mode is enabled and will run as daemon\n");
220 daemonize((char *) "/tmp/",
221 (char *)"/tmp/hfi-events.pid");
222 } else {
223 signal(SIGINT, signal_handler);
224 }
225
226 init_levels();
227
228 if (poll_interval < 0) {
229 ret = hfi_main();
230 if (ret) {
231 fprintf(stderr, "HFI initialization failed\n");
232 }
233 fprintf(stderr, "Must specify poll-interval\n");
234 return ret;
235 }
236
237 debug_printf("Starting loop\n");
238 while (!done) {
239 sleep(poll_interval);
240 poll_for_config_change();
241 }
242
243 return 0;
244}
tools/power/x86/intel-speed-select/isst.h+13−0
@@ -76,6 +76,9 @@ · 75 unmodified lines
76 76
77#define DISP_FREQ_MULTIPLIER 10077#define DISP_FREQ_MULTIPLIER 100
78 78
79#define MAX_PACKAGE_COUNT 8
80#define MAX_DIE_PER_PACKAGE 2
81
79struct isst_clos_config {82struct isst_clos_config {
80 int pkg_id;83 int pkg_id;
81 int die_id;84 int die_id;
@@ -260,4 +263,14 @@ extern int is_skx_based_platform(void); · 178 unmodified lines
260extern int is_spr_platform(void);263extern int is_spr_platform(void);
261extern int is_icx_platform(void);264extern int is_icx_platform(void);
262extern void isst_trl_display_information(int cpu, FILE *outf, unsigned long long trl);265extern void isst_trl_display_information(int cpu, FILE *outf, unsigned long long trl);
266
267extern void set_cpu_online_offline(int cpu, int state);
268extern void for_each_online_package_in_set(void (*callback)(int, void *, void *,
269 void *, void *),
270 void *arg1, void *arg2, void *arg3,
271 void *arg4);
272extern int isst_daemon(int debug_mode, int poll_interval, int no_daemon);
273extern void process_level_change(int cpu);
274extern int hfi_main(void);
275extern void hfi_exit(void);
263#endif276#endif