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 * The average time to complete mailbox commands is less than 40us. Most of 25 * the commands complete in few micro seconds. But the same firmware handles 26 * requests from all power management features. 27 * We can create a scenario where we flood the firmware with requests then 28 * the mailbox response can be delayed for 100s of micro seconds. So define 29 * two timeouts. One for average case and one for long. 30 * If the firmware is taking more than average, just call cond_resched(). 31 */ 32 #define OS_MAILBOX_TIMEOUT_AVG_US 40 33 #define OS_MAILBOX_TIMEOUT_MAX_US 1000 34 35 struct isst_if_device { 36 struct mutex mutex; 37 }; 38 39 static int isst_if_mbox_cmd(struct pci_dev *pdev, 40 struct isst_if_mbox_cmd *mbox_cmd) 41 { 42 s64 tm_delta = 0; 43 ktime_t tm; 44 u32 data; 45 int ret; 46 47 /* Poll for rb bit == 0 */ 48 tm = ktime_get(); 49 do { 50 ret = pci_read_config_dword(pdev, PUNIT_MAILBOX_INTERFACE, 51 &data); 52 if (ret) 53 return ret; 54 55 if (data & BIT_ULL(PUNIT_MAILBOX_BUSY_BIT)) { 56 ret = -EBUSY; 57 tm_delta = ktime_us_delta(ktime_get(), tm); 58 if (tm_delta > OS_MAILBOX_TIMEOUT_AVG_US) 59 cond_resched(); 60 continue; 61 } 62 ret = 0; 63 break; 64 } while (tm_delta < OS_MAILBOX_TIMEOUT_MAX_US); 65 66 if (ret) 67 return ret; 68 69 /* Write DATA register */ 70 ret = pci_write_config_dword(pdev, PUNIT_MAILBOX_DATA, 71 mbox_cmd->req_data); 72 if (ret) 73 return ret; 74 75 /* Write command register */ 76 data = BIT_ULL(PUNIT_MAILBOX_BUSY_BIT) | 77 (mbox_cmd->parameter & GENMASK_ULL(13, 0)) << 16 | 78 (mbox_cmd->sub_command << 8) | 79 mbox_cmd->command; 80 81 ret = pci_write_config_dword(pdev, PUNIT_MAILBOX_INTERFACE, data); 82 if (ret) 83 return ret; 84 85 /* Poll for rb bit == 0 */ 86 tm_delta = 0; 87 tm = ktime_get(); 88 do { 89 ret = pci_read_config_dword(pdev, PUNIT_MAILBOX_INTERFACE, 90 &data); 91 if (ret) 92 return ret; 93 94 if (data & BIT_ULL(PUNIT_MAILBOX_BUSY_BIT)) { 95 ret = -EBUSY; 96 tm_delta = ktime_us_delta(ktime_get(), tm); 97 if (tm_delta > OS_MAILBOX_TIMEOUT_AVG_US) 98 cond_resched(); 99 continue; 100 } 101 102 if (data & 0xff) 103 return -ENXIO; 104 105 ret = pci_read_config_dword(pdev, PUNIT_MAILBOX_DATA, &data); 106 if (ret) 107 return ret; 108 109 mbox_cmd->resp_data = data; 110 ret = 0; 111 break; 112 } while (tm_delta < OS_MAILBOX_TIMEOUT_MAX_US); 113 114 return ret; 115 } 116 117 static long isst_if_mbox_proc_cmd(u8 *cmd_ptr, int *write_only, int resume) 118 { 119 struct isst_if_mbox_cmd *mbox_cmd; 120 struct isst_if_device *punit_dev; 121 struct pci_dev *pdev; 122 int ret; 123 124 mbox_cmd = (struct isst_if_mbox_cmd *)cmd_ptr; 125 126 if (isst_if_mbox_cmd_invalid(mbox_cmd)) 127 return -EINVAL; 128 129 if (isst_if_mbox_cmd_set_req(mbox_cmd) && !capable(CAP_SYS_ADMIN)) 130 return -EPERM; 131 132 pdev = isst_if_get_pci_dev(mbox_cmd->logical_cpu, 1, 30, 1); 133 if (!pdev) 134 return -EINVAL; 135 136 punit_dev = pci_get_drvdata(pdev); 137 if (!punit_dev) 138 return -EINVAL; 139 140 /* 141 * Basically we are allowing one complete mailbox transaction on 142 * a mapped PCI device at a time. 143 */ 144 mutex_lock(&punit_dev->mutex); 145 ret = isst_if_mbox_cmd(pdev, mbox_cmd); 146 if (!ret && !resume && isst_if_mbox_cmd_set_req(mbox_cmd)) 147 ret = isst_store_cmd(mbox_cmd->command, 148 mbox_cmd->sub_command, 149 mbox_cmd->logical_cpu, 1, 150 mbox_cmd->parameter, 151 mbox_cmd->req_data); 152 mutex_unlock(&punit_dev->mutex); 153 if (ret) 154 return ret; 155 156 *write_only = 0; 157 158 return 0; 159 } 160 161 static const struct pci_device_id isst_if_mbox_ids[] = { 162 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CFG_MBOX_DEVID_0)}, 163 { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_INTEL_CFG_MBOX_DEVID_1)}, 164 { 0 }, 165 }; 166 MODULE_DEVICE_TABLE(pci, isst_if_mbox_ids); 167 168 static int isst_if_mbox_probe(struct pci_dev *pdev, 169 const struct pci_device_id *ent) 170 { 171 struct isst_if_device *punit_dev; 172 struct isst_if_cmd_cb cb; 173 int ret; 174 175 punit_dev = devm_kzalloc(&pdev->dev, sizeof(*punit_dev), GFP_KERNEL); 176 if (!punit_dev) 177 return -ENOMEM; 178 179 ret = pcim_enable_device(pdev); 180 if (ret) 181 return ret; 182 183 mutex_init(&punit_dev->mutex); 184 pci_set_drvdata(pdev, punit_dev); 185 186 memset(&cb, 0, sizeof(cb)); 187 cb.cmd_size = sizeof(struct isst_if_mbox_cmd); 188 cb.offset = offsetof(struct isst_if_mbox_cmds, mbox_cmd); 189 cb.cmd_callback = isst_if_mbox_proc_cmd; 190 cb.owner = THIS_MODULE; 191 ret = isst_if_cdev_register(ISST_IF_DEV_MBOX, &cb); 192 193 if (ret) 194 mutex_destroy(&punit_dev->mutex); 195 196 return ret; 197 } 198 199 static void isst_if_mbox_remove(struct pci_dev *pdev) 200 { 201 struct isst_if_device *punit_dev; 202 203 punit_dev = pci_get_drvdata(pdev); 204 isst_if_cdev_unregister(ISST_IF_DEV_MBOX); 205 mutex_destroy(&punit_dev->mutex); 206 } 207 208 static int __maybe_unused isst_if_resume(struct device *device) 209 { 210 isst_resume_common(); 211 return 0; 212 } 213 214 static SIMPLE_DEV_PM_OPS(isst_if_pm_ops, NULL, isst_if_resume); 215 216 static struct pci_driver isst_if_pci_driver = { 217 .name = "isst_if_mbox_pci", 218 .id_table = isst_if_mbox_ids, 219 .probe = isst_if_mbox_probe, 220 .remove = isst_if_mbox_remove, 221 .driver.pm = &isst_if_pm_ops, 222 }; 223 224 module_pci_driver(isst_if_pci_driver); 225 226 MODULE_LICENSE("GPL v2"); 227 MODULE_DESCRIPTION("Intel speed select interface pci mailbox driver"); 228