| @@ -44,6 +44,8 @@ early_param("sysfs.deprecated", sysfs_deprecated_setup); · 43 unmodified lines |
| 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); |
| @@ -430,6 +432,58 @@ struct device_link *device_link_add(struct device *consumer, · 380 unmodified lines |
| 430 | 432 | } |
| 431 | 433 | EXPORT_SYMBOL_GPL(device_link_add); |
| 432 | 434 | |
| 435 | +/** |
| 436 | + * device_link_wait_for_supplier - Add device to wait_for_suppliers list |
| 437 | + * @consumer: Consumer device |
| 438 | + * |
| 439 | + * Marks the @consumer device as waiting for suppliers to become available by |
| 440 | + * adding it to the wait_for_suppliers list. The consumer device will never be |
| 441 | + * probed until it's removed from the wait_for_suppliers list. |
| 442 | + * |
| 443 | + * The caller is responsible for adding the links to the supplier devices once |
| 444 | + * they are available and removing the @consumer device from the |
| 445 | + * wait_for_suppliers list once links to all the suppliers have been created. |
| 446 | + * |
| 447 | + * This function is NOT meant to be called from the probe function of the |
| 448 | + * consumer but rather from code that creates/adds the consumer device. |
| 449 | + */ |
| 450 | +static void device_link_wait_for_supplier(struct device *consumer) |
| 451 | +{ |
| 452 | + mutex_lock(&wfs_lock); |
| 453 | + list_add_tail(&consumer->links.needs_suppliers, &wait_for_suppliers); |
| 454 | + mutex_unlock(&wfs_lock); |
| 455 | +} |
| 456 | + |
| 457 | +/** |
| 458 | + * device_link_add_missing_supplier_links - Add links from consumer devices to |
| 459 | + * supplier devices, leaving any |
| 460 | + * consumer with inactive suppliers on |
| 461 | + * the wait_for_suppliers list |
| 462 | + * |
| 463 | + * Loops through all consumers waiting on suppliers and tries to add all their |
| 464 | + * supplier links. If that succeeds, the consumer device is removed from |
| 465 | + * wait_for_suppliers list. Otherwise, they are left in the wait_for_suppliers |
| 466 | + * list. Devices left on the wait_for_suppliers list will not be probed. |
| 467 | + * |
| 468 | + * The fwnode add_links callback is expected to return 0 if it has found and |
| 469 | + * added all the supplier links for the consumer device. It should return an |
| 470 | + * error if it isn't able to do so. |
| 471 | + * |
| 472 | + * The caller of device_link_wait_for_supplier() is expected to call this once |
| 473 | + * it's aware of potential suppliers becoming available. |
| 474 | + */ |
| 475 | +static void device_link_add_missing_supplier_links(void) |
| 476 | +{ |
| 477 | + struct device *dev, *tmp; |
| 478 | + |
| 479 | + mutex_lock(&wfs_lock); |
| 480 | + list_for_each_entry_safe(dev, tmp, &wait_for_suppliers, |
| 481 | + links.needs_suppliers) |
| 482 | + if (!fwnode_call_int_op(dev->fwnode, add_links, dev)) |
| 483 | + list_del_init(&dev->links.needs_suppliers); |
| 484 | + mutex_unlock(&wfs_lock); |
| 485 | +} |
| 486 | + |
| 433 | 487 | static void device_link_free(struct device_link *link) |
| 434 | 488 | { |
| 435 | 489 | while (refcount_dec_not_one(&link->rpm_active)) |
| @@ -564,6 +618,17 @@ int device_links_check_suppliers(struct device *dev) · 128 unmodified lines |
| 564 | 618 | struct device_link *link; |
| 565 | 619 | int ret = 0; |
| 566 | 620 | |
| 621 | + /* |
| 622 | + * Device waiting for supplier to become available is not allowed to |
| 623 | + * probe. |
| 624 | + */ |
| 625 | + mutex_lock(&wfs_lock); |
| 626 | + if (!list_empty(&dev->links.needs_suppliers)) { |
| 627 | + mutex_unlock(&wfs_lock); |
| 628 | + return -EPROBE_DEFER; |
| 629 | + } |
| 630 | + mutex_unlock(&wfs_lock); |
| 631 | + |
| 567 | 632 | device_links_write_lock(); |
| 568 | 633 | |
| 569 | 634 | list_for_each_entry(link, &dev->links.suppliers, c_node) { |
| @@ -848,6 +913,10 @@ static void device_links_purge(struct device *dev) · 278 unmodified lines |
| 848 | 913 | { |
| 849 | 914 | struct device_link *link, *ln; |
| 850 | 915 | |
| 916 | + mutex_lock(&wfs_lock); |
| 917 | + list_del(&dev->links.needs_suppliers); |
| 918 | + mutex_unlock(&wfs_lock); |
| 919 | + |
| 851 | 920 | /* |
| 852 | 921 | * Delete all of the remaining links from this device to any other |
| 853 | 922 | * devices (either consumers or suppliers). |
| @@ -1712,6 +1781,7 @@ void device_initialize(struct device *dev) · 858 unmodified lines |
| 1712 | 1781 | #endif |
| 1713 | 1782 | INIT_LIST_HEAD(&dev->links.consumers); |
| 1714 | 1783 | INIT_LIST_HEAD(&dev->links.suppliers); |
| 1784 | + INIT_LIST_HEAD(&dev->links.needs_suppliers); |
| 1715 | 1785 | dev->links.status = DL_DEV_NO_DRIVER; |
| 1716 | 1786 | } |
| 1717 | 1787 | EXPORT_SYMBOL_GPL(device_initialize); |
| @@ -2202,6 +2272,24 @@ int device_add(struct device *dev) · 484 unmodified lines |
| 2202 | 2272 | if (dev->fwnode && !dev->fwnode->dev) |
| 2203 | 2273 | dev->fwnode->dev = dev; |
| 2204 | 2274 | |
| 2275 | + /* |
| 2276 | + * Check if any of the other devices (consumers) have been waiting for |
| 2277 | + * this device (supplier) to be added so that they can create a device |
| 2278 | + * link to it. |
| 2279 | + * |
| 2280 | + * This needs to happen after device_pm_add() because device_link_add() |
| 2281 | + * requires the supplier be registered before it's called. |
| 2282 | + * |
| 2283 | + * But this also needs to happe before bus_probe_device() to make sure |
| 2284 | + * waiting consumers can link to it before the driver is bound to the |
| 2285 | + * device and the driver sync_state callback is called for this device. |
| 2286 | + */ |
| 2287 | + device_link_add_missing_supplier_links(); |
| 2288 | + |
| 2289 | + if (fwnode_has_op(dev->fwnode, add_links) |
| 2290 | + && fwnode_call_int_op(dev->fwnode, add_links, dev)) |
| 2291 | + device_link_wait_for_supplier(dev); |
| 2292 | + |
| 2205 | 2293 | bus_probe_device(dev); |
| 2206 | 2294 | if (parent) |
| 2207 | 2295 | klist_add_tail(&dev->p->knode_parent, |