1 // SPDX-License-Identifier: GPL-2.0-only
3 * Performance Limit Reasons via TPMI
5 * Copyright (c) 2024, Intel Corporation.
8 #include <linux/array_size.h>
9 #include <linux/auxiliary_bus.h>
10 #include <linux/bitfield.h>
11 #include <linux/bitmap.h>
12 #include <linux/debugfs.h>
13 #include <linux/device.h>
14 #include <linux/err.h>
15 #include <linux/gfp_types.h>
16 #include <linux/intel_tpmi.h>
18 #include <linux/iopoll.h>
19 #include <linux/kstrtox.h>
20 #include <linux/lockdep.h>
21 #include <linux/module.h>
22 #include <linux/mod_devicetable.h>
23 #include <linux/mutex.h>
24 #include <linux/seq_file.h>
25 #include <linux/sprintf.h>
26 #include <linux/types.h>
28 #include "tpmi_power_domains.h"
30 #define PLR_HEADER 0x00
31 #define PLR_MAILBOX_INTERFACE 0x08
32 #define PLR_MAILBOX_DATA 0x10
33 #define PLR_DIE_LEVEL 0x18
35 #define PLR_MODULE_ID_MASK GENMASK_ULL(19, 12)
36 #define PLR_RUN_BUSY BIT_ULL(63)
38 #define PLR_COMMAND_WRITE 1
40 #define PLR_INVALID GENMASK_ULL(63, 0)
42 #define PLR_TIMEOUT_US 5
43 #define PLR_TIMEOUT_MAX_US 1000
45 #define PLR_COARSE_REASON_BITS 32
51 struct mutex lock
; /* Protect access to PLR mailbox */
58 struct dentry
*dbgfs_dir
;
59 struct tpmi_plr_die
*die_info
;
61 struct auxiliary_device
*auxdev
;
64 static const char * const plr_coarse_reasons
[] = {
77 static const char * const plr_fine_reasons
[] = {
88 "POWER_PKG_PL1_MSR_TPMI",
91 "POWER_PKG_PL2_MSR_TPMI",
94 "POWER_PLATFORM_PL1_MSR_TPMI",
95 "POWER_PLATFORM_PL1_MMIO",
96 "POWER_PLATFORM_PL1_PCS",
97 "POWER_PLATFORM_PL2_MSR_TPMI",
98 "POWER_PLATFORM_PL2_MMIO",
99 "POWER_PLATFORM_PL2_PCS",
110 static u64
plr_read(struct tpmi_plr_die
*plr_die
, int offset
)
112 return readq(plr_die
->base
+ offset
);
115 static void plr_write(u64 val
, struct tpmi_plr_die
*plr_die
, int offset
)
117 writeq(val
, plr_die
->base
+ offset
);
120 static int plr_read_cpu_status(struct tpmi_plr_die
*plr_die
, int cpu
,
126 lockdep_assert_held(&plr_die
->lock
);
128 regval
= FIELD_PREP(PLR_MODULE_ID_MASK
, tpmi_get_punit_core_number(cpu
));
129 regval
|= PLR_RUN_BUSY
;
131 plr_write(regval
, plr_die
, PLR_MAILBOX_INTERFACE
);
133 ret
= readq_poll_timeout(plr_die
->base
+ PLR_MAILBOX_INTERFACE
, regval
,
134 !(regval
& PLR_RUN_BUSY
), PLR_TIMEOUT_US
,
139 *status
= plr_read(plr_die
, PLR_MAILBOX_DATA
);
144 static int plr_clear_cpu_status(struct tpmi_plr_die
*plr_die
, int cpu
)
148 lockdep_assert_held(&plr_die
->lock
);
150 regval
= FIELD_PREP(PLR_MODULE_ID_MASK
, tpmi_get_punit_core_number(cpu
));
151 regval
|= PLR_RUN_BUSY
| PLR_COMMAND_WRITE
;
153 plr_write(0, plr_die
, PLR_MAILBOX_DATA
);
155 plr_write(regval
, plr_die
, PLR_MAILBOX_INTERFACE
);
157 return readq_poll_timeout(plr_die
->base
+ PLR_MAILBOX_INTERFACE
, regval
,
158 !(regval
& PLR_RUN_BUSY
), PLR_TIMEOUT_US
,
162 static void plr_print_bits(struct seq_file
*s
, u64 val
, int bits
)
164 const unsigned long mask
[] = { BITMAP_FROM_U64(val
) };
167 for_each_set_bit(bit
, mask
, bits
) {
168 const char *str
= NULL
;
170 if (bit
< PLR_COARSE_REASON_BITS
) {
171 if (bit
< ARRAY_SIZE(plr_coarse_reasons
))
172 str
= plr_coarse_reasons
[bit
];
174 index
= bit
- PLR_COARSE_REASON_BITS
;
175 if (index
< ARRAY_SIZE(plr_fine_reasons
))
176 str
= plr_fine_reasons
[index
];
180 seq_printf(s
, " %s", str
);
182 seq_printf(s
, " UNKNOWN(%d)", bit
);
186 seq_puts(s
, " none");
191 static int plr_status_show(struct seq_file
*s
, void *unused
)
193 struct tpmi_plr_die
*plr_die
= s
->private;
197 val
= plr_read(plr_die
, PLR_DIE_LEVEL
);
199 plr_print_bits(s
, val
, 32);
201 guard(mutex
)(&plr_die
->lock
);
203 for (int cpu
= 0; cpu
< nr_cpu_ids
; cpu
++) {
204 if (plr_die
->die_id
!= tpmi_get_power_domain_id(cpu
))
207 if (plr_die
->package_id
!= topology_physical_package_id(cpu
))
210 seq_printf(s
, "cpu%d", cpu
);
211 ret
= plr_read_cpu_status(plr_die
, cpu
, &val
);
213 dev_err(&plr_die
->plr
->auxdev
->dev
, "Failed to read PLR for cpu %d, ret=%d\n",
218 plr_print_bits(s
, val
, 64);
224 static ssize_t
plr_status_write(struct file
*filp
, const char __user
*ubuf
,
225 size_t count
, loff_t
*ppos
)
227 struct seq_file
*s
= filp
->private_data
;
228 struct tpmi_plr_die
*plr_die
= s
->private;
232 ret
= kstrtobool_from_user(ubuf
, count
, &val
);
239 plr_write(0, plr_die
, PLR_DIE_LEVEL
);
241 guard(mutex
)(&plr_die
->lock
);
243 for (int cpu
= 0; cpu
< nr_cpu_ids
; cpu
++) {
244 if (plr_die
->die_id
!= tpmi_get_power_domain_id(cpu
))
247 if (plr_die
->package_id
!= topology_physical_package_id(cpu
))
250 plr_clear_cpu_status(plr_die
, cpu
);
255 DEFINE_SHOW_STORE_ATTRIBUTE(plr_status
);
257 static int intel_plr_probe(struct auxiliary_device
*auxdev
, const struct auxiliary_device_id
*id
)
259 struct intel_tpmi_plat_info
*plat_info
;
260 struct dentry
*dentry
;
261 int i
, num_resources
;
262 struct resource
*res
;
263 struct tpmi_plr
*plr
;
268 plat_info
= tpmi_get_platform_data(auxdev
);
270 return dev_err_probe(&auxdev
->dev
, -EINVAL
, "No platform info\n");
272 dentry
= tpmi_get_debugfs_dir(auxdev
);
274 return dev_err_probe(&auxdev
->dev
, -ENODEV
, "No TPMI debugfs directory.\n");
276 num_resources
= tpmi_get_resource_count(auxdev
);
280 plr
= devm_kzalloc(&auxdev
->dev
, sizeof(*plr
), GFP_KERNEL
);
284 plr
->die_info
= devm_kcalloc(&auxdev
->dev
, num_resources
, sizeof(*plr
->die_info
),
289 plr
->num_dies
= num_resources
;
290 plr
->dbgfs_dir
= debugfs_create_dir("plr", dentry
);
291 plr
->auxdev
= auxdev
;
293 for (i
= 0; i
< num_resources
; i
++) {
294 res
= tpmi_get_resource_at_index(auxdev
, i
);
296 err
= dev_err_probe(&auxdev
->dev
, -EINVAL
, "No resource\n");
300 base
= devm_ioremap_resource(&auxdev
->dev
, res
);
306 plr
->die_info
[i
].base
= base
;
307 plr
->die_info
[i
].package_id
= plat_info
->package_id
;
308 plr
->die_info
[i
].die_id
= i
;
309 plr
->die_info
[i
].plr
= plr
;
310 mutex_init(&plr
->die_info
[i
].lock
);
312 if (plr_read(&plr
->die_info
[i
], PLR_HEADER
) == PLR_INVALID
)
315 snprintf(name
, sizeof(name
), "domain%d", i
);
317 dentry
= debugfs_create_dir(name
, plr
->dbgfs_dir
);
318 debugfs_create_file("status", 0444, dentry
, &plr
->die_info
[i
],
322 auxiliary_set_drvdata(auxdev
, plr
);
327 debugfs_remove_recursive(plr
->dbgfs_dir
);
331 static void intel_plr_remove(struct auxiliary_device
*auxdev
)
333 struct tpmi_plr
*plr
= auxiliary_get_drvdata(auxdev
);
335 debugfs_remove_recursive(plr
->dbgfs_dir
);
338 static const struct auxiliary_device_id intel_plr_id_table
[] = {
339 { .name
= "intel_vsec.tpmi-plr" },
342 MODULE_DEVICE_TABLE(auxiliary
, intel_plr_id_table
);
344 static struct auxiliary_driver intel_plr_aux_driver
= {
345 .id_table
= intel_plr_id_table
,
346 .remove
= intel_plr_remove
,
347 .probe
= intel_plr_probe
,
349 module_auxiliary_driver(intel_plr_aux_driver
);
351 MODULE_IMPORT_NS("INTEL_TPMI");
352 MODULE_IMPORT_NS("INTEL_TPMI_POWER_DOMAIN");
353 MODULE_DESCRIPTION("Intel TPMI PLR Driver");
354 MODULE_LICENSE("GPL");