Skip to content

Commit

Permalink
ARM: 8524/1: driver cohandle -EPROBE_DEFER from bus_type.match()
Browse files Browse the repository at this point in the history
Allow implementations of the match() callback in struct bus_type to
return errors and if it's -EPROBE_DEFER then queue the device for
deferred probing.

This is useful to buses such as AMBA in which devices are registered
before their matching information can be retrieved from the HW
(typically because a clock driver hasn't probed yet).

[changed if-else code structure, adjusted documentation to match the code,
extended comments]

Signed-off-by: Tomeu Vizoso <tomeu.vizoso@collabora.com>
Signed-off-by: Marek Szyprowski <m.szyprowski@samsung.com>
Reviewed-by: Ulf Hansson <ulf.hansson@linaro.org>
Acked-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
  • Loading branch information
tomeuv authored and Russell King committed Feb 16, 2016
1 parent 17f29d3 commit 656b803
Show file tree
Hide file tree
Showing 3 changed files with 31 additions and 6 deletions.
6 changes: 4 additions & 2 deletions Documentation/driver-model/porting.txt
Original file line number Diff line number Diff line change
Expand Up @@ -340,8 +340,10 @@ comparison:

int (*match)(struct device * dev, struct device_driver * drv);

match should return '1' if the driver supports the device, and '0'
otherwise.
match should return positive value if the driver supports the device,
and zero otherwise. It may also return error code (for example
-EPROBE_DEFER) if determining that given driver supports the device is
not possible.

When a device is registered, the bus's list of drivers is iterated
over. bus->match() is called for each one until a match is found.
Expand Down
24 changes: 22 additions & 2 deletions drivers/base/dd.c
Original file line number Diff line number Diff line change
Expand Up @@ -560,6 +560,7 @@ static int __device_attach_driver(struct device_driver *drv, void *_data)
struct device_attach_data *data = _data;
struct device *dev = data->dev;
bool async_allowed;
int ret;

/*
* Check if device has already been claimed. This may
Expand All @@ -570,8 +571,17 @@ static int __device_attach_driver(struct device_driver *drv, void *_data)
if (dev->driver)
return -EBUSY;

if (!driver_match_device(drv, dev))
ret = driver_match_device(drv, dev);
if (ret == 0) {
/* no match */
return 0;
} else if (ret == -EPROBE_DEFER) {
dev_dbg(dev, "Device match requests probe deferral\n");
driver_deferred_probe_add(dev);
} else if (ret < 0) {
dev_dbg(dev, "Bus failed to match device: %d", ret);
return ret;
} /* ret > 0 means positive match */

async_allowed = driver_allows_async_probing(drv);

Expand Down Expand Up @@ -691,6 +701,7 @@ void device_initial_probe(struct device *dev)
static int __driver_attach(struct device *dev, void *data)
{
struct device_driver *drv = data;
int ret;

/*
* Lock device and try to bind to it. We drop the error
Expand All @@ -702,8 +713,17 @@ static int __driver_attach(struct device *dev, void *data)
* is an error.
*/

if (!driver_match_device(drv, dev))
ret = driver_match_device(drv, dev);
if (ret == 0) {
/* no match */
return 0;
} else if (ret == -EPROBE_DEFER) {
dev_dbg(dev, "Device match requests probe deferral\n");
driver_deferred_probe_add(dev);
} else if (ret < 0) {
dev_dbg(dev, "Bus failed to match device: %d", ret);
return ret;
} /* ret > 0 means positive match */

if (dev->parent) /* Needed for USB */
device_lock(dev->parent);
Expand Down
7 changes: 5 additions & 2 deletions include/linux/device.h
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,11 @@ extern void bus_remove_file(struct bus_type *, struct bus_attribute *);
* @dev_groups: Default attributes of the devices on the bus.
* @drv_groups: Default attributes of the device drivers on the bus.
* @match: Called, perhaps multiple times, whenever a new device or driver
* is added for this bus. It should return a nonzero value if the
* given device can be handled by the given driver.
* is added for this bus. It should return a positive value if the
* given device can be handled by the given driver and zero
* otherwise. It may also return error code if determining that
* the driver supports the device is not possible. In case of
* -EPROBE_DEFER it will queue the device for deferred probing.
* @uevent: Called when a device is added, removed, or a few other things
* that generate uevents to add the environment variables.
* @probe: Called when a new device or driver add to this bus, and callback
Expand Down

0 comments on commit 656b803

Please sign in to comment.