Skip to content

Commit fc5a251

Browse files
Saravana Kannangregkh
authored andcommitted
driver core: Add sync_state driver/bus callback
This sync_state driver/bus callback is called once all the consumers of a supplier have probed successfully. This allows the supplier device's driver/bus to sync the supplier device's state to the software state with the guarantee that all the consumers are actively managing the resources provided by the supplier device. To maintain backwards compatibility and ease transition from existing frameworks and resource cleanup schemes, late_initcall_sync is the earliest when the sync_state callback might be called. There is no upper bound on the time by which the sync_state callback has to be called. This is because if a consumer device never probes, the supplier has to maintain its resources in the state left by the bootloader. For example, if the bootloader leaves the display backlight at a fixed voltage and the backlight driver is never probed, you don't want the backlight to ever be turned off after boot up. Also, when multiple devices are added after kernel init, some suppliers could be added before their consumer devices get added. In these instances, the supplier devices could get their sync_state callback called right after they probe because the consumers devices haven't had a chance to create device links to the suppliers. To handle this correctly, this change also provides APIs to pause/resume sync state callbacks so that when multiple devices are added, their sync_state callback evaluation can be postponed to happen after all of them are added. kbuild test robot reported missing documentation for device.state_synced Reported-by: kbuild test robot <[email protected]> Signed-off-by: Saravana Kannan <[email protected]> Link: https://lore.kernel.org/r/[email protected] Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent a3e1d1a commit fc5a251

File tree

2 files changed

+96
-0
lines changed

2 files changed

+96
-0
lines changed

drivers/base/core.c

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@ early_param("sysfs.deprecated", sysfs_deprecated_setup);
4646
/* Device links support. */
4747
static LIST_HEAD(wait_for_suppliers);
4848
static DEFINE_MUTEX(wfs_lock);
49+
static LIST_HEAD(deferred_sync);
50+
static unsigned int defer_sync_state_count = 1;
4951

5052
#ifdef CONFIG_SRCU
5153
static DEFINE_MUTEX(device_links_lock);
@@ -648,6 +650,69 @@ int device_links_check_suppliers(struct device *dev)
648650
return ret;
649651
}
650652

653+
static void __device_links_supplier_sync_state(struct device *dev)
654+
{
655+
struct device_link *link;
656+
657+
if (dev->state_synced)
658+
return;
659+
660+
list_for_each_entry(link, &dev->links.consumers, s_node) {
661+
if (!(link->flags & DL_FLAG_MANAGED))
662+
continue;
663+
if (link->status != DL_STATE_ACTIVE)
664+
return;
665+
}
666+
667+
if (dev->bus->sync_state)
668+
dev->bus->sync_state(dev);
669+
else if (dev->driver && dev->driver->sync_state)
670+
dev->driver->sync_state(dev);
671+
672+
dev->state_synced = true;
673+
}
674+
675+
void device_links_supplier_sync_state_pause(void)
676+
{
677+
device_links_write_lock();
678+
defer_sync_state_count++;
679+
device_links_write_unlock();
680+
}
681+
682+
void device_links_supplier_sync_state_resume(void)
683+
{
684+
struct device *dev, *tmp;
685+
686+
device_links_write_lock();
687+
if (!defer_sync_state_count) {
688+
WARN(true, "Unmatched sync_state pause/resume!");
689+
goto out;
690+
}
691+
defer_sync_state_count--;
692+
if (defer_sync_state_count)
693+
goto out;
694+
695+
list_for_each_entry_safe(dev, tmp, &deferred_sync, links.defer_sync) {
696+
__device_links_supplier_sync_state(dev);
697+
list_del_init(&dev->links.defer_sync);
698+
}
699+
out:
700+
device_links_write_unlock();
701+
}
702+
703+
static int sync_state_resume_initcall(void)
704+
{
705+
device_links_supplier_sync_state_resume();
706+
return 0;
707+
}
708+
late_initcall(sync_state_resume_initcall);
709+
710+
static void __device_links_supplier_defer_sync(struct device *sup)
711+
{
712+
if (list_empty(&sup->links.defer_sync))
713+
list_add_tail(&sup->links.defer_sync, &deferred_sync);
714+
}
715+
651716
/**
652717
* device_links_driver_bound - Update device links after probing its driver.
653718
* @dev: Device to update the links for.
@@ -692,6 +757,11 @@ void device_links_driver_bound(struct device *dev)
692757

693758
WARN_ON(link->status != DL_STATE_CONSUMER_PROBE);
694759
WRITE_ONCE(link->status, DL_STATE_ACTIVE);
760+
761+
if (defer_sync_state_count)
762+
__device_links_supplier_defer_sync(link->supplier);
763+
else
764+
__device_links_supplier_sync_state(link->supplier);
695765
}
696766

697767
dev->links.status = DL_DEV_DRIVER_BOUND;
@@ -808,6 +878,7 @@ void device_links_driver_cleanup(struct device *dev)
808878
WRITE_ONCE(link->status, DL_STATE_DORMANT);
809879
}
810880

881+
list_del_init(&dev->links.defer_sync);
811882
__device_links_no_driver(dev);
812883

813884
device_links_write_unlock();
@@ -1782,6 +1853,7 @@ void device_initialize(struct device *dev)
17821853
INIT_LIST_HEAD(&dev->links.consumers);
17831854
INIT_LIST_HEAD(&dev->links.suppliers);
17841855
INIT_LIST_HEAD(&dev->links.needs_suppliers);
1856+
INIT_LIST_HEAD(&dev->links.defer_sync);
17851857
dev->links.status = DL_DEV_NO_DRIVER;
17861858
}
17871859
EXPORT_SYMBOL_GPL(device_initialize);

include/linux/device.h

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -80,6 +80,13 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
8080
* that generate uevents to add the environment variables.
8181
* @probe: Called when a new device or driver add to this bus, and callback
8282
* the specific driver's probe to initial the matched device.
83+
* @sync_state: Called to sync device state to software state after all the
84+
* state tracking consumers linked to this device (present at
85+
* the time of late_initcall) have successfully bound to a
86+
* driver. If the device has no consumers, this function will
87+
* be called at late_initcall_sync level. If the device has
88+
* consumers that are never bound to a driver, this function
89+
* will never get called until they do.
8390
* @remove: Called when a device removed from this bus.
8491
* @shutdown: Called at shut-down time to quiesce the device.
8592
*
@@ -123,6 +130,7 @@ struct bus_type {
123130
int (*match)(struct device *dev, struct device_driver *drv);
124131
int (*uevent)(struct device *dev, struct kobj_uevent_env *env);
125132
int (*probe)(struct device *dev);
133+
void (*sync_state)(struct device *dev);
126134
int (*remove)(struct device *dev);
127135
void (*shutdown)(struct device *dev);
128136

@@ -340,6 +348,13 @@ enum probe_type {
340348
* @probe: Called to query the existence of a specific device,
341349
* whether this driver can work with it, and bind the driver
342350
* to a specific device.
351+
* @sync_state: Called to sync device state to software state after all the
352+
* state tracking consumers linked to this device (present at
353+
* the time of late_initcall) have successfully bound to a
354+
* driver. If the device has no consumers, this function will
355+
* be called at late_initcall_sync level. If the device has
356+
* consumers that are never bound to a driver, this function
357+
* will never get called until they do.
343358
* @remove: Called when the device is removed from the system to
344359
* unbind a device from this driver.
345360
* @shutdown: Called at shut-down time to quiesce the device.
@@ -379,6 +394,7 @@ struct device_driver {
379394
const struct acpi_device_id *acpi_match_table;
380395

381396
int (*probe) (struct device *dev);
397+
void (*sync_state)(struct device *dev);
382398
int (*remove) (struct device *dev);
383399
void (*shutdown) (struct device *dev);
384400
int (*suspend) (struct device *dev, pm_message_t state);
@@ -1136,12 +1152,14 @@ enum dl_dev_state {
11361152
* @suppliers: List of links to supplier devices.
11371153
* @consumers: List of links to consumer devices.
11381154
* @needs_suppliers: Hook to global list of devices waiting for suppliers.
1155+
* @defer_sync: Hook to global list of devices that have deferred sync_state.
11391156
* @status: Driver status information.
11401157
*/
11411158
struct dev_links_info {
11421159
struct list_head suppliers;
11431160
struct list_head consumers;
11441161
struct list_head needs_suppliers;
1162+
struct list_head defer_sync;
11451163
enum dl_dev_state status;
11461164
};
11471165

@@ -1217,6 +1235,9 @@ struct dev_links_info {
12171235
* @offline: Set after successful invocation of bus type's .offline().
12181236
* @of_node_reused: Set if the device-tree node is shared with an ancestor
12191237
* device.
1238+
* @state_synced: The hardware state of this device has been synced to match
1239+
* the software state of this device by calling the driver/bus
1240+
* sync_state() callback.
12201241
* @dma_coherent: this particular device is dma coherent, even if the
12211242
* architecture supports non-coherent devices.
12221243
*
@@ -1313,6 +1334,7 @@ struct device {
13131334
bool offline_disabled:1;
13141335
bool offline:1;
13151336
bool of_node_reused:1;
1337+
bool state_synced:1;
13161338
#if defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_DEVICE) || \
13171339
defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU) || \
13181340
defined(CONFIG_ARCH_HAS_SYNC_DMA_FOR_CPU_ALL)
@@ -1655,6 +1677,8 @@ struct device_link *device_link_add(struct device *consumer,
16551677
struct device *supplier, u32 flags);
16561678
void device_link_del(struct device_link *link);
16571679
void device_link_remove(void *consumer, struct device *supplier);
1680+
void device_links_supplier_sync_state_pause(void);
1681+
void device_links_supplier_sync_state_resume(void);
16581682

16591683
#ifndef dev_fmt
16601684
#define dev_fmt(fmt) fmt

0 commit comments

Comments
 (0)