xref: /linux/drivers/platform/x86/intel/speed_select_if/isst_tpmi_core.c (revision 5b05bb3f6c5716fab6911e12d60dd1f43ad9806a)
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * isst_tpmi.c: SST TPMI interface core
4  *
5  * Copyright (c) 2023, Intel Corporation.
6  * All Rights Reserved.
7  *
8  * This information will be useful to understand flows:
9  * In the current generation of platforms, TPMI is supported via OOB
10  * PCI device. This PCI device has one instance per CPU package.
11  * There is a unique TPMI ID for SST. Each TPMI ID also has multiple
12  * entries, representing per power domain information.
13  *
14  * There is one dev file for complete SST information and control same as the
15  * prior generation of hardware. User spaces don't need to know how the
16  * information is presented by the hardware. The TPMI core module implements
17  * the hardware mapping.
18  */
19 
20 #define dev_fmt(fmt) "tpmi_sst: " fmt
21 
22 #include <linux/auxiliary_bus.h>
23 #include <linux/delay.h>
24 #include <linux/intel_tpmi.h>
25 #include <linux/intel_vsec.h>
26 #include <linux/fs.h>
27 #include <linux/io.h>
28 #include <linux/kernel.h>
29 #include <linux/minmax.h>
30 #include <linux/module.h>
31 #include <asm/msr.h>
32 #include <uapi/linux/isst_if.h>
33 
34 #include "isst_tpmi_core.h"
35 #include "isst_if_common.h"
36 
37 /* Supported SST hardware version by this driver */
38 #define ISST_MAJOR_VERSION	0
39 #define ISST_MINOR_VERSION	3
40 
41 /*
42  * Used to indicate if value read from MMIO needs to get multiplied
43  * to get to a standard unit or not.
44  */
45 #define SST_MUL_FACTOR_NONE    1
46 
47 /* Define 100 as a scaling factor frequency ratio to frequency conversion */
48 #define SST_MUL_FACTOR_FREQ    100
49 
50 /* All SST regs are 64 bit size */
51 #define SST_REG_SIZE   8
52 
53 /**
54  * struct sst_header -	SST main header
55  * @interface_version:	Version number for this interface
56  * @cap_mask:		Bitmask of the supported sub features. 1=the sub feature is enabled.
57  *			0=disabled.
58  *			Bit[8]= SST_CP enable (1), disable (0)
59  *			bit[9]= SST_PP enable (1), disable (0)
60  *			other bits are reserved for future use
61  * @cp_offset:		Qword (8 bytes) offset to the SST_CP register bank
62  * @pp_offset:		Qword (8 bytes) offset to the SST_PP register bank
63  * @reserved:		Reserved for future use
64  *
65  * This register allows SW to discover SST capability and the offsets to SST-CP
66  * and SST-PP register banks.
67  */
68 struct sst_header {
69 	u8 interface_version;
70 	u8 cap_mask;
71 	u8 cp_offset;
72 	u8 pp_offset;
73 	u32 reserved;
74 } __packed;
75 
76 /**
77  * struct cp_header -	SST-CP (core-power) header
78  * @feature_id:		0=SST-CP, 1=SST-PP, 2=SST-BF, 3=SST-TF
79  * @feature_rev:	Interface Version number for this SST feature
80  * @ratio_unit:		Frequency ratio unit. 00: 100MHz. All others are reserved
81  * @reserved:		Reserved for future use
82  *
83  * This structure is used store SST-CP header. This is packed to the same
84  * format as defined in the specifications.
85  */
86 struct cp_header {
87 	u64 feature_id :4;
88 	u64 feature_rev :8;
89 	u64 ratio_unit :2;
90 	u64 reserved :50;
91 } __packed;
92 
93 /**
94  * struct pp_header -	SST-PP (Perf profile) header
95  * @feature_id:		0=SST-CP, 1=SST-PP, 2=SST-BF, 3=SST-TF
96  * @feature_rev:	Interface Version number for this SST feature
97  * @level_en_mask:	SST-PP level enable/disable fuse mask
98  * @allowed_level_mask:	Allowed level mask used for dynamic config level switching
99  * @reserved0:		Reserved for future use
100  * @ratio_unit:		Frequency ratio unit. 00: 100MHz. All others are reserved
101  * @block_size:		Size of PP block in Qword unit (8 bytes)
102  * @dynamic_switch:	If set (1), dynamic switching of SST PP is supported
103  * @memory_ratio_unit:	Memory Controller frequency ratio unit. 00: 100MHz, others reserved
104  * @reserved1:		Reserved for future use
105  *
106  * This structure is used store SST-PP header. This is packed to the same
107  * format as defined in the specifications.
108  */
109 struct pp_header {
110 	u64 feature_id :4;
111 	u64 feature_rev :8;
112 	u64 level_en_mask :8;
113 	u64 allowed_level_mask :8;
114 	u64 reserved0 :4;
115 	u64 ratio_unit :2;
116 	u64 block_size :8;
117 	u64 dynamic_switch :1;
118 	u64 memory_ratio_unit :2;
119 	u64 reserved1 :19;
120 } __packed;
121 
122 /**
123  * struct feature_offset -	Offsets to SST-PP features
124  * @pp_offset:		Qword offset within PP level for the SST_PP register bank
125  * @bf_offset:		Qword offset within PP level for the SST_BF register bank
126  * @tf_offset:		Qword offset within PP level for the SST_TF register bank
127  * @reserved:		Reserved for future use
128  *
129  * This structure is used store offsets for SST features in the register bank.
130  * This is packed to the same format as defined in the specifications.
131  */
132 struct feature_offset {
133 	u64 pp_offset :8;
134 	u64 bf_offset :8;
135 	u64 tf_offset :8;
136 	u64 reserved :40;
137 } __packed;
138 
139 /**
140  * struct levels_offset -	Offsets to each SST PP level
141  * @sst_pp_level0_offset:	Qword offset to the register block of PP level 0
142  * @sst_pp_level1_offset:	Qword offset to the register block of PP level 1
143  * @sst_pp_level2_offset:	Qword offset to the register block of PP level 2
144  * @sst_pp_level3_offset:	Qword offset to the register block of PP level 3
145  * @sst_pp_level4_offset:	Qword offset to the register block of PP level 4
146  * @reserved:			Reserved for future use
147  *
148  * This structure is used store offsets of SST PP levels in the register bank.
149  * This is packed to the same format as defined in the specifications.
150  */
151 struct levels_offset {
152 	u64 sst_pp_level0_offset :8;
153 	u64 sst_pp_level1_offset :8;
154 	u64 sst_pp_level2_offset :8;
155 	u64 sst_pp_level3_offset :8;
156 	u64 sst_pp_level4_offset :8;
157 	u64 reserved :24;
158 } __packed;
159 
160 /**
161  * struct pp_control_offset -	Offsets for SST PP controls
162  * @perf_level:		A SST-PP level that SW intends to switch to
163  * @perf_level_lock:	SST-PP level select lock. 0 - unlocked. 1 - locked till next reset
164  * @resvd0:		Reserved for future use
165  * @current_state:	Bit mask to control the enable(1)/disable(0) state of each feature
166  *			of the current PP level, bit 0 = BF, bit 1 = TF, bit 2-7 = reserved
167  * @reserved:		Reserved for future use
168  *
169  * This structure is used store offsets of SST PP controls in the register bank.
170  * This is packed to the same format as defined in the specifications.
171  */
172 struct pp_control_offset {
173 	u64 perf_level :3;
174 	u64 perf_level_lock :1;
175 	u64 resvd0 :4;
176 	u64 current_state :8;
177 	u64 reserved :48;
178 } __packed;
179 
180 /**
181  * struct pp_status_offset -	Offsets for SST PP status fields
182  * @sst_pp_level:	Returns the current SST-PP level
183  * @sst_pp_lock:	Returns the lock bit setting of perf_level_lock in pp_control_offset
184  * @error_type:		Returns last error of SST-PP level change request. 0: no error,
185  *			1: level change not allowed, others: reserved
186  * @feature_state:	Bit mask to indicate the enable(1)/disable(0) state of each feature of the
187  *			current PP level. bit 0 = BF, bit 1 = TF, bit 2-7 reserved
188  * @reserved0:		Reserved for future use
189  * @feature_error_type: Returns last error of the specific feature. Three error_type bits per
190  *			feature. i.e. ERROR_TYPE[2:0] for BF, ERROR_TYPE[5:3] for TF, etc.
191  *			0x0: no error, 0x1: The specific feature is not supported by the hardware.
192  *			0x2-0x6: Reserved. 0x7: feature state change is not allowed.
193  * @reserved1:		Reserved for future use
194  *
195  * This structure is used store offsets of SST PP status in the register bank.
196  * This is packed to the same format as defined in the specifications.
197  */
198 struct pp_status_offset {
199 	u64 sst_pp_level :3;
200 	u64 sst_pp_lock :1;
201 	u64 error_type :4;
202 	u64 feature_state :8;
203 	u64 reserved0 :16;
204 	u64 feature_error_type : 24;
205 	u64 reserved1 :8;
206 } __packed;
207 
208 /**
209  * struct perf_level -	Used to store perf level and mmio offset
210  * @mmio_offset:	mmio offset for a perf level
211  * @level:		perf level for this offset
212  *
213  * This structure is used store final mmio offset of each perf level from the
214  * SST base mmio offset.
215  */
216 struct perf_level {
217 	int mmio_offset;
218 	int level;
219 };
220 
221 /**
222  * struct tpmi_per_power_domain_info -	Store per power_domain SST info
223  * @package_id:		Package id for this power_domain
224  * @power_domain_id:	Power domain id, Each entry from the SST-TPMI instance is a power_domain.
225  * @max_level:		Max possible PP level possible for this power_domain
226  * @ratio_unit:		Ratio unit for converting to MHz
227  * @avx_levels:		Number of AVX levels
228  * @pp_block_size:	Block size from PP header
229  * @sst_header:		Store SST header for this power_domain
230  * @cp_header:		Store SST-CP header for this power_domain
231  * @pp_header:		Store SST-PP header for this power_domain
232  * @perf_levels:	Pointer to each perf level to map level to mmio offset
233  * @feature_offsets:	Store feature offsets for each PP-level
234  * @control_offset:	Store the control offset for each PP-level
235  * @status_offset:	Store the status offset for each PP-level
236  * @sst_base:		Mapped SST base IO memory
237  * @auxdev:		Auxiliary device instance enumerated this instance
238  * @saved_sst_cp_control: Save SST-CP control configuration to store restore for suspend/resume
239  * @saved_clos_configs:	Save SST-CP CLOS configuration to store restore for suspend/resume
240  * @saved_clos_assocs:	Save SST-CP CLOS association to store restore for suspend/resume
241  * @saved_pp_control:	Save SST-PP control information to store restore for suspend/resume
242  * @write_blocked:	Write operation is blocked, so can't change SST state
243  *
244  * This structure is used store complete SST information for a power_domain. This information
245  * is used to read/write request for any SST IOCTL. Each physical CPU package can have multiple
246  * power_domains. Each power domain describes its own SST information and has its own controls.
247  */
248 struct tpmi_per_power_domain_info {
249 	int package_id;
250 	int power_domain_id;
251 	int max_level;
252 	int ratio_unit;
253 	int avx_levels;
254 	int pp_block_size;
255 	struct sst_header sst_header;
256 	struct cp_header cp_header;
257 	struct pp_header pp_header;
258 	struct perf_level *perf_levels;
259 	struct feature_offset feature_offsets;
260 	struct pp_control_offset control_offset;
261 	struct pp_status_offset status_offset;
262 	void __iomem *sst_base;
263 	struct auxiliary_device *auxdev;
264 	u64 saved_sst_cp_control;
265 	u64 saved_clos_configs[4];
266 	u64 saved_clos_assocs[4];
267 	u64 saved_pp_control;
268 	bool write_blocked;
269 };
270 
271 /* Supported maximum partitions */
272 #define SST_MAX_PARTITIONS	2
273 
274 /**
275  * struct tpmi_sst_struct -	Store sst info for a package
276  * @package_id:			Package id for this aux device instance
277  * @number_of_power_domains:	Number of power_domains pointed by power_domain_info pointer
278  * @power_domain_info:		Pointer to power domains information
279  * @cdie_mask:			Mask of compute dies present in a partition from hardware.
280  *				This mask is not present in the version 1 information header.
281  * @io_dies:			Number of IO dies in a partition. This will be 0 for TPMI
282  *				version 1 information header.
283  * @partition_mask:		Mask of all partitions.
284  * @partition_mask_current:	Current partition mask as some may have been unbound.
285  *
286  * This structure is used store full SST information for a package.
287  * Each package has one or multiple OOB PCI devices. Each package can contain multiple
288  * power domains.
289  */
290 struct tpmi_sst_struct {
291 	int package_id;
292 	struct tpmi_per_power_domain_info *power_domain_info[SST_MAX_PARTITIONS];
293 	u16 cdie_mask[SST_MAX_PARTITIONS];
294 	u8 number_of_power_domains[SST_MAX_PARTITIONS];
295 	u8 io_dies[SST_MAX_PARTITIONS];
296 	u8 partition_mask;
297 	u8 partition_mask_current;
298 };
299 
300 /**
301  * struct tpmi_sst_common_struct -	Store all SST instances
302  * @max_index:		Maximum instances currently present
303  * @sst_inst:		Pointer to per package instance
304  *
305  * Stores every SST Package instance.
306  */
307 struct tpmi_sst_common_struct {
308 	int max_index;
309 	struct tpmi_sst_struct **sst_inst;
310 };
311 
312 /*
313  * Each IOCTL request is processed under this lock. Also used to protect
314  * registration functions and common data structures.
315  */
316 static DEFINE_MUTEX(isst_tpmi_dev_lock);
317 
318 /* Usage count to track, number of TPMI SST instances registered to this core. */
319 static int isst_core_usage_count;
320 
321 /* Stores complete SST information for every package and power_domain */
322 static struct tpmi_sst_common_struct isst_common;
323 
324 #define SST_MAX_AVX_LEVELS	3
325 
326 #define SST_PP_OFFSET_0		8
327 #define SST_PP_OFFSET_1		16
328 #define SST_PP_OFFSET_SIZE	8
329 
sst_add_perf_profiles(struct auxiliary_device * auxdev,struct tpmi_per_power_domain_info * pd_info,int levels)330 static int sst_add_perf_profiles(struct auxiliary_device *auxdev,
331 				 struct tpmi_per_power_domain_info *pd_info,
332 				 int levels)
333 {
334 	struct device *dev = &auxdev->dev;
335 	u64 perf_level_offsets;
336 	int i;
337 
338 	pd_info->perf_levels = devm_kcalloc(dev, levels, sizeof(struct perf_level), GFP_KERNEL);
339 	if (!pd_info->perf_levels) {
340 		pd_info->pp_header.allowed_level_mask = 0;
341 		pd_info->pp_header.level_en_mask = 0;
342 		return -ENOMEM;
343 	}
344 
345 	pd_info->ratio_unit = pd_info->pp_header.ratio_unit;
346 	pd_info->avx_levels = SST_MAX_AVX_LEVELS;
347 	pd_info->pp_block_size = pd_info->pp_header.block_size;
348 
349 	/* Read PP Offset 0: Get feature offset with PP level */
350 	*((u64 *)&pd_info->feature_offsets) = readq(pd_info->sst_base +
351 						    pd_info->sst_header.pp_offset +
352 						    SST_PP_OFFSET_0);
353 
354 	perf_level_offsets = readq(pd_info->sst_base + pd_info->sst_header.pp_offset +
355 				   SST_PP_OFFSET_1);
356 
357 	for (i = 0; i < levels; ++i) {
358 		u64 offset;
359 
360 		offset = perf_level_offsets & (0xffULL << (i * SST_PP_OFFSET_SIZE));
361 		offset >>= (i * 8);
362 		offset &= 0xff;
363 		offset *= 8; /* Convert to byte from QWORD offset */
364 		pd_info->perf_levels[i].mmio_offset = pd_info->sst_header.pp_offset + offset;
365 	}
366 
367 	return 0;
368 }
369 
sst_main(struct auxiliary_device * auxdev,struct tpmi_per_power_domain_info * pd_info)370 static int sst_main(struct auxiliary_device *auxdev, struct tpmi_per_power_domain_info *pd_info)
371 {
372 	struct device *dev = &auxdev->dev;
373 	int i, ret, mask, levels;
374 
375 	*((u64 *)&pd_info->sst_header) = readq(pd_info->sst_base);
376 	pd_info->sst_header.cp_offset *= 8;
377 	pd_info->sst_header.pp_offset *= 8;
378 
379 	if (pd_info->sst_header.interface_version == TPMI_VERSION_INVALID)
380 		return -ENODEV;
381 
382 	if (TPMI_MAJOR_VERSION(pd_info->sst_header.interface_version) != ISST_MAJOR_VERSION) {
383 		dev_err(dev, "SST: Unsupported major version:%lx\n",
384 			TPMI_MAJOR_VERSION(pd_info->sst_header.interface_version));
385 		return -ENODEV;
386 	}
387 
388 	if (TPMI_MINOR_VERSION(pd_info->sst_header.interface_version) > ISST_MINOR_VERSION)
389 		dev_info(dev, "SST: Ignore: Unsupported minor version:%lx\n",
390 			 TPMI_MINOR_VERSION(pd_info->sst_header.interface_version));
391 
392 	/* Read SST CP Header */
393 	*((u64 *)&pd_info->cp_header) = readq(pd_info->sst_base + pd_info->sst_header.cp_offset);
394 
395 	/* Read PP header */
396 	*((u64 *)&pd_info->pp_header) = readq(pd_info->sst_base + pd_info->sst_header.pp_offset);
397 
398 	mask = 0x01;
399 	levels = 0;
400 	for (i = 0; i < 8; ++i) {
401 		if (pd_info->pp_header.level_en_mask & mask)
402 			levels = i;
403 		mask <<= 1;
404 	}
405 
406 	ret = sst_add_perf_profiles(auxdev, pd_info, levels + 1);
407 	if (ret)
408 		return ret;
409 
410 	pd_info->max_level = levels;
411 
412 	return 0;
413 }
414 
isst_instance_count(struct tpmi_sst_struct * sst_inst)415 static u8 isst_instance_count(struct tpmi_sst_struct *sst_inst)
416 {
417 	u8 i, max_part, count = 0;
418 
419 	/* Partition mask starts from bit 0 and contains 1s only */
420 	max_part = hweight8(sst_inst->partition_mask);
421 	for (i = 0; i < max_part; i++)
422 		count += sst_inst->number_of_power_domains[i];
423 
424 	return count;
425 }
426 
427 /**
428  * map_cdies() - Map user domain ID to compute domain ID
429  * @sst_inst: TPMI Instance
430  * @id: User domain ID
431  * @partition: Resolved partition
432  *
433  * Helper function to map_partition_power_domain_id() to resolve compute
434  * domain ID and partition. Use hardware provided cdie_mask for a partition
435  * as is to resolve a compute domain ID.
436  *
437  * Return: %-EINVAL on error, otherwise mapped domain ID >= 0.
438  */
map_cdies(struct tpmi_sst_struct * sst_inst,u8 id,u8 * partition)439 static int map_cdies(struct tpmi_sst_struct *sst_inst, u8 id, u8 *partition)
440 {
441 	u8 i, max_part;
442 
443 	max_part = hweight8(sst_inst->partition_mask);
444 	for (i = 0; i < max_part; i++) {
445 		if (!(sst_inst->cdie_mask[i] & BIT(id)))
446 			continue;
447 
448 		*partition = i;
449 		return id - ffs(sst_inst->cdie_mask[i]) + 1;
450 	}
451 
452 	return -EINVAL;
453 }
454 
455 /**
456  * map_partition_power_domain_id() - Map user domain ID to partition domain ID
457  * @sst_inst: TPMI Instance
458  * @id: User domain ID
459  * @partition: Resolved partition
460  *
461  * In a partitioned system a CPU package has two separate MMIO ranges (Under
462  * two PCI devices). But the CPU package compute die/power domain IDs are
463  * unique in a package. User space can get compute die/power domain ID from
464  * CPUID and MSR 0x54 for a CPU. So, those IDs need to be preserved even if
465  * they are present in two different partitions with its own order.
466  *
467  * For example for command ISST_IF_COUNT_TPMI_INSTANCES, the valid_mask
468  * is 111111b for a 4 compute and 2 IO dies system. This is presented as
469  * provided by the hardware in a non-partitioned system with the following
470  * order:
471  *	I1-I0-C3-C2-C1-C0
472  * Here: "C": for compute and "I" for IO die.
473  * Compute dies are always present first in TPMI instances, as they have
474  * to map to the real power domain/die ID of a system. In a non-partitioned
475  * system there is no way to identify compute and IO die boundaries from
476  * this driver without reading each CPU's mapping.
477  *
478  * The same order needs to be preserved, even if those compute dies are
479  * distributed among multiple partitions. For example:
480  * Partition 1 can contain: I1-C1-C0
481  * Partition 2 can contain: I2-C3-C2
482  *
483  * This will require a conversion of user space IDs to the actual index into
484  * array of stored power domains for each partition. For the above example
485  * this function will return partition and index as follows:
486  *
487  * =============	=========	=====	========
488  * User space ID	Partition	Index	Die type
489  * =============	=========	=====	========
490  * 0			0		0	Compute
491  * 1			0		1	Compute
492  * 2			1		0	Compute
493  * 3			1		1	Compute
494  * 4			0		2	IO
495  * 5			1		2	IO
496  * =============	=========	=====	========
497  *
498  * Return: %-EINVAL on error, otherwise mapped domain ID >= 0.
499  */
map_partition_power_domain_id(struct tpmi_sst_struct * sst_inst,u8 id,u8 * partition)500 static int map_partition_power_domain_id(struct tpmi_sst_struct *sst_inst, u8 id, u8 *partition)
501 {
502 	u8 i, io_start_id, max_part;
503 
504 	*partition = 0;
505 
506 	/* If any PCI device for partition is unbound, treat this as failure */
507 	if (sst_inst->partition_mask != sst_inst->partition_mask_current)
508 		return -EINVAL;
509 
510 	max_part = hweight8(sst_inst->partition_mask);
511 
512 	/* IO Index begin here */
513 	io_start_id = fls(sst_inst->cdie_mask[max_part - 1]);
514 
515 	if (id < io_start_id)
516 		return map_cdies(sst_inst, id, partition);
517 
518 	for (i = 0; i < max_part; i++) {
519 		u8 io_id;
520 
521 		io_id = id - io_start_id;
522 		if (io_id < sst_inst->io_dies[i]) {
523 			u8 cdie_range;
524 
525 			cdie_range = fls(sst_inst->cdie_mask[i]) - ffs(sst_inst->cdie_mask[i]) + 1;
526 			*partition = i;
527 			return cdie_range + io_id;
528 		}
529 		io_start_id += sst_inst->io_dies[i];
530 	}
531 
532 	return -EINVAL;
533 }
534 
535 /*
536  * Map a package and power_domain id to SST information structure unique for a power_domain.
537  * The caller should call under isst_tpmi_dev_lock.
538  */
get_instance(int pkg_id,int power_domain_id)539 static struct tpmi_per_power_domain_info *get_instance(int pkg_id, int power_domain_id)
540 {
541 	struct tpmi_per_power_domain_info *power_domain_info;
542 	struct tpmi_sst_struct *sst_inst;
543 	u8 part;
544 
545 	if (!in_range(pkg_id, 0, topology_max_packages()) || pkg_id > isst_common.max_index)
546 		return NULL;
547 
548 	sst_inst = isst_common.sst_inst[pkg_id];
549 	if (!sst_inst)
550 		return NULL;
551 
552 	power_domain_id = map_partition_power_domain_id(sst_inst, power_domain_id, &part);
553 	if (power_domain_id < 0)
554 		return NULL;
555 
556 	power_domain_info = &sst_inst->power_domain_info[part][power_domain_id];
557 
558 	if (power_domain_info && !power_domain_info->sst_base)
559 		return NULL;
560 
561 	return power_domain_info;
562 }
563 
disable_dynamic_sst_features(void)564 static bool disable_dynamic_sst_features(void)
565 {
566 	u64 value;
567 
568 	if (!cpu_feature_enabled(X86_FEATURE_HWP))
569 		return true;
570 
571 	rdmsrq(MSR_PM_ENABLE, value);
572 	return !(value & 0x1);
573 }
574 
575 #define _read_cp_info(name_str, name, offset, start, width, mult_factor)\
576 {\
577 	u64 val, mask;\
578 	\
579 	val = readq(power_domain_info->sst_base + power_domain_info->sst_header.cp_offset +\
580 			(offset));\
581 	mask = GENMASK_ULL((start + width - 1), start);\
582 	val &= mask; \
583 	val >>= start;\
584 	name = (val * mult_factor);\
585 }
586 
587 #define _write_cp_info(name_str, name, offset, start, width, div_factor)\
588 {\
589 	u64 val, mask;\
590 	\
591 	val = readq(power_domain_info->sst_base +\
592 		    power_domain_info->sst_header.cp_offset + (offset));\
593 	mask = GENMASK_ULL((start + width - 1), start);\
594 	val &= ~mask;\
595 	val |= (name / div_factor) << start;\
596 	writeq(val, power_domain_info->sst_base + power_domain_info->sst_header.cp_offset +\
597 		(offset));\
598 }
599 
600 #define	SST_CP_CONTROL_OFFSET	8
601 #define	SST_CP_STATUS_OFFSET	16
602 
603 #define SST_CP_ENABLE_START		0
604 #define SST_CP_ENABLE_WIDTH		1
605 
606 #define SST_CP_PRIORITY_TYPE_START	1
607 #define SST_CP_PRIORITY_TYPE_WIDTH	1
608 
609 #define SST_CP_MAX_ENABLE		1
610 #define SST_CP_MAX_PRIORITY_TYPE	1
611 
isst_if_core_power_state(void __user * argp)612 static long isst_if_core_power_state(void __user *argp)
613 {
614 	struct tpmi_per_power_domain_info *power_domain_info;
615 	struct isst_core_power core_power;
616 
617 	if (copy_from_user(&core_power, argp, sizeof(core_power)))
618 		return -EFAULT;
619 
620 	if (core_power.get_set && disable_dynamic_sst_features())
621 		return -EFAULT;
622 
623 	power_domain_info = get_instance(core_power.socket_id, core_power.power_domain_id);
624 	if (!power_domain_info)
625 		return -EINVAL;
626 
627 	if (core_power.get_set) {
628 		if (power_domain_info->write_blocked || !capable(CAP_SYS_ADMIN))
629 			return -EPERM;
630 
631 		if (core_power.enable > SST_CP_MAX_ENABLE ||
632 		    core_power.priority_type > SST_CP_MAX_PRIORITY_TYPE)
633 			return -EINVAL;
634 
635 		_write_cp_info("cp_enable", core_power.enable, SST_CP_CONTROL_OFFSET,
636 			       SST_CP_ENABLE_START, SST_CP_ENABLE_WIDTH, SST_MUL_FACTOR_NONE)
637 		_write_cp_info("cp_prio_type", core_power.priority_type, SST_CP_CONTROL_OFFSET,
638 			       SST_CP_PRIORITY_TYPE_START, SST_CP_PRIORITY_TYPE_WIDTH,
639 			       SST_MUL_FACTOR_NONE)
640 	} else {
641 		/* get */
642 		_read_cp_info("cp_enable", core_power.enable, SST_CP_STATUS_OFFSET,
643 			      SST_CP_ENABLE_START, SST_CP_ENABLE_WIDTH, SST_MUL_FACTOR_NONE)
644 		_read_cp_info("cp_prio_type", core_power.priority_type, SST_CP_STATUS_OFFSET,
645 			      SST_CP_PRIORITY_TYPE_START, SST_CP_PRIORITY_TYPE_WIDTH,
646 			      SST_MUL_FACTOR_NONE)
647 		core_power.supported = !!(power_domain_info->sst_header.cap_mask & BIT(0));
648 		if (copy_to_user(argp, &core_power, sizeof(core_power)))
649 			return -EFAULT;
650 	}
651 
652 	return 0;
653 }
654 
655 #define SST_CLOS_CONFIG_0_OFFSET	24
656 
657 #define SST_CLOS_CONFIG_PRIO_START	4
658 #define SST_CLOS_CONFIG_PRIO_WIDTH	4
659 
660 #define SST_CLOS_CONFIG_MIN_START	8
661 #define SST_CLOS_CONFIG_MIN_WIDTH	8
662 
663 #define SST_CLOS_CONFIG_MAX_START	16
664 #define SST_CLOS_CONFIG_MAX_WIDTH	8
665 
666 #define SST_MAX_CLOS			3
667 
668 #define SST_MAX_FREQ			0xff
669 #define SST_CLOS_MAX_PRIORITY		0x0f
670 
isst_if_clos_param(void __user * argp)671 static long isst_if_clos_param(void __user *argp)
672 {
673 	struct tpmi_per_power_domain_info *power_domain_info;
674 	struct isst_clos_param clos_param;
675 
676 	if (copy_from_user(&clos_param, argp, sizeof(clos_param)))
677 		return -EFAULT;
678 
679 	if (clos_param.clos > SST_MAX_CLOS)
680 		return -EINVAL;
681 
682 	power_domain_info = get_instance(clos_param.socket_id, clos_param.power_domain_id);
683 	if (!power_domain_info)
684 		return -EINVAL;
685 
686 	if (clos_param.get_set) {
687 		if (power_domain_info->write_blocked || !capable(CAP_SYS_ADMIN))
688 			return -EPERM;
689 
690 		if (!in_range(clos_param.min_freq_mhz / SST_MUL_FACTOR_FREQ, 0, SST_MAX_FREQ + 1))
691 			return -EINVAL;
692 
693 		if (!in_range(clos_param.max_freq_mhz / SST_MUL_FACTOR_FREQ, 0, SST_MAX_FREQ + 1))
694 			return -EINVAL;
695 
696 		if (!in_range(clos_param.prop_prio, 0, SST_CLOS_MAX_PRIORITY + 1))
697 			return -EINVAL;
698 
699 		_write_cp_info("clos.min_freq", clos_param.min_freq_mhz,
700 			       (SST_CLOS_CONFIG_0_OFFSET + clos_param.clos * SST_REG_SIZE),
701 			       SST_CLOS_CONFIG_MIN_START, SST_CLOS_CONFIG_MIN_WIDTH,
702 			       SST_MUL_FACTOR_FREQ);
703 		_write_cp_info("clos.max_freq", clos_param.max_freq_mhz,
704 			       (SST_CLOS_CONFIG_0_OFFSET + clos_param.clos * SST_REG_SIZE),
705 			       SST_CLOS_CONFIG_MAX_START, SST_CLOS_CONFIG_MAX_WIDTH,
706 			       SST_MUL_FACTOR_FREQ);
707 		_write_cp_info("clos.prio", clos_param.prop_prio,
708 			       (SST_CLOS_CONFIG_0_OFFSET + clos_param.clos * SST_REG_SIZE),
709 			       SST_CLOS_CONFIG_PRIO_START, SST_CLOS_CONFIG_PRIO_WIDTH,
710 			       SST_MUL_FACTOR_NONE);
711 	} else {
712 		/* get */
713 		_read_cp_info("clos.min_freq", clos_param.min_freq_mhz,
714 				(SST_CLOS_CONFIG_0_OFFSET + clos_param.clos * SST_REG_SIZE),
715 				SST_CLOS_CONFIG_MIN_START, SST_CLOS_CONFIG_MIN_WIDTH,
716 				SST_MUL_FACTOR_FREQ)
717 		_read_cp_info("clos.max_freq", clos_param.max_freq_mhz,
718 				(SST_CLOS_CONFIG_0_OFFSET + clos_param.clos * SST_REG_SIZE),
719 				SST_CLOS_CONFIG_MAX_START, SST_CLOS_CONFIG_MAX_WIDTH,
720 				SST_MUL_FACTOR_FREQ)
721 		_read_cp_info("clos.prio", clos_param.prop_prio,
722 				(SST_CLOS_CONFIG_0_OFFSET + clos_param.clos * SST_REG_SIZE),
723 				SST_CLOS_CONFIG_PRIO_START, SST_CLOS_CONFIG_PRIO_WIDTH,
724 				SST_MUL_FACTOR_NONE)
725 
726 		if (copy_to_user(argp, &clos_param, sizeof(clos_param)))
727 			return -EFAULT;
728 	}
729 
730 	return 0;
731 }
732 
733 #define SST_CLOS_ASSOC_0_OFFSET		56
734 #define SST_CLOS_ASSOC_CPUS_PER_REG	16
735 #define SST_CLOS_ASSOC_BITS_PER_CPU	4
736 
737 #define SST_CLOS_ASSOC_MAX_LOGICAL_CPU	63
738 
isst_if_clos_assoc(void __user * argp)739 static long isst_if_clos_assoc(void __user *argp)
740 {
741 	struct isst_if_clos_assoc_cmds assoc_cmds;
742 	unsigned char __user *ptr;
743 	int i;
744 
745 	/* Each multi command has u16 command count as the first field */
746 	if (copy_from_user(&assoc_cmds, argp, sizeof(assoc_cmds)))
747 		return -EFAULT;
748 
749 	if (!assoc_cmds.cmd_count || assoc_cmds.cmd_count > ISST_IF_CMD_LIMIT)
750 		return -EINVAL;
751 
752 	ptr = argp + offsetof(struct isst_if_clos_assoc_cmds, assoc_info);
753 	for (i = 0; i < assoc_cmds.cmd_count; ++i) {
754 		struct tpmi_per_power_domain_info *power_domain_info;
755 		struct isst_if_clos_assoc clos_assoc;
756 		int punit_id, punit_cpu_no, pkg_id;
757 		struct tpmi_sst_struct *sst_inst;
758 		int offset, shift, cpu;
759 		u64 val, mask, clos;
760 		u8 part;
761 
762 		if (copy_from_user(&clos_assoc, ptr, sizeof(clos_assoc)))
763 			return -EFAULT;
764 
765 		if (clos_assoc.clos > SST_MAX_CLOS)
766 			return -EINVAL;
767 
768 		if (clos_assoc.socket_id >= topology_max_packages())
769 			return -EINVAL;
770 
771 		if (clos_assoc.logical_cpu > SST_CLOS_ASSOC_MAX_LOGICAL_CPU)
772 			return -EINVAL;
773 
774 		cpu = clos_assoc.logical_cpu;
775 		clos = clos_assoc.clos;
776 
777 		if (assoc_cmds.punit_cpu_map)
778 			punit_cpu_no = cpu;
779 		else
780 			return -EOPNOTSUPP;
781 
782 		if (punit_cpu_no < 0)
783 			return -EINVAL;
784 
785 		punit_id = clos_assoc.power_domain_id;
786 		pkg_id = clos_assoc.socket_id;
787 
788 		sst_inst = isst_common.sst_inst[pkg_id];
789 		if (!sst_inst)
790 			return -EINVAL;
791 
792 		punit_id = map_partition_power_domain_id(sst_inst, punit_id, &part);
793 		if (punit_id < 0)
794 			return -EINVAL;
795 
796 		power_domain_info = &sst_inst->power_domain_info[part][punit_id];
797 
798 		if (assoc_cmds.get_set && (power_domain_info->write_blocked ||
799 					   !capable(CAP_SYS_ADMIN)))
800 			return -EPERM;
801 
802 		offset = SST_CLOS_ASSOC_0_OFFSET +
803 				(punit_cpu_no / SST_CLOS_ASSOC_CPUS_PER_REG) * SST_REG_SIZE;
804 		shift = punit_cpu_no % SST_CLOS_ASSOC_CPUS_PER_REG;
805 		shift *= SST_CLOS_ASSOC_BITS_PER_CPU;
806 
807 		val = readq(power_domain_info->sst_base +
808 				power_domain_info->sst_header.cp_offset + offset);
809 		if (assoc_cmds.get_set) {
810 			mask = GENMASK_ULL((shift + SST_CLOS_ASSOC_BITS_PER_CPU - 1), shift);
811 			val &= ~mask;
812 			val |= (clos << shift);
813 			writeq(val, power_domain_info->sst_base +
814 					power_domain_info->sst_header.cp_offset + offset);
815 		} else {
816 			val >>= shift;
817 			clos_assoc.clos = val & GENMASK(SST_CLOS_ASSOC_BITS_PER_CPU - 1, 0);
818 			if (copy_to_user(ptr, &clos_assoc, sizeof(clos_assoc)))
819 				return -EFAULT;
820 		}
821 
822 		ptr += sizeof(clos_assoc);
823 	}
824 
825 	return 0;
826 }
827 
828 #define _read_pp_info(name_str, name, offset, start, width, mult_factor)\
829 {\
830 	u64 val, _mask;\
831 	\
832 	val = readq(power_domain_info->sst_base + power_domain_info->sst_header.pp_offset +\
833 		    (offset));\
834 	_mask = GENMASK_ULL((start + width - 1), start);\
835 	val &= _mask;\
836 	val >>= start;\
837 	name = (val * mult_factor);\
838 }
839 
840 #define _write_pp_info(name_str, name, offset, start, width, div_factor)\
841 {\
842 	u64 val, _mask;\
843 	\
844 	val = readq(power_domain_info->sst_base + power_domain_info->sst_header.pp_offset +\
845 		    (offset));\
846 	_mask = GENMASK((start + width - 1), start);\
847 	val &= ~_mask;\
848 	val |= (name / div_factor) << start;\
849 	writeq(val, power_domain_info->sst_base + power_domain_info->sst_header.pp_offset +\
850 	      (offset));\
851 }
852 
853 #define _read_bf_level_info(name_str, name, level, offset, start, width, mult_factor)\
854 {\
855 	u64 val, _mask;\
856 	\
857 	val = readq(power_domain_info->sst_base +\
858 		    power_domain_info->perf_levels[level].mmio_offset +\
859 		(power_domain_info->feature_offsets.bf_offset * 8) + (offset));\
860 	_mask = GENMASK_ULL((start + width - 1), start);\
861 	val &= _mask; \
862 	val >>= start;\
863 	name = (val * mult_factor);\
864 }
865 
866 #define _read_tf_level_info(name_str, name, level, offset, start, width, mult_factor)\
867 {\
868 	u64 val, _mask;\
869 	\
870 	val = readq(power_domain_info->sst_base +\
871 		    power_domain_info->perf_levels[level].mmio_offset +\
872 		(power_domain_info->feature_offsets.tf_offset * 8) + (offset));\
873 	_mask = GENMASK_ULL((start + width - 1), start);\
874 	val &= _mask; \
875 	val >>= start;\
876 	name = (val * mult_factor);\
877 }
878 
879 #define SST_PP_STATUS_OFFSET	32
880 
881 #define SST_PP_LEVEL_START	0
882 #define SST_PP_LEVEL_WIDTH	3
883 
884 #define SST_PP_LOCK_START	3
885 #define SST_PP_LOCK_WIDTH	1
886 
887 #define SST_PP_FEATURE_STATE_START	8
888 #define SST_PP_FEATURE_STATE_WIDTH	8
889 #define SST_PP_FEATURE_STATE_VALID_MASK	GENMASK(1, 0)
890 
891 #define SST_BF_FEATURE_SUPPORTED_START	12
892 #define SST_BF_FEATURE_SUPPORTED_WIDTH	1
893 
894 #define SST_TF_FEATURE_SUPPORTED_START	12
895 #define SST_TF_FEATURE_SUPPORTED_WIDTH	1
896 
isst_if_get_perf_level(void __user * argp)897 static int isst_if_get_perf_level(void __user *argp)
898 {
899 	struct isst_perf_level_info perf_level;
900 	struct tpmi_per_power_domain_info *power_domain_info;
901 	unsigned long level_mask;
902 	u8 level, support;
903 
904 	if (copy_from_user(&perf_level, argp, sizeof(perf_level)))
905 		return -EFAULT;
906 
907 	power_domain_info = get_instance(perf_level.socket_id, perf_level.power_domain_id);
908 	if (!power_domain_info)
909 		return -EINVAL;
910 
911 	perf_level.max_level = power_domain_info->max_level;
912 	perf_level.level_mask = power_domain_info->pp_header.level_en_mask;
913 	perf_level.feature_rev = power_domain_info->pp_header.feature_rev;
914 	_read_pp_info("current_level", perf_level.current_level, SST_PP_STATUS_OFFSET,
915 		      SST_PP_LEVEL_START, SST_PP_LEVEL_WIDTH, SST_MUL_FACTOR_NONE)
916 	_read_pp_info("locked", perf_level.locked, SST_PP_STATUS_OFFSET,
917 		      SST_PP_LOCK_START, SST_PP_LOCK_WIDTH, SST_MUL_FACTOR_NONE)
918 	_read_pp_info("feature_state", perf_level.feature_state, SST_PP_STATUS_OFFSET,
919 		      SST_PP_FEATURE_STATE_START, SST_PP_FEATURE_STATE_WIDTH, SST_MUL_FACTOR_NONE)
920 	perf_level.enabled = !!(power_domain_info->sst_header.cap_mask & BIT(1));
921 
922 	level_mask = perf_level.level_mask & power_domain_info->pp_header.level_en_mask;
923 	perf_level.sst_bf_support = 0;
924 	for_each_set_bit(level, &level_mask, BITS_PER_BYTE) {
925 		/*
926 		 * Read BF support for a level. Read output is updated
927 		 * to "support" variable by the below macro.
928 		 */
929 		_read_bf_level_info("bf_support", support, level, 0, SST_BF_FEATURE_SUPPORTED_START,
930 				    SST_BF_FEATURE_SUPPORTED_WIDTH, SST_MUL_FACTOR_NONE);
931 
932 		/* If supported set the bit for the level */
933 		if (support)
934 			perf_level.sst_bf_support |= BIT(level);
935 	}
936 
937 	perf_level.sst_tf_support = 0;
938 	for_each_set_bit(level, &level_mask, BITS_PER_BYTE) {
939 		/*
940 		 * Read TF support for a level. Read output is updated
941 		 * to "support" variable by the below macro.
942 		 */
943 		_read_tf_level_info("tf_support", support, level, 0, SST_TF_FEATURE_SUPPORTED_START,
944 				    SST_TF_FEATURE_SUPPORTED_WIDTH, SST_MUL_FACTOR_NONE);
945 
946 		/* If supported set the bit for the level */
947 		if (support)
948 			perf_level.sst_tf_support |= BIT(level);
949 	}
950 
951 	if (copy_to_user(argp, &perf_level, sizeof(perf_level)))
952 		return -EFAULT;
953 
954 	return 0;
955 }
956 
957 #define SST_PP_CONTROL_OFFSET		24
958 #define SST_PP_LEVEL_CHANGE_TIME_MS	5
959 #define SST_PP_LEVEL_CHANGE_RETRY_COUNT	3
960 
isst_if_set_perf_level(void __user * argp)961 static int isst_if_set_perf_level(void __user *argp)
962 {
963 	struct isst_perf_level_control perf_level;
964 	struct tpmi_per_power_domain_info *power_domain_info;
965 	int level, retry = 0;
966 
967 	if (disable_dynamic_sst_features())
968 		return -EFAULT;
969 
970 	if (copy_from_user(&perf_level, argp, sizeof(perf_level)))
971 		return -EFAULT;
972 
973 	power_domain_info = get_instance(perf_level.socket_id, perf_level.power_domain_id);
974 	if (!power_domain_info)
975 		return -EINVAL;
976 
977 	if (perf_level.level > power_domain_info->max_level)
978 		return -EINVAL;
979 
980 	if (power_domain_info->write_blocked || !capable(CAP_SYS_ADMIN))
981 		return -EPERM;
982 
983 	if (!(power_domain_info->pp_header.allowed_level_mask & BIT(perf_level.level)))
984 		return -EINVAL;
985 
986 	_read_pp_info("current_level", level, SST_PP_STATUS_OFFSET,
987 		      SST_PP_LEVEL_START, SST_PP_LEVEL_WIDTH, SST_MUL_FACTOR_NONE)
988 
989 	/* If the requested new level is same as the current level, reject */
990 	if (perf_level.level == level)
991 		return -EINVAL;
992 
993 	_write_pp_info("perf_level", perf_level.level, SST_PP_CONTROL_OFFSET,
994 		       SST_PP_LEVEL_START, SST_PP_LEVEL_WIDTH, SST_MUL_FACTOR_NONE)
995 
996 	/* It is possible that firmware is busy (although unlikely), so retry */
997 	do {
998 		/* Give time to FW to process */
999 		msleep(SST_PP_LEVEL_CHANGE_TIME_MS);
1000 
1001 		_read_pp_info("current_level", level, SST_PP_STATUS_OFFSET,
1002 			      SST_PP_LEVEL_START, SST_PP_LEVEL_WIDTH, SST_MUL_FACTOR_NONE)
1003 
1004 		/* Check if the new level is active */
1005 		if (perf_level.level == level)
1006 			break;
1007 
1008 	} while (retry++ < SST_PP_LEVEL_CHANGE_RETRY_COUNT);
1009 
1010 	/* If the level change didn't happen, return fault */
1011 	if (perf_level.level != level)
1012 		return -EFAULT;
1013 
1014 	/* Reset the feature state on level change */
1015 	_write_pp_info("perf_feature", 0, SST_PP_CONTROL_OFFSET,
1016 		       SST_PP_FEATURE_STATE_START, SST_PP_FEATURE_STATE_WIDTH,
1017 		       SST_MUL_FACTOR_NONE)
1018 
1019 	/* Give time to FW to process */
1020 	msleep(SST_PP_LEVEL_CHANGE_TIME_MS);
1021 
1022 	return 0;
1023 }
1024 
isst_if_set_perf_feature(void __user * argp)1025 static int isst_if_set_perf_feature(void __user *argp)
1026 {
1027 	struct isst_perf_feature_control perf_feature;
1028 	struct tpmi_per_power_domain_info *power_domain_info;
1029 
1030 	if (disable_dynamic_sst_features())
1031 		return -EFAULT;
1032 
1033 	if (copy_from_user(&perf_feature, argp, sizeof(perf_feature)))
1034 		return -EFAULT;
1035 
1036 	power_domain_info = get_instance(perf_feature.socket_id, perf_feature.power_domain_id);
1037 	if (!power_domain_info)
1038 		return -EINVAL;
1039 
1040 	if (power_domain_info->write_blocked || !capable(CAP_SYS_ADMIN))
1041 		return -EPERM;
1042 
1043 	if (perf_feature.feature & ~SST_PP_FEATURE_STATE_VALID_MASK)
1044 		return -EINVAL;
1045 
1046 	_write_pp_info("perf_feature", perf_feature.feature, SST_PP_CONTROL_OFFSET,
1047 		       SST_PP_FEATURE_STATE_START, SST_PP_FEATURE_STATE_WIDTH,
1048 		       SST_MUL_FACTOR_NONE)
1049 
1050 	return 0;
1051 }
1052 
1053 #define _read_pp_level_info(name_str, name, level, offset, start, width, mult_factor)\
1054 {\
1055 	u64 val, _mask;\
1056 	\
1057 	val = readq(power_domain_info->sst_base +\
1058 		    power_domain_info->perf_levels[level].mmio_offset +\
1059 		(power_domain_info->feature_offsets.pp_offset * 8) + (offset));\
1060 	_mask = GENMASK_ULL((start + width - 1), start);\
1061 	val &= _mask; \
1062 	val >>= start;\
1063 	name = (val * mult_factor);\
1064 }
1065 
1066 #define SST_PP_INFO_0_OFFSET	0
1067 #define SST_PP_INFO_1_OFFSET	8
1068 #define SST_PP_INFO_2_OFFSET	16
1069 #define SST_PP_INFO_3_OFFSET	24
1070 
1071 /* SST_PP_INFO_4_OFFSET to SST_PP_INFO_9_OFFSET are trl levels */
1072 #define SST_PP_INFO_4_OFFSET	32
1073 
1074 #define SST_PP_INFO_10_OFFSET	80
1075 #define SST_PP_INFO_11_OFFSET	88
1076 #define SST_PP_INFO_12_OFFSET	96
1077 
1078 #define SST_PP_P1_SSE_START	0
1079 #define SST_PP_P1_SSE_WIDTH	8
1080 
1081 #define SST_PP_P1_AVX2_START	8
1082 #define SST_PP_P1_AVX2_WIDTH	8
1083 
1084 #define SST_PP_P1_AVX512_START	16
1085 #define SST_PP_P1_AVX512_WIDTH	8
1086 
1087 #define SST_PP_P1_AMX_START	24
1088 #define SST_PP_P1_AMX_WIDTH	8
1089 
1090 #define SST_PP_TDP_START	32
1091 #define SST_PP_TDP_WIDTH	15
1092 
1093 #define SST_PP_T_PROCHOT_START	47
1094 #define SST_PP_T_PROCHOT_WIDTH	8
1095 
1096 #define SST_PP_MAX_MEMORY_FREQ_START	55
1097 #define SST_PP_MAX_MEMORY_FREQ_WIDTH	7
1098 
1099 #define SST_PP_COOLING_TYPE_START	62
1100 #define SST_PP_COOLING_TYPE_WIDTH	2
1101 
1102 #define SST_PP_TRL_0_RATIO_0_START	0
1103 #define SST_PP_TRL_0_RATIO_0_WIDTH	8
1104 
1105 #define SST_PP_TRL_CORES_BUCKET_0_START	0
1106 #define SST_PP_TRL_CORES_BUCKET_0_WIDTH	8
1107 
1108 #define SST_PP_CORE_RATIO_P0_START	0
1109 #define SST_PP_CORE_RATIO_P0_WIDTH	8
1110 
1111 #define SST_PP_CORE_RATIO_P1_START	8
1112 #define SST_PP_CORE_RATIO_P1_WIDTH	8
1113 
1114 #define SST_PP_CORE_RATIO_PN_START	16
1115 #define SST_PP_CORE_RATIO_PN_WIDTH	8
1116 
1117 #define SST_PP_CORE_RATIO_PM_START	24
1118 #define SST_PP_CORE_RATIO_PM_WIDTH	8
1119 
1120 #define SST_PP_CORE_RATIO_P0_FABRIC_START	32
1121 #define SST_PP_CORE_RATIO_P0_FABRIC_WIDTH	8
1122 
1123 #define SST_PP_CORE_RATIO_P1_FABRIC_START	40
1124 #define SST_PP_CORE_RATIO_P1_FABRIC_WIDTH	8
1125 
1126 #define SST_PP_CORE_RATIO_PM_FABRIC_START	48
1127 #define SST_PP_CORE_RATIO_PM_FABRIC_WIDTH	8
1128 
1129 #define SST_PP_CORE_RATIO_P0_FABRIC_1_START	0
1130 #define SST_PP_CORE_RATIO_P0_FABRIC_1_WIDTH	8
1131 
1132 #define SST_PP_CORE_RATIO_P1_FABRIC_1_START	8
1133 #define SST_PP_CORE_RATIO_P1_FABRIC_1_WIDTH	8
1134 
1135 #define SST_PP_CORE_RATIO_PM_FABRIC_1_START	16
1136 #define SST_PP_CORE_RATIO_PM_FABRIC_1_WIDTH	8
1137 
isst_if_get_perf_level_info(void __user * argp)1138 static int isst_if_get_perf_level_info(void __user *argp)
1139 {
1140 	struct isst_perf_level_data_info perf_level;
1141 	struct tpmi_per_power_domain_info *power_domain_info;
1142 	int i, j;
1143 
1144 	if (copy_from_user(&perf_level, argp, sizeof(perf_level)))
1145 		return -EFAULT;
1146 
1147 	power_domain_info = get_instance(perf_level.socket_id, perf_level.power_domain_id);
1148 	if (!power_domain_info)
1149 		return -EINVAL;
1150 
1151 	if (perf_level.level > power_domain_info->max_level)
1152 		return -EINVAL;
1153 
1154 	if (!(power_domain_info->pp_header.level_en_mask & BIT(perf_level.level)))
1155 		return -EINVAL;
1156 
1157 	_read_pp_level_info("tdp_ratio", perf_level.tdp_ratio, perf_level.level,
1158 			    SST_PP_INFO_0_OFFSET, SST_PP_P1_SSE_START, SST_PP_P1_SSE_WIDTH,
1159 			    SST_MUL_FACTOR_NONE)
1160 	_read_pp_level_info("base_freq_mhz", perf_level.base_freq_mhz, perf_level.level,
1161 			    SST_PP_INFO_0_OFFSET, SST_PP_P1_SSE_START, SST_PP_P1_SSE_WIDTH,
1162 			    SST_MUL_FACTOR_FREQ)
1163 	_read_pp_level_info("base_freq_avx2_mhz", perf_level.base_freq_avx2_mhz, perf_level.level,
1164 			    SST_PP_INFO_0_OFFSET, SST_PP_P1_AVX2_START, SST_PP_P1_AVX2_WIDTH,
1165 			    SST_MUL_FACTOR_FREQ)
1166 	_read_pp_level_info("base_freq_avx512_mhz", perf_level.base_freq_avx512_mhz,
1167 			    perf_level.level, SST_PP_INFO_0_OFFSET, SST_PP_P1_AVX512_START,
1168 			    SST_PP_P1_AVX512_WIDTH, SST_MUL_FACTOR_FREQ)
1169 	_read_pp_level_info("base_freq_amx_mhz", perf_level.base_freq_amx_mhz, perf_level.level,
1170 			    SST_PP_INFO_0_OFFSET, SST_PP_P1_AMX_START, SST_PP_P1_AMX_WIDTH,
1171 			    SST_MUL_FACTOR_FREQ)
1172 
1173 	_read_pp_level_info("thermal_design_power_w", perf_level.thermal_design_power_w,
1174 			    perf_level.level, SST_PP_INFO_1_OFFSET, SST_PP_TDP_START,
1175 			    SST_PP_TDP_WIDTH, SST_MUL_FACTOR_NONE)
1176 	perf_level.thermal_design_power_w /= 8; /* units are in 1/8th watt */
1177 	_read_pp_level_info("tjunction_max_c", perf_level.tjunction_max_c, perf_level.level,
1178 			    SST_PP_INFO_1_OFFSET, SST_PP_T_PROCHOT_START, SST_PP_T_PROCHOT_WIDTH,
1179 			    SST_MUL_FACTOR_NONE)
1180 	_read_pp_level_info("max_memory_freq_mhz", perf_level.max_memory_freq_mhz,
1181 			    perf_level.level, SST_PP_INFO_1_OFFSET, SST_PP_MAX_MEMORY_FREQ_START,
1182 			    SST_PP_MAX_MEMORY_FREQ_WIDTH, SST_MUL_FACTOR_FREQ)
1183 	_read_pp_level_info("cooling_type", perf_level.cooling_type, perf_level.level,
1184 			    SST_PP_INFO_1_OFFSET, SST_PP_COOLING_TYPE_START,
1185 			    SST_PP_COOLING_TYPE_WIDTH, SST_MUL_FACTOR_NONE)
1186 
1187 	for (i = 0; i < TRL_MAX_LEVELS; ++i) {
1188 		for (j = 0; j < TRL_MAX_BUCKETS; ++j)
1189 			_read_pp_level_info("trl*_bucket*_freq_mhz",
1190 					    perf_level.trl_freq_mhz[i][j], perf_level.level,
1191 					    SST_PP_INFO_4_OFFSET + (i * SST_PP_TRL_0_RATIO_0_WIDTH),
1192 					    j * SST_PP_TRL_0_RATIO_0_WIDTH,
1193 					    SST_PP_TRL_0_RATIO_0_WIDTH,
1194 					    SST_MUL_FACTOR_FREQ);
1195 	}
1196 
1197 	for (i = 0; i < TRL_MAX_BUCKETS; ++i)
1198 		_read_pp_level_info("bucket*_core_count", perf_level.bucket_core_counts[i],
1199 				    perf_level.level, SST_PP_INFO_10_OFFSET,
1200 				    SST_PP_TRL_CORES_BUCKET_0_WIDTH * i,
1201 				    SST_PP_TRL_CORES_BUCKET_0_WIDTH, SST_MUL_FACTOR_NONE)
1202 
1203 	perf_level.max_buckets = TRL_MAX_BUCKETS;
1204 	perf_level.max_trl_levels = TRL_MAX_LEVELS;
1205 
1206 	_read_pp_level_info("p0_freq_mhz", perf_level.p0_freq_mhz, perf_level.level,
1207 			    SST_PP_INFO_11_OFFSET, SST_PP_CORE_RATIO_P0_START,
1208 			    SST_PP_CORE_RATIO_P0_WIDTH, SST_MUL_FACTOR_FREQ)
1209 	_read_pp_level_info("p1_freq_mhz", perf_level.p1_freq_mhz, perf_level.level,
1210 			    SST_PP_INFO_11_OFFSET, SST_PP_CORE_RATIO_P1_START,
1211 			    SST_PP_CORE_RATIO_P1_WIDTH, SST_MUL_FACTOR_FREQ)
1212 	_read_pp_level_info("pn_freq_mhz", perf_level.pn_freq_mhz, perf_level.level,
1213 			    SST_PP_INFO_11_OFFSET, SST_PP_CORE_RATIO_PN_START,
1214 			    SST_PP_CORE_RATIO_PN_WIDTH, SST_MUL_FACTOR_FREQ)
1215 	_read_pp_level_info("pm_freq_mhz", perf_level.pm_freq_mhz, perf_level.level,
1216 			    SST_PP_INFO_11_OFFSET, SST_PP_CORE_RATIO_PM_START,
1217 			    SST_PP_CORE_RATIO_PM_WIDTH, SST_MUL_FACTOR_FREQ)
1218 	_read_pp_level_info("p0_fabric_freq_mhz", perf_level.p0_fabric_freq_mhz,
1219 			    perf_level.level, SST_PP_INFO_11_OFFSET,
1220 			    SST_PP_CORE_RATIO_P0_FABRIC_START,
1221 			    SST_PP_CORE_RATIO_P0_FABRIC_WIDTH, SST_MUL_FACTOR_FREQ)
1222 	_read_pp_level_info("p1_fabric_freq_mhz", perf_level.p1_fabric_freq_mhz,
1223 			    perf_level.level, SST_PP_INFO_11_OFFSET,
1224 			    SST_PP_CORE_RATIO_P1_FABRIC_START,
1225 			    SST_PP_CORE_RATIO_P1_FABRIC_WIDTH, SST_MUL_FACTOR_FREQ)
1226 	_read_pp_level_info("pm_fabric_freq_mhz", perf_level.pm_fabric_freq_mhz,
1227 			    perf_level.level, SST_PP_INFO_11_OFFSET,
1228 			    SST_PP_CORE_RATIO_PM_FABRIC_START,
1229 			    SST_PP_CORE_RATIO_PM_FABRIC_WIDTH, SST_MUL_FACTOR_FREQ)
1230 
1231 	if (copy_to_user(argp, &perf_level, sizeof(perf_level)))
1232 		return -EFAULT;
1233 
1234 	return 0;
1235 }
1236 
isst_if_get_perf_level_fabric_info(void __user * argp)1237 static int isst_if_get_perf_level_fabric_info(void __user *argp)
1238 {
1239 	struct isst_perf_level_fabric_info perf_level_fabric;
1240 	struct tpmi_per_power_domain_info *power_domain_info;
1241 	int start = SST_PP_CORE_RATIO_P0_FABRIC_START;
1242 	int width = SST_PP_CORE_RATIO_P0_FABRIC_WIDTH;
1243 	int offset = SST_PP_INFO_11_OFFSET;
1244 	int i;
1245 
1246 	if (copy_from_user(&perf_level_fabric, argp, sizeof(perf_level_fabric)))
1247 		return -EFAULT;
1248 
1249 	power_domain_info = get_instance(perf_level_fabric.socket_id,
1250 					 perf_level_fabric.power_domain_id);
1251 	if (!power_domain_info)
1252 		return -EINVAL;
1253 
1254 	if (perf_level_fabric.level > power_domain_info->max_level)
1255 		return -EINVAL;
1256 
1257 	if (power_domain_info->pp_header.feature_rev < 2)
1258 		return -EINVAL;
1259 
1260 	if (!(power_domain_info->pp_header.level_en_mask & BIT(perf_level_fabric.level)))
1261 		return -EINVAL;
1262 
1263 	/* For revision 2, maximum number of fabrics is 2 */
1264 	perf_level_fabric.max_fabrics = 2;
1265 
1266 	for (i = 0; i < perf_level_fabric.max_fabrics; i++) {
1267 		_read_pp_level_info("p0_fabric_freq_mhz", perf_level_fabric.p0_fabric_freq_mhz[i],
1268 				    perf_level_fabric.level, offset, start, width,
1269 				    SST_MUL_FACTOR_FREQ)
1270 		start += width;
1271 
1272 		_read_pp_level_info("p1_fabric_freq_mhz", perf_level_fabric.p1_fabric_freq_mhz[i],
1273 				    perf_level_fabric.level, offset, start, width,
1274 				    SST_MUL_FACTOR_FREQ)
1275 		start += width;
1276 
1277 		_read_pp_level_info("pm_fabric_freq_mhz", perf_level_fabric.pm_fabric_freq_mhz[i],
1278 				    perf_level_fabric.level, offset, start, width,
1279 				    SST_MUL_FACTOR_FREQ)
1280 		offset = SST_PP_INFO_12_OFFSET;
1281 		start = SST_PP_CORE_RATIO_P0_FABRIC_1_START;
1282 	}
1283 
1284 	if (copy_to_user(argp, &perf_level_fabric, sizeof(perf_level_fabric)))
1285 		return -EFAULT;
1286 
1287 	return 0;
1288 }
1289 
1290 #define SST_PP_FUSED_CORE_COUNT_START	0
1291 #define SST_PP_FUSED_CORE_COUNT_WIDTH	8
1292 
1293 #define SST_PP_RSLVD_CORE_COUNT_START	8
1294 #define SST_PP_RSLVD_CORE_COUNT_WIDTH	8
1295 
1296 #define SST_PP_RSLVD_CORE_MASK_START	0
1297 #define SST_PP_RSLVD_CORE_MASK_WIDTH	64
1298 
isst_if_get_perf_level_mask(void __user * argp)1299 static int isst_if_get_perf_level_mask(void __user *argp)
1300 {
1301 	static struct isst_perf_level_cpu_mask cpumask;
1302 	struct tpmi_per_power_domain_info *power_domain_info;
1303 	u64 mask;
1304 
1305 	if (copy_from_user(&cpumask, argp, sizeof(cpumask)))
1306 		return -EFAULT;
1307 
1308 	power_domain_info = get_instance(cpumask.socket_id, cpumask.power_domain_id);
1309 	if (!power_domain_info)
1310 		return -EINVAL;
1311 
1312 	if (cpumask.level > power_domain_info->max_level)
1313 		return -EINVAL;
1314 
1315 	if (!(power_domain_info->pp_header.level_en_mask & BIT(cpumask.level)))
1316 		return -EINVAL;
1317 
1318 	_read_pp_level_info("mask", mask, cpumask.level, SST_PP_INFO_2_OFFSET,
1319 			    SST_PP_RSLVD_CORE_MASK_START, SST_PP_RSLVD_CORE_MASK_WIDTH,
1320 			    SST_MUL_FACTOR_NONE)
1321 
1322 	cpumask.mask = mask;
1323 
1324 	if (!cpumask.punit_cpu_map)
1325 		return -EOPNOTSUPP;
1326 
1327 	if (copy_to_user(argp, &cpumask, sizeof(cpumask)))
1328 		return -EFAULT;
1329 
1330 	return 0;
1331 }
1332 
1333 #define SST_BF_INFO_0_OFFSET	0
1334 #define SST_BF_INFO_1_OFFSET	8
1335 
1336 #define SST_BF_P1_HIGH_START	13
1337 #define SST_BF_P1_HIGH_WIDTH	8
1338 
1339 #define SST_BF_P1_LOW_START	21
1340 #define SST_BF_P1_LOW_WIDTH	8
1341 
1342 #define SST_BF_T_PROHOT_START	38
1343 #define SST_BF_T_PROHOT_WIDTH	8
1344 
1345 #define SST_BF_TDP_START	46
1346 #define SST_BF_TDP_WIDTH	15
1347 
isst_if_get_base_freq_info(void __user * argp)1348 static int isst_if_get_base_freq_info(void __user *argp)
1349 {
1350 	static struct isst_base_freq_info base_freq;
1351 	struct tpmi_per_power_domain_info *power_domain_info;
1352 
1353 	if (copy_from_user(&base_freq, argp, sizeof(base_freq)))
1354 		return -EFAULT;
1355 
1356 	power_domain_info = get_instance(base_freq.socket_id, base_freq.power_domain_id);
1357 	if (!power_domain_info)
1358 		return -EINVAL;
1359 
1360 	if (base_freq.level > power_domain_info->max_level)
1361 		return -EINVAL;
1362 
1363 	if (!(power_domain_info->pp_header.level_en_mask & BIT(base_freq.level)))
1364 		return -EINVAL;
1365 
1366 	_read_bf_level_info("p1_high", base_freq.high_base_freq_mhz, base_freq.level,
1367 			    SST_BF_INFO_0_OFFSET, SST_BF_P1_HIGH_START, SST_BF_P1_HIGH_WIDTH,
1368 			    SST_MUL_FACTOR_FREQ)
1369 	_read_bf_level_info("p1_low", base_freq.low_base_freq_mhz, base_freq.level,
1370 			    SST_BF_INFO_0_OFFSET, SST_BF_P1_LOW_START, SST_BF_P1_LOW_WIDTH,
1371 			    SST_MUL_FACTOR_FREQ)
1372 	_read_bf_level_info("BF-TJ", base_freq.tjunction_max_c, base_freq.level,
1373 			    SST_BF_INFO_0_OFFSET, SST_BF_T_PROHOT_START, SST_BF_T_PROHOT_WIDTH,
1374 			    SST_MUL_FACTOR_NONE)
1375 	_read_bf_level_info("BF-tdp", base_freq.thermal_design_power_w, base_freq.level,
1376 			    SST_BF_INFO_0_OFFSET, SST_BF_TDP_START, SST_BF_TDP_WIDTH,
1377 			    SST_MUL_FACTOR_NONE)
1378 	base_freq.thermal_design_power_w /= 8; /*unit = 1/8th watt*/
1379 
1380 	if (copy_to_user(argp, &base_freq, sizeof(base_freq)))
1381 		return -EFAULT;
1382 
1383 	return 0;
1384 }
1385 
1386 #define P1_HI_CORE_MASK_START	0
1387 #define P1_HI_CORE_MASK_WIDTH	64
1388 
isst_if_get_base_freq_mask(void __user * argp)1389 static int isst_if_get_base_freq_mask(void __user *argp)
1390 {
1391 	static struct isst_perf_level_cpu_mask cpumask;
1392 	struct tpmi_per_power_domain_info *power_domain_info;
1393 	u64 mask;
1394 
1395 	if (copy_from_user(&cpumask, argp, sizeof(cpumask)))
1396 		return -EFAULT;
1397 
1398 	power_domain_info = get_instance(cpumask.socket_id, cpumask.power_domain_id);
1399 	if (!power_domain_info)
1400 		return -EINVAL;
1401 
1402 	if (cpumask.level > power_domain_info->max_level)
1403 		return -EINVAL;
1404 
1405 	if (!(power_domain_info->pp_header.level_en_mask & BIT(cpumask.level)))
1406 		return -EINVAL;
1407 
1408 	_read_bf_level_info("BF-cpumask", mask, cpumask.level, SST_BF_INFO_1_OFFSET,
1409 			    P1_HI_CORE_MASK_START, P1_HI_CORE_MASK_WIDTH,
1410 			    SST_MUL_FACTOR_NONE)
1411 
1412 	cpumask.mask = mask;
1413 
1414 	if (!cpumask.punit_cpu_map)
1415 		return -EOPNOTSUPP;
1416 
1417 	if (copy_to_user(argp, &cpumask, sizeof(cpumask)))
1418 		return -EFAULT;
1419 
1420 	return 0;
1421 }
1422 
isst_if_get_tpmi_instance_count(void __user * argp)1423 static int isst_if_get_tpmi_instance_count(void __user *argp)
1424 {
1425 	struct isst_tpmi_instance_count tpmi_inst;
1426 	struct tpmi_sst_struct *sst_inst;
1427 	int i;
1428 
1429 	if (copy_from_user(&tpmi_inst, argp, sizeof(tpmi_inst)))
1430 		return -EFAULT;
1431 
1432 	if (tpmi_inst.socket_id >= topology_max_packages())
1433 		return -EINVAL;
1434 
1435 	sst_inst = isst_common.sst_inst[tpmi_inst.socket_id];
1436 	if (!sst_inst)
1437 		return -EINVAL;
1438 
1439 	tpmi_inst.count = isst_instance_count(sst_inst);
1440 
1441 	tpmi_inst.valid_mask = 0;
1442 	for (i = 0; i < tpmi_inst.count; i++) {
1443 		struct tpmi_per_power_domain_info *pd_info;
1444 		u8 part;
1445 		int pd;
1446 
1447 		pd = map_partition_power_domain_id(sst_inst, i, &part);
1448 		if (pd < 0)
1449 			continue;
1450 
1451 		pd_info = &sst_inst->power_domain_info[part][pd];
1452 		if (pd_info->sst_base)
1453 			tpmi_inst.valid_mask |= BIT(i);
1454 	}
1455 
1456 	if (!tpmi_inst.valid_mask)
1457 		tpmi_inst.count = 0;
1458 
1459 	if (copy_to_user(argp, &tpmi_inst, sizeof(tpmi_inst)))
1460 		return -EFAULT;
1461 
1462 	return 0;
1463 }
1464 
1465 #define SST_TF_INFO_0_OFFSET	0
1466 #define SST_TF_INFO_1_OFFSET	8
1467 #define SST_TF_INFO_2_OFFSET	16
1468 #define SST_TF_INFO_8_OFFSET	64
1469 #define SST_TF_INFO_8_BUCKETS	3
1470 
1471 #define SST_TF_MAX_LP_CLIP_RATIOS	TRL_MAX_LEVELS
1472 
1473 #define SST_TF_FEATURE_REV_START	4
1474 #define SST_TF_FEATURE_REV_WIDTH	8
1475 
1476 #define SST_TF_LP_CLIP_RATIO_0_START	16
1477 #define SST_TF_LP_CLIP_RATIO_0_WIDTH	8
1478 
1479 #define SST_TF_RATIO_0_START	0
1480 #define SST_TF_RATIO_0_WIDTH	8
1481 
1482 #define SST_TF_NUM_CORE_0_START 0
1483 #define SST_TF_NUM_CORE_0_WIDTH 8
1484 
1485 #define SST_TF_NUM_MOD_0_START	0
1486 #define SST_TF_NUM_MOD_0_WIDTH	16
1487 
isst_if_get_turbo_freq_info(void __user * argp)1488 static int isst_if_get_turbo_freq_info(void __user *argp)
1489 {
1490 	static struct isst_turbo_freq_info turbo_freq;
1491 	struct tpmi_per_power_domain_info *power_domain_info;
1492 	u8 feature_rev;
1493 	int i, j;
1494 
1495 	if (copy_from_user(&turbo_freq, argp, sizeof(turbo_freq)))
1496 		return -EFAULT;
1497 
1498 	power_domain_info = get_instance(turbo_freq.socket_id, turbo_freq.power_domain_id);
1499 	if (!power_domain_info)
1500 		return -EINVAL;
1501 
1502 	if (turbo_freq.level > power_domain_info->max_level)
1503 		return -EINVAL;
1504 
1505 	if (!(power_domain_info->pp_header.level_en_mask & BIT(turbo_freq.level)))
1506 		return -EINVAL;
1507 
1508 	turbo_freq.max_buckets = TRL_MAX_BUCKETS;
1509 	turbo_freq.max_trl_levels = TRL_MAX_LEVELS;
1510 	turbo_freq.max_clip_freqs = SST_TF_MAX_LP_CLIP_RATIOS;
1511 
1512 	_read_tf_level_info("feature_rev", feature_rev, turbo_freq.level,
1513 			    SST_TF_INFO_0_OFFSET, SST_TF_FEATURE_REV_START,
1514 			    SST_TF_FEATURE_REV_WIDTH, SST_MUL_FACTOR_NONE);
1515 
1516 	for (i = 0; i < turbo_freq.max_clip_freqs; ++i)
1517 		_read_tf_level_info("lp_clip*", turbo_freq.lp_clip_freq_mhz[i],
1518 				    turbo_freq.level, SST_TF_INFO_0_OFFSET,
1519 				    SST_TF_LP_CLIP_RATIO_0_START +
1520 				    (i * SST_TF_LP_CLIP_RATIO_0_WIDTH),
1521 				    SST_TF_LP_CLIP_RATIO_0_WIDTH, SST_MUL_FACTOR_FREQ)
1522 
1523 	for (i = 0; i < TRL_MAX_LEVELS; ++i) {
1524 		for (j = 0; j < TRL_MAX_BUCKETS; ++j)
1525 			_read_tf_level_info("cydn*_bucket_*_trl",
1526 					    turbo_freq.trl_freq_mhz[i][j], turbo_freq.level,
1527 					    SST_TF_INFO_2_OFFSET + (i * SST_TF_RATIO_0_WIDTH),
1528 					    j * SST_TF_RATIO_0_WIDTH, SST_TF_RATIO_0_WIDTH,
1529 					    SST_MUL_FACTOR_FREQ)
1530 	}
1531 
1532 	memset(turbo_freq.bucket_core_counts, 0, sizeof(turbo_freq.bucket_core_counts));
1533 
1534 	if (feature_rev >= 2) {
1535 		bool has_tf_info_8 = false;
1536 
1537 		for (i = 0; i < SST_TF_INFO_8_BUCKETS; ++i) {
1538 			_read_tf_level_info("bucket_*_mod_count", turbo_freq.bucket_core_counts[i],
1539 					    turbo_freq.level, SST_TF_INFO_8_OFFSET,
1540 					    SST_TF_NUM_MOD_0_WIDTH * i, SST_TF_NUM_MOD_0_WIDTH,
1541 					    SST_MUL_FACTOR_NONE)
1542 
1543 			if (turbo_freq.bucket_core_counts[i])
1544 				has_tf_info_8 = true;
1545 		}
1546 
1547 		if (has_tf_info_8)
1548 			goto done_core_count;
1549 	}
1550 
1551 	for (i = 0; i < TRL_MAX_BUCKETS; ++i)
1552 		_read_tf_level_info("bucket_*_core_count", turbo_freq.bucket_core_counts[i],
1553 				    turbo_freq.level, SST_TF_INFO_1_OFFSET,
1554 				    SST_TF_NUM_CORE_0_WIDTH * i, SST_TF_NUM_CORE_0_WIDTH,
1555 				    SST_MUL_FACTOR_NONE)
1556 
1557 
1558 done_core_count:
1559 
1560 	if (copy_to_user(argp, &turbo_freq, sizeof(turbo_freq)))
1561 		return -EFAULT;
1562 
1563 	return 0;
1564 }
1565 
isst_if_def_ioctl(struct file * file,unsigned int cmd,unsigned long arg)1566 static long isst_if_def_ioctl(struct file *file, unsigned int cmd,
1567 			      unsigned long arg)
1568 {
1569 	void __user *argp = (void __user *)arg;
1570 	long ret = -ENOTTY;
1571 
1572 	mutex_lock(&isst_tpmi_dev_lock);
1573 	switch (cmd) {
1574 	case ISST_IF_COUNT_TPMI_INSTANCES:
1575 		ret = isst_if_get_tpmi_instance_count(argp);
1576 		break;
1577 	case ISST_IF_CORE_POWER_STATE:
1578 		ret = isst_if_core_power_state(argp);
1579 		break;
1580 	case ISST_IF_CLOS_PARAM:
1581 		ret = isst_if_clos_param(argp);
1582 		break;
1583 	case ISST_IF_CLOS_ASSOC:
1584 		ret = isst_if_clos_assoc(argp);
1585 		break;
1586 	case ISST_IF_PERF_LEVELS:
1587 		ret = isst_if_get_perf_level(argp);
1588 		break;
1589 	case ISST_IF_PERF_SET_LEVEL:
1590 		ret = isst_if_set_perf_level(argp);
1591 		break;
1592 	case ISST_IF_PERF_SET_FEATURE:
1593 		ret = isst_if_set_perf_feature(argp);
1594 		break;
1595 	case ISST_IF_GET_PERF_LEVEL_INFO:
1596 		ret = isst_if_get_perf_level_info(argp);
1597 		break;
1598 	case ISST_IF_GET_PERF_LEVEL_FABRIC_INFO:
1599 		ret = isst_if_get_perf_level_fabric_info(argp);
1600 		break;
1601 	case ISST_IF_GET_PERF_LEVEL_CPU_MASK:
1602 		ret = isst_if_get_perf_level_mask(argp);
1603 		break;
1604 	case ISST_IF_GET_BASE_FREQ_INFO:
1605 		ret = isst_if_get_base_freq_info(argp);
1606 		break;
1607 	case ISST_IF_GET_BASE_FREQ_CPU_MASK:
1608 		ret = isst_if_get_base_freq_mask(argp);
1609 		break;
1610 	case ISST_IF_GET_TURBO_FREQ_INFO:
1611 		ret = isst_if_get_turbo_freq_info(argp);
1612 		break;
1613 	default:
1614 		break;
1615 	}
1616 	mutex_unlock(&isst_tpmi_dev_lock);
1617 
1618 	return ret;
1619 }
1620 
1621 #define TPMI_SST_AUTO_SUSPEND_DELAY_MS	2000
1622 
tpmi_sst_dev_add(struct auxiliary_device * auxdev)1623 int tpmi_sst_dev_add(struct auxiliary_device *auxdev)
1624 {
1625 	struct tpmi_per_power_domain_info *pd_info;
1626 	bool read_blocked = 0, write_blocked = 0;
1627 	struct oobmsm_plat_info *plat_info;
1628 	struct device *dev = &auxdev->dev;
1629 	struct tpmi_sst_struct *tpmi_sst;
1630 	u8 i, num_resources, io_die_cnt;
1631 	int ret, pkg = 0, inst = 0;
1632 	bool first_enum = false;
1633 	u16 cdie_mask;
1634 	u8 partition;
1635 
1636 	ret = tpmi_get_feature_status(auxdev, TPMI_ID_SST, &read_blocked, &write_blocked);
1637 	if (ret)
1638 		dev_info(dev, "Can't read feature status: ignoring read/write blocked status\n");
1639 
1640 	if (read_blocked) {
1641 		dev_info(dev, "Firmware has blocked reads, exiting\n");
1642 		return -ENODEV;
1643 	}
1644 
1645 	plat_info = tpmi_get_platform_data(auxdev);
1646 	if (!plat_info) {
1647 		dev_err(dev, "No platform info\n");
1648 		return -EINVAL;
1649 	}
1650 
1651 	pkg = plat_info->package_id;
1652 	if (pkg >= topology_max_packages()) {
1653 		dev_err(dev, "Invalid package id :%x\n", pkg);
1654 		return -EINVAL;
1655 	}
1656 
1657 	partition = plat_info->partition;
1658 	if (partition >= SST_MAX_PARTITIONS) {
1659 		dev_err(&auxdev->dev, "Invalid partition :%x\n", partition);
1660 		return -EINVAL;
1661 	}
1662 
1663 	num_resources = tpmi_get_resource_count(auxdev);
1664 
1665 	if (!num_resources)
1666 		return -EINVAL;
1667 
1668 	mutex_lock(&isst_tpmi_dev_lock);
1669 
1670 	if (isst_common.sst_inst[pkg]) {
1671 		tpmi_sst = isst_common.sst_inst[pkg];
1672 	} else {
1673 		/*
1674 		 * tpmi_sst instance is for a package. So needs to be
1675 		 * allocated only once for both partitions. We can't use
1676 		 * devm_* allocation here as each partition is a
1677 		 * different device, which can be unbound.
1678 		 */
1679 		tpmi_sst = kzalloc_obj(*tpmi_sst);
1680 		if (!tpmi_sst) {
1681 			ret = -ENOMEM;
1682 			goto unlock_exit;
1683 		}
1684 		first_enum = true;
1685 	}
1686 
1687 	ret = 0;
1688 
1689 	pd_info = devm_kcalloc(dev, num_resources, sizeof(*pd_info), GFP_KERNEL);
1690 	if (!pd_info) {
1691 		ret = -ENOMEM;
1692 		goto unlock_free;
1693 	}
1694 
1695 	/* Get the IO die count, if cdie_mask is present */
1696 	if (plat_info->cdie_mask) {
1697 		u8 cdie_range;
1698 
1699 		cdie_mask = plat_info->cdie_mask;
1700 		cdie_range = fls(cdie_mask) - ffs(cdie_mask) + 1;
1701 		io_die_cnt = num_resources - cdie_range;
1702 	} else {
1703 		/*
1704 		 * This is a synthetic mask, careful when assuming that
1705 		 * they are compute dies only.
1706 		 */
1707 		cdie_mask = (1 << num_resources) - 1;
1708 		io_die_cnt = 0;
1709 	}
1710 
1711 	for (i = 0; i < num_resources; ++i) {
1712 		struct resource *res;
1713 
1714 		res = tpmi_get_resource_at_index(auxdev, i);
1715 		if (!res) {
1716 			pd_info[i].sst_base = NULL;
1717 			continue;
1718 		}
1719 
1720 		pd_info[i].package_id = pkg;
1721 		pd_info[i].power_domain_id = i;
1722 		pd_info[i].auxdev = auxdev;
1723 		pd_info[i].write_blocked = write_blocked;
1724 		pd_info[i].sst_base = devm_ioremap_resource(dev, res);
1725 		if (IS_ERR(pd_info[i].sst_base)) {
1726 			ret = PTR_ERR(pd_info[i].sst_base);
1727 			goto unlock_free;
1728 		}
1729 
1730 		if (sst_main(auxdev, &pd_info[i])) {
1731 			/*
1732 			 * This entry is not valid, hardware can partially
1733 			 * populate dies. In this case MMIO will have 0xFFs.
1734 			 * Also possible some pre-production hardware has
1735 			 * invalid data. But don't fail and continue to use
1736 			 * other dies with valid data.
1737 			 */
1738 			devm_iounmap(dev, pd_info[i].sst_base);
1739 			pd_info[i].sst_base = NULL;
1740 			continue;
1741 		}
1742 
1743 		++inst;
1744 	}
1745 
1746 	if (!inst) {
1747 		ret = -ENODEV;
1748 		goto unlock_free;
1749 	}
1750 
1751 	tpmi_sst->package_id = pkg;
1752 
1753 	tpmi_sst->power_domain_info[partition] = pd_info;
1754 	tpmi_sst->number_of_power_domains[partition] = num_resources;
1755 	tpmi_sst->cdie_mask[partition] = cdie_mask;
1756 	tpmi_sst->io_dies[partition] = io_die_cnt;
1757 	tpmi_sst->partition_mask |= BIT(partition);
1758 	tpmi_sst->partition_mask_current |= BIT(partition);
1759 
1760 	auxiliary_set_drvdata(auxdev, tpmi_sst);
1761 
1762 	if (isst_common.max_index < pkg)
1763 		isst_common.max_index = pkg;
1764 	isst_common.sst_inst[pkg] = tpmi_sst;
1765 
1766 unlock_free:
1767 	if (ret && first_enum)
1768 		kfree(tpmi_sst);
1769 unlock_exit:
1770 	mutex_unlock(&isst_tpmi_dev_lock);
1771 
1772 	return ret;
1773 }
1774 EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_add, "INTEL_TPMI_SST");
1775 
tpmi_sst_dev_remove(struct auxiliary_device * auxdev)1776 void tpmi_sst_dev_remove(struct auxiliary_device *auxdev)
1777 {
1778 	struct tpmi_sst_struct *tpmi_sst = auxiliary_get_drvdata(auxdev);
1779 	struct oobmsm_plat_info *plat_info;
1780 
1781 	plat_info = tpmi_get_platform_data(auxdev);
1782 	if (!plat_info)
1783 		return;
1784 
1785 	mutex_lock(&isst_tpmi_dev_lock);
1786 	tpmi_sst->power_domain_info[plat_info->partition] = NULL;
1787 	tpmi_sst->partition_mask_current &= ~BIT(plat_info->partition);
1788 	/* Free the package instance when the all partitions are removed */
1789 	if (!tpmi_sst->partition_mask_current) {
1790 		isst_common.sst_inst[tpmi_sst->package_id] = NULL;
1791 		kfree(tpmi_sst);
1792 	}
1793 	mutex_unlock(&isst_tpmi_dev_lock);
1794 }
1795 EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_remove, "INTEL_TPMI_SST");
1796 
1797 #define SST_PP_CAP_CP_ENABLE	BIT(0)
1798 #define SST_PP_CAP_PP_ENABLE	BIT(1)
1799 
tpmi_sst_dev_suspend(struct auxiliary_device * auxdev)1800 void tpmi_sst_dev_suspend(struct auxiliary_device *auxdev)
1801 {
1802 	struct tpmi_sst_struct *tpmi_sst = auxiliary_get_drvdata(auxdev);
1803 	struct tpmi_per_power_domain_info *power_domain_info, *pd_info;
1804 	struct oobmsm_plat_info *plat_info;
1805 	void __iomem *cp_base;
1806 	int num_resources, i;
1807 
1808 	plat_info = tpmi_get_platform_data(auxdev);
1809 	if (!plat_info)
1810 		return;
1811 
1812 	power_domain_info = tpmi_sst->power_domain_info[plat_info->partition];
1813 	num_resources = tpmi_sst->number_of_power_domains[plat_info->partition];
1814 
1815 	for (i = 0; i < num_resources; i++) {
1816 		pd_info = &power_domain_info[i];
1817 		if (!pd_info || !pd_info->sst_base)
1818 			continue;
1819 
1820 		if (!(pd_info->sst_header.cap_mask & SST_PP_CAP_CP_ENABLE))
1821 			goto process_pp_suspend;
1822 
1823 		cp_base = pd_info->sst_base + pd_info->sst_header.cp_offset;
1824 		pd_info->saved_sst_cp_control = readq(cp_base + SST_CP_CONTROL_OFFSET);
1825 		memcpy_fromio(pd_info->saved_clos_configs, cp_base + SST_CLOS_CONFIG_0_OFFSET,
1826 			      sizeof(pd_info->saved_clos_configs));
1827 		memcpy_fromio(pd_info->saved_clos_assocs, cp_base + SST_CLOS_ASSOC_0_OFFSET,
1828 			      sizeof(pd_info->saved_clos_assocs));
1829 
1830 process_pp_suspend:
1831 		if (!(pd_info->sst_header.cap_mask & SST_PP_CAP_PP_ENABLE))
1832 			continue;
1833 
1834 		pd_info->saved_pp_control = readq(pd_info->sst_base +
1835 						  pd_info->sst_header.pp_offset +
1836 						  SST_PP_CONTROL_OFFSET);
1837 	}
1838 }
1839 EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_suspend, "INTEL_TPMI_SST");
1840 
tpmi_sst_dev_resume(struct auxiliary_device * auxdev)1841 void tpmi_sst_dev_resume(struct auxiliary_device *auxdev)
1842 {
1843 	struct tpmi_sst_struct *tpmi_sst = auxiliary_get_drvdata(auxdev);
1844 	struct tpmi_per_power_domain_info *power_domain_info, *pd_info;
1845 	struct oobmsm_plat_info *plat_info;
1846 	void __iomem *cp_base;
1847 	int num_resources, i;
1848 
1849 	plat_info = tpmi_get_platform_data(auxdev);
1850 	if (!plat_info)
1851 		return;
1852 
1853 	power_domain_info = tpmi_sst->power_domain_info[plat_info->partition];
1854 	num_resources = tpmi_sst->number_of_power_domains[plat_info->partition];
1855 
1856 	for (i = 0; i < num_resources; i++) {
1857 		pd_info = &power_domain_info[i];
1858 		if (!pd_info || !pd_info->sst_base)
1859 			continue;
1860 
1861 		if (!(pd_info->sst_header.cap_mask & SST_PP_CAP_CP_ENABLE))
1862 			goto process_pp_resume;
1863 
1864 		cp_base = pd_info->sst_base + pd_info->sst_header.cp_offset;
1865 		writeq(pd_info->saved_sst_cp_control, cp_base + SST_CP_CONTROL_OFFSET);
1866 		memcpy_toio(cp_base + SST_CLOS_CONFIG_0_OFFSET, pd_info->saved_clos_configs,
1867 			    sizeof(pd_info->saved_clos_configs));
1868 		memcpy_toio(cp_base + SST_CLOS_ASSOC_0_OFFSET, pd_info->saved_clos_assocs,
1869 			    sizeof(pd_info->saved_clos_assocs));
1870 
1871 process_pp_resume:
1872 		if (!(pd_info->sst_header.cap_mask & SST_PP_CAP_PP_ENABLE))
1873 			continue;
1874 
1875 		writeq(pd_info->saved_pp_control, pd_info->sst_base +
1876 		       pd_info->sst_header.pp_offset + SST_PP_CONTROL_OFFSET);
1877 	}
1878 }
1879 EXPORT_SYMBOL_NS_GPL(tpmi_sst_dev_resume, "INTEL_TPMI_SST");
1880 
1881 #define ISST_TPMI_API_VERSION	0x03
1882 
tpmi_sst_init(void)1883 int tpmi_sst_init(void)
1884 {
1885 	struct isst_if_cmd_cb cb;
1886 	int ret = 0;
1887 
1888 	mutex_lock(&isst_tpmi_dev_lock);
1889 
1890 	if (isst_core_usage_count) {
1891 		++isst_core_usage_count;
1892 		goto init_done;
1893 	}
1894 
1895 	isst_common.sst_inst = kzalloc_objs(*isst_common.sst_inst,
1896 					    topology_max_packages());
1897 	if (!isst_common.sst_inst) {
1898 		ret = -ENOMEM;
1899 		goto init_done;
1900 	}
1901 
1902 	memset(&cb, 0, sizeof(cb));
1903 	cb.cmd_size = sizeof(struct isst_if_io_reg);
1904 	cb.offset = offsetof(struct isst_if_io_regs, io_reg);
1905 	cb.cmd_callback = NULL;
1906 	cb.api_version = ISST_TPMI_API_VERSION;
1907 	cb.def_ioctl = isst_if_def_ioctl;
1908 	cb.owner = THIS_MODULE;
1909 	ret = isst_if_cdev_register(ISST_IF_DEV_TPMI, &cb);
1910 	if (ret)
1911 		kfree(isst_common.sst_inst);
1912 	else
1913 		++isst_core_usage_count;
1914 init_done:
1915 	mutex_unlock(&isst_tpmi_dev_lock);
1916 	return ret;
1917 }
1918 EXPORT_SYMBOL_NS_GPL(tpmi_sst_init, "INTEL_TPMI_SST");
1919 
tpmi_sst_exit(void)1920 void tpmi_sst_exit(void)
1921 {
1922 	mutex_lock(&isst_tpmi_dev_lock);
1923 	if (isst_core_usage_count)
1924 		--isst_core_usage_count;
1925 
1926 	if (!isst_core_usage_count) {
1927 		isst_if_cdev_unregister(ISST_IF_DEV_TPMI);
1928 		kfree(isst_common.sst_inst);
1929 	}
1930 	mutex_unlock(&isst_tpmi_dev_lock);
1931 }
1932 EXPORT_SYMBOL_NS_GPL(tpmi_sst_exit, "INTEL_TPMI_SST");
1933 
1934 MODULE_IMPORT_NS("INTEL_TPMI");
1935 MODULE_IMPORT_NS("INTEL_TPMI_POWER_DOMAIN");
1936 
1937 MODULE_DESCRIPTION("ISST TPMI interface module");
1938 MODULE_LICENSE("GPL");
1939