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

device.c (5298B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2// Copyright (c) 2018-2021 Intel Corporation
      3
      4#include <linux/bitfield.h>
      5#include <linux/peci.h>
      6#include <linux/peci-cpu.h>
      7#include <linux/slab.h>
      8
      9#include "internal.h"
     10
     11/*
     12 * PECI device can be removed using sysfs, but the removal can also happen as
     13 * a result of controller being removed.
     14 * Mutex is used to protect PECI device from being double-deleted.
     15 */
     16static DEFINE_MUTEX(peci_device_del_lock);
     17
     18#define REVISION_NUM_MASK GENMASK(15, 8)
     19static int peci_get_revision(struct peci_device *device, u8 *revision)
     20{
     21	struct peci_request *req;
     22	u64 dib;
     23
     24	req = peci_xfer_get_dib(device);
     25	if (IS_ERR(req))
     26		return PTR_ERR(req);
     27
     28	/*
     29	 * PECI device may be in a state where it is unable to return a proper
     30	 * DIB, in which case it returns 0 as DIB value.
     31	 * Let's treat this as an error to avoid carrying on with the detection
     32	 * using invalid revision.
     33	 */
     34	dib = peci_request_dib_read(req);
     35	if (dib == 0) {
     36		peci_request_free(req);
     37		return -EIO;
     38	}
     39
     40	*revision = FIELD_GET(REVISION_NUM_MASK, dib);
     41
     42	peci_request_free(req);
     43
     44	return 0;
     45}
     46
     47static int peci_get_cpu_id(struct peci_device *device, u32 *cpu_id)
     48{
     49	struct peci_request *req;
     50	int ret;
     51
     52	req = peci_xfer_pkg_cfg_readl(device, PECI_PCS_PKG_ID, PECI_PKG_ID_CPU_ID);
     53	if (IS_ERR(req))
     54		return PTR_ERR(req);
     55
     56	ret = peci_request_status(req);
     57	if (ret)
     58		goto out_req_free;
     59
     60	*cpu_id = peci_request_data_readl(req);
     61out_req_free:
     62	peci_request_free(req);
     63
     64	return ret;
     65}
     66
     67static unsigned int peci_x86_cpu_family(unsigned int sig)
     68{
     69	unsigned int x86;
     70
     71	x86 = (sig >> 8) & 0xf;
     72
     73	if (x86 == 0xf)
     74		x86 += (sig >> 20) & 0xff;
     75
     76	return x86;
     77}
     78
     79static unsigned int peci_x86_cpu_model(unsigned int sig)
     80{
     81	unsigned int fam, model;
     82
     83	fam = peci_x86_cpu_family(sig);
     84
     85	model = (sig >> 4) & 0xf;
     86
     87	if (fam >= 0x6)
     88		model += ((sig >> 16) & 0xf) << 4;
     89
     90	return model;
     91}
     92
     93static int peci_device_info_init(struct peci_device *device)
     94{
     95	u8 revision;
     96	u32 cpu_id;
     97	int ret;
     98
     99	ret = peci_get_cpu_id(device, &cpu_id);
    100	if (ret)
    101		return ret;
    102
    103	device->info.family = peci_x86_cpu_family(cpu_id);
    104	device->info.model = peci_x86_cpu_model(cpu_id);
    105
    106	ret = peci_get_revision(device, &revision);
    107	if (ret)
    108		return ret;
    109	device->info.peci_revision = revision;
    110
    111	device->info.socket_id = device->addr - PECI_BASE_ADDR;
    112
    113	return 0;
    114}
    115
    116static int peci_detect(struct peci_controller *controller, u8 addr)
    117{
    118	/*
    119	 * PECI Ping is a command encoded by tx_len = 0, rx_len = 0.
    120	 * We expect correct Write FCS if the device at the target address
    121	 * is able to respond.
    122	 */
    123	struct peci_request req = { 0 };
    124	int ret;
    125
    126	mutex_lock(&controller->bus_lock);
    127	ret = controller->ops->xfer(controller, addr, &req);
    128	mutex_unlock(&controller->bus_lock);
    129
    130	return ret;
    131}
    132
    133static bool peci_addr_valid(u8 addr)
    134{
    135	return addr >= PECI_BASE_ADDR && addr < PECI_BASE_ADDR + PECI_DEVICE_NUM_MAX;
    136}
    137
    138static int peci_dev_exists(struct device *dev, void *data)
    139{
    140	struct peci_device *device = to_peci_device(dev);
    141	u8 *addr = data;
    142
    143	if (device->addr == *addr)
    144		return -EBUSY;
    145
    146	return 0;
    147}
    148
    149int peci_device_create(struct peci_controller *controller, u8 addr)
    150{
    151	struct peci_device *device;
    152	int ret;
    153
    154	if (!peci_addr_valid(addr))
    155		return -EINVAL;
    156
    157	/* Check if we have already detected this device before. */
    158	ret = device_for_each_child(&controller->dev, &addr, peci_dev_exists);
    159	if (ret)
    160		return 0;
    161
    162	ret = peci_detect(controller, addr);
    163	if (ret) {
    164		/*
    165		 * Device not present or host state doesn't allow successful
    166		 * detection at this time.
    167		 */
    168		if (ret == -EIO || ret == -ETIMEDOUT)
    169			return 0;
    170
    171		return ret;
    172	}
    173
    174	device = kzalloc(sizeof(*device), GFP_KERNEL);
    175	if (!device)
    176		return -ENOMEM;
    177
    178	device_initialize(&device->dev);
    179
    180	device->addr = addr;
    181	device->dev.parent = &controller->dev;
    182	device->dev.bus = &peci_bus_type;
    183	device->dev.type = &peci_device_type;
    184
    185	ret = peci_device_info_init(device);
    186	if (ret)
    187		goto err_put;
    188
    189	ret = dev_set_name(&device->dev, "%d-%02x", controller->id, device->addr);
    190	if (ret)
    191		goto err_put;
    192
    193	ret = device_add(&device->dev);
    194	if (ret)
    195		goto err_put;
    196
    197	return 0;
    198
    199err_put:
    200	put_device(&device->dev);
    201
    202	return ret;
    203}
    204
    205void peci_device_destroy(struct peci_device *device)
    206{
    207	mutex_lock(&peci_device_del_lock);
    208	if (!device->deleted) {
    209		device_unregister(&device->dev);
    210		device->deleted = true;
    211	}
    212	mutex_unlock(&peci_device_del_lock);
    213}
    214
    215int __peci_driver_register(struct peci_driver *driver, struct module *owner,
    216			   const char *mod_name)
    217{
    218	driver->driver.bus = &peci_bus_type;
    219	driver->driver.owner = owner;
    220	driver->driver.mod_name = mod_name;
    221
    222	if (!driver->probe) {
    223		pr_err("peci: trying to register driver without probe callback\n");
    224		return -EINVAL;
    225	}
    226
    227	if (!driver->id_table) {
    228		pr_err("peci: trying to register driver without device id table\n");
    229		return -EINVAL;
    230	}
    231
    232	return driver_register(&driver->driver);
    233}
    234EXPORT_SYMBOL_NS_GPL(__peci_driver_register, PECI);
    235
    236void peci_driver_unregister(struct peci_driver *driver)
    237{
    238	driver_unregister(&driver->driver);
    239}
    240EXPORT_SYMBOL_NS_GPL(peci_driver_unregister, PECI);
    241
    242static void peci_device_release(struct device *dev)
    243{
    244	struct peci_device *device = to_peci_device(dev);
    245
    246	kfree(device);
    247}
    248
    249struct device_type peci_device_type = {
    250	.groups		= peci_device_groups,
    251	.release	= peci_device_release,
    252};