1 // SPDX-License-Identifier: GPL-2.0-only
3 * intel_rapl_tpmi: Intel RAPL driver via TPMI interface
5 * Copyright (c) 2023, Intel Corporation.
9 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
11 #include <linux/auxiliary_bus.h>
13 #include <linux/intel_tpmi.h>
14 #include <linux/intel_rapl.h>
15 #include <linux/module.h>
16 #include <linux/slab.h>
18 #define TPMI_RAPL_MAJOR_VERSION 0
19 #define TPMI_RAPL_MINOR_VERSION 1
21 /* 1 header + 10 registers + 5 reserved. 8 bytes for each. */
22 #define TPMI_RAPL_DOMAIN_SIZE 128
24 enum tpmi_rapl_domain_type
{
25 TPMI_RAPL_DOMAIN_INVALID
,
26 TPMI_RAPL_DOMAIN_SYSTEM
,
27 TPMI_RAPL_DOMAIN_PACKAGE
,
28 TPMI_RAPL_DOMAIN_RESERVED
,
29 TPMI_RAPL_DOMAIN_MEMORY
,
33 enum tpmi_rapl_register
{
40 TPMI_RAPL_REG_RESERVED
,
41 TPMI_RAPL_REG_ENERGY_STATUS
,
42 TPMI_RAPL_REG_PERF_STATUS
,
43 TPMI_RAPL_REG_POWER_INFO
,
44 TPMI_RAPL_REG_DOMAIN_INFO
,
45 TPMI_RAPL_REG_INTERRUPT
,
46 TPMI_RAPL_REG_MAX
= 15,
49 struct tpmi_rapl_package
{
50 struct rapl_if_priv priv
;
51 struct intel_tpmi_plat_info
*tpmi_info
;
52 struct rapl_package
*rp
;
54 struct list_head node
;
57 static LIST_HEAD(tpmi_rapl_packages
);
58 static DEFINE_MUTEX(tpmi_rapl_lock
);
60 static struct powercap_control_type
*tpmi_control_type
;
62 static int tpmi_rapl_read_raw(int id
, struct reg_action
*ra
)
67 ra
->value
= readq(ra
->reg
.mmio
);
69 ra
->value
&= ra
->mask
;
73 static int tpmi_rapl_write_raw(int id
, struct reg_action
*ra
)
80 val
= readq(ra
->reg
.mmio
);
85 writeq(val
, ra
->reg
.mmio
);
89 static struct tpmi_rapl_package
*trp_alloc(int pkg_id
)
91 struct tpmi_rapl_package
*trp
;
94 mutex_lock(&tpmi_rapl_lock
);
96 if (list_empty(&tpmi_rapl_packages
)) {
97 tpmi_control_type
= powercap_register_control_type(NULL
, "intel-rapl", NULL
);
98 if (IS_ERR(tpmi_control_type
)) {
99 ret
= PTR_ERR(tpmi_control_type
);
104 trp
= kzalloc(sizeof(*trp
), GFP_KERNEL
);
107 goto err_del_powercap
;
110 list_add(&trp
->node
, &tpmi_rapl_packages
);
112 mutex_unlock(&tpmi_rapl_lock
);
116 if (list_empty(&tpmi_rapl_packages
))
117 powercap_unregister_control_type(tpmi_control_type
);
119 mutex_unlock(&tpmi_rapl_lock
);
123 static void trp_release(struct tpmi_rapl_package
*trp
)
125 mutex_lock(&tpmi_rapl_lock
);
126 list_del(&trp
->node
);
128 if (list_empty(&tpmi_rapl_packages
))
129 powercap_unregister_control_type(tpmi_control_type
);
132 mutex_unlock(&tpmi_rapl_lock
);
136 * Bit 0 of TPMI_RAPL_REG_DOMAIN_INFO indicates if the current package is a domain
137 * root or not. Only domain root packages can enumerate System (Psys) Domain.
139 #define TPMI_RAPL_DOMAIN_ROOT BIT(0)
141 static int parse_one_domain(struct tpmi_rapl_package
*trp
, u32 offset
)
143 u8 tpmi_domain_version
;
144 enum rapl_domain_type domain_type
;
145 enum tpmi_rapl_domain_type tpmi_domain_type
;
146 enum tpmi_rapl_register reg_index
;
147 enum rapl_domain_reg_id reg_id
;
148 int tpmi_domain_size
, tpmi_domain_flags
;
149 u64 tpmi_domain_header
= readq(trp
->base
+ offset
);
150 u64 tpmi_domain_info
;
152 /* Domain Parent bits are ignored for now */
153 tpmi_domain_version
= tpmi_domain_header
& 0xff;
154 tpmi_domain_type
= tpmi_domain_header
>> 8 & 0xff;
155 tpmi_domain_size
= tpmi_domain_header
>> 16 & 0xff;
156 tpmi_domain_flags
= tpmi_domain_header
>> 32 & 0xffff;
158 if (tpmi_domain_version
== TPMI_VERSION_INVALID
) {
159 pr_warn(FW_BUG
"Invalid version\n");
163 if (TPMI_MAJOR_VERSION(tpmi_domain_version
) != TPMI_RAPL_MAJOR_VERSION
) {
164 pr_warn(FW_BUG
"Unsupported major version:%ld\n",
165 TPMI_MAJOR_VERSION(tpmi_domain_version
));
169 if (TPMI_MINOR_VERSION(tpmi_domain_version
) > TPMI_RAPL_MINOR_VERSION
)
170 pr_info("Ignore: Unsupported minor version:%ld\n",
171 TPMI_MINOR_VERSION(tpmi_domain_version
));
173 /* Domain size: in unit of 128 Bytes */
174 if (tpmi_domain_size
!= 1) {
175 pr_warn(FW_BUG
"Invalid Domain size %d\n", tpmi_domain_size
);
179 /* Unit register and Energy Status register are mandatory for each domain */
180 if (!(tpmi_domain_flags
& BIT(TPMI_RAPL_REG_UNIT
)) ||
181 !(tpmi_domain_flags
& BIT(TPMI_RAPL_REG_ENERGY_STATUS
))) {
182 pr_warn(FW_BUG
"Invalid Domain flag 0x%x\n", tpmi_domain_flags
);
186 switch (tpmi_domain_type
) {
187 case TPMI_RAPL_DOMAIN_PACKAGE
:
188 domain_type
= RAPL_DOMAIN_PACKAGE
;
190 case TPMI_RAPL_DOMAIN_SYSTEM
:
191 if (!(tpmi_domain_flags
& BIT(TPMI_RAPL_REG_DOMAIN_INFO
))) {
192 pr_warn(FW_BUG
"System domain must support Domain Info register\n");
195 tpmi_domain_info
= readq(trp
->base
+ offset
+ TPMI_RAPL_REG_DOMAIN_INFO
* 8);
196 if (!(tpmi_domain_info
& TPMI_RAPL_DOMAIN_ROOT
))
198 domain_type
= RAPL_DOMAIN_PLATFORM
;
200 case TPMI_RAPL_DOMAIN_MEMORY
:
201 domain_type
= RAPL_DOMAIN_DRAM
;
204 pr_warn(FW_BUG
"Unsupported Domain type %d\n", tpmi_domain_type
);
208 if (trp
->priv
.regs
[domain_type
][RAPL_DOMAIN_REG_UNIT
].mmio
) {
209 pr_warn(FW_BUG
"Duplicate Domain type %d\n", tpmi_domain_type
);
213 reg_index
= TPMI_RAPL_REG_HEADER
;
214 while (++reg_index
!= TPMI_RAPL_REG_MAX
) {
215 if (!(tpmi_domain_flags
& BIT(reg_index
)))
219 case TPMI_RAPL_REG_UNIT
:
220 reg_id
= RAPL_DOMAIN_REG_UNIT
;
222 case TPMI_RAPL_REG_PL1
:
223 reg_id
= RAPL_DOMAIN_REG_LIMIT
;
224 trp
->priv
.limits
[domain_type
] |= BIT(POWER_LIMIT1
);
226 case TPMI_RAPL_REG_PL2
:
227 reg_id
= RAPL_DOMAIN_REG_PL2
;
228 trp
->priv
.limits
[domain_type
] |= BIT(POWER_LIMIT2
);
230 case TPMI_RAPL_REG_PL4
:
231 reg_id
= RAPL_DOMAIN_REG_PL4
;
232 trp
->priv
.limits
[domain_type
] |= BIT(POWER_LIMIT4
);
234 case TPMI_RAPL_REG_ENERGY_STATUS
:
235 reg_id
= RAPL_DOMAIN_REG_STATUS
;
237 case TPMI_RAPL_REG_PERF_STATUS
:
238 reg_id
= RAPL_DOMAIN_REG_PERF
;
240 case TPMI_RAPL_REG_POWER_INFO
:
241 reg_id
= RAPL_DOMAIN_REG_INFO
;
246 trp
->priv
.regs
[domain_type
][reg_id
].mmio
= trp
->base
+ offset
+ reg_index
* 8;
252 static int intel_rapl_tpmi_probe(struct auxiliary_device
*auxdev
,
253 const struct auxiliary_device_id
*id
)
255 struct tpmi_rapl_package
*trp
;
256 struct intel_tpmi_plat_info
*info
;
257 struct resource
*res
;
261 info
= tpmi_get_platform_data(auxdev
);
265 trp
= trp_alloc(info
->package_id
);
269 if (tpmi_get_resource_count(auxdev
) > 1) {
270 dev_err(&auxdev
->dev
, "does not support multiple resources\n");
275 res
= tpmi_get_resource_at_index(auxdev
, 0);
277 dev_err(&auxdev
->dev
, "can't fetch device resource info\n");
282 trp
->base
= devm_ioremap_resource(&auxdev
->dev
, res
);
283 if (IS_ERR(trp
->base
)) {
284 ret
= PTR_ERR(trp
->base
);
288 for (offset
= 0; offset
< resource_size(res
); offset
+= TPMI_RAPL_DOMAIN_SIZE
) {
289 ret
= parse_one_domain(trp
, offset
);
294 trp
->tpmi_info
= info
;
295 trp
->priv
.type
= RAPL_IF_TPMI
;
296 trp
->priv
.read_raw
= tpmi_rapl_read_raw
;
297 trp
->priv
.write_raw
= tpmi_rapl_write_raw
;
298 trp
->priv
.control_type
= tpmi_control_type
;
300 /* RAPL TPMI I/F is per physical package */
301 trp
->rp
= rapl_find_package_domain(info
->package_id
, &trp
->priv
, false);
303 dev_err(&auxdev
->dev
, "Domain for Package%d already exists\n", info
->package_id
);
308 trp
->rp
= rapl_add_package(info
->package_id
, &trp
->priv
, false);
309 if (IS_ERR(trp
->rp
)) {
310 dev_err(&auxdev
->dev
, "Failed to add RAPL Domain for Package%d, %ld\n",
311 info
->package_id
, PTR_ERR(trp
->rp
));
312 ret
= PTR_ERR(trp
->rp
);
316 rapl_package_add_pmu(trp
->rp
);
318 auxiliary_set_drvdata(auxdev
, trp
);
326 static void intel_rapl_tpmi_remove(struct auxiliary_device
*auxdev
)
328 struct tpmi_rapl_package
*trp
= auxiliary_get_drvdata(auxdev
);
330 rapl_package_remove_pmu(trp
->rp
);
331 rapl_remove_package(trp
->rp
);
335 static const struct auxiliary_device_id intel_rapl_tpmi_ids
[] = {
336 {.name
= "intel_vsec.tpmi-rapl" },
340 MODULE_DEVICE_TABLE(auxiliary
, intel_rapl_tpmi_ids
);
342 static struct auxiliary_driver intel_rapl_tpmi_driver
= {
343 .probe
= intel_rapl_tpmi_probe
,
344 .remove
= intel_rapl_tpmi_remove
,
345 .id_table
= intel_rapl_tpmi_ids
,
348 module_auxiliary_driver(intel_rapl_tpmi_driver
)
350 MODULE_IMPORT_NS(INTEL_TPMI
);
352 MODULE_DESCRIPTION("Intel RAPL TPMI Driver");
353 MODULE_LICENSE("GPL");