cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

isst_if_mmio.c (4877B)


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