1 // SPDX-License-Identifier: GPL-2.0+ 2 /* 3 * Surface System Aggregator Module bus and device integration. 4 * 5 * Copyright (C) 2019-2022 Maximilian Luz <luzmaximilian@gmail.com> 6 */ 7 8 #include <linux/device.h> 9 #include <linux/property.h> 10 #include <linux/slab.h> 11 12 #include <linux/surface_aggregator/controller.h> 13 #include <linux/surface_aggregator/device.h> 14 15 #include "bus.h" 16 #include "controller.h" 17 18 19 /* -- Device and bus functions. --------------------------------------------- */ 20 21 static ssize_t modalias_show(struct device *dev, struct device_attribute *attr, 22 char *buf) 23 { 24 struct ssam_device *sdev = to_ssam_device(dev); 25 26 return sysfs_emit(buf, "ssam:d%02Xc%02Xt%02Xi%02Xf%02X\n", 27 sdev->uid.domain, sdev->uid.category, sdev->uid.target, 28 sdev->uid.instance, sdev->uid.function); 29 } 30 static DEVICE_ATTR_RO(modalias); 31 32 static struct attribute *ssam_device_attrs[] = { 33 &dev_attr_modalias.attr, 34 NULL, 35 }; 36 ATTRIBUTE_GROUPS(ssam_device); 37 38 static const struct bus_type ssam_bus_type; 39 40 static int ssam_device_uevent(const struct device *dev, struct kobj_uevent_env *env) 41 { 42 const struct ssam_device *sdev = to_ssam_device(dev); 43 44 return add_uevent_var(env, "MODALIAS=ssam:d%02Xc%02Xt%02Xi%02Xf%02X", 45 sdev->uid.domain, sdev->uid.category, 46 sdev->uid.target, sdev->uid.instance, 47 sdev->uid.function); 48 } 49 50 static void ssam_device_release(struct device *dev) 51 { 52 struct ssam_device *sdev = to_ssam_device(dev); 53 54 ssam_controller_put(sdev->ctrl); 55 fwnode_handle_put(sdev->dev.fwnode); 56 kfree(sdev); 57 } 58 59 const struct device_type ssam_device_type = { 60 .name = "surface_aggregator_device", 61 .groups = ssam_device_groups, 62 .uevent = ssam_device_uevent, 63 .release = ssam_device_release, 64 }; 65 EXPORT_SYMBOL_GPL(ssam_device_type); 66 67 /** 68 * ssam_device_alloc() - Allocate and initialize a SSAM client device. 69 * @ctrl: The controller under which the device should be added. 70 * @uid: The UID of the device to be added. 71 * 72 * Allocates and initializes a new client device. The parent of the device 73 * will be set to the controller device and the name will be set based on the 74 * UID. Note that the device still has to be added via ssam_device_add(). 75 * Refer to that function for more details. 76 * 77 * Return: Returns the newly allocated and initialized SSAM client device, or 78 * %NULL if it could not be allocated. 79 */ 80 struct ssam_device *ssam_device_alloc(struct ssam_controller *ctrl, 81 struct ssam_device_uid uid) 82 { 83 struct ssam_device *sdev; 84 85 sdev = kzalloc(sizeof(*sdev), GFP_KERNEL); 86 if (!sdev) 87 return NULL; 88 89 device_initialize(&sdev->dev); 90 sdev->dev.bus = &ssam_bus_type; 91 sdev->dev.type = &ssam_device_type; 92 sdev->dev.parent = ssam_controller_device(ctrl); 93 sdev->ctrl = ssam_controller_get(ctrl); 94 sdev->uid = uid; 95 96 dev_set_name(&sdev->dev, "%02x:%02x:%02x:%02x:%02x", 97 sdev->uid.domain, sdev->uid.category, sdev->uid.target, 98 sdev->uid.instance, sdev->uid.function); 99 100 return sdev; 101 } 102 EXPORT_SYMBOL_GPL(ssam_device_alloc); 103 104 /** 105 * ssam_device_add() - Add a SSAM client device. 106 * @sdev: The SSAM client device to be added. 107 * 108 * Added client devices must be guaranteed to always have a valid and active 109 * controller. Thus, this function will fail with %-ENODEV if the controller 110 * of the device has not been initialized yet, has been suspended, or has been 111 * shut down. 112 * 113 * The caller of this function should ensure that the corresponding call to 114 * ssam_device_remove() is issued before the controller is shut down. If the 115 * added device is a direct child of the controller device (default), it will 116 * be automatically removed when the controller is shut down. 117 * 118 * By default, the controller device will become the parent of the newly 119 * created client device. The parent may be changed before ssam_device_add is 120 * called, but care must be taken that a) the correct suspend/resume ordering 121 * is guaranteed and b) the client device does not outlive the controller, 122 * i.e. that the device is removed before the controller is being shut down. 123 * In case these guarantees have to be manually enforced, please refer to the 124 * ssam_client_link() and ssam_client_bind() functions, which are intended to 125 * set up device-links for this purpose. 126 * 127 * Return: Returns zero on success, a negative error code on failure. 128 */ 129 int ssam_device_add(struct ssam_device *sdev) 130 { 131 int status; 132 133 /* 134 * Ensure that we can only add new devices to a controller if it has 135 * been started and is not going away soon. This works in combination 136 * with ssam_controller_remove_clients to ensure driver presence for the 137 * controller device, i.e. it ensures that the controller (sdev->ctrl) 138 * is always valid and can be used for requests as long as the client 139 * device we add here is registered as child under it. This essentially 140 * guarantees that the client driver can always expect the preconditions 141 * for functions like ssam_request_do_sync() (controller has to be 142 * started and is not suspended) to hold and thus does not have to check 143 * for them. 144 * 145 * Note that for this to work, the controller has to be a parent device. 146 * If it is not a direct parent, care has to be taken that the device is 147 * removed via ssam_device_remove(), as device_unregister does not 148 * remove child devices recursively. 149 */ 150 ssam_controller_statelock(sdev->ctrl); 151 152 if (sdev->ctrl->state != SSAM_CONTROLLER_STARTED) { 153 ssam_controller_stateunlock(sdev->ctrl); 154 return -ENODEV; 155 } 156 157 status = device_add(&sdev->dev); 158 159 ssam_controller_stateunlock(sdev->ctrl); 160 return status; 161 } 162 EXPORT_SYMBOL_GPL(ssam_device_add); 163 164 /** 165 * ssam_device_remove() - Remove a SSAM client device. 166 * @sdev: The device to remove. 167 * 168 * Removes and unregisters the provided SSAM client device. 169 */ 170 void ssam_device_remove(struct ssam_device *sdev) 171 { 172 device_unregister(&sdev->dev); 173 } 174 EXPORT_SYMBOL_GPL(ssam_device_remove); 175 176 /** 177 * ssam_device_id_compatible() - Check if a device ID matches a UID. 178 * @id: The device ID as potential match. 179 * @uid: The device UID matching against. 180 * 181 * Check if the given ID is a match for the given UID, i.e. if a device with 182 * the provided UID is compatible to the given ID following the match rules 183 * described in its &ssam_device_id.match_flags member. 184 * 185 * Return: Returns %true if the given UID is compatible to the match rule 186 * described by the given ID, %false otherwise. 187 */ 188 static bool ssam_device_id_compatible(const struct ssam_device_id *id, 189 struct ssam_device_uid uid) 190 { 191 if (id->domain != uid.domain || id->category != uid.category) 192 return false; 193 194 if ((id->match_flags & SSAM_MATCH_TARGET) && id->target != uid.target) 195 return false; 196 197 if ((id->match_flags & SSAM_MATCH_INSTANCE) && id->instance != uid.instance) 198 return false; 199 200 if ((id->match_flags & SSAM_MATCH_FUNCTION) && id->function != uid.function) 201 return false; 202 203 return true; 204 } 205 206 /** 207 * ssam_device_id_is_null() - Check if a device ID is null. 208 * @id: The device ID to check. 209 * 210 * Check if a given device ID is null, i.e. all zeros. Used to check for the 211 * end of ``MODULE_DEVICE_TABLE(ssam, ...)`` or similar lists. 212 * 213 * Return: Returns %true if the given ID represents a null ID, %false 214 * otherwise. 215 */ 216 static bool ssam_device_id_is_null(const struct ssam_device_id *id) 217 { 218 return id->match_flags == 0 && 219 id->domain == 0 && 220 id->category == 0 && 221 id->target == 0 && 222 id->instance == 0 && 223 id->function == 0 && 224 id->driver_data == 0; 225 } 226 227 /** 228 * ssam_device_id_match() - Find the matching ID table entry for the given UID. 229 * @table: The table to search in. 230 * @uid: The UID to matched against the individual table entries. 231 * 232 * Find the first match for the provided device UID in the provided ID table 233 * and return it. Returns %NULL if no match could be found. 234 */ 235 const struct ssam_device_id *ssam_device_id_match(const struct ssam_device_id *table, 236 const struct ssam_device_uid uid) 237 { 238 const struct ssam_device_id *id; 239 240 for (id = table; !ssam_device_id_is_null(id); ++id) 241 if (ssam_device_id_compatible(id, uid)) 242 return id; 243 244 return NULL; 245 } 246 EXPORT_SYMBOL_GPL(ssam_device_id_match); 247 248 /** 249 * ssam_device_get_match() - Find and return the ID matching the device in the 250 * ID table of the bound driver. 251 * @dev: The device for which to get the matching ID table entry. 252 * 253 * Find the fist match for the UID of the device in the ID table of the 254 * currently bound driver and return it. Returns %NULL if the device does not 255 * have a driver bound to it, the driver does not have match_table (i.e. it is 256 * %NULL), or there is no match in the driver's match_table. 257 * 258 * This function essentially calls ssam_device_id_match() with the ID table of 259 * the bound device driver and the UID of the device. 260 * 261 * Return: Returns the first match for the UID of the device in the device 262 * driver's match table, or %NULL if no such match could be found. 263 */ 264 const struct ssam_device_id *ssam_device_get_match(const struct ssam_device *dev) 265 { 266 const struct ssam_device_driver *sdrv; 267 268 sdrv = to_ssam_device_driver(dev->dev.driver); 269 if (!sdrv) 270 return NULL; 271 272 if (!sdrv->match_table) 273 return NULL; 274 275 return ssam_device_id_match(sdrv->match_table, dev->uid); 276 } 277 EXPORT_SYMBOL_GPL(ssam_device_get_match); 278 279 /** 280 * ssam_device_get_match_data() - Find the ID matching the device in the 281 * ID table of the bound driver and return its ``driver_data`` member. 282 * @dev: The device for which to get the match data. 283 * 284 * Find the fist match for the UID of the device in the ID table of the 285 * corresponding driver and return its driver_data. Returns %NULL if the 286 * device does not have a driver bound to it, the driver does not have 287 * match_table (i.e. it is %NULL), there is no match in the driver's 288 * match_table, or the match does not have any driver_data. 289 * 290 * This function essentially calls ssam_device_get_match() and, if any match 291 * could be found, returns its ``struct ssam_device_id.driver_data`` member. 292 * 293 * Return: Returns the driver data associated with the first match for the UID 294 * of the device in the device driver's match table, or %NULL if no such match 295 * could be found. 296 */ 297 const void *ssam_device_get_match_data(const struct ssam_device *dev) 298 { 299 const struct ssam_device_id *id; 300 301 id = ssam_device_get_match(dev); 302 if (!id) 303 return NULL; 304 305 return (const void *)id->driver_data; 306 } 307 EXPORT_SYMBOL_GPL(ssam_device_get_match_data); 308 309 static int ssam_bus_match(struct device *dev, const struct device_driver *drv) 310 { 311 const struct ssam_device_driver *sdrv = to_ssam_device_driver(drv); 312 struct ssam_device *sdev = to_ssam_device(dev); 313 314 if (!is_ssam_device(dev)) 315 return 0; 316 317 return !!ssam_device_id_match(sdrv->match_table, sdev->uid); 318 } 319 320 static int ssam_bus_probe(struct device *dev) 321 { 322 return to_ssam_device_driver(dev->driver) 323 ->probe(to_ssam_device(dev)); 324 } 325 326 static void ssam_bus_remove(struct device *dev) 327 { 328 struct ssam_device_driver *sdrv = to_ssam_device_driver(dev->driver); 329 330 if (sdrv->remove) 331 sdrv->remove(to_ssam_device(dev)); 332 } 333 334 static const struct bus_type ssam_bus_type = { 335 .name = "surface_aggregator", 336 .match = ssam_bus_match, 337 .probe = ssam_bus_probe, 338 .remove = ssam_bus_remove, 339 }; 340 341 /** 342 * __ssam_device_driver_register() - Register a SSAM client device driver. 343 * @sdrv: The driver to register. 344 * @owner: The module owning the provided driver. 345 * 346 * Please refer to the ssam_device_driver_register() macro for the normal way 347 * to register a driver from inside its owning module. 348 */ 349 int __ssam_device_driver_register(struct ssam_device_driver *sdrv, 350 struct module *owner) 351 { 352 sdrv->driver.owner = owner; 353 sdrv->driver.bus = &ssam_bus_type; 354 355 /* force drivers to async probe so I/O is possible in probe */ 356 sdrv->driver.probe_type = PROBE_PREFER_ASYNCHRONOUS; 357 358 return driver_register(&sdrv->driver); 359 } 360 EXPORT_SYMBOL_GPL(__ssam_device_driver_register); 361 362 /** 363 * ssam_device_driver_unregister - Unregister a SSAM device driver. 364 * @sdrv: The driver to unregister. 365 */ 366 void ssam_device_driver_unregister(struct ssam_device_driver *sdrv) 367 { 368 driver_unregister(&sdrv->driver); 369 } 370 EXPORT_SYMBOL_GPL(ssam_device_driver_unregister); 371 372 373 /* -- Bus registration. ----------------------------------------------------- */ 374 375 /** 376 * ssam_bus_register() - Register and set-up the SSAM client device bus. 377 */ 378 int ssam_bus_register(void) 379 { 380 return bus_register(&ssam_bus_type); 381 } 382 383 /** 384 * ssam_bus_unregister() - Unregister the SSAM client device bus. 385 */ 386 void ssam_bus_unregister(void) 387 { 388 return bus_unregister(&ssam_bus_type); 389 } 390 391 392 /* -- Helpers for controller and hub devices. ------------------------------- */ 393 394 static int ssam_device_uid_from_string(const char *str, struct ssam_device_uid *uid) 395 { 396 u8 d, tc, tid, iid, fn; 397 int n; 398 399 n = sscanf(str, "%hhx:%hhx:%hhx:%hhx:%hhx", &d, &tc, &tid, &iid, &fn); 400 if (n != 5) 401 return -EINVAL; 402 403 uid->domain = d; 404 uid->category = tc; 405 uid->target = tid; 406 uid->instance = iid; 407 uid->function = fn; 408 409 return 0; 410 } 411 412 static int ssam_get_uid_for_node(struct fwnode_handle *node, struct ssam_device_uid *uid) 413 { 414 const char *str = fwnode_get_name(node); 415 416 /* 417 * To simplify definitions of firmware nodes, we set the device name 418 * based on the UID of the device, prefixed with "ssam:". 419 */ 420 if (strncmp(str, "ssam:", strlen("ssam:")) != 0) 421 return -ENODEV; 422 423 str += strlen("ssam:"); 424 return ssam_device_uid_from_string(str, uid); 425 } 426 427 static int ssam_add_client_device(struct device *parent, struct ssam_controller *ctrl, 428 struct fwnode_handle *node) 429 { 430 struct ssam_device_uid uid; 431 struct ssam_device *sdev; 432 int status; 433 434 status = ssam_get_uid_for_node(node, &uid); 435 if (status) 436 return status; 437 438 sdev = ssam_device_alloc(ctrl, uid); 439 if (!sdev) 440 return -ENOMEM; 441 442 sdev->dev.parent = parent; 443 sdev->dev.fwnode = fwnode_handle_get(node); 444 445 status = ssam_device_add(sdev); 446 if (status) 447 ssam_device_put(sdev); 448 449 return status; 450 } 451 452 /** 453 * __ssam_register_clients() - Register client devices defined under the 454 * given firmware node as children of the given device. 455 * @parent: The parent device under which clients should be registered. 456 * @ctrl: The controller with which client should be registered. 457 * @node: The firmware node holding definitions of the devices to be added. 458 * 459 * Register all clients that have been defined as children of the given root 460 * firmware node as children of the given parent device. The respective child 461 * firmware nodes will be associated with the correspondingly created child 462 * devices. 463 * 464 * The given controller will be used to instantiate the new devices. See 465 * ssam_device_add() for details. 466 * 467 * Note that, generally, the use of either ssam_device_register_clients() or 468 * ssam_register_clients() should be preferred as they directly use the 469 * firmware node and/or controller associated with the given device. This 470 * function is only intended for use when different device specifications (e.g. 471 * ACPI and firmware nodes) need to be combined (as is done in the platform hub 472 * of the device registry). 473 * 474 * Return: Returns zero on success, nonzero on failure. 475 */ 476 int __ssam_register_clients(struct device *parent, struct ssam_controller *ctrl, 477 struct fwnode_handle *node) 478 { 479 struct fwnode_handle *child; 480 int status; 481 482 fwnode_for_each_child_node(node, child) { 483 /* 484 * Try to add the device specified in the firmware node. If 485 * this fails with -ENODEV, the node does not specify any SSAM 486 * device, so ignore it and continue with the next one. 487 */ 488 status = ssam_add_client_device(parent, ctrl, child); 489 if (status && status != -ENODEV) { 490 fwnode_handle_put(child); 491 goto err; 492 } 493 } 494 495 return 0; 496 err: 497 ssam_remove_clients(parent); 498 return status; 499 } 500 EXPORT_SYMBOL_GPL(__ssam_register_clients); 501 502 static int ssam_remove_device(struct device *dev, void *_data) 503 { 504 struct ssam_device *sdev = to_ssam_device(dev); 505 506 if (is_ssam_device(dev)) 507 ssam_device_remove(sdev); 508 509 return 0; 510 } 511 512 /** 513 * ssam_remove_clients() - Remove SSAM client devices registered as direct 514 * children under the given parent device. 515 * @dev: The (parent) device to remove all direct clients for. 516 * 517 * Remove all SSAM client devices registered as direct children under the given 518 * device. Note that this only accounts for direct children of the device. 519 * Refer to ssam_device_add()/ssam_device_remove() for more details. 520 */ 521 void ssam_remove_clients(struct device *dev) 522 { 523 device_for_each_child_reverse(dev, NULL, ssam_remove_device); 524 } 525 EXPORT_SYMBOL_GPL(ssam_remove_clients); 526