]> asedeno.scripts.mit.edu Git - linux.git/blob - drivers/platform/x86/intel_speed_select_if/isst_if_mbox_msr.c
Merge tag 'for-5.4-rc2-tag' of git://git.kernel.org/pub/scm/linux/kernel/git/kdave/linux
[linux.git] / drivers / platform / x86 / intel_speed_select_if / isst_if_mbox_msr.c
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
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! */
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
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
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 #define ICPU(model)     { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
164
165 static const struct x86_cpu_id isst_if_cpu_ids[] = {
166         ICPU(INTEL_FAM6_SKYLAKE_X),
167         {}
168 };
169 MODULE_DEVICE_TABLE(x86cpu, isst_if_cpu_ids);
170
171 static int __init isst_if_mbox_init(void)
172 {
173         struct isst_if_cmd_cb cb;
174         const struct x86_cpu_id *id;
175         u64 data;
176         int ret;
177
178         id = x86_match_cpu(isst_if_cpu_ids);
179         if (!id)
180                 return -ENODEV;
181
182         /* Check presence of mailbox MSRs */
183         ret = rdmsrl_safe(MSR_OS_MAILBOX_INTERFACE, &data);
184         if (ret)
185                 return ret;
186
187         ret = rdmsrl_safe(MSR_OS_MAILBOX_DATA, &data);
188         if (ret)
189                 return ret;
190
191         memset(&cb, 0, sizeof(cb));
192         cb.cmd_size = sizeof(struct isst_if_mbox_cmd);
193         cb.offset = offsetof(struct isst_if_mbox_cmds, mbox_cmd);
194         cb.cmd_callback = isst_if_mbox_proc_cmd;
195         cb.owner = THIS_MODULE;
196         ret = isst_if_cdev_register(ISST_IF_DEV_MBOX, &cb);
197         if (ret)
198                 return ret;
199
200         ret = register_pm_notifier(&isst_pm_nb);
201         if (ret)
202                 isst_if_cdev_unregister(ISST_IF_DEV_MBOX);
203
204         return ret;
205 }
206 module_init(isst_if_mbox_init)
207
208 static void __exit isst_if_mbox_exit(void)
209 {
210         unregister_pm_notifier(&isst_pm_nb);
211         isst_if_cdev_unregister(ISST_IF_DEV_MBOX);
212 }
213 module_exit(isst_if_mbox_exit)
214
215 MODULE_LICENSE("GPL v2");
216 MODULE_DESCRIPTION("Intel speed select interface mailbox driver");