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

platform/x86/amd/hsmp: Add support for HSMP protocol version 7 messages

Following new HSMP messages are available on family 0x1A, model 0x00-0x1F
platforms with protocol version 7. Add support for them in the driver.
- SetXgmiPstateRange(26h)
- CpuRailIsoFreqPolicy(27h)
- DfcEnable(28h)
- GetRaplUnit(30h)
- GetRaplCoreCounter(31h)
- GetRaplPackageCounter(32h)

Also update HSMP message PwrEfficiencyModeSelection-21h. This message is
updated to include GET option in recent firmware.

Signed-off-by: Suma Hegde <suma.hegde@amd.com>
Reviewed-by: Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com>
Link: https://lore.kernel.org/r/20241118102752.11703-1-suma.hegde@amd.com
Reviewed-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>
Signed-off-by: Ilpo Järvinen <ilpo.jarvinen@linux.intel.com>

authored by

Suma Hegde and committed by
Ilpo Järvinen
836d0d71 0ffafd4a

+103 -8
+62 -2
arch/x86/include/uapi/asm/amd_hsmp.h
··· 50 50 HSMP_GET_METRIC_TABLE_VER, /* 23h Get metrics table version */ 51 51 HSMP_GET_METRIC_TABLE, /* 24h Get metrics table */ 52 52 HSMP_GET_METRIC_TABLE_DRAM_ADDR,/* 25h Get metrics table dram address */ 53 + HSMP_SET_XGMI_PSTATE_RANGE, /* 26h Set xGMI P-state range */ 54 + HSMP_CPU_RAIL_ISO_FREQ_POLICY, /* 27h Get/Set Cpu Iso frequency policy */ 55 + HSMP_DFC_ENABLE_CTRL, /* 28h Enable/Disable DF C-state */ 56 + HSMP_GET_RAPL_UNITS = 0x30, /* 30h Get scaling factor for energy */ 57 + HSMP_GET_RAPL_CORE_COUNTER, /* 31h Get core energy counter value */ 58 + HSMP_GET_RAPL_PACKAGE_COUNTER, /* 32h Get package energy counter value */ 53 59 HSMP_MSG_ID_MAX, 54 60 }; 55 61 ··· 71 65 HSMP_RSVD = -1, 72 66 HSMP_SET = 0, 73 67 HSMP_GET = 1, 68 + HSMP_SET_GET = 2, 74 69 }; 75 70 76 71 enum hsmp_proto_versions { ··· 79 72 HSMP_PROTO_VER3, 80 73 HSMP_PROTO_VER4, 81 74 HSMP_PROTO_VER5, 82 - HSMP_PROTO_VER6 75 + HSMP_PROTO_VER6, 76 + HSMP_PROTO_VER7 83 77 }; 84 78 85 79 struct hsmp_msg_desc { ··· 308 300 * HSMP_SET_POWER_MODE, num_args = 1, response_sz = 0 309 301 * input: args[0] = power efficiency mode[2:0] 310 302 */ 311 - {1, 0, HSMP_SET}, 303 + {1, 1, HSMP_SET_GET}, 312 304 313 305 /* 314 306 * HSMP_SET_PSTATE_MAX_MIN, num_args = 1, response_sz = 0 ··· 333 325 * output: args[1] = upper 32 bits of the address 334 326 */ 335 327 {0, 2, HSMP_GET}, 328 + 329 + /* 330 + * HSMP_SET_XGMI_PSTATE_RANGE, num_args = 1, response_sz = 0 331 + * input: args[0] = min xGMI p-state[15:8] + max xGMI p-state[7:0] 332 + */ 333 + {1, 0, HSMP_SET}, 334 + 335 + /* 336 + * HSMP_CPU_RAIL_ISO_FREQ_POLICY, num_args = 1, response_sz = 1 337 + * input: args[0] = set/get policy[31] + 338 + * disable/enable independent control[0] 339 + * output: args[0] = current policy[0] 340 + */ 341 + {1, 1, HSMP_SET_GET}, 342 + 343 + /* 344 + * HSMP_DFC_ENABLE_CTRL, num_args = 1, response_sz = 1 345 + * input: args[0] = set/get policy[31] + enable/disable DFC[0] 346 + * output: args[0] = current policy[0] 347 + */ 348 + {1, 1, HSMP_SET_GET}, 349 + 350 + /* RESERVED(0x29-0x2f) */ 351 + {0, 0, HSMP_RSVD}, 352 + {0, 0, HSMP_RSVD}, 353 + {0, 0, HSMP_RSVD}, 354 + {0, 0, HSMP_RSVD}, 355 + {0, 0, HSMP_RSVD}, 356 + {0, 0, HSMP_RSVD}, 357 + {0, 0, HSMP_RSVD}, 358 + 359 + /* 360 + * HSMP_GET_RAPL_UNITS, response_sz = 1 361 + * output: args[0] = tu value[19:16] + esu value[12:8] 362 + */ 363 + {0, 1, HSMP_GET}, 364 + 365 + /* 366 + * HSMP_GET_RAPL_CORE_COUNTER, num_args = 1, response_sz = 1 367 + * input: args[0] = apic id[15:0] 368 + * output: args[0] = lower 32 bits of energy 369 + * output: args[1] = upper 32 bits of energy 370 + */ 371 + {1, 2, HSMP_GET}, 372 + 373 + /* 374 + * HSMP_GET_RAPL_PACKAGE_COUNTER, num_args = 0, response_sz = 1 375 + * output: args[0] = lower 32 bits of energy 376 + * output: args[1] = upper 32 bits of energy 377 + */ 378 + {0, 2, HSMP_GET}, 379 + 336 380 }; 337 381 338 382 /* Metrics table (supported only with proto version 6) */
+41 -6
drivers/platform/x86/amd/hsmp/hsmp.c
··· 33 33 #define HSMP_WR true 34 34 #define HSMP_RD false 35 35 36 - #define DRIVER_VERSION "2.3" 36 + #define DRIVER_VERSION "2.4" 37 + 38 + /* 39 + * When same message numbers are used for both GET and SET operation, 40 + * bit:31 indicates whether its SET or GET operation. 41 + */ 42 + #define CHECK_GET_BIT BIT(31) 37 43 38 44 static struct hsmp_plat_device hsmp_pdev; 39 45 ··· 173 167 if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_RSVD) 174 168 return -ENOMSG; 175 169 176 - /* num_args and response_sz against the HSMP spec */ 177 - if (msg->num_args != hsmp_msg_desc_table[msg->msg_id].num_args || 178 - msg->response_sz != hsmp_msg_desc_table[msg->msg_id].response_sz) 170 + /* 171 + * num_args passed by user should match the num_args specified in 172 + * message description table. 173 + */ 174 + if (msg->num_args != hsmp_msg_desc_table[msg->msg_id].num_args) 179 175 return -EINVAL; 180 176 177 + /* 178 + * Some older HSMP SET messages are updated to add GET in the same message. 179 + * In these messages, GET returns the current value and SET also returns 180 + * the successfully set value. To support this GET and SET in same message 181 + * while maintaining backward compatibility for the HSMP users, 182 + * hsmp_msg_desc_table[] indicates only maximum allowed response_sz. 183 + */ 184 + if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_SET_GET) { 185 + if (msg->response_sz > hsmp_msg_desc_table[msg->msg_id].response_sz) 186 + return -EINVAL; 187 + } else { 188 + /* only HSMP_SET or HSMP_GET messages go through this strict check */ 189 + if (msg->response_sz != hsmp_msg_desc_table[msg->msg_id].response_sz) 190 + return -EINVAL; 191 + } 181 192 return 0; 182 193 } 183 194 ··· 262 239 } 263 240 EXPORT_SYMBOL_NS_GPL(hsmp_test, AMD_HSMP); 264 241 242 + static bool is_get_msg(struct hsmp_message *msg) 243 + { 244 + if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_GET) 245 + return true; 246 + 247 + if (hsmp_msg_desc_table[msg->msg_id].type == HSMP_SET_GET && 248 + (msg->args[0] & CHECK_GET_BIT)) 249 + return true; 250 + 251 + return false; 252 + } 253 + 265 254 long hsmp_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) 266 255 { 267 256 int __user *arguser = (int __user *)arg; ··· 296 261 * Device is opened in O_WRONLY mode 297 262 * Execute only set/configure commands 298 263 */ 299 - if (hsmp_msg_desc_table[msg.msg_id].type != HSMP_SET) 264 + if (is_get_msg(&msg)) 300 265 return -EPERM; 301 266 break; 302 267 case FMODE_READ: ··· 304 269 * Device is opened in O_RDONLY mode 305 270 * Execute only get/monitor commands 306 271 */ 307 - if (hsmp_msg_desc_table[msg.msg_id].type != HSMP_GET) 272 + if (!is_get_msg(&msg)) 308 273 return -EPERM; 309 274 break; 310 275 case FMODE_READ | FMODE_WRITE: