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