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