[RFC][PATCH] add driver matching priorities

From: Adam Belay
Date: Fri Jan 28 2005 - 17:42:38 EST


Hi,

This patch adds initial support for driver matching priorities to the
driver model. It is needed for my work on converting the pci bridge
driver to use "struct device_driver". It may also be helpful for driver
with more complex (or long id lists as I've seen in many cases) matching
criteria.

"match" has been added to "struct device_driver". There are now two
steps in the matching process. The first step is a bus specific filter
that determines possible driver candidates. The second step is a driver
specific match function that verifies if the driver will work with the
hardware, and returns a priority code (how well it is able to handle the
device). The bus layer could override the driver's match function if
necessary (similar to how it passes *probe through it's layer and then
on to the actual driver).

The current priorities are as follows:

enum {
MATCH_PRIORITY_FAILURE = 0,
MATCH_PRIORITY_GENERIC,
MATCH_PRIORITY_NORMAL,
MATCH_PRIORITY_VENDOR,
};

let me know if any of this would need to be changed. For example, the
"struct bus_type" match function could return a priority code.

Of course this patch is not going to be effective alone. We also need
to change the init order. If a driver is registered early but isn't the
best available, it will be bound to the device prematurely. This would
be a problem for carbus (yenta) bridges.

I think we may have to load all in kernel drivers first, and then begin
matching them to hardware. Do you agree? If so, I'd be happy to make a
patch for that too.

Thanks,
Adam


--- a/drivers/base/bus.c 2005-01-20 17:37:46.000000000 -0500
+++ b/drivers/base/bus.c 2005-01-28 16:59:00.000000000 -0500
@@ -286,6 +286,9 @@
if (drv->bus->match && !drv->bus->match(dev, drv))
return -ENODEV;

+ if (drv->match && !drv->match(dev))
+ return -ENODEV;
+
dev->driver = drv;
if (drv->probe) {
int error = drv->probe(dev);
@@ -299,6 +302,42 @@
return 0;
}

+/**
+ * driver_probe_device_priority - attempt to bind device & driver with a
+ * given match level priority
+ * @drv: driver.
+ * @dev: device.
+ * @priority the match level priority
+ */
+
+static int driver_probe_device_priority(struct device_driver * drv,
+ struct device * dev, int priority)
+{
+ int matchp;
+
+ if (drv->bus->match && !drv->bus->match(dev, drv))
+ return -ENODEV;
+
+ if (drv->match) {
+ matchp = drv->match(dev);
+ } else
+ matchp = MATCH_PRIORITY_NORMAL;
+
+ if (matchp != priority)
+ return -ENODEV;
+
+ dev->driver = drv;
+ if (drv->probe) {
+ int error = drv->probe(dev);
+ if (error) {
+ dev->driver = NULL;
+ return error;
+ }
+ }
+
+ device_bind_driver(dev);
+ return 0;
+}

/**
* device_attach - try to attach device to a driver.
@@ -312,17 +351,20 @@
{
struct bus_type * bus = dev->bus;
struct list_head * entry;
- int error;
+ int error, matchp = MATCH_PRIORITY_VENDOR;

if (dev->driver) {
device_bind_driver(dev);
return 1;
}

- if (bus->match) {
+ if (!bus->match)
+ return 0;
+
+ while (matchp > 0) {
list_for_each(entry, &bus->drivers.list) {
struct device_driver * drv = to_drv(entry);
- error = driver_probe_device(drv, dev);
+ error = driver_probe_device_priority(drv, dev, matchp);
if (!error)
/* success, driver matched */
return 1;
@@ -332,6 +374,7 @@
"%s: probe of %s failed with error %d\n",
drv->name, dev->bus_id, error);
}
+ matchp--;
}

return 0;
--- a/include/linux/device.h 2005-01-20 17:37:26.000000000 -0500
+++ b/include/linux/device.h 2005-01-28 16:40:22.000000000 -0500
@@ -41,6 +41,13 @@
RESUME_ENABLE,
};

+enum {
+ MATCH_PRIORITY_FAILURE = 0,
+ MATCH_PRIORITY_GENERIC,
+ MATCH_PRIORITY_NORMAL,
+ MATCH_PRIORITY_VENDOR,
+};
+
struct device;
struct device_driver;
struct class;
@@ -108,6 +115,7 @@

struct module * owner;

+ int (*match) (struct device * dev);
int (*probe) (struct device * dev);
int (*remove) (struct device * dev);
void (*shutdown) (struct device * dev);



-
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/