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 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 
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 }
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