1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * Intel Speed Select Interface: Mbox via MSR Interface
4 * Copyright (c) 2019, Intel Corporation.
5 * All rights reserved.
6 *
7 * Author: Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>
8 */
9
10 #include <linux/module.h>
11 #include <linux/cpuhotplug.h>
12 #include <linux/pci.h>
13 #include <linux/sched/signal.h>
14 #include <linux/slab.h>
15 #include <linux/suspend.h>
16 #include <linux/topology.h>
17 #include <linux/uaccess.h>
18 #include <uapi/linux/isst_if.h>
19 #include <asm/cpu_device_id.h>
20 #include <asm/intel-family.h>
21
22 #include "isst_if_common.h"
23
24 #define MSR_OS_MAILBOX_INTERFACE 0xB0
25 #define MSR_OS_MAILBOX_DATA 0xB1
26 #define MSR_OS_MAILBOX_BUSY_BIT 31
27
28 /*
29 * Based on experiments count is never more than 1, as the MSR overhead
30 * is enough to finish the command. So here this is the worst case number.
31 */
32 #define OS_MAILBOX_RETRY_COUNT 3
33
isst_if_send_mbox_cmd(u8 command,u8 sub_command,u32 parameter,u32 command_data,u32 * response_data)34 static int isst_if_send_mbox_cmd(u8 command, u8 sub_command, u32 parameter,
35 u32 command_data, u32 *response_data)
36 {
37 u32 retries;
38 u64 data;
39 int ret;
40
41 /* Poll for rb bit == 0 */
42 retries = OS_MAILBOX_RETRY_COUNT;
43 do {
44 rdmsrl(MSR_OS_MAILBOX_INTERFACE, data);
45 if (data & BIT_ULL(MSR_OS_MAILBOX_BUSY_BIT)) {
46 ret = -EBUSY;
47 continue;
48 }
49 ret = 0;
50 break;
51 } while (--retries);
52
53 if (ret)
54 return ret;
55
56 /* Write DATA register */
57 wrmsrl(MSR_OS_MAILBOX_DATA, command_data);
58
59 /* Write command register */
60 data = BIT_ULL(MSR_OS_MAILBOX_BUSY_BIT) |
61 (parameter & GENMASK_ULL(13, 0)) << 16 |
62 (sub_command << 8) |
63 command;
64 wrmsrl(MSR_OS_MAILBOX_INTERFACE, data);
65
66 /* Poll for rb bit == 0 */
67 retries = OS_MAILBOX_RETRY_COUNT;
68 do {
69 rdmsrl(MSR_OS_MAILBOX_INTERFACE, data);
70 if (data & BIT_ULL(MSR_OS_MAILBOX_BUSY_BIT)) {
71 ret = -EBUSY;
72 continue;
73 }
74
75 if (data & 0xff)
76 return -ENXIO;
77
78 if (response_data) {
79 rdmsrl(MSR_OS_MAILBOX_DATA, data);
80 *response_data = data;
81 }
82 ret = 0;
83 break;
84 } while (--retries);
85
86 return ret;
87 }
88
89 struct msrl_action {
90 int err;
91 struct isst_if_mbox_cmd *mbox_cmd;
92 };
93
94 /* revisit, smp_call_function_single should be enough for atomic mailbox! */
msrl_update_func(void * info)95 static void msrl_update_func(void *info)
96 {
97 struct msrl_action *act = info;
98
99 act->err = isst_if_send_mbox_cmd(act->mbox_cmd->command,
100 act->mbox_cmd->sub_command,
101 act->mbox_cmd->parameter,
102 act->mbox_cmd->req_data,
103 &act->mbox_cmd->resp_data);
104 }
105
isst_if_mbox_proc_cmd(u8 * cmd_ptr,int * write_only,int resume)106 static long isst_if_mbox_proc_cmd(u8 *cmd_ptr, int *write_only, int resume)
107 {
108 struct msrl_action action;
109 int ret;
110
111 action.mbox_cmd = (struct isst_if_mbox_cmd *)cmd_ptr;
112
113 if (isst_if_mbox_cmd_invalid(action.mbox_cmd))
114 return -EINVAL;
115
116 if (isst_if_mbox_cmd_set_req(action.mbox_cmd) &&
117 !capable(CAP_SYS_ADMIN))
118 return -EPERM;
119
120 /*
121 * To complete mailbox command, we need to access two MSRs.
122 * So we don't want race to complete a mailbox transcation.
123 * Here smp_call ensures that msrl_update_func() has no race
124 * and also with wait flag, wait for completion.
125 * smp_call_function_single is using get_cpu() and put_cpu().
126 */
127 ret = smp_call_function_single(action.mbox_cmd->logical_cpu,
128 msrl_update_func, &action, 1);
129 if (ret)
130 return ret;
131
132 if (!action.err && !resume && isst_if_mbox_cmd_set_req(action.mbox_cmd))
133 action.err = isst_store_cmd(action.mbox_cmd->command,
134 action.mbox_cmd->sub_command,
135 action.mbox_cmd->logical_cpu, 1,
136 action.mbox_cmd->parameter,
137 action.mbox_cmd->req_data);
138 *write_only = 0;
139
140 return action.err;
141 }
142
143
isst_pm_notify(struct notifier_block * nb,unsigned long mode,void * _unused)144 static int isst_pm_notify(struct notifier_block *nb,
145 unsigned long mode, void *_unused)
146 {
147 switch (mode) {
148 case PM_POST_HIBERNATION:
149 case PM_POST_RESTORE:
150 case PM_POST_SUSPEND:
151 isst_resume_common();
152 break;
153 default:
154 break;
155 }
156 return 0;
157 }
158
159 static struct notifier_block isst_pm_nb = {
160 .notifier_call = isst_pm_notify,
161 };
162
163 static const struct x86_cpu_id isst_if_cpu_ids[] = {
164 X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_X, NULL),
165 {}
166 };
167 MODULE_DEVICE_TABLE(x86cpu, isst_if_cpu_ids);
168
isst_if_mbox_init(void)169 static int __init isst_if_mbox_init(void)
170 {
171 struct isst_if_cmd_cb cb;
172 const struct x86_cpu_id *id;
173 u64 data;
174 int ret;
175
176 id = x86_match_cpu(isst_if_cpu_ids);
177 if (!id)
178 return -ENODEV;
179
180 /* Check presence of mailbox MSRs */
181 ret = rdmsrl_safe(MSR_OS_MAILBOX_INTERFACE, &data);
182 if (ret)
183 return ret;
184
185 ret = rdmsrl_safe(MSR_OS_MAILBOX_DATA, &data);
186 if (ret)
187 return ret;
188
189 memset(&cb, 0, sizeof(cb));
190 cb.cmd_size = sizeof(struct isst_if_mbox_cmd);
191 cb.offset = offsetof(struct isst_if_mbox_cmds, mbox_cmd);
192 cb.cmd_callback = isst_if_mbox_proc_cmd;
193 cb.owner = THIS_MODULE;
194 ret = isst_if_cdev_register(ISST_IF_DEV_MBOX, &cb);
195 if (ret)
196 return ret;
197
198 ret = register_pm_notifier(&isst_pm_nb);
199 if (ret)
200 isst_if_cdev_unregister(ISST_IF_DEV_MBOX);
201
202 return ret;
203 }
module_init(isst_if_mbox_init)204 module_init(isst_if_mbox_init)
205
206 static void __exit isst_if_mbox_exit(void)
207 {
208 unregister_pm_notifier(&isst_pm_nb);
209 isst_if_cdev_unregister(ISST_IF_DEV_MBOX);
210 }
211 module_exit(isst_if_mbox_exit)
212
213 MODULE_LICENSE("GPL v2");
214 MODULE_DESCRIPTION("Intel speed select interface mailbox driver");
215