Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

driver core: Add support for linking devices during device addition

The firmware corresponding to a device (dev.fwnode) might be able to
provide functional dependency information between a device and its
supplier and consumer devices. Tracking this functional dependency
allows optimizing device probe order and informing a supplier when all
its consumers have probed (and thereby actively managing their
resources).

The existing device links feature allows tracking and using
supplier-consumer relationships. So, this patch adds the add_links()
fwnode callback to allow firmware to create device links for each
device as the device is added.

However, when consumer devices are added, they might not have a supplier
device to link to despite needing mandatory resources/functionality from
one or more suppliers. A waiting_for_suppliers list is created to track
such consumers and retry linking them when new devices get added.

Signed-off-by: Saravana Kannan <saravanak@google.com>
Link: https://lore.kernel.org/r/20190904211126.47518-3-saravanak@google.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Saravana Kannan and committed by
Greg Kroah-Hartman
e2ae9bcc 372a67c0

+109 -1
+2 -1
Documentation/driver-api/device_link.rst
··· 281 281 :c:func:`driver_bound()`.) 282 282 283 283 * Before a consumer device is probed, presence of supplier drivers is 284 - verified by checking that links to suppliers are in ``DL_STATE_AVAILABLE`` 284 + verified by checking the consumer device is not in the wait_for_suppliers 285 + list and by checking that links to suppliers are in ``DL_STATE_AVAILABLE`` 285 286 state. The state of the links is updated to ``DL_STATE_CONSUMER_PROBE``. 286 287 (Call to :c:func:`device_links_check_suppliers()` from 287 288 :c:func:`really_probe()`.)
+88
drivers/base/core.c
··· 44 44 #endif 45 45 46 46 /* Device links support. */ 47 + static LIST_HEAD(wait_for_suppliers); 48 + static DEFINE_MUTEX(wfs_lock); 47 49 48 50 #ifdef CONFIG_SRCU 49 51 static DEFINE_MUTEX(device_links_lock); ··· 432 430 } 433 431 EXPORT_SYMBOL_GPL(device_link_add); 434 432 433 + /** 434 + * device_link_wait_for_supplier - Add device to wait_for_suppliers list 435 + * @consumer: Consumer device 436 + * 437 + * Marks the @consumer device as waiting for suppliers to become available by 438 + * adding it to the wait_for_suppliers list. The consumer device will never be 439 + * probed until it's removed from the wait_for_suppliers list. 440 + * 441 + * The caller is responsible for adding the links to the supplier devices once 442 + * they are available and removing the @consumer device from the 443 + * wait_for_suppliers list once links to all the suppliers have been created. 444 + * 445 + * This function is NOT meant to be called from the probe function of the 446 + * consumer but rather from code that creates/adds the consumer device. 447 + */ 448 + static void device_link_wait_for_supplier(struct device *consumer) 449 + { 450 + mutex_lock(&wfs_lock); 451 + list_add_tail(&consumer->links.needs_suppliers, &wait_for_suppliers); 452 + mutex_unlock(&wfs_lock); 453 + } 454 + 455 + /** 456 + * device_link_add_missing_supplier_links - Add links from consumer devices to 457 + * supplier devices, leaving any 458 + * consumer with inactive suppliers on 459 + * the wait_for_suppliers list 460 + * 461 + * Loops through all consumers waiting on suppliers and tries to add all their 462 + * supplier links. If that succeeds, the consumer device is removed from 463 + * wait_for_suppliers list. Otherwise, they are left in the wait_for_suppliers 464 + * list. Devices left on the wait_for_suppliers list will not be probed. 465 + * 466 + * The fwnode add_links callback is expected to return 0 if it has found and 467 + * added all the supplier links for the consumer device. It should return an 468 + * error if it isn't able to do so. 469 + * 470 + * The caller of device_link_wait_for_supplier() is expected to call this once 471 + * it's aware of potential suppliers becoming available. 472 + */ 473 + static void device_link_add_missing_supplier_links(void) 474 + { 475 + struct device *dev, *tmp; 476 + 477 + mutex_lock(&wfs_lock); 478 + list_for_each_entry_safe(dev, tmp, &wait_for_suppliers, 479 + links.needs_suppliers) 480 + if (!fwnode_call_int_op(dev->fwnode, add_links, dev)) 481 + list_del_init(&dev->links.needs_suppliers); 482 + mutex_unlock(&wfs_lock); 483 + } 484 + 435 485 static void device_link_free(struct device_link *link) 436 486 { 437 487 while (refcount_dec_not_one(&link->rpm_active)) ··· 617 563 { 618 564 struct device_link *link; 619 565 int ret = 0; 566 + 567 + /* 568 + * Device waiting for supplier to become available is not allowed to 569 + * probe. 570 + */ 571 + mutex_lock(&wfs_lock); 572 + if (!list_empty(&dev->links.needs_suppliers)) { 573 + mutex_unlock(&wfs_lock); 574 + return -EPROBE_DEFER; 575 + } 576 + mutex_unlock(&wfs_lock); 620 577 621 578 device_links_write_lock(); 622 579 ··· 912 847 static void device_links_purge(struct device *dev) 913 848 { 914 849 struct device_link *link, *ln; 850 + 851 + mutex_lock(&wfs_lock); 852 + list_del(&dev->links.needs_suppliers); 853 + mutex_unlock(&wfs_lock); 915 854 916 855 /* 917 856 * Delete all of the remaining links from this device to any other ··· 1781 1712 #endif 1782 1713 INIT_LIST_HEAD(&dev->links.consumers); 1783 1714 INIT_LIST_HEAD(&dev->links.suppliers); 1715 + INIT_LIST_HEAD(&dev->links.needs_suppliers); 1784 1716 dev->links.status = DL_DEV_NO_DRIVER; 1785 1717 } 1786 1718 EXPORT_SYMBOL_GPL(device_initialize); ··· 2271 2201 2272 2202 if (dev->fwnode && !dev->fwnode->dev) 2273 2203 dev->fwnode->dev = dev; 2204 + 2205 + /* 2206 + * Check if any of the other devices (consumers) have been waiting for 2207 + * this device (supplier) to be added so that they can create a device 2208 + * link to it. 2209 + * 2210 + * This needs to happen after device_pm_add() because device_link_add() 2211 + * requires the supplier be registered before it's called. 2212 + * 2213 + * But this also needs to happe before bus_probe_device() to make sure 2214 + * waiting consumers can link to it before the driver is bound to the 2215 + * device and the driver sync_state callback is called for this device. 2216 + */ 2217 + device_link_add_missing_supplier_links(); 2218 + 2219 + if (fwnode_has_op(dev->fwnode, add_links) 2220 + && fwnode_call_int_op(dev->fwnode, add_links, dev)) 2221 + device_link_wait_for_supplier(dev); 2274 2222 2275 2223 bus_probe_device(dev); 2276 2224 if (parent)
+2
include/linux/device.h
··· 1135 1135 * struct dev_links_info - Device data related to device links. 1136 1136 * @suppliers: List of links to supplier devices. 1137 1137 * @consumers: List of links to consumer devices. 1138 + * @needs_suppliers: Hook to global list of devices waiting for suppliers. 1138 1139 * @status: Driver status information. 1139 1140 */ 1140 1141 struct dev_links_info { 1141 1142 struct list_head suppliers; 1142 1143 struct list_head consumers; 1144 + struct list_head needs_suppliers; 1143 1145 enum dl_dev_state status; 1144 1146 }; 1145 1147
+17
include/linux/fwnode.h
··· 66 66 * endpoint node. 67 67 * @graph_get_port_parent: Return the parent node of a port node. 68 68 * @graph_parse_endpoint: Parse endpoint for port and endpoint id. 69 + * @add_links: Called after the device corresponding to the fwnode is added 70 + * using device_add(). The function is expected to create device 71 + * links to all the suppliers of the device that are available at 72 + * the time this function is called. The function must NOT stop 73 + * at the first failed device link if other unlinked supplier 74 + * devices are present in the system. If some suppliers are not 75 + * yet available, this function will be called again when other 76 + * devices are added to allow creating device links to any newly 77 + * available suppliers. 78 + * 79 + * Return 0 if device links have been successfully created to all 80 + * the suppliers of this device or if the supplier information is 81 + * not known. Return an error if and only if the supplier 82 + * information is known but some of the suppliers are not yet 83 + * available to create device links to. 69 84 */ 70 85 struct fwnode_operations { 71 86 struct fwnode_handle *(*get)(struct fwnode_handle *fwnode); ··· 118 103 (*graph_get_port_parent)(struct fwnode_handle *fwnode); 119 104 int (*graph_parse_endpoint)(const struct fwnode_handle *fwnode, 120 105 struct fwnode_endpoint *endpoint); 106 + int (*add_links)(const struct fwnode_handle *fwnode, 107 + struct device *dev); 121 108 }; 122 109 123 110 #define fwnode_has_op(fwnode, op) \