Date: Tue, 3 Jul 2007 13:28:53 GMT From: Maxim Zhuravlev <thioretic@FreeBSD.org> To: Perforce Change Reviews <perforce@FreeBSD.org> Subject: PERFORCE change 122775 for review Message-ID: <200707031328.l63DSrEm056929@repoman.freebsd.org>
next in thread | raw e-mail | index | archive | help
http://perforce.freebsd.org/chv.cgi?CH=122775 Change 122775 by thioretic@thioretic on 2007/07/03 13:28:45 Yeserday's attempt failed. So now there is being intoduced the compatibility layer to newbus (drv_compat_*). It's supposed to be a more *delicate* way to let old- and new-*fashioned* drivers to coexist. Overwise all those current drivers could just fall on my head. :o) Affected files ... .. //depot/projects/soc2007/thioretic_gidl/TODO#5 edit .. //depot/projects/soc2007/thioretic_gidl/kern/subr_bus.c#4 edit Differences ... ==== //depot/projects/soc2007/thioretic_gidl/TODO#5 (text+ko) ==== @@ -48,9 +48,10 @@ FILE(S) AFFECTED: kern/sns_drivers.c a. ADD a.1.drivers - SOLUTION: modify newbus so that it's aware about stacked - structure of a device. + SOLUTION: add compatibility layer to newbus FILE(S) AFFECTED: sys/bus.h, kern/subr_bus.c # since now internally (and externally) for newbus, driver is # not just kernel object class to be compiled into device, but - # also has flags, default driversops (TODO)... + # also has flags, default driversops (TODO)... + # all these are hosted by compatibility layer (drv_compat_*) +#TODO: check drivers, which use chainevh ==== //depot/projects/soc2007/thioretic_gidl/kern/subr_bus.c#4 (text+ko) ==== @@ -63,17 +63,23 @@ */ typedef struct driverlink *driverlink_t; struct driverlink { -// kobj_class_t driver; - drv_internal_t driver; + kobj_class_t driver; TAILQ_ENTRY(driverlink) link; /* list of drivers in devclass */ }; +struct drv_compat { + kobj_class_t driver; + uint32_t flags; + TAILQ_ENTRY(drv_compat) link; +}; +typedef struct drv_compat *drv_compat_t; /* * Forward declarations */ typedef TAILQ_HEAD(devclass_list, devclass) devclass_list_t; typedef TAILQ_HEAD(driver_list, driverlink) driver_list_t; typedef TAILQ_HEAD(device_list, device) device_list_t; +typedef TAILQ_HEAD(drv_compat_list, drv_compat) drv_compat_list_t; struct devclass { TAILQ_ENTRY(devclass) link; @@ -108,9 +114,10 @@ /* * Details of this device. */ -// driver_t *driver; /**< current driver */ - driver_list_t drivers[DRV_LEVELS]; /**< list of all drivers in stack*/ - devclass_t devclass; /**< current device class */ /*TODO*/ + //driver_t *driver; /**< current driver */ + driver_list_t drivers[DRV_LEVELS]; + int drv_compat_flags; + devclass_t devclass; /**< current device class */ int unit; /**< current unit number */ char* nameunit; /**< name+unit e.g. foodev0 */ char* desc; /**< driver specific description */ @@ -241,10 +248,8 @@ { device_t dev = (device_t)arg1; const char *value; - char *buf, *tmpbuf; + char *buf; int error; - int level; - driverlink_t dl; buf = NULL; switch (arg2) { @@ -264,9 +269,9 @@ } if (strlen(tmpbuf)+strlen(buf)>1023) break; TAILQ_FOREACH(dl,&((dev->drivers)[level]),link){ - if(strlen(dl->driver->devops->name)+strlen(buf)>1022) + if(strlen(dl->driver->name)+strlen(buf)>1022) break; - strcat(buf,dl->driver->devops->name); + strcat(buf,dl->driver->name); strcat(buf,","); } buf[strlen(buf)]='\0'; @@ -311,10 +316,10 @@ OID_AUTO, "%desc", CTLFLAG_RD, dev, DEVICE_SYSCTL_DESC, device_sysctl_handler, "A", "device description"); - SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), /**TODO*/ + SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), OID_AUTO, "%driver", CTLFLAG_RD, dev, DEVICE_SYSCTL_DRIVER, device_sysctl_handler, "A", - "device stacked drivers names"); + "device driver name"); /*TODO*/ SYSCTL_ADD_PROC(&dev->sysctl_ctx, SYSCTL_CHILDREN(dev->sysctl_tree), OID_AUTO, "%location", CTLFLAG_RD, dev, DEVICE_SYSCTL_LOCATION, device_sysctl_handler, "A", @@ -755,6 +760,161 @@ DEFINE_CLASS(null, null_methods, 0); /* + * Driver compatibility layer implementation + */ + +static drv_compat_list_t drv_compat_layer = TAILQ_HEAD_INITIALIZER(drv_compat_layer); + +/** + * @internal + * @brief Find or add driver compatibility settings + * + * If a driver is already present in compatibility layer + * return it, else, if @p add non-zero, add it. + * + * @param driver the device class and flags + * @param add non-zero to add driver to layer + */ +static drv_compat_t +drv_compat_find_internal (drv_internal_t driver, int add) { + drv_compat_t drvc; + + PDEBUG(("looking for driver %s to compatibility layer"), driver->devops->name); + if (!driver) + return (NULL); + + TAILQ_FOREACH(drvc,&drv_compat_layer,link){ + if (driver->devops == drvc->driver) + break; + } + + if (!drvc && add){ + PDEBUG(("adding driver %s to compatibility layer"), driver->devops->name); + drvc = malloc(sizeof(struct drv_compat), M_BUS, M_NOWAIT|M_ZERO); + if (!drvc) + return (NULL); + drvc->driver = driver->devops; + drvc->flags = driver->flags; + TAILQ_INSERT_TAIL(&drv_compat_layer, drvc, link); + + bus_data_generation_update(); + } + return (drvc); +} + +/** + * @internal + * @brief find compartibility layer entry, associated + * with the driver + * + * @param driver device kobj_class pointer + */ +static drv_compat_t +drv_compat_find_driver (driver_t *driver) { + drv_compat_t drvc; + + TAILQ_FOREACH(drvc,&drv_compat_layer,link){ + if (driver == drvc->driver) + break; + } + + return drvc; +} + +/** + * @internal + * @brief Add driver to compatibility layer + * + * If driver is already in compartibility layer + * return it, else add it + * + * @param driver devops plus flags + */ +static drv_compat_t +drv_compat_add_driver (drv_internal_t driver) { + return (drv_compat_find_internal(driver, TRUE)); +} + +/** + * @internal + * @brief Removes a driver from compatibility layer + * + * @param driver pointer to device methods + * implementation + */ +static void +drv_compat_delete_driver (driver_t *driver) { + drv_compat_t drvc; + drvc = drv_compat_find_driver(driver); + TAILQ_REMOVE(&drv_compat_layer, drvc, link); +} + +/** + * @internal + * @brief Get compatibility layer's flags for a driver + * + * @param driver pointer to device methods implementation + * @param flags pointer to flags to be stored + */ +static int +drv_compat_get_flags (driver_t *driver, uint32_t *flags){ + drv_compat_t drvc; + + drvc = drv_compat_find_driver(driver); + + if (!drvc) + return (0); + + *flags = drvc->flags; + return (1); +} + +/** + * @internal + * @brief Set compatibility layer's flags for a driver + * + * @param driver pointer to device methods implementation + * @param flags flags to be set + */ +static int +drv_compat_set_flags (driver_t *driver, uint32_t flags){ + drv_compat_t drvc; + + drvc = drv_compat_find_driver(driver); + + if (!drvc) + return (0); + drvc->flags = flags; + return (1); +} +/* + * End of compatibility layer implementaion + */ + +int +is_device_driver (device_t dev, driver_t *driver){ /*TODO*/ + int level; + uint32_t flags; + driverlink_t dl; + + if (!drv_compat_get_flags(driver, &flags)) + /*todo what?*/ + + switch ((flags)&(DR_LOWEST|DR_LOWER|DR_MIDDLE|DR_UPPER|DR_TOPMOST)) { + case DR_LOWEST: level=DRV_LOWEST; break; + case DR_LOWER: level=DRV_LOWER; break; + case DR_MIDDLE: level=DRV_MIDDLE; break; + case DR_UPPER: level=DRV_UPPER; break; + case DR_TOPMOST: level=DRV_TOPMOST; break; + } + TAILQ_FOREACH(dl,&((dev->drivers)[level]),link){ + if (dl->driver==driver) return(TRUE); + } + return(FALSE); +} + + +/* * Devclass implementation */ @@ -862,12 +1022,12 @@ * @param driver the driver to register */ int -devclass_add_driver(devclass_t dc, /*driver_t **/ drv_internal_t driver) /**TODO*/ +devclass_add_driver(devclass_t dc, driver_t *driver) { driverlink_t dl; int i; - PDEBUG(("%s", DRIVERNAME(driver->devops))); + PDEBUG(("%s", DRIVERNAME(driver))); dl = malloc(sizeof *dl, M_BUS, M_NOWAIT|M_ZERO); if (!dl) @@ -879,12 +1039,12 @@ * goes. This means we can safely use static methods and avoids a * double-free in devclass_delete_driver. */ - kobj_class_compile((kobj_class_t) (driver->devops)); + kobj_class_compile((kobj_class_t) driver); /* * Make sure the devclass which the driver is implementing exists. */ - devclass_find_internal(driver->devops->name, 0, TRUE); + devclass_find_internal(driver->name, 0, TRUE); dl->driver = driver; TAILQ_INSERT_TAIL(&dc->drivers, dl, link); @@ -901,23 +1061,6 @@ return (0); } -int -is_device_driver (device_t dev, drv_internal_t driver){ - int level; - driverlink_t dl; - - switch ((driver->flags)&(DR_LOWEST|DR_LOWER|DR_MIDDLE|DR_UPPER|DR_TOPMOST)) { - case DR_LOWEST: level=DRV_LOWEST; break; - case DR_LOWER: level=DRV_LOWER; break; - case DR_MIDDLE: level=DRV_MIDDLE; break; - case DR_UPPER: level=DRV_UPPER; break; - case DR_TOPMOST: level=DRV_TOPMOST; break; - } - TAILQ_FOREACH(dl,&((dev->drivers)[level]),link){ - if (dl->driver==driver) return(1); - } - return(0); -} /** * @brief Delete a device driver from a device class * @@ -933,16 +1076,15 @@ * @param driver the driver to unregister */ int -devclass_delete_driver(devclass_t busclass, /*driver_t **/drv_internal_t driver) -/**TODO*/ +devclass_delete_driver(devclass_t busclass, driver_t *driver) /*TODO*/ { - devclass_t dc = devclass_find(driver->devops->name); + devclass_t dc = devclass_find(driver->name); driverlink_t dl; device_t dev; int i; int error; - PDEBUG(("%s from devclass %s", driver->devops->name, DEVCLANAME(busclass))); + PDEBUG(("%s from devclass %s", driver->name, DEVCLANAME(busclass))); if (!dc) return (0); @@ -956,7 +1098,7 @@ } if (!dl) { - PDEBUG(("%s not found in %s list", driver->devops->name, + PDEBUG(("%s not found in %s list", driver->name, busclass->name)); return (ENOENT); } @@ -974,8 +1116,8 @@ for (i = 0; i < dc->maxunit; i++) { if (dc->devices[i]) { dev = dc->devices[i]; - if (/*dev->driver == driver*/ - is_device_driver(dev,driver) && dev->parent && + if (/*dev->driver == driver*/ + is_device_driver(dev, driver) && dev->parent && dev->parent->devclass == busclass) { if ((error = device_detach(dev)) != 0) return (error); @@ -990,7 +1132,7 @@ /* XXX: kobj_mtx */ driver->refs--; if (driver->refs == 0) - kobj_class_free((kobj_class_t) (driver->devops)); + kobj_class_free((kobj_class_t) driver); bus_data_generation_update(); return (0); @@ -1010,15 +1152,15 @@ * @param driver the driver to unregister */ int -devclass_quiesce_driver(devclass_t busclass, /*driver_t **/ drv_internal_t driver) /**TODO*/ +devclass_quiesce_driver(devclass_t busclass, driver_t *driver) /*TODO*/ { - devclass_t dc = devclass_find(driver->devops->name); + devclass_t dc = devclass_find(driver->name); driverlink_t dl; device_t dev; int i; int error; - PDEBUG(("%s from devclass %s", driver->devops->name, DEVCLANAME(busclass))); + PDEBUG(("%s from devclass %s", driver->name, DEVCLANAME(busclass))); if (!dc) return (0); @@ -1032,7 +1174,7 @@ } if (!dl) { - PDEBUG(("%s not found in %s list", driver->devops->name, + PDEBUG(("%s not found in %s list", driver->name, busclass->name)); return (ENOENT); } @@ -1050,8 +1192,8 @@ for (i = 0; i < dc->maxunit; i++) { if (dc->devices[i]) { dev = dc->devices[i]; - if (/*dev->driver == driver*/ - is_device_driver(dev,driver) && dev->parent && + if (/*dev->driver == driver*/ + is_device_driver(dev, driver) && dev->parent && dev->parent->devclass == busclass) { if ((error = device_quiesce(dev)) != 0) return (error); @@ -1066,14 +1208,14 @@ * @internal */ static driverlink_t -devclass_find_driver_internal(devclass_t dc, const char *classname) /**TODO*/ +devclass_find_driver_internal(devclass_t dc, const char *classname) { driverlink_t dl; PDEBUG(("%s in devclass %s", classname, DEVCLANAME(dc))); TAILQ_FOREACH(dl, &dc->drivers, link) { - if (!strcmp(dl->driver->devops->name, classname)) + if (!strcmp(dl->driver->name, classname)) return (dl); } @@ -1091,8 +1233,8 @@ * @param dc the devclass to search * @param classname the driver name to search for */ -/*kobj_class_t*/ drv_internal_t -devclass_find_driver(devclass_t dc, const char *classname) /**TODO*/ +kobj_class_t +devclass_find_driver(devclass_t dc, const char *classname) { driverlink_t dl; @@ -1208,17 +1350,16 @@ * @retval ENOMEM the array allocation failed */ int -devclass_get_drivers(devclass_t dc, /*driver_t **/ - drv_internal_t **listp, int *countp) /**TODO*/ +devclass_get_drivers(devclass_t dc, driver_t ***listp, int *countp) { driverlink_t dl; - /*driver_t **/ drv_internal_t *list; + driver_t **list; int count; count = 0; TAILQ_FOREACH(dl, &dc->drivers, link) count++; - list = malloc(count * sizeof(/*driver_t **/drv_internal_t), M_TEMP, M_NOWAIT); + list = malloc(count * sizeof(driver_t *), M_TEMP, M_NOWAIT); if (list == NULL) return (ENOMEM); @@ -1474,7 +1615,7 @@ * @returns the new device */ static device_t -make_device(device_t parent, const char *name, int unit) /**TODO*/ +make_device(device_t parent, const char *name, int unit) /*TODO*/ { device_t dev; devclass_t dc; @@ -1500,10 +1641,9 @@ dev->parent = parent; TAILQ_INIT(&dev->children); kobj_init((kobj_t) dev, &null_class); -// dev->driver = NULL; - for (level=DRV_LOWEST;level<=DRV_TOPMOST;level++){ + //dev->driver = NULL; + for (level=DRV_LOWEST; level<=DRV_TOPMOST; level++) TAILQ_INIT(&((dev->drivers)[level])); - } dev->devclass = NULL; dev->unit = unit; dev->nameunit = NULL; @@ -1710,7 +1850,7 @@ * @internal */ static driverlink_t -first_matching_driver(devclass_t dc, device_t dev) /**TODO*/ +first_matching_driver(devclass_t dc, device_t dev) { if (dev->devclass) return (devclass_find_driver_internal(dc, dev->devclass->name)); @@ -1721,12 +1861,12 @@ * @internal */ static driverlink_t -next_matching_driver(devclass_t dc, device_t dev, driverlink_t last) /**TODO*/ +next_matching_driver(devclass_t dc, device_t dev, driverlink_t last) { if (dev->devclass) { driverlink_t dl; for (dl = TAILQ_NEXT(last, link); dl; dl = TAILQ_NEXT(dl, link)) - if (!strcmp(dev->devclass->name, dl->driver->devops->name)) + if (!strcmp(dev->devclass->name, dl->driver->name)) return (dl); return (NULL); } @@ -1737,13 +1877,14 @@ * @internal */ static int -device_probe_child(device_t dev, device_t child) /*TODO*/ +device_probe_child(device_t dev, device_t child) { devclass_t dc; driverlink_t best = 0; driverlink_t dl; int result, pri = 0; int hasclass = (child->devclass != 0); + uint32_t flags; GIANT_REQUIRED; @@ -1755,22 +1896,25 @@ * If the state is already probed, then return. However, don't * return if we can rebid this object. */ - if (/*child->state == DS_ALIVE && */(child->flags & DF_REBID) == 0) + if (/*child->state == DS_ALIVE &&*/ (child->flags & DF_REBID) == 0) return (0); for (; dc; dc = dc->parent) { for (dl = first_matching_driver(dc, child); dl; dl = next_matching_driver(dc, child, dl)) { - if ((child->state == DS_ALIVE && dl->driver->flags & DR_STACKAWARE && dl->driver->flags & DR_LOWEST) || (child->state != DS_ALIVE && dl->driver->flags & ~DR_LOWEST)) + if(!drv_compat_get_flags(dl->driver, &flags)) + /*todo what?*/; + if (child->state == DS_ALIVE && flags & DR_LOWEST || + (child->state != DS_ALIVE && flags & ~(DR_STACKAWARE|DR_LOWEST))) continue; - PDEBUG(("Trying %s", DRIVERNAME(dl->driver->devops))); + PDEBUG(("Trying %s", DRIVERNAME(dl->driver))); device_set_driver(child, dl->driver); if (!hasclass) - device_set_devclass(child, dl->driver->devops->name); + device_set_devclass(child, dl->driver->name); /* Fetch any flags for the device before probing. */ - resource_int_value(dl->driver->devops->name, child->unit, + resource_int_value(dl->driver->name, child->unit, "flags", &child->devflags); result = DEVICE_PROBE(child); @@ -1846,9 +1990,9 @@ /* Set the winning driver, devclass, and flags. */ if (!child->devclass) - device_set_devclass(child, best->driver->devops->name); + device_set_devclass(child, best->driver->name); device_set_driver(child, best->driver); - resource_int_value(best->driver->devops->name, child->unit, + resource_int_value(best->driver->name, child->unit, "flags", &child->devflags); if (pri < 0) { @@ -1929,9 +2073,14 @@ * is no driver currently attached */ driver_t * -device_get_driver(device_t dev) /*TODO*/ +device_get_driver(device_t dev) { - return (dev->driver); + driverlink_t dl; + if (!TAILQ_EMPTY(&((dev->drivers)[DRV_LOWEST]))){ + dl=TAILQ_FIRST(&((dev->drivers)[DRV_LOWEST])); + return (dl->driver); + } + return (NULL); } /** @@ -2309,7 +2458,7 @@ * @retval ENOMEM a memory allocation failure occurred */ int -device_set_driver(device_t dev, driver_t *driver) /*TODO*/ +device_set_driver(device_t dev, driver_t *driver) { if (dev->state >= DS_ATTACHED) return (EBUSY); @@ -2370,7 +2519,7 @@ * @retval non-zero some other unix error code */ int -device_probe_and_attach(device_t dev) /*TODO*/ +device_probe_and_attach(device_t dev) { int error; @@ -2419,7 +2568,7 @@ * @retval non-zero some other unix error code */ int -device_attach(device_t dev) /*TODO*/ +device_attach(device_t dev) { int error; @@ -2459,7 +2608,7 @@ * @retval non-zero some other unix error code */ int -device_detach(device_t dev) /*TODO*/ +device_detach(device_t dev) { int error; @@ -2906,7 +3055,7 @@ * devclass. */ int -bus_generic_probe(device_t dev) /*TODO*/ +bus_generic_probe(device_t dev) { devclass_t dc = dev->devclass; driverlink_t dl; @@ -2926,7 +3075,7 @@ * children. */ int -bus_generic_attach(device_t dev) /*TODO*/ +bus_generic_attach(device_t dev) { device_t child; @@ -3126,14 +3275,14 @@ * and then calls device_probe_and_attach() for each unattached child. */ void -bus_generic_driver_added(device_t dev, driver_t *driver) /*TODO*/ +bus_generic_driver_added(device_t dev, driver_t *driver) { device_t child; DEVICE_IDENTIFY(driver, dev); TAILQ_FOREACH(child, &dev->children, link) { - if (child->state == DS_NOTPRESENT || - (child->flags & DF_REBID)) +// if (child->state == DS_NOTPRESENT || +// (child->flags & DF_REBID)) device_probe_and_attach(child); } } @@ -3146,7 +3295,7 @@ */ int bus_generic_setup_intr(device_t dev, device_t child, struct resource *irq, - int flags, driver_intr_t *intr, void *arg, void **cookiep) /*TODO*/ + int flags, driver_intr_t *intr, void *arg, void **cookiep) { /* Propagate up the bus hierarchy until someone handles it. */ if (dev->parent) @@ -3459,7 +3608,7 @@ */ int bus_setup_intr(device_t dev, struct resource *r, int flags, - driver_intr_t handler, void *arg, void **cookiep) /*TODO*/ + driver_intr_t handler, void *arg, void **cookiep) { int error; @@ -3670,7 +3819,7 @@ return (-1); } -static kobj_method_t root_methods[] = { /*TODO*/ +static kobj_method_t root_methods[] = { /* Device interface */ KOBJMETHOD(device_shutdown, bus_generic_shutdown), KOBJMETHOD(device_suspend, bus_generic_suspend), @@ -3696,7 +3845,7 @@ devclass_t root_devclass; static int -root_bus_module_handler(module_t mod, int what, void* arg) /*TODO*/ +root_bus_module_handler(module_t mod, int what, void* arg) { switch (what) { case MOD_LOAD: @@ -3755,11 +3904,12 @@ * driver_module_data structure pointed to by @p arg */ int -driver_module_handler(module_t mod, int what, void *arg) /*TODO*/ +driver_module_handler(module_t mod, int what, void *arg) { int error; struct driver_module_data *dmd; devclass_t bus_devclass; + drv_internal_t drv_intnl; kobj_class_t driver; dmd = (struct driver_module_data *)arg; @@ -3771,7 +3921,10 @@ if (dmd->dmd_chainevh) error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg); - driver = dmd->dmd_driver; + //driver = dmd->dmd_driver; + drv_intnl = dmd->dmd_driver; + drv_compat_add_driver(drv_intnl); + driver = drv_intnl->devops; PDEBUG(("Loading module: driver %s on bus %s", DRIVERNAME(driver), dmd->dmd_busname)); error = devclass_add_driver(bus_devclass, driver); @@ -3798,16 +3951,18 @@ break; case MOD_UNLOAD: + drv_intnl = dmd->dmd_driver; + driver = drv_intnl->devops; PDEBUG(("Unloading module: driver %s from bus %s", - DRIVERNAME(dmd->dmd_driver), + DRIVERNAME(driver), dmd->dmd_busname)); error = devclass_delete_driver(bus_devclass, - dmd->dmd_driver); - + driver); + drv_compat_delete_driver(driver); if (!error && dmd->dmd_chainevh) error = dmd->dmd_chainevh(mod,what,dmd->dmd_chainarg); break; - case MOD_QUIESCE: + case MOD_QUIESCE: /*TODO*/ PDEBUG(("Quiesce module: driver %s from bus %s", DRIVERNAME(dmd->dmd_driver), dmd->dmd_busname));
Want to link to this message? Use this URL: <https://mail-archive.FreeBSD.org/cgi/mid.cgi?200707031328.l63DSrEm056929>