aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMartin Liu <liumartin@google.com>2018-05-30 12:31:36 -0400
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>2018-05-31 04:12:07 -0400
commit8c97a46af04b4f7c0a0dded031fef1806872e648 (patch)
tree5405b6d743493ce9fc0ab0a411573531ab33eef3
parent0dda2bb6242361afd68332bf19bd67cd5981eb26 (diff)
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 bf74ad5bc417 ("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 <liumartin@google.com> Acked-by: Alan Stern <stern@rowland.harvard.edu> Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
-rw-r--r--drivers/base/bus.c16
-rw-r--r--drivers/base/dd.c8
-rw-r--r--drivers/usb/core/driver.c1
-rw-r--r--include/linux/device.h3
4 files changed, 16 insertions, 12 deletions
diff --git a/drivers/base/bus.c b/drivers/base/bus.c
index ef6183306b40..8bfd27ec73d6 100644
--- a/drivers/base/bus.c
+++ b/drivers/base/bus.c
@@ -184,10 +184,10 @@ static ssize_t unbind_store(struct device_driver *drv, const char *buf,
184 184
185 dev = bus_find_device_by_name(bus, NULL, buf); 185 dev = bus_find_device_by_name(bus, NULL, buf);
186 if (dev && dev->driver == drv) { 186 if (dev && dev->driver == drv) {
187 if (dev->parent) /* Needed for USB */ 187 if (dev->parent && dev->bus->need_parent_lock)
188 device_lock(dev->parent); 188 device_lock(dev->parent);
189 device_release_driver(dev); 189 device_release_driver(dev);
190 if (dev->parent) 190 if (dev->parent && dev->bus->need_parent_lock)
191 device_unlock(dev->parent); 191 device_unlock(dev->parent);
192 err = count; 192 err = count;
193 } 193 }
@@ -211,12 +211,12 @@ static ssize_t bind_store(struct device_driver *drv, const char *buf,
211 211
212 dev = bus_find_device_by_name(bus, NULL, buf); 212 dev = bus_find_device_by_name(bus, NULL, buf);
213 if (dev && dev->driver == NULL && driver_match_device(drv, dev)) { 213 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)
215 device_lock(dev->parent); 215 device_lock(dev->parent);
216 device_lock(dev); 216 device_lock(dev);
217 err = driver_probe_device(drv, dev); 217 err = driver_probe_device(drv, dev);
218 device_unlock(dev); 218 device_unlock(dev);
219 if (dev->parent) 219 if (dev->parent && bus->need_parent_lock)
220 device_unlock(dev->parent); 220 device_unlock(dev->parent);
221 221
222 if (err > 0) { 222 if (err > 0) {
@@ -735,10 +735,10 @@ static int __must_check bus_rescan_devices_helper(struct device *dev,
735 int ret = 0; 735 int ret = 0;
736 736
737 if (!dev->driver) { 737 if (!dev->driver) {
738 if (dev->parent) /* Needed for USB */ 738 if (dev->parent && dev->bus->need_parent_lock)
739 device_lock(dev->parent); 739 device_lock(dev->parent);
740 ret = device_attach(dev); 740 ret = device_attach(dev);
741 if (dev->parent) 741 if (dev->parent && dev->bus->need_parent_lock)
742 device_unlock(dev->parent); 742 device_unlock(dev->parent);
743 } 743 }
744 return ret < 0 ? ret : 0; 744 return ret < 0 ? ret : 0;
@@ -770,10 +770,10 @@ EXPORT_SYMBOL_GPL(bus_rescan_devices);
770int device_reprobe(struct device *dev) 770int device_reprobe(struct device *dev)
771{ 771{
772 if (dev->driver) { 772 if (dev->driver) {
773 if (dev->parent) /* Needed for USB */ 773 if (dev->parent && dev->bus->need_parent_lock)
774 device_lock(dev->parent); 774 device_lock(dev->parent);
775 device_release_driver(dev); 775 device_release_driver(dev);
776 if (dev->parent) 776 if (dev->parent && dev->bus->need_parent_lock)
777 device_unlock(dev->parent); 777 device_unlock(dev->parent);
778 } 778 }
779 return bus_rescan_devices_helper(dev, NULL); 779 return bus_rescan_devices_helper(dev, NULL);
diff --git a/drivers/base/dd.c b/drivers/base/dd.c
index c9f54089429b..7c09f73b96f3 100644
--- a/drivers/base/dd.c
+++ b/drivers/base/dd.c
@@ -817,13 +817,13 @@ static int __driver_attach(struct device *dev, void *data)
817 return ret; 817 return ret;
818 } /* ret > 0 means positive match */ 818 } /* ret > 0 means positive match */
819 819
820 if (dev->parent) /* Needed for USB */ 820 if (dev->parent && dev->bus->need_parent_lock)
821 device_lock(dev->parent); 821 device_lock(dev->parent);
822 device_lock(dev); 822 device_lock(dev);
823 if (!dev->driver) 823 if (!dev->driver)
824 driver_probe_device(drv, dev); 824 driver_probe_device(drv, dev);
825 device_unlock(dev); 825 device_unlock(dev);
826 if (dev->parent) 826 if (dev->parent && dev->bus->need_parent_lock)
827 device_unlock(dev->parent); 827 device_unlock(dev->parent);
828 828
829 return 0; 829 return 0;
@@ -919,7 +919,7 @@ void device_release_driver_internal(struct device *dev,
919 struct device_driver *drv, 919 struct device_driver *drv,
920 struct device *parent) 920 struct device *parent)
921{ 921{
922 if (parent) 922 if (parent && dev->bus->need_parent_lock)
923 device_lock(parent); 923 device_lock(parent);
924 924
925 device_lock(dev); 925 device_lock(dev);
@@ -927,7 +927,7 @@ void device_release_driver_internal(struct device *dev,
927 __device_release_driver(dev, parent); 927 __device_release_driver(dev, parent);
928 928
929 device_unlock(dev); 929 device_unlock(dev);
930 if (parent) 930 if (parent && dev->bus->need_parent_lock)
931 device_unlock(parent); 931 device_unlock(parent);
932} 932}
933 933
diff --git a/drivers/usb/core/driver.c b/drivers/usb/core/driver.c
index 9792cedfc351..e76e95f62f76 100644
--- a/drivers/usb/core/driver.c
+++ b/drivers/usb/core/driver.c
@@ -1922,4 +1922,5 @@ struct bus_type usb_bus_type = {
1922 .name = "usb", 1922 .name = "usb",
1923 .match = usb_device_match, 1923 .match = usb_device_match,
1924 .uevent = usb_uevent, 1924 .uevent = usb_uevent,
1925 .need_parent_lock = true,
1925}; 1926};
diff --git a/include/linux/device.h b/include/linux/device.h
index 477956990f5e..beca424395dd 100644
--- a/include/linux/device.h
+++ b/include/linux/device.h
@@ -98,6 +98,8 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
98 * @lock_key: Lock class key for use by the lock validator 98 * @lock_key: Lock class key for use by the lock validator
99 * @force_dma: Assume devices on this bus should be set up by dma_configure() 99 * @force_dma: Assume devices on this bus should be set up by dma_configure()
100 * even if DMA capability is not explicitly described by firmware. 100 * 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.
101 * 103 *
102 * A bus is a channel between the processor and one or more devices. For the 104 * A bus is a channel between the processor and one or more devices. For the
103 * purposes of the device model, all devices are connected via a bus, even if 105 * purposes of the device model, all devices are connected via a bus, even if
@@ -138,6 +140,7 @@ struct bus_type {
138 struct lock_class_key lock_key; 140 struct lock_class_key lock_key;
139 141
140 bool force_dma; 142 bool force_dma;
143 bool need_parent_lock;
141}; 144};
142 145
143extern int __must_check bus_register(struct bus_type *bus); 146extern int __must_check bus_register(struct bus_type *bus);