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

core.c (5534B)


      1// SPDX-License-Identifier: GPL-2.0-only
      2// Copyright (c) 2018-2021 Intel Corporation
      3
      4#include <linux/bug.h>
      5#include <linux/device.h>
      6#include <linux/export.h>
      7#include <linux/idr.h>
      8#include <linux/module.h>
      9#include <linux/of.h>
     10#include <linux/peci.h>
     11#include <linux/pm_runtime.h>
     12#include <linux/property.h>
     13#include <linux/slab.h>
     14
     15#include "internal.h"
     16
     17static DEFINE_IDA(peci_controller_ida);
     18
     19static void peci_controller_dev_release(struct device *dev)
     20{
     21	struct peci_controller *controller = to_peci_controller(dev);
     22
     23	mutex_destroy(&controller->bus_lock);
     24	ida_free(&peci_controller_ida, controller->id);
     25	kfree(controller);
     26}
     27
     28struct device_type peci_controller_type = {
     29	.release	= peci_controller_dev_release,
     30};
     31
     32int peci_controller_scan_devices(struct peci_controller *controller)
     33{
     34	int ret;
     35	u8 addr;
     36
     37	for (addr = PECI_BASE_ADDR; addr < PECI_BASE_ADDR + PECI_DEVICE_NUM_MAX; addr++) {
     38		ret = peci_device_create(controller, addr);
     39		if (ret)
     40			return ret;
     41	}
     42
     43	return 0;
     44}
     45
     46static struct peci_controller *peci_controller_alloc(struct device *dev,
     47						     struct peci_controller_ops *ops)
     48{
     49	struct peci_controller *controller;
     50	int ret;
     51
     52	if (!ops->xfer)
     53		return ERR_PTR(-EINVAL);
     54
     55	controller = kzalloc(sizeof(*controller), GFP_KERNEL);
     56	if (!controller)
     57		return ERR_PTR(-ENOMEM);
     58
     59	ret = ida_alloc_max(&peci_controller_ida, U8_MAX, GFP_KERNEL);
     60	if (ret < 0)
     61		goto err;
     62	controller->id = ret;
     63
     64	controller->ops = ops;
     65
     66	controller->dev.parent = dev;
     67	controller->dev.bus = &peci_bus_type;
     68	controller->dev.type = &peci_controller_type;
     69
     70	device_initialize(&controller->dev);
     71
     72	mutex_init(&controller->bus_lock);
     73
     74	return controller;
     75
     76err:
     77	kfree(controller);
     78	return ERR_PTR(ret);
     79}
     80
     81static int unregister_child(struct device *dev, void *dummy)
     82{
     83	peci_device_destroy(to_peci_device(dev));
     84
     85	return 0;
     86}
     87
     88static void unregister_controller(void *_controller)
     89{
     90	struct peci_controller *controller = _controller;
     91
     92	/*
     93	 * Detach any active PECI devices. This can't fail, thus we do not
     94	 * check the returned value.
     95	 */
     96	device_for_each_child_reverse(&controller->dev, NULL, unregister_child);
     97
     98	device_unregister(&controller->dev);
     99
    100	fwnode_handle_put(controller->dev.fwnode);
    101
    102	pm_runtime_disable(&controller->dev);
    103}
    104
    105/**
    106 * devm_peci_controller_add() - add PECI controller
    107 * @dev: device for devm operations
    108 * @ops: pointer to controller specific methods
    109 *
    110 * In final stage of its probe(), peci_controller driver calls
    111 * devm_peci_controller_add() to register itself with the PECI bus.
    112 *
    113 * Return: Pointer to the newly allocated controller or ERR_PTR() in case of failure.
    114 */
    115struct peci_controller *devm_peci_controller_add(struct device *dev,
    116						 struct peci_controller_ops *ops)
    117{
    118	struct peci_controller *controller;
    119	int ret;
    120
    121	controller = peci_controller_alloc(dev, ops);
    122	if (IS_ERR(controller))
    123		return controller;
    124
    125	ret = dev_set_name(&controller->dev, "peci-%d", controller->id);
    126	if (ret)
    127		goto err_put;
    128
    129	pm_runtime_no_callbacks(&controller->dev);
    130	pm_suspend_ignore_children(&controller->dev, true);
    131	pm_runtime_enable(&controller->dev);
    132
    133	device_set_node(&controller->dev, fwnode_handle_get(dev_fwnode(dev)));
    134
    135	ret = device_add(&controller->dev);
    136	if (ret)
    137		goto err_fwnode;
    138
    139	ret = devm_add_action_or_reset(dev, unregister_controller, controller);
    140	if (ret)
    141		return ERR_PTR(ret);
    142
    143	/*
    144	 * Ignoring retval since failures during scan are non-critical for
    145	 * controller itself.
    146	 */
    147	peci_controller_scan_devices(controller);
    148
    149	return controller;
    150
    151err_fwnode:
    152	fwnode_handle_put(controller->dev.fwnode);
    153
    154	pm_runtime_disable(&controller->dev);
    155
    156err_put:
    157	put_device(&controller->dev);
    158
    159	return ERR_PTR(ret);
    160}
    161EXPORT_SYMBOL_NS_GPL(devm_peci_controller_add, PECI);
    162
    163static const struct peci_device_id *
    164peci_bus_match_device_id(const struct peci_device_id *id, struct peci_device *device)
    165{
    166	while (id->family != 0) {
    167		if (id->family == device->info.family &&
    168		    id->model == device->info.model)
    169			return id;
    170		id++;
    171	}
    172
    173	return NULL;
    174}
    175
    176static int peci_bus_device_match(struct device *dev, struct device_driver *drv)
    177{
    178	struct peci_device *device = to_peci_device(dev);
    179	struct peci_driver *peci_drv = to_peci_driver(drv);
    180
    181	if (dev->type != &peci_device_type)
    182		return 0;
    183
    184	return !!peci_bus_match_device_id(peci_drv->id_table, device);
    185}
    186
    187static int peci_bus_device_probe(struct device *dev)
    188{
    189	struct peci_device *device = to_peci_device(dev);
    190	struct peci_driver *driver = to_peci_driver(dev->driver);
    191
    192	return driver->probe(device, peci_bus_match_device_id(driver->id_table, device));
    193}
    194
    195static void peci_bus_device_remove(struct device *dev)
    196{
    197	struct peci_device *device = to_peci_device(dev);
    198	struct peci_driver *driver = to_peci_driver(dev->driver);
    199
    200	if (driver->remove)
    201		driver->remove(device);
    202}
    203
    204struct bus_type peci_bus_type = {
    205	.name		= "peci",
    206	.match		= peci_bus_device_match,
    207	.probe		= peci_bus_device_probe,
    208	.remove		= peci_bus_device_remove,
    209	.bus_groups	= peci_bus_groups,
    210};
    211
    212static int __init peci_init(void)
    213{
    214	int ret;
    215
    216	ret = bus_register(&peci_bus_type);
    217	if (ret < 0) {
    218		pr_err("peci: failed to register PECI bus type!\n");
    219		return ret;
    220	}
    221
    222	return 0;
    223}
    224module_init(peci_init);
    225
    226static void __exit peci_exit(void)
    227{
    228	bus_unregister(&peci_bus_type);
    229}
    230module_exit(peci_exit);
    231
    232MODULE_AUTHOR("Jason M Bills <jason.m.bills@linux.intel.com>");
    233MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");
    234MODULE_AUTHOR("Iwona Winiarska <iwona.winiarska@intel.com>");
    235MODULE_DESCRIPTION("PECI bus core module");
    236MODULE_LICENSE("GPL");