Module Name: src Committed By: kardel Date: Sun Jul 3 12:26:55 UTC 2016
Modified Files: src/sys/dev/i2c: hytp14.c hytp14var.h Log Message: convert device polling from callout to kthread. Solves: - hung initialization on A20 (bananapi) - allows iic_exec() implementations to use condvars To generate a diff of this commit: cvs rdiff -u -r1.6 -r1.7 src/sys/dev/i2c/hytp14.c cvs rdiff -u -r1.3 -r1.4 src/sys/dev/i2c/hytp14var.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/dev/i2c/hytp14.c diff -u src/sys/dev/i2c/hytp14.c:1.6 src/sys/dev/i2c/hytp14.c:1.7 --- src/sys/dev/i2c/hytp14.c:1.6 Fri Sep 18 17:21:43 2015 +++ src/sys/dev/i2c/hytp14.c Sun Jul 3 12:26:55 2016 @@ -1,5 +1,5 @@ /*- - * Copyright (c) 2014 The NetBSD Foundation, Inc. + * Copyright (c) 2014,2016 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -37,7 +37,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: hytp14.c,v 1.6 2015/09/18 17:21:43 phx Exp $"); +__KERNEL_RCSID(0, "$NetBSD: hytp14.c,v 1.7 2016/07/03 12:26:55 kardel Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -45,6 +45,9 @@ __KERNEL_RCSID(0, "$NetBSD: hytp14.c,v 1 #include <sys/device.h> #include <sys/module.h> #include <sys/sysctl.h> +#include <sys/mutex.h> +#include <sys/condvar.h> +#include <sys/kthread.h> #include <dev/sysmon/sysmonvar.h> #include <dev/i2c/i2cvar.h> @@ -59,9 +62,11 @@ static int hytp14_refresh_sensor(struct static void hytp14_refresh(struct sysmon_envsys *, envsys_data_t *); static void hytp14_refresh_humidity(struct hytp14_sc *, envsys_data_t *); static void hytp14_refresh_temp(struct hytp14_sc *, envsys_data_t *); +static void hytp14_thread(void *); static int sysctl_hytp14_interval(SYSCTLFN_ARGS); -/*#define HYT_DEBUG 3*/ +/* #define HYT_DEBUG 3 */ + #ifdef HYT_DEBUG volatile int hythygtemp_debug = HYT_DEBUG; @@ -115,7 +120,7 @@ hytp14_attach(device_t parent, device_t const struct sysctlnode *rnode, *node; struct hytp14_sc *sc; struct i2c_attach_args *ia; - int i; + int i, rv; ia = aux; sc = device_private(self); @@ -123,6 +128,12 @@ hytp14_attach(device_t parent, device_t sc->sc_dev = self; sc->sc_tag = ia->ia_tag; sc->sc_addr = ia->ia_addr; + + mutex_init(&sc->sc_mutex, MUTEX_DEFAULT, IPL_NONE); + cv_init(&sc->sc_condvar, "hytcv"); + + sc->sc_state = HYTP14_THR_INIT; + sc->sc_valid = ENVSYS_SINVALID; sc->sc_numsensors = __arraycount(hytp14_sensors); @@ -180,15 +191,18 @@ hytp14_attach(device_t parent, device_t sysctl_hytp14_interval, 0, (void *)sc, 0, CTL_HW, rnode->sysctl_num, CTL_CREATE, CTL_EOL); - aprint_normal(": HYT-221/271/939 humidity and temperature sensor\n"); - /* set up callout for the default measurement interval */ + /* set up the default measurement interval for worker thread */ sc->sc_mrinterval = HYTP14_MR_INTERVAL; - callout_init(&sc->sc_mrcallout, 0); - callout_setfunc(&sc->sc_mrcallout, hytp14_measurement_request, sc); - /* issue initial measurement request */ - hytp14_measurement_request(sc); + /* create worker kthread */ + rv = kthread_create(PRI_NONE, KTHREAD_MUSTJOIN, NULL, + hytp14_thread, sc, &sc->sc_thread, + "%s", device_xname(sc->sc_dev)); + if (rv) + aprint_error_dev(self, "unable to create intr thread\n"); + + aprint_normal(": HYT-221/271/939 humidity and temperature sensor\n"); } static int @@ -203,14 +217,65 @@ hytp14_detach(device_t self, int flags) sc->sc_sme = NULL; } - /* stop our measurement requests */ - callout_stop(&sc->sc_mrcallout); - callout_destroy(&sc->sc_mrcallout); - + /* stop measurement thread */ + mutex_enter(&sc->sc_mutex); + sc->sc_state = HYTP14_THR_STOP; + cv_signal(&sc->sc_condvar); + mutex_exit(&sc->sc_mutex); + + /* await thread completion */ + kthread_join(sc->sc_thread); + + /* cleanup */ + cv_destroy(&sc->sc_condvar); + mutex_destroy(&sc->sc_mutex); + return 0; } static void +hytp14_thread(void *aux) +{ + struct hytp14_sc *sc = aux; + int rv; + + mutex_enter(&sc->sc_mutex); + + DPRINTF(2, ("%s(%s): thread start - state=%d\n", + __func__, device_xname(sc->sc_dev), + sc->sc_state)); + + while (sc->sc_state != HYTP14_THR_STOP) { + sc->sc_state = HYTP14_THR_RUN; + + DPRINTF(2, ("%s(%s): waiting %d seconds\n", + __func__, device_xname(sc->sc_dev), + sc->sc_mrinterval)); + + rv = cv_timedwait(&sc->sc_condvar, &sc->sc_mutex, hz * sc->sc_mrinterval); + + if (rv == EWOULDBLOCK) { + /* timeout - run measurement */ + DPRINTF(2, ("%s(%s): timeout -> measurement\n", + __func__, device_xname(sc->sc_dev))); + + hytp14_measurement_request(sc); + } else { + DPRINTF(2, ("%s(%s): condvar signalled - state=%d\n", + __func__, device_xname(sc->sc_dev), + sc->sc_state)); + } + } + + mutex_exit(&sc->sc_mutex); + + DPRINTF(2, ("%s(%s): thread exit\n", + __func__, device_xname(sc->sc_dev))); + + kthread_exit(0); +} + +static void hytp14_measurement_request(void *aux) { uint8_t buf[I2C_EXEC_MAX_BUFLEN]; @@ -267,9 +332,6 @@ hytp14_measurement_request(void *aux) DPRINTF(2, ("%s: %s: failed acquire i2c bus - error %d\n", device_xname(sc->sc_dev), __func__, error)); } - - /* schedule next measurement interval */ - callout_schedule(&sc->sc_mrcallout, sc->sc_mrinterval * hz); } static int Index: src/sys/dev/i2c/hytp14var.h diff -u src/sys/dev/i2c/hytp14var.h:1.3 src/sys/dev/i2c/hytp14var.h:1.4 --- src/sys/dev/i2c/hytp14var.h:1.3 Wed Sep 9 17:16:20 2015 +++ src/sys/dev/i2c/hytp14var.h Sun Jul 3 12:26:55 2016 @@ -1,7 +1,7 @@ -/* $NetBSD: hytp14var.h,v 1.3 2015/09/09 17:16:20 phx Exp $ */ +/* $NetBSD: hytp14var.h,v 1.4 2016/07/03 12:26:55 kardel Exp $ */ /*- - * Copyright (c) 2014 The NetBSD Foundation, Inc. + * Copyright (c) 2014,2016 The NetBSD Foundation, Inc. * All rights reserved. * * This code is derived from software contributed to The NetBSD Foundation @@ -47,18 +47,26 @@ /* the default measurement interval is 50 seconds */ #define HYTP14_MR_INTERVAL 50 +#define HYTP14_THR_INIT 0 +#define HYTP14_THR_RUN 1 +#define HYTP14_THR_STOP 2 + struct hytp14_sc { device_t sc_dev; i2c_tag_t sc_tag; i2c_addr_t sc_addr; - + + kmutex_t sc_mutex; + kcondvar_t sc_condvar; + struct lwp *sc_thread; /* measurement poll thread */ + int sc_state; /* thread communication */ + int sc_valid; /* ENVSYS validity state for this sensor */ uint8_t sc_data[4]; /* current sensor data */ uint8_t sc_last[4]; /* last sensor data, before MR */ int sc_numsensors; - callout_t sc_mrcallout; int32_t sc_mrinterval; struct sysmon_envsys *sc_sme;