Module Name: src Committed By: thorpej Date: Sun May 16 21:03:38 UTC 2021
Modified Files: src/sys/dev/i2c [thorpej-i2c-spi-conf]: i2c.c Log Message: - Set D_MCLOSE in the iic_cdevsw so that we get a d_close call for each close so that the module ref counting works properly. - Rearrange things a little to avoid holding the iic_mtx a long as previously done. To generate a diff of this commit: cvs rdiff -u -r1.78.2.3 -r1.78.2.4 src/sys/dev/i2c/i2c.c 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/i2c.c diff -u src/sys/dev/i2c/i2c.c:1.78.2.3 src/sys/dev/i2c/i2c.c:1.78.2.4 --- src/sys/dev/i2c/i2c.c:1.78.2.3 Sun May 16 04:40:08 2021 +++ src/sys/dev/i2c/i2c.c Sun May 16 21:03:38 2021 @@ -1,4 +1,4 @@ -/* $NetBSD: i2c.c,v 1.78.2.3 2021/05/16 04:40:08 thorpej Exp $ */ +/* $NetBSD: i2c.c,v 1.78.2.4 2021/05/16 21:03:38 thorpej Exp $ */ /*- * Copyright (c) 2021 The NetBSD Foundation, Inc. @@ -69,7 +69,7 @@ #endif #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.78.2.3 2021/05/16 04:40:08 thorpej Exp $"); +__KERNEL_RCSID(0, "$NetBSD: i2c.c,v 1.78.2.4 2021/05/16 21:03:38 thorpej Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -115,13 +115,6 @@ static dev_type_open(iic_open); static dev_type_close(iic_close); static dev_type_ioctl(iic_ioctl); -int iic_init(void); - -kmutex_t iic_mtx; -int iic_refcnt; - -ONCE_DECL(iic_once); - const struct cdevsw iic_cdevsw = { .d_open = iic_open, .d_close = iic_close, @@ -134,11 +127,16 @@ const struct cdevsw iic_cdevsw = { .d_mmap = nommap, .d_kqfilter = nokqfilter, .d_discard = nodiscard, - .d_flag = D_OTHER + .d_flag = D_OTHER | D_MCLOSE, }; static void iic_smbus_intr_thread(void *); +static kmutex_t iic_mtx; +static int iic_refcnt; +static bool iic_unloading; +static ONCE_DECL(iic_once); + static struct i2c_device_link * iic_devslot_lookup(struct iic_softc *sc, i2c_addr_t addr) { @@ -928,22 +926,43 @@ iic_use_direct_match(const struct i2c_at static int iic_open(dev_t dev, int flag, int fmt, lwp_t *l) { - struct iic_softc *sc = device_lookup_private(&iic_cd, minor(dev)); + struct iic_softc *sc; mutex_enter(&iic_mtx); - if (sc == NULL) { + + if (iic_unloading) { mutex_exit(&iic_mtx); return ENXIO; } + + /* Hold a refrence while we look up the softc. */ + if (iic_refcnt == INT_MAX) { + mutex_exit(&iic_mtx); + return EBUSY; + } iic_refcnt++; + mutex_exit(&iic_mtx); + sc = device_lookup_private(&iic_cd, minor(dev)); + + if (sc == NULL) { + mutex_enter(&iic_mtx); + iic_refcnt--; + mutex_exit(&iic_mtx); + return ENXIO; + } + return 0; } static int iic_close(dev_t dev, int flag, int fmt, lwp_t *l) { + struct iic_softc *sc = device_lookup_private(&iic_cd, minor(dev));; + + KASSERT(iic_refcnt != 0); + KASSERT(sc != NULL); mutex_enter(&iic_mtx); iic_refcnt--; @@ -1037,7 +1056,7 @@ MODULE(MODULE_CLASS_DRIVER, iic, "i2cexe #include "ioconf.c" #endif -int +static int iic_init(void) { @@ -1084,19 +1103,26 @@ iic_modcmd(modcmd_t cmd, void *opaque) mutex_exit(&iic_mtx); return EBUSY; } + iic_unloading = true; + mutex_exit(&iic_mtx); #ifdef _MODULE error = config_fini_component(cfdriver_ioconf_iic, cfattach_ioconf_iic, cfdata_ioconf_iic); if (error != 0) { + mutex_enter(&iic_mtx); + iic_unloading = false; mutex_exit(&iic_mtx); break; } error = devsw_detach(NULL, &iic_cdevsw); - if (error != 0) + if (error != 0) { config_init_component(cfdriver_ioconf_iic, cfattach_ioconf_iic, cfdata_ioconf_iic); + mutex_enter(&iic_mtx); + iic_unloading = false; + mutex_exit(&iic_mtx); + } #endif - mutex_exit(&iic_mtx); break; default: error = ENOTTY;