root/drivers/platform/x86/intel_speed_select_if/isst_if_mbox_msr.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. isst_if_send_mbox_cmd
  2. msrl_update_func
  3. isst_if_mbox_proc_cmd
  4. isst_pm_notify
  5. isst_if_mbox_init
  6. module_init

   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");

/* [<][>][^][v][top][bottom][index][help] */