aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/platform/x86/intel_speed_select_if/Makefile1
-rw-r--r--drivers/platform/x86/intel_speed_select_if/isst_if_mbox_msr.c180
2 files changed, 181 insertions, 0 deletions
diff --git a/drivers/platform/x86/intel_speed_select_if/Makefile b/drivers/platform/x86/intel_speed_select_if/Makefile
index 8dec8c858649..856076206f35 100644
--- a/drivers/platform/x86/intel_speed_select_if/Makefile
+++ b/drivers/platform/x86/intel_speed_select_if/Makefile
@@ -7,3 +7,4 @@
7obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) += isst_if_common.o 7obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) += isst_if_common.o
8obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) += isst_if_mmio.o 8obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) += isst_if_mmio.o
9obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) += isst_if_mbox_pci.o 9obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) += isst_if_mbox_pci.o
10obj-$(CONFIG_INTEL_SPEED_SELECT_INTERFACE) += isst_if_mbox_msr.o
diff --git a/drivers/platform/x86/intel_speed_select_if/isst_if_mbox_msr.c b/drivers/platform/x86/intel_speed_select_if/isst_if_mbox_msr.c
new file mode 100644
index 000000000000..d4bfc32546b5
--- /dev/null
+++ b/drivers/platform/x86/intel_speed_select_if/isst_if_mbox_msr.c
@@ -0,0 +1,180 @@
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/topology.h>
16#include <linux/uaccess.h>
17#include <uapi/linux/isst_if.h>
18#include <asm/cpu_device_id.h>
19#include <asm/intel-family.h>
20
21#include "isst_if_common.h"
22
23#define MSR_OS_MAILBOX_INTERFACE 0xB0
24#define MSR_OS_MAILBOX_DATA 0xB1
25#define MSR_OS_MAILBOX_BUSY_BIT 31
26
27/*
28 * Based on experiments count is never more than 1, as the MSR overhead
29 * is enough to finish the command. So here this is the worst case number.
30 */
31#define OS_MAILBOX_RETRY_COUNT 3
32
33static int isst_if_send_mbox_cmd(u8 command, u8 sub_command, u32 parameter,
34 u32 command_data, u32 *response_data)
35{
36 u32 retries;
37 u64 data;
38 int ret;
39
40 /* Poll for rb bit == 0 */
41 retries = OS_MAILBOX_RETRY_COUNT;
42 do {
43 rdmsrl(MSR_OS_MAILBOX_INTERFACE, data);
44 if (data & BIT_ULL(MSR_OS_MAILBOX_BUSY_BIT)) {
45 ret = -EBUSY;
46 continue;
47 }
48 ret = 0;
49 break;
50 } while (--retries);
51
52 if (ret)
53 return ret;
54
55 /* Write DATA register */
56 wrmsrl(MSR_OS_MAILBOX_DATA, command_data);
57
58 /* Write command register */
59 data = BIT_ULL(MSR_OS_MAILBOX_BUSY_BIT) |
60 (parameter & GENMASK_ULL(13, 0)) << 16 |
61 (sub_command << 8) |
62 command;
63 wrmsrl(MSR_OS_MAILBOX_INTERFACE, data);
64
65 /* Poll for rb bit == 0 */
66 retries = OS_MAILBOX_RETRY_COUNT;
67 do {
68 rdmsrl(MSR_OS_MAILBOX_INTERFACE, data);
69 if (data & BIT_ULL(MSR_OS_MAILBOX_BUSY_BIT)) {
70 ret = -EBUSY;
71 continue;
72 }
73
74 if (data & 0xff)
75 return -ENXIO;
76
77 if (response_data) {
78 rdmsrl(MSR_OS_MAILBOX_DATA, data);
79 *response_data = data;
80 }
81 ret = 0;
82 break;
83 } while (--retries);
84
85 return ret;
86}
87
88struct msrl_action {
89 int err;
90 struct isst_if_mbox_cmd *mbox_cmd;
91};
92
93/* revisit, smp_call_function_single should be enough for atomic mailbox! */
94static void msrl_update_func(void *info)
95{
96 struct msrl_action *act = info;
97
98 act->err = isst_if_send_mbox_cmd(act->mbox_cmd->command,
99 act->mbox_cmd->sub_command,
100 act->mbox_cmd->parameter,
101 act->mbox_cmd->req_data,
102 &act->mbox_cmd->resp_data);
103}
104
105static long isst_if_mbox_proc_cmd(u8 *cmd_ptr, int *write_only, int resume)
106{
107 struct msrl_action action;
108 int ret;
109
110 action.mbox_cmd = (struct isst_if_mbox_cmd *)cmd_ptr;
111
112 if (isst_if_mbox_cmd_invalid(action.mbox_cmd))
113 return -EINVAL;
114
115 if (isst_if_mbox_cmd_set_req(action.mbox_cmd) &&
116 !capable(CAP_SYS_ADMIN))
117 return -EPERM;
118
119 /*
120 * To complete mailbox command, we need to access two MSRs.
121 * So we don't want race to complete a mailbox transcation.
122 * Here smp_call ensures that msrl_update_func() has no race
123 * and also with wait flag, wait for completion.
124 * smp_call_function_single is using get_cpu() and put_cpu().
125 */
126 ret = smp_call_function_single(action.mbox_cmd->logical_cpu,
127 msrl_update_func, &action, 1);
128 if (ret)
129 return ret;
130
131 *write_only = 0;
132
133 return action.err;
134}
135
136#define ICPU(model) { X86_VENDOR_INTEL, 6, model, X86_FEATURE_ANY, }
137
138static const struct x86_cpu_id isst_if_cpu_ids[] = {
139 ICPU(INTEL_FAM6_SKYLAKE_X),
140 {}
141};
142MODULE_DEVICE_TABLE(x86cpu, isst_if_cpu_ids);
143
144static int __init isst_if_mbox_init(void)
145{
146 struct isst_if_cmd_cb cb;
147 const struct x86_cpu_id *id;
148 u64 data;
149 int ret;
150
151 id = x86_match_cpu(isst_if_cpu_ids);
152 if (!id)
153 return -ENODEV;
154
155 /* Check presence of mailbox MSRs */
156 ret = rdmsrl_safe(MSR_OS_MAILBOX_INTERFACE, &data);
157 if (ret)
158 return ret;
159
160 ret = rdmsrl_safe(MSR_OS_MAILBOX_DATA, &data);
161 if (ret)
162 return ret;
163
164 memset(&cb, 0, sizeof(cb));
165 cb.cmd_size = sizeof(struct isst_if_mbox_cmd);
166 cb.offset = offsetof(struct isst_if_mbox_cmds, mbox_cmd);
167 cb.cmd_callback = isst_if_mbox_proc_cmd;
168 cb.owner = THIS_MODULE;
169 return isst_if_cdev_register(ISST_IF_DEV_MBOX, &cb);
170}
171module_init(isst_if_mbox_init)
172
173static void __exit isst_if_mbox_exit(void)
174{
175 isst_if_cdev_unregister(ISST_IF_DEV_MBOX);
176}
177module_exit(isst_if_mbox_exit)
178
179MODULE_LICENSE("GPL v2");
180MODULE_DESCRIPTION("Intel speed select interface mailbox driver");