Skip to content

Commit bb13a84

Browse files
akky16gregkh
authored andcommitted
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 <[email protected]> Signed-off-by: Akshay Gupta <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 35ac203 commit bb13a84

File tree

3 files changed

+209
-1
lines changed

3 files changed

+209
-1
lines changed

drivers/misc/amd-sbi/rmi-core.c

Lines changed: 168 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,11 +17,160 @@
1717

1818
/* Mask for Status Register bit[1] */
1919
#define SW_ALERT_MASK 0x2
20+
/* Mask to check H/W Alert status bit */
21+
#define HW_ALERT_MASK 0x80
2022

2123
/* Software Interrupt for triggering */
2224
#define START_CMD 0x80
2325
#define TRIGGER_MAILBOX 0x01
2426

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+
}
173+
25174
int rmi_mailbox_xfer(struct sbrmi_data *data,
26175
struct apml_mbox_msg *msg)
27176
{
@@ -123,6 +272,23 @@ static int apml_mailbox_xfer(struct sbrmi_data *data, struct apml_mbox_msg __use
123272
return copy_to_user(arg, &msg, sizeof(struct apml_mbox_msg));
124273
}
125274

275+
static int apml_cpuid_xfer(struct sbrmi_data *data, struct apml_cpuid_msg __user *arg)
276+
{
277+
struct apml_cpuid_msg msg = { 0 };
278+
int ret;
279+
280+
/* Copy the structure from user */
281+
if (copy_from_user(&msg, arg, sizeof(struct apml_cpuid_msg)))
282+
return -EFAULT;
283+
284+
/* CPUID Protocol */
285+
ret = rmi_cpuid_read(data, &msg);
286+
if (ret && ret != -EPROTOTYPE)
287+
return ret;
288+
289+
return copy_to_user(arg, &msg, sizeof(struct apml_cpuid_msg));
290+
}
291+
126292
static long sbrmi_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
127293
{
128294
void __user *argp = (void __user *)arg;
@@ -132,6 +298,8 @@ static long sbrmi_ioctl(struct file *fp, unsigned int cmd, unsigned long arg)
132298
switch (cmd) {
133299
case SBRMI_IOCTL_MBOX_CMD:
134300
return apml_mailbox_xfer(data, argp);
301+
case SBRMI_IOCTL_CPUID_CMD:
302+
return apml_cpuid_xfer(data, argp);
135303
default:
136304
return -ENOTTY;
137305
}

drivers/misc/amd-sbi/rmi-core.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,8 @@
1515

1616
/* SB-RMI registers */
1717
enum sbrmi_reg {
18-
SBRMI_CTRL = 0x01,
18+
SBRMI_REV,
19+
SBRMI_CTRL,
1920
SBRMI_STATUS,
2021
SBRMI_OUTBNDMSG0 = 0x30,
2122
SBRMI_OUTBNDMSG1,
@@ -34,6 +35,7 @@ enum sbrmi_reg {
3435
SBRMI_INBNDMSG6,
3536
SBRMI_INBNDMSG7,
3637
SBRMI_SW_INTERRUPT,
38+
SBRMI_THREAD128CS = 0x4b,
3739
};
3840

3941
/*
@@ -56,6 +58,7 @@ struct sbrmi_data {
5658
struct mutex lock;
5759
u32 pwr_limit_max;
5860
u8 dev_static_addr;
61+
u8 rev;
5962
};
6063

6164
int rmi_mailbox_xfer(struct sbrmi_data *data, struct apml_mbox_msg *msg);

include/uapi/misc/amd-apml.h

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,24 @@ struct apml_mbox_msg {
2525
__u32 fw_ret_code;
2626
};
2727

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+
2846
/*
2947
* AMD sideband interface base IOCTL
3048
*/
@@ -48,4 +66,23 @@ struct apml_mbox_msg {
4866
*/
4967
#define SBRMI_IOCTL_MBOX_CMD _IOWR(SB_BASE_IOCTL_NR, 0, struct apml_mbox_msg)
5068

69+
/**
70+
* DOC: SBRMI_IOCTL_CPUID_CMD
71+
*
72+
* @Parameters
73+
*
74+
* @struct apml_cpuid_msg
75+
* Pointer to the &struct apml_cpuid_msg that will contain the protocol
76+
* information
77+
*
78+
* @Description
79+
* IOCTL command for APML messages using generic _IOWR
80+
* The IOCTL provides userspace access to AMD sideband cpuid protocol
81+
* - CPUID protocol to get CPU details for Function/Ext Function
82+
* at thread level
83+
* - returning "-EFAULT" if none of the above
84+
* "-EPROTOTYPE" error is returned to provide additional error details
85+
*/
86+
#define SBRMI_IOCTL_CPUID_CMD _IOWR(SB_BASE_IOCTL_NR, 1, struct apml_cpuid_msg)
87+
5188
#endif /*_AMD_APML_H_*/

0 commit comments

Comments
 (0)