Index: sys/dev/led/led.c =================================================================== --- sys/dev/led/led.c +++ sys/dev/led/led.c @@ -14,14 +14,17 @@ __FBSDID("$FreeBSD$"); #include +#include #include #include +#include #include #include #include #include #include #include +#include #include #include #include @@ -30,7 +33,7 @@ #include struct ledsc { - LIST_ENTRY(ledsc) list; + CK_LIST_ENTRY(ledsc) list; char *name; void *private; int unit; @@ -44,11 +47,11 @@ }; static struct unrhdr *led_unit; -static struct mtx led_mtx; +static __read_mostly epoch_t led_epoch; static struct sx led_sx; -static LIST_HEAD(, ledsc) led_list = LIST_HEAD_INITIALIZER(led_list); +static CK_LIST_HEAD(, ledsc) led_list = CK_LIST_HEAD_INITIALIZER(led_list); static struct callout led_ch; -static int blinkers = 0; +static unsigned int blinkers; static MALLOC_DEFINE(M_LED, "LED", "LED driver"); @@ -56,8 +59,11 @@ led_timeout(void *p) { struct ledsc *sc; + struct epoch_tracker et; + unsigned int b; - LIST_FOREACH(sc, &led_list, list) { + epoch_enter_preempt(led_epoch, &et); + CK_LIST_FOREACH(sc, &led_list, list) { if (sc->ptr == NULL) continue; if (sc->count > 0) { @@ -66,7 +72,7 @@ } if (*sc->ptr == '.') { sc->ptr = NULL; - blinkers--; + refcount_release(&blinkers); continue; } else if (*sc->ptr == 'U' || *sc->ptr == 'u') { if (sc->last_second == time_second) @@ -84,8 +90,10 @@ if (*sc->ptr == '\0') sc->ptr = sc->str; } - if (blinkers > 0) + b = refcount_load(&blinkers); + if (b > 0) callout_reset(&led_ch, hz / 10, led_timeout, p); + epoch_exit_preempt(led_epoch, &et); } static int @@ -98,14 +106,14 @@ if (*sb != NULL) { sc->str = sbuf_data(*sb); if (sc->ptr == NULL) { - blinkers++; + refcount_acquire(&blinkers); callout_reset(&led_ch, hz / 10, led_timeout, NULL); } sc->ptr = sc->str; } else { sc->str = NULL; if (sc->ptr != NULL) - blinkers--; + refcount_release(&blinkers); sc->ptr = NULL; sc->func(sc->private, state); } @@ -215,6 +223,7 @@ led_write(struct cdev *dev, struct uio *uio, int ioflag) { struct ledsc *sc; + struct epoch_tracker et; char *s; struct sbuf *sb = NULL; int error, state = 0; @@ -232,11 +241,11 @@ free(s, M_DEVBUF); if (error) return (error); - mtx_lock(&led_mtx); + epoch_enter_preempt(led_epoch, &et); sc = dev->si_drv1; if (sc != NULL) error = led_state(sc, &sb, state); - mtx_unlock(&led_mtx); + epoch_exit_preempt(led_epoch, &et); if (sb != NULL) sbuf_delete(sb); return (error); @@ -246,14 +255,16 @@ led_set(char const *name, char const *cmd) { struct ledsc *sc; + struct epoch_tracker et; struct sbuf *sb = NULL; int error, state = 0; error = led_parse(cmd, &sb, &state); if (error) return (error); - mtx_lock(&led_mtx); - LIST_FOREACH(sc, &led_list, list) { + + epoch_enter_preempt(led_epoch, &et); + CK_LIST_FOREACH(sc, &led_list, list) { if (strcmp(sc->name, name) == 0) break; } @@ -261,7 +272,7 @@ error = led_state(sc, &sb, state); else error = ENOENT; - mtx_unlock(&led_mtx); + epoch_exit_preempt(led_epoch, &et); if (sb != NULL) sbuf_delete(sb); return (error); @@ -283,24 +294,25 @@ led_create_state(led_t *func, void *priv, char const *name, int state) { struct ledsc *sc; + struct epoch_tracker et; sc = malloc(sizeof *sc, M_LED, M_WAITOK | M_ZERO); - sx_xlock(&led_sx); sc->name = strdup(name, M_LED); sc->unit = alloc_unr(led_unit); sc->private = priv; sc->func = func; sc->dev = make_dev(&led_cdevsw, sc->unit, UID_ROOT, GID_WHEEL, 0600, "led/%s", name); - sx_xunlock(&led_sx); - - mtx_lock(&led_mtx); sc->dev->si_drv1 = sc; - LIST_INSERT_HEAD(&led_list, sc, list); + + sx_xlock(&led_sx); + epoch_enter_preempt(led_epoch, &et); + CK_LIST_INSERT_HEAD(&led_list, sc, list); if (state != -1) sc->func(sc->private, state != 0); - mtx_unlock(&led_mtx); + epoch_exit_preempt(led_epoch, &et); + sx_unlock(&led_sx); return (sc->dev); } @@ -310,17 +322,16 @@ { struct ledsc *sc; - mtx_lock(&led_mtx); + sx_xlock(&led_sx); + epoch_wait_preempt(led_epoch); sc = dev->si_drv1; dev->si_drv1 = NULL; if (sc->ptr != NULL) - blinkers--; - LIST_REMOVE(sc, list); - if (LIST_EMPTY(&led_list)) + refcount_release(&blinkers); + CK_LIST_REMOVE(sc, list); + if (CK_LIST_EMPTY(&led_list)) callout_stop(&led_ch); - mtx_unlock(&led_mtx); - sx_xlock(&led_sx); free_unr(led_unit, sc->unit); destroy_dev(dev); if (sc->spec != NULL) @@ -335,9 +346,10 @@ { led_unit = new_unrhdr(0, INT_MAX, NULL); - mtx_init(&led_mtx, "LED mtx", NULL, MTX_DEF); + led_epoch = epoch_alloc("LEDs", EPOCH_PREEMPT); + refcount_init(&blinkers, 0); sx_init(&led_sx, "LED sx"); - callout_init_mtx(&led_ch, &led_mtx, 0); + callout_init(&led_ch, 1); } SYSINIT(leddev, SI_SUB_DRIVERS, SI_ORDER_MIDDLE, led_drvinit, NULL);