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

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

DEFINITIONS

This source file includes following definitions.
  1. isst_if_mbox_cmd
  2. isst_if_mbox_proc_cmd
  3. isst_if_mbox_probe
  4. isst_if_mbox_remove
  5. isst_if_resume

   1 // SPDX-License-Identifier: GPL-2.0
   2 /*
   3  * Intel Speed Select Interface: Mbox via PCI 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/cpufeature.h>
  11 #include <linux/module.h>
  12 #include <linux/pci.h>
  13 #include <linux/sched/signal.h>
  14 #include <linux/uaccess.h>
  15 #include <uapi/linux/isst_if.h>
  16 
  17 #include "isst_if_common.h"
  18 
  19 #define PUNIT_MAILBOX_DATA              0xA0
  20 #define PUNIT_MAILBOX_INTERFACE         0xA4
  21 #define PUNIT_MAILBOX_BUSY_BIT          31
  22 
  23 /*
  24  * Commands has variable amount of processing time. Most of the commands will
  25  * be done in 0-3 tries, but some takes up to 50.
  26  * The real processing time was observed as 25us for the most of the commands
  27  * at 2GHz. It is possible to optimize this count taking samples on customer
  28  * systems.
  29  */
  30 #define OS_MAILBOX_RETRY_COUNT          50
  31 
  32 struct isst_if_device {
  33         struct mutex mutex;
  34 };
  35 
  36 static int isst_if_mbox_cmd(struct pci_dev *pdev,
  37                             struct isst_if_mbox_cmd *mbox_cmd)
  38 {
  39         u32 retries, data;
  40         int ret;
  41 
  42         /* Poll for rb bit == 0 */
  43         retries = OS_MAILBOX_RETRY_COUNT;
  44         do {
  45                 ret = pci_read_config_dword(pdev, PUNIT_MAILBOX_INTERFACE,
  46                                             &data);
  47                 if (ret)
  48                         return ret;
  49 
  50                 if (data & BIT_ULL(PUNIT_MAILBOX_BUSY_BIT)) {
  51                         ret = -EBUSY;
  52                         continue;
  53                 }
  54                 ret = 0;
  55                 break;
  56         } while (--retries);
  57 
  58         if (ret)
  59                 return ret;
  60 
  61         /* Write DATA register */
  62         ret = pci_write_config_dword(pdev, PUNIT_MAILBOX_DATA,
  63                                      mbox_cmd->req_data);
  64         if (ret)
  65                 return ret;
  66 
  67         /* Write command register */
  68         data = BIT_ULL(PUNIT_MAILBOX_BUSY_BIT) |
  69                       (mbox_cmd->parameter & GENMASK_ULL(13, 0)) << 16 |
  70                       (mbox_cmd->sub_command << 8) |
  71                       mbox_cmd->command;
  72 
  73         ret = pci_write_config_dword(pdev, PUNIT_MAILBOX_INTERFACE, data);
  74         if (ret)
  75                 return ret;
  76 
  77         /* Poll for rb bit == 0 */
  78         retries = OS_MAILBOX_RETRY_COUNT;
  79         do {
  80                 ret = pci_read_config_dword(pdev, PUNIT_MAILBOX_INTERFACE,
  81                                             &data);
  82                 if (ret)
  83                         return ret;
  84 
  85                 if (data & BIT_ULL(PUNIT_MAILBOX_BUSY_BIT)) {
  86                         ret = -EBUSY;
  87                         continue;
  88                 }
  89 
  90                 if (data & 0xff)
  91                         return -ENXIO;
  92 
  93                 ret = pci_read_config_dword(pdev, PUNIT_MAILBOX_DATA, &data);
  94                 if (ret)
  95                         return ret;
  96 
  97                 mbox_cmd->resp_data = data;
  98                 ret = 0;
  99                 break;
 100         } while (--retries);
 101 
 102         return ret;
 103 }
 104 
 105 static long isst_if_mbox_proc_cmd(u8 *cmd_ptr, int *write_only, int resume)
 106 {
 107         struct isst_if_mbox_cmd *mbox_cmd;
 108         struct isst_if_device *punit_dev;
 109         struct pci_dev *pdev;
 110         int ret;
 111 
 112         mbox_cmd = (struct isst_if_mbox_cmd *)cmd_ptr;
 113 
 114         if (isst_if_mbox_cmd_invalid(mbox_cmd))
 115                 return -EINVAL;
 116 
 117         if (isst_if_mbox_cmd_set_req(mbox_cmd) && !capable(CAP_SYS_ADMIN))
 118                 return -EPERM;
 119 
 120         pdev = isst_if_get_pci_dev(mbox_cmd->logical_cpu, 1, 30, 1);
 121         if (!pdev)
 122                 return -EINVAL;
 123 
 124         punit_dev = pci_get_drvdata(pdev);
 125         if (!punit_dev)
 126                 return -EINVAL;
 127 
 128         /*
 129          * Basically we are allowing one complete mailbox transaction on
 130          * a mapped PCI device at a time.
 131          */
 132         mutex_lock(&punit_dev->mutex);
 133         ret = isst_if_mbox_cmd(pdev, mbox_cmd);
 134         if (!ret && !resume && isst_if_mbox_cmd_set_req(mbox_cmd))
 135                 ret = isst_store_cmd(mbox_cmd->command,
 136                                      mbox_cmd->sub_command,
 137                                      mbox_cmd->logical_cpu, 1,
 138                                      mbox_cmd->parameter,
 139                                      mbox_cmd->req_data);
 140         mutex_unlock(&punit_dev->mutex);
 141         if (ret)
 142                 return ret;
 143 
 144         *write_only = 0;
 145 
 146         return 0;
 147 }
 148 
 149 static const struct pci_device_id isst_if_mbox_ids[] = {
 150         { PCI_DEVICE(PCI_VENDOR_ID_INTEL, INTEL_CFG_MBOX_DEVID_0)},
 151         { 0 },
 152 };
 153 MODULE_DEVICE_TABLE(pci, isst_if_mbox_ids);
 154 
 155 static int isst_if_mbox_probe(struct pci_dev *pdev,
 156                               const struct pci_device_id *ent)
 157 {
 158         struct isst_if_device *punit_dev;
 159         struct isst_if_cmd_cb cb;
 160         int ret;
 161 
 162         punit_dev = devm_kzalloc(&pdev->dev, sizeof(*punit_dev), GFP_KERNEL);
 163         if (!punit_dev)
 164                 return -ENOMEM;
 165 
 166         ret = pcim_enable_device(pdev);
 167         if (ret)
 168                 return ret;
 169 
 170         mutex_init(&punit_dev->mutex);
 171         pci_set_drvdata(pdev, punit_dev);
 172 
 173         memset(&cb, 0, sizeof(cb));
 174         cb.cmd_size = sizeof(struct isst_if_mbox_cmd);
 175         cb.offset = offsetof(struct isst_if_mbox_cmds, mbox_cmd);
 176         cb.cmd_callback = isst_if_mbox_proc_cmd;
 177         cb.owner = THIS_MODULE;
 178         ret = isst_if_cdev_register(ISST_IF_DEV_MBOX, &cb);
 179 
 180         if (ret)
 181                 mutex_destroy(&punit_dev->mutex);
 182 
 183         return ret;
 184 }
 185 
 186 static void isst_if_mbox_remove(struct pci_dev *pdev)
 187 {
 188         struct isst_if_device *punit_dev;
 189 
 190         punit_dev = pci_get_drvdata(pdev);
 191         isst_if_cdev_unregister(ISST_IF_DEV_MBOX);
 192         mutex_destroy(&punit_dev->mutex);
 193 }
 194 
 195 static int __maybe_unused isst_if_resume(struct device *device)
 196 {
 197         isst_resume_common();
 198         return 0;
 199 }
 200 
 201 static SIMPLE_DEV_PM_OPS(isst_if_pm_ops, NULL, isst_if_resume);
 202 
 203 static struct pci_driver isst_if_pci_driver = {
 204         .name                   = "isst_if_mbox_pci",
 205         .id_table               = isst_if_mbox_ids,
 206         .probe                  = isst_if_mbox_probe,
 207         .remove                 = isst_if_mbox_remove,
 208         .driver.pm              = &isst_if_pm_ops,
 209 };
 210 
 211 module_pci_driver(isst_if_pci_driver);
 212 
 213 MODULE_LICENSE("GPL v2");
 214 MODULE_DESCRIPTION("Intel speed select interface pci mailbox driver");

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