#define CPUID_WR_DATA_LEN 0x8
#define CPUID_RD_REG_LEN 0xa
#define CPUID_WR_REG_LEN 0x9
+/* MSR */
+#define MSR_RD_REG_LEN 0xa
+#define MSR_WR_REG_LEN 0x8
+#define MSR_RD_DATA_LEN 0x8
+#define MSR_WR_DATA_LEN 0x7
/* CPUID MSR Command Ids */
#define CPUID_MCA_CMD 0x73
#define RD_CPUID_CMD 0x91
+#define RD_MCA_CMD 0x86
/* CPUID MCAMSR mask & index */
#define CPUID_MCA_THRD_MASK GENMASK(15, 0)
input->ext = ext_func;
}
+static inline void prepare_mca_msr_input_message(struct cpu_msr_indata *input,
+ u8 thread_id, u32 data_in)
+{
+ input->rd_len = MSR_RD_DATA_LEN;
+ input->wr_len = MSR_WR_DATA_LEN;
+ input->proto_cmd = RD_MCA_CMD;
+ input->thread = thread_id << 1;
+ input->value = data_in;
+}
+
static int sbrmi_get_rev(struct sbrmi_data *data)
{
unsigned int rev;
return ret;
}
+/* MCA MSR protocol */
+static int rmi_mca_msr_read(struct sbrmi_data *data,
+ struct apml_mcamsr_msg *msg)
+{
+ struct cpu_msr_outdata output = {0};
+ struct cpu_msr_indata input = {0};
+ int ret, val = 0;
+ int hw_status;
+ u16 thread;
+
+ mutex_lock(&data->lock);
+ /* cache the rev value to identify if protocol is supported or not */
+ if (!data->rev) {
+ ret = sbrmi_get_rev(data);
+ if (ret < 0)
+ goto exit_unlock;
+ }
+ /* MCA MSR protocol for REV 0x10 is not supported*/
+ if (data->rev == 0x10) {
+ ret = -EOPNOTSUPP;
+ goto exit_unlock;
+ }
+
+ thread = msg->mcamsr_in_out << CPUID_MCA_THRD_INDEX & CPUID_MCA_THRD_MASK;
+
+ /* Thread > 127, Thread128 CS register, 1'b1 needs to be set to 1 */
+ if (thread > 127) {
+ thread -= 128;
+ val = 1;
+ }
+ ret = regmap_write(data->regmap, SBRMI_THREAD128CS, val);
+ if (ret < 0)
+ goto exit_unlock;
+
+ prepare_mca_msr_input_message(&input, thread,
+ msg->mcamsr_in_out & CPUID_MCA_FUNC_MASK);
+
+ ret = regmap_bulk_write(data->regmap, CPUID_MCA_CMD,
+ &input, MSR_WR_REG_LEN);
+ if (ret < 0)
+ goto exit_unlock;
+
+ /*
+ * For RMI Rev 0x20, new h/w status bit is introduced. which is used
+ * by firmware to indicate completion of commands (0x71, 0x72, 0x73).
+ * wait for the status bit to be set by the hardware before
+ * reading the data out.
+ */
+ ret = regmap_read_poll_timeout(data->regmap, SBRMI_STATUS, hw_status,
+ hw_status & HW_ALERT_MASK, 500, 2000000);
+ if (ret)
+ goto exit_unlock;
+
+ ret = regmap_bulk_read(data->regmap, CPUID_MCA_CMD,
+ &output, MSR_RD_REG_LEN);
+ if (ret < 0)
+ goto exit_unlock;
+
+ ret = regmap_write(data->regmap, SBRMI_STATUS,
+ HW_ALERT_MASK);
+ if (ret < 0)
+ goto exit_unlock;
+
+ if (output.num_bytes != MSR_RD_REG_LEN - 1) {
+ ret = -EMSGSIZE;
+ goto exit_unlock;
+ }
+ if (output.status) {
+ ret = -EPROTOTYPE;
+ msg->fw_ret_code = output.status;
+ goto exit_unlock;
+ }
+ msg->mcamsr_in_out = output.value;
+
+exit_unlock:
+ mutex_unlock(&data->lock);
+ return ret;
+}
+
int rmi_mailbox_xfer(struct sbrmi_data *data,
struct apml_mbox_msg *msg)
{
return copy_to_user(arg, &msg, sizeof(struct apml_cpuid_msg));
}
+static int apml_mcamsr_xfer(struct sbrmi_data *data, struct apml_mcamsr_msg __user *arg)
+{
+ struct apml_mcamsr_msg msg = { 0 };
+ int ret;
+
+ /* Copy the structure from user */
+ if (copy_from_user(&msg, arg, sizeof(struct apml_mcamsr_msg)))
+ return -EFAULT;
+
+ /* MCAMSR Protocol */
+ ret = rmi_mca_msr_read(data, &msg);
+ if (ret && ret != -EPROTOTYPE)
+ return ret;
+
+ return copy_to_user(arg, &msg, sizeof(struct apml_mcamsr_msg));
+}
+
static long sbrmi_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
{
void __user *argp = (void __user *)arg;
return apml_mailbox_xfer(data, argp);
case SBRMI_IOCTL_CPUID_CMD:
return apml_cpuid_xfer(data, argp);
+ case SBRMI_IOCTL_MCAMSR_CMD:
+ return apml_mcamsr_xfer(data, argp);
default:
return -ENOTTY;
}
__u32 pad;
};
+struct apml_mcamsr_msg {
+ /*
+ * MCAMSR input
+ * [0]...[3] mca msr func,
+ * [4][5] thread
+ * MCAMSR output
+ */
+ __u64 mcamsr_in_out;
+ /*
+ * Status code for MCA/MSR access
+ */
+ __u32 fw_ret_code;
+ __u32 pad;
+};
+
/*
* AMD sideband interface base IOCTL
*/
*/
#define SBRMI_IOCTL_CPUID_CMD _IOWR(SB_BASE_IOCTL_NR, 1, struct apml_cpuid_msg)
+/**
+ * DOC: SBRMI_IOCTL_MCAMSR_CMD
+ *
+ * @Parameters
+ *
+ * @struct apml_mcamsr_msg
+ * Pointer to the &struct apml_mcamsr_msg that will contain the protocol
+ * information
+ *
+ * @Description
+ * IOCTL command for APML messages using generic _IOWR
+ * The IOCTL provides userspace access to AMD sideband MCAMSR protocol
+ * - MCAMSR protocol to get MCA bank details for Function at thread level
+ * - returning "-EFAULT" if none of the above
+ * "-EPROTOTYPE" error is returned to provide additional error details
+ */
+#define SBRMI_IOCTL_MCAMSR_CMD _IOWR(SB_BASE_IOCTL_NR, 2, struct apml_mcamsr_msg)
+
#endif /*_AMD_APML_H_*/