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