236 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2// Copyright (c) 2018-2021 Intel Corporation3 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 28const struct 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 const 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 not94 * 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 controller107 * @dev: device for devm operations108 * @ops: pointer to controller specific methods109 *110 * In final stage of its probe(), peci_controller driver calls111 * 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 const 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 for145 * 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->x86_vfm != 0) {167 if (id->x86_vfm == device->info.x86_vfm)168 return id;169 id++;170 }171 172 return NULL;173}174 175static int peci_bus_device_match(struct device *dev, const struct device_driver *drv)176{177 struct peci_device *device = to_peci_device(dev);178 const struct peci_driver *peci_drv = to_peci_driver(drv);179 180 if (dev->type != &peci_device_type)181 return 0;182 183 return !!peci_bus_match_device_id(peci_drv->id_table, device);184}185 186static int peci_bus_device_probe(struct device *dev)187{188 struct peci_device *device = to_peci_device(dev);189 struct peci_driver *driver = to_peci_driver(dev->driver);190 191 return driver->probe(device, peci_bus_match_device_id(driver->id_table, device));192}193 194static void peci_bus_device_remove(struct device *dev)195{196 struct peci_device *device = to_peci_device(dev);197 struct peci_driver *driver = to_peci_driver(dev->driver);198 199 if (driver->remove)200 driver->remove(device);201}202 203const struct bus_type peci_bus_type = {204 .name = "peci",205 .match = peci_bus_device_match,206 .probe = peci_bus_device_probe,207 .remove = peci_bus_device_remove,208 .bus_groups = peci_bus_groups,209};210 211static int __init peci_init(void)212{213 int ret;214 215 ret = bus_register(&peci_bus_type);216 if (ret < 0) {217 pr_err("peci: failed to register PECI bus type!\n");218 return ret;219 }220 221 return 0;222}223module_init(peci_init);224 225static void __exit peci_exit(void)226{227 bus_unregister(&peci_bus_type);228}229module_exit(peci_exit);230 231MODULE_AUTHOR("Jason M Bills <jason.m.bills@linux.intel.com>");232MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>");233MODULE_AUTHOR("Iwona Winiarska <iwona.winiarska@intel.com>");234MODULE_DESCRIPTION("PECI bus core module");235MODULE_LICENSE("GPL");236