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 17 static DEFINE_IDA(peci_controller_ida); 18 19 static 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 28 const struct device_type peci_controller_type = { 29 .release = peci_controller_dev_release, 30 }; 31 32 int 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 46 static 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 76 err: 77 kfree(controller); 78 return ERR_PTR(ret); 79 } 80 81 static int unregister_child(struct device *dev, void *dummy) 82 { 83 peci_device_destroy(to_peci_device(dev)); 84 85 return 0; 86 } 87 88 static 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 */ 115 struct 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 for 145 * controller itself. 146 */ 147 peci_controller_scan_devices(controller); 148 149 return controller; 150 151 err_fwnode: 152 fwnode_handle_put(controller->dev.fwnode); 153 154 pm_runtime_disable(&controller->dev); 155 156 err_put: 157 put_device(&controller->dev); 158 159 return ERR_PTR(ret); 160 } 161 EXPORT_SYMBOL_NS_GPL(devm_peci_controller_add, PECI); 162 163 static const struct peci_device_id * 164 peci_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 175 static 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 186 static 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 194 static 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 203 const 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 211 static 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 } 223 module_init(peci_init); 224 225 static void __exit peci_exit(void) 226 { 227 bus_unregister(&peci_bus_type); 228 } 229 module_exit(peci_exit); 230 231 MODULE_AUTHOR("Jason M Bills <jason.m.bills@linux.intel.com>"); 232 MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>"); 233 MODULE_AUTHOR("Iwona Winiarska <iwona.winiarska@intel.com>"); 234 MODULE_DESCRIPTION("PECI bus core module"); 235 MODULE_LICENSE("GPL"); 236