Module Name: src Committed By: dyoung Date: Thu Nov 12 19:10:31 UTC 2009
Modified Files: src/sys/kern: subr_autoconf.c src/sys/sys: device.h Log Message: Move a device-deactivation pattern that is replicated throughout the system into config_deactivate(dev): deactivate dev and all of its descendants. Block all interrupts while calling each device's activation hook, ca_activate. Now it is possible to simplify or to delete several device-activation hooks throughout the system. Do not deactivate a driver while detaching it! If the driver was already deactivated (because of accidental/emergency removal), let the driver cope with the knowledge that DVF_ACTIVE has been cleared. Otherwise, let the driver access the underlying hardware (so that it can flush caches, restore original register settings, et cetera) until it exits its device-detachment hook. Let multiple readers and writers simultaneously access the system's device_t list, alldevs, from either interrupt or thread context: postpone changing alldevs linkages and freeing autoconf device structures until a garbage-collection phase that runs after all readers & writers have left the list. Give device iterators (deviter(9)) a consistent view of alldevs no matter whether device_t's are added and deleted during iteration: keep a global alldevs generation number. When an iterator enters alldevs, record the current generation number in the iterator and increase the global number. When a device_t is created, label it with the current global generation number. When a device_t is deleted, add a second label, the current global generation number. During iteration, compare a device_t's added- and deleted-generation with the iterator's generation and skip a device_t that was deleted before the iterator entered the list or added after the iterator entered the list. The alldevs generation number is never 0. The garbage collector reaps device_t's whose delete-generation number is non-zero. Make alldevs private to sys/kern/subr_autoconf.c. Use deviter(9) to access it. To generate a diff of this commit: cvs rdiff -u -r1.186 -r1.187 src/sys/kern/subr_autoconf.c cvs rdiff -u -r1.124 -r1.125 src/sys/sys/device.h Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/kern/subr_autoconf.c diff -u src/sys/kern/subr_autoconf.c:1.186 src/sys/kern/subr_autoconf.c:1.187 --- src/sys/kern/subr_autoconf.c:1.186 Mon Oct 12 23:33:02 2009 +++ src/sys/kern/subr_autoconf.c Thu Nov 12 19:10:30 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: subr_autoconf.c,v 1.186 2009/10/12 23:33:02 yamt Exp $ */ +/* $NetBSD: subr_autoconf.c,v 1.187 2009/11/12 19:10:30 dyoung Exp $ */ /* * Copyright (c) 1996, 2000 Christopher G. Demetriou @@ -77,7 +77,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.186 2009/10/12 23:33:02 yamt Exp $"); +__KERNEL_RCSID(0, "$NetBSD: subr_autoconf.c,v 1.187 2009/11/12 19:10:30 dyoung Exp $"); #ifdef _KERNEL_OPT #include "opt_ddb.h" @@ -165,10 +165,13 @@ static char *number(char *, int); static void mapply(struct matchinfo *, cfdata_t); static device_t config_devalloc(const device_t, const cfdata_t, const int *); -static void config_devdealloc(device_t); +static void config_devdelete(device_t); static void config_makeroom(int, struct cfdriver *); static void config_devlink(device_t); -static void config_devunlink(device_t); +static void config_alldevs_unlock(int); +static int config_alldevs_lock(void); + +static void config_collect_garbage(void); static void pmflock_debug(device_t, const char *, int); @@ -202,12 +205,12 @@ static int config_finalize_done; /* list of all devices */ -struct devicelist alldevs = TAILQ_HEAD_INITIALIZER(alldevs); -kcondvar_t alldevs_cv; -kmutex_t alldevs_mtx; -static int alldevs_nread = 0; -static int alldevs_nwrite = 0; -static lwp_t *alldevs_writer = NULL; +static struct devicelist alldevs = TAILQ_HEAD_INITIALIZER(alldevs); +static kmutex_t alldevs_mtx; +static volatile bool alldevs_garbage = false; +static volatile devgen_t alldevs_gen = 1; +static volatile int alldevs_nread = 0; +static volatile int alldevs_nwrite = 0; static int config_pending; /* semaphore for mountroot */ static kmutex_t config_misc_lock; @@ -238,8 +241,7 @@ KASSERT(config_initialized == false); - mutex_init(&alldevs_mtx, MUTEX_DEFAULT, IPL_NONE); - cv_init(&alldevs_cv, "alldevs"); + mutex_init(&alldevs_mtx, MUTEX_DEFAULT, IPL_HIGH); mutex_init(&config_misc_lock, MUTEX_DEFAULT, IPL_NONE); cv_init(&config_misc_cv, "cfgmisc"); @@ -366,13 +368,21 @@ int config_cfdriver_detach(struct cfdriver *cd) { - int i; + int i, rc = 0, s; + s = config_alldevs_lock(); + config_collect_garbage(); /* Make sure there are no active instances. */ for (i = 0; i < cd->cd_ndevs; i++) { - if (cd->cd_devs[i] != NULL) - return EBUSY; + if (cd->cd_devs[i] != NULL) { + rc = EBUSY; + break; + } } + config_alldevs_unlock(s); + + if (rc != 0) + return rc; /* ...and no attachments loaded. */ if (LIST_EMPTY(&cd->cd_attach) == 0) @@ -433,19 +443,27 @@ { struct cfdriver *cd; device_t dev; - int i; + int i, rc = 0, s; cd = config_cfdriver_lookup(driver); if (cd == NULL) return ESRCH; + s = config_alldevs_lock(); + config_collect_garbage(); /* Make sure there are no active instances. */ for (i = 0; i < cd->cd_ndevs; i++) { if ((dev = cd->cd_devs[i]) == NULL) continue; - if (dev->dv_cfattach == ca) - return EBUSY; + if (dev->dv_cfattach == ca) { + rc = EBUSY; + break; + } } + config_alldevs_unlock(s); + + if (rc != 0) + return rc; LIST_REMOVE(ca, ca_list); @@ -923,6 +941,11 @@ /* * Expand the size of the cd_devs array if necessary. + * + * The caller must hold alldevs_mtx. config_makeroom() may release and + * re-acquire alldevs_mtx, so callers should re-check conditions such + * as alldevs_nwrite == 0 and alldevs_nread == 0 when config_makeroom() + * returns. */ static void config_makeroom(int n, struct cfdriver *cd) @@ -930,8 +953,11 @@ int old, new; device_t *nsp; + alldevs_nwrite++; + mutex_exit(&alldevs_mtx); + if (n < cd->cd_ndevs) - return; + goto out; /* * Need to expand the array. @@ -943,7 +969,6 @@ new = old * 2; while (new <= n) new *= 2; - cd->cd_ndevs = new; nsp = kmem_alloc(sizeof(device_t [new]), KM_SLEEP); if (nsp == NULL) panic("config_attach: %sing dev array", @@ -953,37 +978,50 @@ memcpy(nsp, cd->cd_devs, sizeof(device_t [old])); kmem_free(cd->cd_devs, sizeof(device_t [old])); } + cd->cd_ndevs = new; cd->cd_devs = nsp; +out: + mutex_enter(&alldevs_mtx); + alldevs_nwrite--; } static void config_devlink(device_t dev) { struct cfdriver *cd = dev->dv_cfdriver; + int s; /* put this device in the devices array */ + s = config_alldevs_lock(); config_makeroom(dev->dv_unit, cd); if (cd->cd_devs[dev->dv_unit]) panic("config_attach: duplicate %s", device_xname(dev)); cd->cd_devs[dev->dv_unit] = dev; /* It is safe to add a device to the tail of the list while - * readers are in the list, but not while a writer is in - * the list. Wait for any writer to complete. + * readers and writers are in the list. */ - mutex_enter(&alldevs_mtx); - while (alldevs_nwrite != 0 && alldevs_writer != curlwp) - cv_wait(&alldevs_cv, &alldevs_mtx); + dev->dv_add_gen = alldevs_gen; TAILQ_INSERT_TAIL(&alldevs, dev, dv_list); /* link up */ - cv_signal(&alldevs_cv); - mutex_exit(&alldevs_mtx); + config_alldevs_unlock(s); } +/* + * Caller must hold alldevs_mtx. config_devdelete() may release and + * re-acquire alldevs_mtx, so callers should re-check conditions such as + * alldevs_nwrite == 0 && alldevs_nread == 0 after config_devdelete() + * returns. + */ static void -config_devunlink(device_t dev) +config_devdelete(device_t dev) { + device_lock_t dvl = device_getlock(dev); + int priv = (dev->dv_flags & DVF_PRIV_ALLOC); struct cfdriver *cd = dev->dv_cfdriver; - int i; + device_t *devs = NULL; + int i, ndevs = 0; + + KASSERT(mutex_owned(&alldevs_mtx)); /* Unlink from device list. */ TAILQ_REMOVE(&alldevs, dev, dv_list); @@ -996,14 +1034,47 @@ */ for (i = 0; i < cd->cd_ndevs; i++) { if (cd->cd_devs[i] != NULL) - return; + break; + } + /* nothing found. unlink, now. deallocate below. */ + if (i == cd->cd_ndevs) { + ndevs = cd->cd_ndevs; + devs = cd->cd_devs; + cd->cd_devs = NULL; + cd->cd_ndevs = 0; + } + + mutex_exit(&alldevs_mtx); + + KASSERT(!mutex_owned(&alldevs_mtx)); + + if (devs != NULL) + kmem_free(devs, sizeof(device_t [ndevs])); + + cv_destroy(&dvl->dvl_cv); + mutex_destroy(&dvl->dvl_mtx); + + KASSERT(dev->dv_properties != NULL); + prop_object_release(dev->dv_properties); + + if (dev->dv_activity_handlers) + panic("%s with registered handlers", __func__); + + if (dev->dv_locators) { + size_t amount = *--dev->dv_locators; + kmem_free(dev->dv_locators, amount); } - /* nothing found; deallocate */ - kmem_free(cd->cd_devs, sizeof(device_t [cd->cd_ndevs])); - cd->cd_devs = NULL; - cd->cd_ndevs = 0; + + if (dev->dv_cfattach->ca_devsize > 0) + kmem_free(dev->dv_private, dev->dv_cfattach->ca_devsize); + if (priv) + kmem_free(dev, sizeof(*dev)); + + KASSERT(!mutex_owned(&alldevs_mtx)); + + mutex_enter(&alldevs_mtx); } - + static device_t config_devalloc(const device_t parent, const cfdata_t cf, const int *locs) { @@ -1011,7 +1082,7 @@ struct cfattach *ca; size_t lname, lunit; const char *xunit; - int myunit; + int myunit, s; char num[10]; device_t dev; void *dev_private; @@ -1031,6 +1102,8 @@ panic("config_devalloc: %s", cf->cf_atname); #ifndef __BROKEN_CONFIG_UNIT_USAGE + s = config_alldevs_lock(); + config_collect_garbage(); if (cf->cf_fstate == FSTATE_STAR) { for (myunit = cf->cf_unit; myunit < cd->cd_ndevs; myunit++) if (cd->cd_devs[myunit] == NULL) @@ -1042,8 +1115,11 @@ } else { myunit = cf->cf_unit; if (myunit < cd->cd_ndevs && cd->cd_devs[myunit] != NULL) - return NULL; - } + myunit = -1; + } + config_alldevs_unlock(s); + if (myunit == -1) + return NULL; #else myunit = cf->cf_unit; #endif /* ! __BROKEN_CONFIG_UNIT_USAGE */ @@ -1116,32 +1192,6 @@ return dev; } -static void -config_devdealloc(device_t dev) -{ - device_lock_t dvl = device_getlock(dev); - int priv = (dev->dv_flags & DVF_PRIV_ALLOC); - - cv_destroy(&dvl->dvl_cv); - mutex_destroy(&dvl->dvl_mtx); - - KASSERT(dev->dv_properties != NULL); - prop_object_release(dev->dv_properties); - - if (dev->dv_activity_handlers) - panic("config_devdealloc with registered handlers"); - - if (dev->dv_locators) { - size_t amount = *--dev->dv_locators; - kmem_free(dev->dv_locators, amount); - } - - if (dev->dv_cfattach->ca_devsize > 0) - kmem_free(dev->dv_private, dev->dv_cfattach->ca_devsize); - if (priv) - kmem_free(dev, sizeof(*dev)); -} - /* * Attach a found device. */ @@ -1284,6 +1334,33 @@ } /* + * Caller must hold alldevs_mtx. config_collect_garbage() may + * release and re-acquire alldevs_mtx, so callers should re-check + * conditions such as alldevs_nwrite == 0 && alldevs_nread == 0 after + * config_collect_garbage() returns. + */ +static void +config_collect_garbage(void) +{ + device_t dv; + + KASSERT(mutex_owned(&alldevs_mtx)); + + while (alldevs_nwrite == 0 && alldevs_nread == 0 && alldevs_garbage) { + TAILQ_FOREACH(dv, &alldevs, dv_list) { + if (dv->dv_del_gen != 0) + break; + } + if (dv == NULL) { + alldevs_garbage = false; + break; + } + config_devdelete(dv); + } + KASSERT(mutex_owned(&alldevs_mtx)); +} + +/* * Detach a device. Optionally forced (e.g. because of hardware * removal) and quiet. Returns zero if successful, non-zero * (an error code) otherwise. @@ -1302,7 +1379,7 @@ #ifdef DIAGNOSTIC device_t d; #endif - int rv = 0; + int rv = 0, s; #ifdef DIAGNOSTIC cf = dev->dv_cfdata; @@ -1317,51 +1394,43 @@ ca = dev->dv_cfattach; KASSERT(ca != NULL); - KASSERT(curlwp != NULL); - mutex_enter(&alldevs_mtx); - if (alldevs_nwrite > 0 && alldevs_writer == NULL) - ; - else while (alldevs_nread != 0 || - (alldevs_nwrite != 0 && alldevs_writer != curlwp)) - cv_wait(&alldevs_cv, &alldevs_mtx); - if (alldevs_nwrite++ == 0) - alldevs_writer = curlwp; - mutex_exit(&alldevs_mtx); + s = config_alldevs_lock(); + if (dev->dv_del_gen != 0) { + config_alldevs_unlock(s); +#ifdef DIAGNOSTIC + printf("%s: %s is already detached\n", __func__, + device_xname(dev)); +#endif /* DIAGNOSTIC */ + return ENOENT; + } + alldevs_nwrite++; + config_alldevs_unlock(s); - /* - * Ensure the device is deactivated. If the device doesn't - * have an activation entry point, we allow DVF_ACTIVE to - * remain set. Otherwise, if DVF_ACTIVE is still set, the - * device is busy, and the detach fails. - */ if (!detachall && (flags & (DETACH_SHUTDOWN|DETACH_FORCE)) == DETACH_SHUTDOWN && (dev->dv_flags & DVF_DETACH_SHUTDOWN) == 0) { rv = EOPNOTSUPP; - } else if ((rv = config_deactivate(dev)) == EOPNOTSUPP) - rv = 0; /* Do not treat EOPNOTSUPP as an error */ + } else if (ca->ca_detach != NULL) { + rv = (*ca->ca_detach)(dev, flags); + } else + rv = EOPNOTSUPP; /* - * Try to detach the device. If that's not possible, then - * we either panic() (for the forced but failed case), or - * return an error. + * If it was not possible to detach the device, then we either + * panic() (for the forced but failed case), or return an error. + * + * If it was possible to detach the device, ensure that the + * device is deactivated. */ - if (rv == 0) { - if (ca->ca_detach != NULL) - rv = (*ca->ca_detach)(dev, flags); - else - rv = EOPNOTSUPP; - } - if (rv != 0) { - if ((flags & DETACH_FORCE) == 0) - goto out; - else - panic("config_detach: forced detach of %s failed (%d)", - device_xname(dev), rv); + if (rv == 0) + dev->dv_flags &= ~DVF_ACTIVE; + else if ((flags & DETACH_FORCE) == 0) + goto out; + else { + panic("config_detach: forced detach of %s failed (%d)", + device_xname(dev), rv); } - dev->dv_flags &= ~DVF_ACTIVE; - /* * The device has now been successfully detached. */ @@ -1378,7 +1447,7 @@ */ for (d = TAILQ_NEXT(dev, dv_list); d != NULL; d = TAILQ_NEXT(d, dv_list)) { - if (d->dv_parent == dev) { + if (d->dv_parent == dev && d->dv_del_gen == 0) { printf("config_detach: detached device %s" " has children %s\n", device_xname(dev), device_xname(d)); panic("config_detach"); @@ -1416,20 +1485,24 @@ } } - config_devunlink(dev); - if (dev->dv_cfdata != NULL && (flags & DETACH_QUIET) == 0) aprint_normal_dev(dev, "detached\n"); - config_devdealloc(dev); - out: - mutex_enter(&alldevs_mtx); + s = config_alldevs_lock(); KASSERT(alldevs_nwrite != 0); - if (--alldevs_nwrite == 0) - alldevs_writer = NULL; - cv_signal(&alldevs_cv); - mutex_exit(&alldevs_mtx); + --alldevs_nwrite; + if (rv != 0) + ; + else if (dev->dv_del_gen != 0) + ; + else { + dev->dv_del_gen = alldevs_gen; + alldevs_garbage = true; + } + config_collect_garbage(); + config_alldevs_unlock(s); + return rv; } @@ -1497,21 +1570,49 @@ return progress; } +static bool +device_is_ancestor_of(device_t ancestor, device_t descendant) +{ + device_t dv; + + for (dv = descendant; dv != NULL; dv = device_parent(dv)) { + if (device_parent(dv) == ancestor) + return true; + } + return false; +} + int config_deactivate(device_t dev) { - const struct cfattach *ca = dev->dv_cfattach; - int rv = 0, oflags = dev->dv_flags; + deviter_t di; + const struct cfattach *ca; + device_t descendant; + int s, rv = 0, oflags; - if (ca->ca_activate == NULL) - return EOPNOTSUPP; + for (descendant = deviter_first(&di, DEVITER_F_ROOT_FIRST); + descendant != NULL; + descendant = deviter_next(&di)) { + if (dev != descendant && + !device_is_ancestor_of(dev, descendant)) + continue; - if (dev->dv_flags & DVF_ACTIVE) { - dev->dv_flags &= ~DVF_ACTIVE; - rv = (*ca->ca_activate)(dev, DVACT_DEACTIVATE); - if (rv) - dev->dv_flags = oflags; + if ((descendant->dv_flags & DVF_ACTIVE) == 0) + continue; + + ca = descendant->dv_cfattach; + oflags = descendant->dv_flags; + + descendant->dv_flags &= ~DVF_ACTIVE; + if (ca->ca_activate == NULL) + continue; + s = splhigh(); + rv = (*ca->ca_activate)(descendant, DVACT_DEACTIVATE); + splx(s); + if (rv != 0) + descendant->dv_flags = oflags; } + deviter_release(&di); return rv; } @@ -1740,6 +1841,23 @@ mutex_exit(&config_misc_lock); } +static int +config_alldevs_lock(void) +{ + int s; + + s = splhigh(); + mutex_enter(&alldevs_mtx); + return s; +} + +static void +config_alldevs_unlock(int s) +{ + mutex_exit(&alldevs_mtx); + splx(s); +} + /* * device_lookup: * @@ -1748,11 +1866,20 @@ device_t device_lookup(cfdriver_t cd, int unit) { + device_t dv; + int s; + s = config_alldevs_lock(); + config_collect_garbage(); + KASSERT(mutex_owned(&alldevs_mtx)); if (unit < 0 || unit >= cd->cd_ndevs) - return NULL; - - return cd->cd_devs[unit]; + dv = NULL; + else + dv = cd->cd_devs[unit]; + config_alldevs_unlock(s); + + KASSERT(!mutex_owned(&alldevs_mtx)); + return dv; } /* @@ -1764,14 +1891,22 @@ device_lookup_private(cfdriver_t cd, int unit) { device_t dv; + int s; + void *priv; + s = config_alldevs_lock(); + config_collect_garbage(); + KASSERT(mutex_owned(&alldevs_mtx)); if (unit < 0 || unit >= cd->cd_ndevs) - return NULL; - - if ((dv = cd->cd_devs[unit]) == NULL) - return NULL; + priv = NULL; + else if ((dv = cd->cd_devs[unit]) == NULL) + priv = NULL; + else + priv = dv->dv_private; + config_alldevs_unlock(s); - return dv->dv_private; + KASSERT(!mutex_owned(&alldevs_mtx)); + return priv; } /* @@ -2363,6 +2498,20 @@ old_handlers[i] = NULL; } +/* Return true iff the device_t `dev' exists at generation `gen'. */ +static bool +device_exists_at(device_t dv, devgen_t gen) +{ + return (dv->dv_del_gen == 0 || dv->dv_del_gen > gen) && + dv->dv_add_gen <= gen; +} + +static bool +deviter_visits(const deviter_t *di, device_t dv) +{ + return device_exists_at(dv, di->di_gen); +} + /* * Device Iteration * @@ -2423,43 +2572,37 @@ deviter_init(deviter_t *di, deviter_flags_t flags) { device_t dv; - bool rw; + int s; - mutex_enter(&alldevs_mtx); - if ((flags & DEVITER_F_SHUTDOWN) != 0) { - flags |= DEVITER_F_RW; - alldevs_nwrite++; - alldevs_writer = NULL; - alldevs_nread = 0; - } else { - rw = (flags & DEVITER_F_RW) != 0; + memset(di, 0, sizeof(*di)); - if (alldevs_nwrite > 0 && alldevs_writer == NULL) - ; - else while ((alldevs_nwrite != 0 && alldevs_writer != curlwp) || - (rw && alldevs_nread != 0)) - cv_wait(&alldevs_cv, &alldevs_mtx); - - if (rw) { - if (alldevs_nwrite++ == 0) - alldevs_writer = curlwp; - } else - alldevs_nread++; - } - mutex_exit(&alldevs_mtx); + s = config_alldevs_lock(); + if ((flags & DEVITER_F_SHUTDOWN) != 0) + flags |= DEVITER_F_RW; - memset(di, 0, sizeof(*di)); + if ((flags & DEVITER_F_RW) != 0) + alldevs_nwrite++; + else + alldevs_nread++; + di->di_gen = alldevs_gen++; + config_alldevs_unlock(s); di->di_flags = flags; switch (di->di_flags & (DEVITER_F_LEAVES_FIRST|DEVITER_F_ROOT_FIRST)) { case DEVITER_F_LEAVES_FIRST: - TAILQ_FOREACH(dv, &alldevs, dv_list) + TAILQ_FOREACH(dv, &alldevs, dv_list) { + if (!deviter_visits(di, dv)) + continue; di->di_curdepth = MAX(di->di_curdepth, dv->dv_depth); + } break; case DEVITER_F_ROOT_FIRST: - TAILQ_FOREACH(dv, &alldevs, dv_list) + TAILQ_FOREACH(dv, &alldevs, dv_list) { + if (!deviter_visits(di, dv)) + continue; di->di_maxdepth = MAX(di->di_maxdepth, dv->dv_depth); + } break; default: break; @@ -2485,7 +2628,7 @@ } static device_t -deviter_next1(deviter_t *di) +deviter_next2(deviter_t *di) { device_t dv; @@ -2501,6 +2644,18 @@ return dv; } +static device_t +deviter_next1(deviter_t *di) +{ + device_t dv; + + do { + dv = deviter_next2(di); + } while (dv != NULL && !deviter_visits(di, dv)); + + return dv; +} + device_t deviter_next(deviter_t *di) { @@ -2536,20 +2691,15 @@ deviter_release(deviter_t *di) { bool rw = (di->di_flags & DEVITER_F_RW) != 0; + int s; - mutex_enter(&alldevs_mtx); - if (!rw) { + s = config_alldevs_lock(); + if (rw) + --alldevs_nwrite; + else --alldevs_nread; - cv_signal(&alldevs_cv); - } else if (alldevs_nwrite > 0 && alldevs_writer == NULL) { - --alldevs_nwrite; /* shutting down: do not signal */ - } else { - KASSERT(alldevs_nwrite != 0); - if (--alldevs_nwrite == 0) - alldevs_writer = NULL; - cv_signal(&alldevs_cv); - } - mutex_exit(&alldevs_mtx); + /* XXX wake a garbage-collection thread */ + config_alldevs_unlock(s); } static void Index: src/sys/sys/device.h diff -u src/sys/sys/device.h:1.124 src/sys/sys/device.h:1.125 --- src/sys/sys/device.h:1.124 Mon Sep 21 12:14:47 2009 +++ src/sys/sys/device.h Thu Nov 12 19:10:30 2009 @@ -1,4 +1,4 @@ -/* $NetBSD: device.h,v 1.124 2009/09/21 12:14:47 pooka Exp $ */ +/* $NetBSD: device.h,v 1.125 2009/11/12 19:10:30 dyoung Exp $ */ /* * Copyright (c) 1996, 2000 Christopher G. Demetriou @@ -174,6 +174,9 @@ bool (*dv_class_resume)(device_t PMF_FN_PROTO); void (*dv_class_deregister)(device_t); + devgen_t dv_add_gen, + dv_del_gen; + struct device_lock dv_lock; device_suspensor_t dv_bus_suspensors[DEVICE_SUSPENSORS_MAX]; device_suspensor_t dv_driver_suspensors[DEVICE_SUSPENSORS_MAX]; @@ -205,6 +208,7 @@ deviter_flags_t di_flags; int di_curdepth; int di_maxdepth; + devgen_t di_gen; }; typedef struct deviter deviter_t; @@ -412,7 +416,6 @@ #ifdef _KERNEL extern struct cfdriverlist allcfdrivers;/* list of all cfdrivers */ -extern struct devicelist alldevs; /* list of all devices */ extern struct cftablelist allcftables; /* list of all cfdata tables */ extern device_t booted_device; /* the device we booted from */ extern device_t booted_wedge; /* the wedge on that device */