Skip to content

Commit 8c97a46

Browse files
martinliu628gregkh
authored andcommitted
driver core: hold dev's parent lock when needed
SoC have internal I/O buses that can't be proved for devices. The devices on the buses can be accessed directly without additinal configuration required. This type of bus is represented as "simple-bus". In some platforms, we name "soc" with "simple-bus" attribute and many devices are hooked under it described in DT (device tree). In commit bf74ad5 ("Hold the device's parent's lock during probe and remove") to solve USB subsystem lock sequence since USB device's characteristic. Thus "soc" needs to be locked whenever a device and driver's probing happen under "soc" bus. During this period, an async driver tries to probe a device which is under the "soc" bus would be blocked until previous driver finish the probing and release "soc" lock. And the next probing under the "soc" bus need to wait for async finish. Because of that, driver's async probe for init time improvement will be shadowed. Since many devices don't have USB devices' characteristic, they actually don't need parent's lock. Thus, we introduce a lock flag in bus_type struct and driver core would lock the parent lock base on the flag. For USB, we set this flag in usb_bus_type to keep original lock behavior in driver core. Async probe could have more benefit after this patch. Signed-off-by: Martin Liu <[email protected]> Acked-by: Alan Stern <[email protected]> Signed-off-by: Greg Kroah-Hartman <[email protected]>
1 parent 0dda2bb commit 8c97a46

File tree

4 files changed

+16
-12
lines changed

4 files changed

+16
-12
lines changed

drivers/base/bus.c

Lines changed: 8 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -184,10 +184,10 @@ static ssize_t unbind_store(struct device_driver *drv, const char *buf,
184184

185185
dev = bus_find_device_by_name(bus, NULL, buf);
186186
if (dev && dev->driver == drv) {
187-
if (dev->parent) /* Needed for USB */
187+
if (dev->parent && dev->bus->need_parent_lock)
188188
device_lock(dev->parent);
189189
device_release_driver(dev);
190-
if (dev->parent)
190+
if (dev->parent && dev->bus->need_parent_lock)
191191
device_unlock(dev->parent);
192192
err = count;
193193
}
@@ -211,12 +211,12 @@ static ssize_t bind_store(struct device_driver *drv, const char *buf,
211211

212212
dev = bus_find_device_by_name(bus, NULL, buf);
213213
if (dev && dev->driver == NULL && driver_match_device(drv, dev)) {
214-
if (dev->parent) /* Needed for USB */
214+
if (dev->parent && bus->need_parent_lock)
215215
device_lock(dev->parent);
216216
device_lock(dev);
217217
err = driver_probe_device(drv, dev);
218218
device_unlock(dev);
219-
if (dev->parent)
219+
if (dev->parent && bus->need_parent_lock)
220220
device_unlock(dev->parent);
221221

222222
if (err > 0) {
@@ -735,10 +735,10 @@ static int __must_check bus_rescan_devices_helper(struct device *dev,
735735
int ret = 0;
736736

737737
if (!dev->driver) {
738-
if (dev->parent) /* Needed for USB */
738+
if (dev->parent && dev->bus->need_parent_lock)
739739
device_lock(dev->parent);
740740
ret = device_attach(dev);
741-
if (dev->parent)
741+
if (dev->parent && dev->bus->need_parent_lock)
742742
device_unlock(dev->parent);
743743
}
744744
return ret < 0 ? ret : 0;
@@ -770,10 +770,10 @@ EXPORT_SYMBOL_GPL(bus_rescan_devices);
770770
int device_reprobe(struct device *dev)
771771
{
772772
if (dev->driver) {
773-
if (dev->parent) /* Needed for USB */
773+
if (dev->parent && dev->bus->need_parent_lock)
774774
device_lock(dev->parent);
775775
device_release_driver(dev);
776-
if (dev->parent)
776+
if (dev->parent && dev->bus->need_parent_lock)
777777
device_unlock(dev->parent);
778778
}
779779
return bus_rescan_devices_helper(dev, NULL);

drivers/base/dd.c

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -817,13 +817,13 @@ static int __driver_attach(struct device *dev, void *data)
817817
return ret;
818818
} /* ret > 0 means positive match */
819819

820-
if (dev->parent) /* Needed for USB */
820+
if (dev->parent && dev->bus->need_parent_lock)
821821
device_lock(dev->parent);
822822
device_lock(dev);
823823
if (!dev->driver)
824824
driver_probe_device(drv, dev);
825825
device_unlock(dev);
826-
if (dev->parent)
826+
if (dev->parent && dev->bus->need_parent_lock)
827827
device_unlock(dev->parent);
828828

829829
return 0;
@@ -919,15 +919,15 @@ void device_release_driver_internal(struct device *dev,
919919
struct device_driver *drv,
920920
struct device *parent)
921921
{
922-
if (parent)
922+
if (parent && dev->bus->need_parent_lock)
923923
device_lock(parent);
924924

925925
device_lock(dev);
926926
if (!drv || drv == dev->driver)
927927
__device_release_driver(dev, parent);
928928

929929
device_unlock(dev);
930-
if (parent)
930+
if (parent && dev->bus->need_parent_lock)
931931
device_unlock(parent);
932932
}
933933

drivers/usb/core/driver.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1922,4 +1922,5 @@ struct bus_type usb_bus_type = {
19221922
.name = "usb",
19231923
.match = usb_device_match,
19241924
.uevent = usb_uevent,
1925+
.need_parent_lock = true,
19251926
};

include/linux/device.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -98,6 +98,8 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
9898
* @lock_key: Lock class key for use by the lock validator
9999
* @force_dma: Assume devices on this bus should be set up by dma_configure()
100100
* even if DMA capability is not explicitly described by firmware.
101+
* @need_parent_lock: When probing or removing a device on this bus, the
102+
* device core should lock the device's parent.
101103
*
102104
* A bus is a channel between the processor and one or more devices. For the
103105
* purposes of the device model, all devices are connected via a bus, even if
@@ -138,6 +140,7 @@ struct bus_type {
138140
struct lock_class_key lock_key;
139141

140142
bool force_dma;
143+
bool need_parent_lock;
141144
};
142145

143146
extern int __must_check bus_register(struct bus_type *bus);

0 commit comments

Comments
 (0)