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