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

misc: amd-sbi: Add support for CPUID protocol

- AMD provides custom protocol to read Processor feature
capabilities and configuration information through side band.
The information is accessed by providing CPUID Function,
extended function and thread ID to the protocol.
Undefined function returns 0.

Reviewed-by: Naveen Krishna Chatradhi <naveenkrishna.chatradhi@amd.com>
Signed-off-by: Akshay Gupta <akshay.gupta@amd.com>
Link: https://lore.kernel.org/r/20250428063034.2145566-8-akshay.gupta@amd.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Akshay Gupta and committed by
Greg Kroah-Hartman
bb13a84e 35ac2034

+209 -1
+168
drivers/misc/amd-sbi/rmi-core.c
··· 17 17 18 18 /* Mask for Status Register bit[1] */ 19 19 #define SW_ALERT_MASK 0x2 20 + /* Mask to check H/W Alert status bit */ 21 + #define HW_ALERT_MASK 0x80 20 22 21 23 /* Software Interrupt for triggering */ 22 24 #define START_CMD 0x80 23 25 #define TRIGGER_MAILBOX 0x01 26 + 27 + /* Default message lengths as per APML command protocol */ 28 + /* CPUID */ 29 + #define CPUID_RD_DATA_LEN 0x8 30 + #define CPUID_WR_DATA_LEN 0x8 31 + #define CPUID_RD_REG_LEN 0xa 32 + #define CPUID_WR_REG_LEN 0x9 33 + 34 + /* CPUID MSR Command Ids */ 35 + #define CPUID_MCA_CMD 0x73 36 + #define RD_CPUID_CMD 0x91 37 + 38 + /* CPUID MCAMSR mask & index */ 39 + #define CPUID_MCA_THRD_MASK GENMASK(15, 0) 40 + #define CPUID_MCA_THRD_INDEX 32 41 + #define CPUID_MCA_FUNC_MASK GENMASK(31, 0) 42 + #define CPUID_EXT_FUNC_INDEX 56 43 + 44 + /* input for bulk write to CPUID protocol */ 45 + struct cpu_msr_indata { 46 + u8 wr_len; /* const value */ 47 + u8 rd_len; /* const value */ 48 + u8 proto_cmd; /* const value */ 49 + u8 thread; /* thread number */ 50 + union { 51 + u8 reg_offset[4]; /* input value */ 52 + u32 value; 53 + } __packed; 54 + u8 ext; /* extended function */ 55 + }; 56 + 57 + /* output for bulk read from CPUID protocol */ 58 + struct cpu_msr_outdata { 59 + u8 num_bytes; /* number of bytes return */ 60 + u8 status; /* Protocol status code */ 61 + union { 62 + u64 value; 63 + u8 reg_data[8]; 64 + } __packed; 65 + }; 66 + 67 + static inline void prepare_cpuid_input_message(struct cpu_msr_indata *input, 68 + u8 thread_id, u32 func, 69 + u8 ext_func) 70 + { 71 + input->rd_len = CPUID_RD_DATA_LEN; 72 + input->wr_len = CPUID_WR_DATA_LEN; 73 + input->proto_cmd = RD_CPUID_CMD; 74 + input->thread = thread_id << 1; 75 + input->value = func; 76 + input->ext = ext_func; 77 + } 78 + 79 + static int sbrmi_get_rev(struct sbrmi_data *data) 80 + { 81 + unsigned int rev; 82 + u16 offset = SBRMI_REV; 83 + int ret; 84 + 85 + ret = regmap_read(data->regmap, offset, &rev); 86 + if (ret < 0) 87 + return ret; 88 + 89 + data->rev = rev; 90 + return 0; 91 + } 92 + 93 + /* Read CPUID function protocol */ 94 + static int rmi_cpuid_read(struct sbrmi_data *data, 95 + struct apml_cpuid_msg *msg) 96 + { 97 + struct cpu_msr_indata input = {0}; 98 + struct cpu_msr_outdata output = {0}; 99 + int val = 0; 100 + int ret, hw_status; 101 + u16 thread; 102 + 103 + mutex_lock(&data->lock); 104 + /* cache the rev value to identify if protocol is supported or not */ 105 + if (!data->rev) { 106 + ret = sbrmi_get_rev(data); 107 + if (ret < 0) 108 + goto exit_unlock; 109 + } 110 + /* CPUID protocol for REV 0x10 is not supported*/ 111 + if (data->rev == 0x10) { 112 + ret = -EOPNOTSUPP; 113 + goto exit_unlock; 114 + } 115 + 116 + thread = msg->cpu_in_out << CPUID_MCA_THRD_INDEX & CPUID_MCA_THRD_MASK; 117 + 118 + /* Thread > 127, Thread128 CS register, 1'b1 needs to be set to 1 */ 119 + if (thread > 127) { 120 + thread -= 128; 121 + val = 1; 122 + } 123 + ret = regmap_write(data->regmap, SBRMI_THREAD128CS, val); 124 + if (ret < 0) 125 + goto exit_unlock; 126 + 127 + prepare_cpuid_input_message(&input, thread, 128 + msg->cpu_in_out & CPUID_MCA_FUNC_MASK, 129 + msg->cpu_in_out >> CPUID_EXT_FUNC_INDEX); 130 + 131 + ret = regmap_bulk_write(data->regmap, CPUID_MCA_CMD, 132 + &input, CPUID_WR_REG_LEN); 133 + if (ret < 0) 134 + goto exit_unlock; 135 + 136 + /* 137 + * For RMI Rev 0x20, new h/w status bit is introduced. which is used 138 + * by firmware to indicate completion of commands (0x71, 0x72, 0x73). 139 + * wait for the status bit to be set by the hardware before 140 + * reading the data out. 141 + */ 142 + ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, hw_status, 143 + hw_status & HW_ALERT_MASK, 500, 2000000); 144 + if (ret) 145 + goto exit_unlock; 146 + 147 + ret = regmap_bulk_read(data->regmap, CPUID_MCA_CMD, 148 + &output, CPUID_RD_REG_LEN); 149 + if (ret < 0) 150 + goto exit_unlock; 151 + 152 + ret = regmap_write(data->regmap, SBRMI_STATUS, 153 + HW_ALERT_MASK); 154 + if (ret < 0) 155 + goto exit_unlock; 156 + 157 + if (output.num_bytes != CPUID_RD_REG_LEN - 1) { 158 + ret = -EMSGSIZE; 159 + goto exit_unlock; 160 + } 161 + if (output.status) { 162 + ret = -EPROTOTYPE; 163 + msg->fw_ret_code = output.status; 164 + goto exit_unlock; 165 + } 166 + msg->cpu_in_out = output.value; 167 + exit_unlock: 168 + if (ret < 0) 169 + msg->cpu_in_out = 0; 170 + mutex_unlock(&data->lock); 171 + return ret; 172 + } 24 173 25 174 int rmi_mailbox_xfer(struct sbrmi_data *data, 26 175 struct apml_mbox_msg *msg) ··· 272 123 return copy_to_user(arg, &msg, sizeof(struct apml_mbox_msg)); 273 124 } 274 125 126 + static int apml_cpuid_xfer(struct sbrmi_data *data, struct apml_cpuid_msg __user *arg) 127 + { 128 + struct apml_cpuid_msg msg = { 0 }; 129 + int ret; 130 + 131 + /* Copy the structure from user */ 132 + if (copy_from_user(&msg, arg, sizeof(struct apml_cpuid_msg))) 133 + return -EFAULT; 134 + 135 + /* CPUID Protocol */ 136 + ret = rmi_cpuid_read(data, &msg); 137 + if (ret && ret != -EPROTOTYPE) 138 + return ret; 139 + 140 + return copy_to_user(arg, &msg, sizeof(struct apml_cpuid_msg)); 141 + } 142 + 275 143 static long sbrmi_ioctl(struct file *fp, unsigned int cmd, unsigned long arg) 276 144 { 277 145 void __user *argp = (void __user *)arg; ··· 298 132 switch (cmd) { 299 133 case SBRMI_IOCTL_MBOX_CMD: 300 134 return apml_mailbox_xfer(data, argp); 135 + case SBRMI_IOCTL_CPUID_CMD: 136 + return apml_cpuid_xfer(data, argp); 301 137 default: 302 138 return -ENOTTY; 303 139 }
+4 -1
drivers/misc/amd-sbi/rmi-core.h
··· 15 15 16 16 /* SB-RMI registers */ 17 17 enum sbrmi_reg { 18 - SBRMI_CTRL = 0x01, 18 + SBRMI_REV, 19 + SBRMI_CTRL, 19 20 SBRMI_STATUS, 20 21 SBRMI_OUTBNDMSG0 = 0x30, 21 22 SBRMI_OUTBNDMSG1, ··· 35 34 SBRMI_INBNDMSG6, 36 35 SBRMI_INBNDMSG7, 37 36 SBRMI_SW_INTERRUPT, 37 + SBRMI_THREAD128CS = 0x4b, 38 38 }; 39 39 40 40 /* ··· 58 56 struct mutex lock; 59 57 u32 pwr_limit_max; 60 58 u8 dev_static_addr; 59 + u8 rev; 61 60 }; 62 61 63 62 int rmi_mailbox_xfer(struct sbrmi_data *data, struct apml_mbox_msg *msg);
+37
include/uapi/misc/amd-apml.h
··· 25 25 __u32 fw_ret_code; 26 26 }; 27 27 28 + struct apml_cpuid_msg { 29 + /* 30 + * CPUID input 31 + * [0]...[3] cpuid func, 32 + * [4][5] cpuid: thread 33 + * [6] cpuid: ext function & read eax/ebx or ecx/edx 34 + * [7:0] -> bits [7:4] -> ext function & 35 + * bit [0] read eax/ebx or ecx/edx 36 + * CPUID output 37 + */ 38 + __u64 cpu_in_out; 39 + /* 40 + * Status code for CPUID read 41 + */ 42 + __u32 fw_ret_code; 43 + __u32 pad; 44 + }; 45 + 28 46 /* 29 47 * AMD sideband interface base IOCTL 30 48 */ ··· 65 47 * "-EPROTOTYPE" error is returned to provide additional error details 66 48 */ 67 49 #define SBRMI_IOCTL_MBOX_CMD _IOWR(SB_BASE_IOCTL_NR, 0, struct apml_mbox_msg) 50 + 51 + /** 52 + * DOC: SBRMI_IOCTL_CPUID_CMD 53 + * 54 + * @Parameters 55 + * 56 + * @struct apml_cpuid_msg 57 + * Pointer to the &struct apml_cpuid_msg that will contain the protocol 58 + * information 59 + * 60 + * @Description 61 + * IOCTL command for APML messages using generic _IOWR 62 + * The IOCTL provides userspace access to AMD sideband cpuid protocol 63 + * - CPUID protocol to get CPU details for Function/Ext Function 64 + * at thread level 65 + * - returning "-EFAULT" if none of the above 66 + * "-EPROTOTYPE" error is returned to provide additional error details 67 + */ 68 + #define SBRMI_IOCTL_CPUID_CMD _IOWR(SB_BASE_IOCTL_NR, 1, struct apml_cpuid_msg) 68 69 69 70 #endif /*_AMD_APML_H_*/