FILE
isst_if_mmio.c
File preview with syntax highlighting.
linux-6.19.14/drivers/platform/x86/intel/speed_select_if/isst_if_mmio.c
1// SPDX-License-Identifier: GPL-2.0 2/* 3 * Intel Speed Select Interface: MMIO 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/pci.h> 12#include <linux/sched/signal.h> 13#include <linux/uaccess.h> 14#include <uapi/linux/isst_if.h> 15 16#include "isst_if_common.h" 17 18struct isst_mmio_range { 19 int beg; 20 int end; 21 int size; 22}; 23 24static struct isst_mmio_range mmio_range_devid_0[] = { 25 {0x04, 0x14, 0x18}, 26 {0x20, 0xD0, 0xD4}, 27}; 28 29static struct isst_mmio_range mmio_range_devid_1[] = { 30 {0x04, 0x14, 0x18}, 31 {0x20, 0x11C, 0x120}, 32}; 33 34struct isst_if_device { 35 void __iomem *punit_mmio; 36 u32 range_0[5]; 37 u32 range_1[64]; 38 struct isst_mmio_range *mmio_range; 39 struct mutex mutex; 40}; 41 42static long isst_if_mmio_rd_wr(u8 *cmd_ptr, int *write_only, int resume) 43{ 44 struct isst_if_device *punit_dev; 45 struct isst_if_io_reg *io_reg; 46 struct pci_dev *pdev; 47 48 io_reg = (struct isst_if_io_reg *)cmd_ptr; 49 50 if (io_reg->reg % 4) 51 return -EINVAL; 52 53 if (io_reg->read_write && !capable(CAP_SYS_ADMIN)) 54 return -EPERM; 55 56 pdev = isst_if_get_pci_dev(io_reg->logical_cpu, 0, 0, 1); 57 if (!pdev) 58 return -EINVAL; 59 60 punit_dev = pci_get_drvdata(pdev); 61 if (!punit_dev) 62 return -EINVAL; 63 64 if (io_reg->reg < punit_dev->mmio_range[0].beg || 65 io_reg->reg > punit_dev->mmio_range[1].end) 66 return -EINVAL; 67 68 /* 69 * Ensure that operation is complete on a PCI device to avoid read 70 * write race by using per PCI device mutex. 71 */ 72 mutex_lock(&punit_dev->mutex); 73 if (io_reg->read_write) { 74 writel(io_reg->value, punit_dev->punit_mmio+io_reg->reg); 75 *write_only = 1; 76 } else { 77 io_reg->value = readl(punit_dev->punit_mmio+io_reg->reg); 78 *write_only = 0; 79 } 80 mutex_unlock(&punit_dev->mutex); 81 82 return 0; 83} 84 85static const struct pci_device_id isst_if_ids[] = { 86 { PCI_DEVICE_DATA(INTEL, RAPL_PRIO_DEVID_0, &mmio_range_devid_0)}, 87 { PCI_DEVICE_DATA(INTEL, RAPL_PRIO_DEVID_1, &mmio_range_devid_1)}, 88 { 0 }, 89}; 90MODULE_DEVICE_TABLE(pci, isst_if_ids); 91 92static int isst_if_probe(struct pci_dev *pdev, const struct pci_device_id *ent) 93{ 94 struct isst_if_device *punit_dev; 95 struct isst_if_cmd_cb cb; 96 u32 mmio_base, pcu_base; 97 struct resource r; 98 u64 base_addr; 99 int ret; 100 101 punit_dev = devm_kzalloc(&pdev->dev, sizeof(*punit_dev), GFP_KERNEL); 102 if (!punit_dev) 103 return -ENOMEM; 104 105 ret = pcim_enable_device(pdev); 106 if (ret) 107 return ret; 108 109 ret = pci_read_config_dword(pdev, 0xD0, &mmio_base); 110 if (ret) 111 return pcibios_err_to_errno(ret); 112 113 ret = pci_read_config_dword(pdev, 0xFC, &pcu_base); 114 if (ret) 115 return pcibios_err_to_errno(ret); 116 117 pcu_base &= GENMASK(10, 0); 118 base_addr = (u64)mmio_base << 23 | (u64) pcu_base << 12; 119 120 punit_dev->mmio_range = (struct isst_mmio_range *) ent->driver_data; 121 122 r = DEFINE_RES_MEM(base_addr, punit_dev->mmio_range[1].size); 123 punit_dev->punit_mmio = devm_ioremap_resource(&pdev->dev, &r); 124 if (IS_ERR(punit_dev->punit_mmio)) 125 return PTR_ERR(punit_dev->punit_mmio); 126 127 mutex_init(&punit_dev->mutex); 128 pci_set_drvdata(pdev, punit_dev); 129 130 memset(&cb, 0, sizeof(cb)); 131 cb.cmd_size = sizeof(struct isst_if_io_reg); 132 cb.offset = offsetof(struct isst_if_io_regs, io_reg); 133 cb.cmd_callback = isst_if_mmio_rd_wr; 134 cb.owner = THIS_MODULE; 135 ret = isst_if_cdev_register(ISST_IF_DEV_MMIO, &cb); 136 if (ret) 137 mutex_destroy(&punit_dev->mutex); 138 139 return ret; 140} 141 142static void isst_if_remove(struct pci_dev *pdev) 143{ 144 struct isst_if_device *punit_dev; 145 146 punit_dev = pci_get_drvdata(pdev); 147 isst_if_cdev_unregister(ISST_IF_DEV_MMIO); 148 mutex_destroy(&punit_dev->mutex); 149} 150 151static int __maybe_unused isst_if_suspend(struct device *device) 152{ 153 struct isst_if_device *punit_dev = dev_get_drvdata(device); 154 int i; 155 156 for (i = 0; i < ARRAY_SIZE(punit_dev->range_0); ++i) 157 punit_dev->range_0[i] = readl(punit_dev->punit_mmio + 158 punit_dev->mmio_range[0].beg + 4 * i); 159 for (i = 0; i < ARRAY_SIZE(punit_dev->range_1); ++i) { 160 u32 addr; 161 162 addr = punit_dev->mmio_range[1].beg + 4 * i; 163 if (addr > punit_dev->mmio_range[1].end) 164 break; 165 punit_dev->range_1[i] = readl(punit_dev->punit_mmio + addr); 166 } 167 168 return 0; 169} 170 171static int __maybe_unused isst_if_resume(struct device *device) 172{ 173 struct isst_if_device *punit_dev = dev_get_drvdata(device); 174 int i; 175 176 for (i = 0; i < ARRAY_SIZE(punit_dev->range_0); ++i) 177 writel(punit_dev->range_0[i], punit_dev->punit_mmio + 178 punit_dev->mmio_range[0].beg + 4 * i); 179 for (i = 0; i < ARRAY_SIZE(punit_dev->range_1); ++i) { 180 u32 addr; 181 182 addr = punit_dev->mmio_range[1].beg + 4 * i; 183 if (addr > punit_dev->mmio_range[1].end) 184 break; 185 186 writel(punit_dev->range_1[i], punit_dev->punit_mmio + addr); 187 } 188 189 return 0; 190} 191 192static SIMPLE_DEV_PM_OPS(isst_if_pm_ops, isst_if_suspend, isst_if_resume); 193 194static struct pci_driver isst_if_pci_driver = { 195 .name = "isst_if_pci", 196 .id_table = isst_if_ids, 197 .probe = isst_if_probe, 198 .remove = isst_if_remove, 199 .driver.pm = &isst_if_pm_ops, 200}; 201 202module_pci_driver(isst_if_pci_driver); 203 204MODULE_LICENSE("GPL v2"); 205MODULE_DESCRIPTION("Intel speed select interface mmio driver");
~/
Read-only file preview.