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 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->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 176 static 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 187 static 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 195 static 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 204 struct 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 212 static 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 } 224 module_init(peci_init); 225 226 static void __exit peci_exit(void) 227 { 228 bus_unregister(&peci_bus_type); 229 } 230 module_exit(peci_exit); 231 232 MODULE_AUTHOR("Jason M Bills <jason.m.bills@linux.intel.com>"); 233 MODULE_AUTHOR("Jae Hyun Yoo <jae.hyun.yoo@linux.intel.com>"); 234 MODULE_AUTHOR("Iwona Winiarska <iwona.winiarska@intel.com>"); 235 MODULE_DESCRIPTION("PECI bus core module"); 236 MODULE_LICENSE("GPL"); 237