Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

platform/x86/intel/tpmi: Read feature control status

Some of the PM features can be locked or disabled. In that case, write
interface can be locked.

This status is read via a mailbox. There is one TPMI ID which provides
base address for interface and data register for mail box operation.
The mailbox operations is defined in the TPMI specification. Refer to
https://github.com/intel/tpmi_power_management/ for TPMI specifications.

An API is exposed to feature drivers to read feature control status.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
Reviewed-by: Andy Shevchenko <andriy.shevchenko@linux.intel.com>
Link: https://lore.kernel.org/r/20230712225950.171326-2-srinivas.pandruvada@linux.intel.com
Signed-off-by: Hans de Goede <hdegoede@redhat.com>

authored by

Srinivas Pandruvada and committed by
Hans de Goede
61457949 2dd074c4

+182
+180
drivers/platform/x86/intel/tpmi.c
··· 47 47 */ 48 48 49 49 #include <linux/auxiliary_bus.h> 50 + #include <linux/bitfield.h> 51 + #include <linux/delay.h> 50 52 #include <linux/intel_tpmi.h> 51 53 #include <linux/io.h> 54 + #include <linux/iopoll.h> 52 55 #include <linux/module.h> 53 56 #include <linux/pci.h> 57 + #include <linux/sizes.h> 54 58 55 59 #include "vsec.h" 56 60 ··· 102 98 * @feature_count: Number of TPMI of TPMI instances pointed by tpmi_features 103 99 * @pfs_start: Start of PFS offset for the TPMI instances in this device 104 100 * @plat_info: Stores platform info which can be used by the client drivers 101 + * @tpmi_control_mem: Memory mapped IO for getting control information 105 102 * 106 103 * Stores the information for all TPMI devices enumerated from a single PCI device. 107 104 */ ··· 112 107 int feature_count; 113 108 u64 pfs_start; 114 109 struct intel_tpmi_plat_info plat_info; 110 + void __iomem *tpmi_control_mem; 115 111 }; 116 112 117 113 /** ··· 145 139 TPMI_ID_PEM = 1, /* Power and Perf excursion Monitor */ 146 140 TPMI_ID_UNCORE = 2, /* Uncore Frequency Scaling */ 147 141 TPMI_ID_SST = 5, /* Speed Select Technology */ 142 + TPMI_CONTROL_ID = 0x80, /* Special ID for getting feature status */ 148 143 TPMI_INFO_ID = 0x81, /* Special ID for PCI BDF and Package ID information */ 149 144 }; 145 + 146 + /* 147 + * The size from hardware is in u32 units. This size is from a trusted hardware, 148 + * but better to verify for pre silicon platforms. Set size to 0, when invalid. 149 + */ 150 + #define TPMI_GET_SINGLE_ENTRY_SIZE(pfs) \ 151 + ({ \ 152 + pfs->pfs_header.entry_size > SZ_1K ? 0 : pfs->pfs_header.entry_size << 2; \ 153 + }) 150 154 151 155 /* Used during auxbus device creation */ 152 156 static DEFINE_IDA(intel_vsec_tpmi_ida); ··· 190 174 return NULL; 191 175 } 192 176 EXPORT_SYMBOL_NS_GPL(tpmi_get_resource_at_index, INTEL_TPMI); 177 + 178 + /* TPMI Control Interface */ 179 + 180 + #define TPMI_CONTROL_STATUS_OFFSET 0x00 181 + #define TPMI_COMMAND_OFFSET 0x08 182 + 183 + /* 184 + * Spec is calling for max 1 seconds to get ownership at the worst 185 + * case. Read at 10 ms timeouts and repeat up to 1 second. 186 + */ 187 + #define TPMI_CONTROL_TIMEOUT_US (10 * USEC_PER_MSEC) 188 + #define TPMI_CONTROL_TIMEOUT_MAX_US (1 * USEC_PER_SEC) 189 + 190 + #define TPMI_RB_TIMEOUT_US (10 * USEC_PER_MSEC) 191 + #define TPMI_RB_TIMEOUT_MAX_US USEC_PER_SEC 192 + 193 + /* TPMI Control status register defines */ 194 + 195 + #define TPMI_CONTROL_STATUS_RB BIT_ULL(0) 196 + 197 + #define TPMI_CONTROL_STATUS_OWNER GENMASK_ULL(5, 4) 198 + #define TPMI_OWNER_NONE 0 199 + #define TPMI_OWNER_IN_BAND 1 200 + 201 + #define TPMI_CONTROL_STATUS_CPL BIT_ULL(6) 202 + #define TPMI_CONTROL_STATUS_RESULT GENMASK_ULL(15, 8) 203 + #define TPMI_CONTROL_STATUS_LEN GENMASK_ULL(31, 16) 204 + 205 + #define TPMI_CMD_PKT_LEN 2 206 + #define TPMI_CMD_STATUS_SUCCESS 0x40 207 + 208 + /* TPMI command data registers */ 209 + #define TMPI_CONTROL_DATA_CMD GENMASK_ULL(7, 0) 210 + #define TMPI_CONTROL_DATA_VAL GENMASK_ULL(63, 32) 211 + #define TPMI_CONTROL_DATA_VAL_FEATURE GENMASK_ULL(48, 40) 212 + 213 + /* Command to send via control interface */ 214 + #define TPMI_CONTROL_GET_STATE_CMD 0x10 215 + 216 + #define TPMI_CONTROL_CMD_MASK GENMASK_ULL(48, 40) 217 + 218 + #define TPMI_CMD_LEN_MASK GENMASK_ULL(18, 16) 219 + 220 + #define TPMI_STATE_DISABLED BIT_ULL(0) 221 + #define TPMI_STATE_LOCKED BIT_ULL(31) 222 + 223 + /* Mutex to complete get feature status without interruption */ 224 + static DEFINE_MUTEX(tpmi_dev_lock); 225 + 226 + static int tpmi_wait_for_owner(struct intel_tpmi_info *tpmi_info, u8 owner) 227 + { 228 + u64 control; 229 + 230 + return readq_poll_timeout(tpmi_info->tpmi_control_mem + TPMI_CONTROL_STATUS_OFFSET, 231 + control, owner == FIELD_GET(TPMI_CONTROL_STATUS_OWNER, control), 232 + TPMI_CONTROL_TIMEOUT_US, TPMI_CONTROL_TIMEOUT_MAX_US); 233 + } 234 + 235 + static int tpmi_read_feature_status(struct intel_tpmi_info *tpmi_info, int feature_id, 236 + int *locked, int *disabled) 237 + { 238 + u64 control, data; 239 + int ret; 240 + 241 + if (!tpmi_info->tpmi_control_mem) 242 + return -EFAULT; 243 + 244 + mutex_lock(&tpmi_dev_lock); 245 + 246 + /* Wait for owner bit set to 0 (none) */ 247 + ret = tpmi_wait_for_owner(tpmi_info, TPMI_OWNER_NONE); 248 + if (ret) 249 + goto err_unlock; 250 + 251 + /* set command id to 0x10 for TPMI_GET_STATE */ 252 + data = FIELD_PREP(TMPI_CONTROL_DATA_CMD, TPMI_CONTROL_GET_STATE_CMD); 253 + 254 + /* 32 bits for DATA offset and +8 for feature_id field */ 255 + data |= FIELD_PREP(TPMI_CONTROL_DATA_VAL_FEATURE, feature_id); 256 + 257 + /* Write at command offset for qword access */ 258 + writeq(data, tpmi_info->tpmi_control_mem + TPMI_COMMAND_OFFSET); 259 + 260 + /* Wait for owner bit set to in-band */ 261 + ret = tpmi_wait_for_owner(tpmi_info, TPMI_OWNER_IN_BAND); 262 + if (ret) 263 + goto err_unlock; 264 + 265 + /* Set Run Busy and packet length of 2 dwords */ 266 + control = TPMI_CONTROL_STATUS_RB; 267 + control |= FIELD_PREP(TPMI_CONTROL_STATUS_LEN, TPMI_CMD_PKT_LEN); 268 + 269 + /* Write at status offset for qword access */ 270 + writeq(control, tpmi_info->tpmi_control_mem + TPMI_CONTROL_STATUS_OFFSET); 271 + 272 + /* Wait for Run Busy clear */ 273 + ret = readq_poll_timeout(tpmi_info->tpmi_control_mem + TPMI_CONTROL_STATUS_OFFSET, 274 + control, !(control & TPMI_CONTROL_STATUS_RB), 275 + TPMI_RB_TIMEOUT_US, TPMI_RB_TIMEOUT_MAX_US); 276 + if (ret) 277 + goto done_proc; 278 + 279 + control = FIELD_GET(TPMI_CONTROL_STATUS_RESULT, control); 280 + if (control != TPMI_CMD_STATUS_SUCCESS) { 281 + ret = -EBUSY; 282 + goto done_proc; 283 + } 284 + 285 + /* Response is ready */ 286 + data = readq(tpmi_info->tpmi_control_mem + TPMI_COMMAND_OFFSET); 287 + data = FIELD_GET(TMPI_CONTROL_DATA_VAL, data); 288 + 289 + *disabled = 0; 290 + *locked = 0; 291 + 292 + if (!(data & TPMI_STATE_DISABLED)) 293 + *disabled = 1; 294 + 295 + if (data & TPMI_STATE_LOCKED) 296 + *locked = 1; 297 + 298 + ret = 0; 299 + 300 + done_proc: 301 + /* Set CPL "completion" bit */ 302 + writeq(TPMI_CONTROL_STATUS_CPL, tpmi_info->tpmi_control_mem + TPMI_CONTROL_STATUS_OFFSET); 303 + 304 + err_unlock: 305 + mutex_unlock(&tpmi_dev_lock); 306 + 307 + return ret; 308 + } 309 + 310 + int tpmi_get_feature_status(struct auxiliary_device *auxdev, int feature_id, 311 + int *locked, int *disabled) 312 + { 313 + struct intel_vsec_device *intel_vsec_dev = dev_to_ivdev(auxdev->dev.parent); 314 + struct intel_tpmi_info *tpmi_info = auxiliary_get_drvdata(&intel_vsec_dev->auxdev); 315 + 316 + return tpmi_read_feature_status(tpmi_info, feature_id, locked, disabled); 317 + } 318 + EXPORT_SYMBOL_NS_GPL(tpmi_get_feature_status, INTEL_TPMI); 319 + 320 + static void tpmi_set_control_base(struct auxiliary_device *auxdev, 321 + struct intel_tpmi_info *tpmi_info, 322 + struct intel_tpmi_pm_feature *pfs) 323 + { 324 + void __iomem *mem; 325 + u32 size; 326 + 327 + size = TPMI_GET_SINGLE_ENTRY_SIZE(pfs); 328 + if (!size) 329 + return; 330 + 331 + mem = devm_ioremap(&auxdev->dev, pfs->vsec_offset, size); 332 + if (!mem) 333 + return; 334 + 335 + /* mem is pointing to TPMI CONTROL base */ 336 + tpmi_info->tpmi_control_mem = mem; 337 + } 193 338 194 339 static const char *intel_tpmi_name(enum intel_tpmi_id id) 195 340 { ··· 546 369 */ 547 370 if (pfs->pfs_header.tpmi_id == TPMI_INFO_ID) 548 371 tpmi_process_info(tpmi_info, pfs); 372 + 373 + if (pfs->pfs_header.tpmi_id == TPMI_CONTROL_ID) 374 + tpmi_set_control_base(auxdev, tpmi_info, pfs); 549 375 } 550 376 551 377 tpmi_info->pfs_start = pfs_start;
+2
include/linux/intel_tpmi.h
··· 27 27 struct resource *tpmi_get_resource_at_index(struct auxiliary_device *auxdev, int index); 28 28 int tpmi_get_resource_count(struct auxiliary_device *auxdev); 29 29 30 + int tpmi_get_feature_status(struct auxiliary_device *auxdev, int feature_id, int *locked, 31 + int *disabled); 30 32 #endif