Module Name: src
Committed By: ad
Date: Sat Nov 30 23:04:12 UTC 2019
Modified Files:
src/sys/dev/gpio: gpioow.c
src/sys/dev/onewire: onewire.c onewire_bitbang.c onewirevar.h
Log Message:
onewire:
- Re-do the signalling to be a little more forgiving and efficient.
- If bus reset fails during probe, try a second time.
- Spread out kernel threads for many busses to avoid thundering herd effect.
To generate a diff of this commit:
cvs rdiff -u -r1.15 -r1.16 src/sys/dev/gpio/gpioow.c
cvs rdiff -u -r1.17 -r1.18 src/sys/dev/onewire/onewire.c
cvs rdiff -u -r1.1 -r1.2 src/sys/dev/onewire/onewire_bitbang.c
cvs rdiff -u -r1.5 -r1.6 src/sys/dev/onewire/onewirevar.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/gpio/gpioow.c
diff -u src/sys/dev/gpio/gpioow.c:1.15 src/sys/dev/gpio/gpioow.c:1.16
--- src/sys/dev/gpio/gpioow.c:1.15 Sat Oct 28 04:53:56 2017
+++ src/sys/dev/gpio/gpioow.c Sat Nov 30 23:04:12 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: gpioow.c,v 1.15 2017/10/28 04:53:56 riastradh Exp $ */
+/* $NetBSD: gpioow.c,v 1.16 2019/11/30 23:04:12 ad Exp $ */
/* $OpenBSD: gpioow.c,v 1.1 2006/03/04 16:27:03 grange Exp $ */
/*
@@ -18,7 +18,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: gpioow.c,v 1.15 2017/10/28 04:53:56 riastradh Exp $");
+__KERNEL_RCSID(0, "$NetBSD: gpioow.c,v 1.16 2019/11/30 23:04:12 ad Exp $");
/*
* 1-Wire bus bit-banging through GPIO pin.
@@ -57,7 +57,8 @@ int gpioow_detach(device_t, int);
int gpioow_activate(device_t, enum devact);
int gpioow_ow_reset(void *);
-int gpioow_ow_bit(void *, int);
+int gpioow_ow_read_bit(void *);
+void gpioow_ow_write_bit(void *, int);
void gpioow_bb_rx(void *);
void gpioow_bb_tx(void *);
@@ -143,7 +144,8 @@ gpioow_attach(device_t parent, device_t
/* Attach 1-Wire bus */
sc->sc_ow_bus.bus_cookie = sc;
sc->sc_ow_bus.bus_reset = gpioow_ow_reset;
- sc->sc_ow_bus.bus_bit = gpioow_ow_bit;
+ sc->sc_ow_bus.bus_read_bit = gpioow_ow_read_bit;
+ sc->sc_ow_bus.bus_write_bit = gpioow_ow_write_bit;
memset(&oba, 0, sizeof(oba));
oba.oba_bus = &sc->sc_ow_bus;
@@ -193,9 +195,15 @@ gpioow_ow_reset(void *arg)
}
int
-gpioow_ow_bit(void *arg, int value)
+gpioow_ow_read_bit(void *arg)
{
- return (onewire_bb_bit(&gpioow_bbops, arg, value));
+ return (onewire_bb_read_bit(&gpioow_bbops, arg));
+}
+
+void
+gpioow_ow_write_bit(void *arg, int value)
+{
+ onewire_bb_write_bit(&gpioow_bbops, arg, value);
}
void
Index: src/sys/dev/onewire/onewire.c
diff -u src/sys/dev/onewire/onewire.c:1.17 src/sys/dev/onewire/onewire.c:1.18
--- src/sys/dev/onewire/onewire.c:1.17 Fri Oct 25 16:25:14 2019
+++ src/sys/dev/onewire/onewire.c Sat Nov 30 23:04:12 2019
@@ -1,6 +1,35 @@
-/* $NetBSD: onewire.c,v 1.17 2019/10/25 16:25:14 martin Exp $ */
+/* $NetBSD: onewire.c,v 1.18 2019/11/30 23:04:12 ad Exp $ */
/* $OpenBSD: onewire.c,v 1.1 2006/03/04 16:27:03 grange Exp $ */
+/*-
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Doran.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
/*
* Copyright (c) 2006 Alexander Yurchenko <[email protected]>
*
@@ -18,7 +47,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: onewire.c,v 1.17 2019/10/25 16:25:14 martin Exp $");
+__KERNEL_RCSID(0, "$NetBSD: onewire.c,v 1.18 2019/11/30 23:04:12 ad Exp $");
/*
* 1-Wire bus driver.
@@ -202,14 +231,25 @@ onewire_reset(void *arg)
}
int
-onewire_bit(void *arg, int value)
+onewire_read_bit(void *arg)
{
struct onewire_softc *sc = arg;
struct onewire_bus *bus = sc->sc_bus;
KASSERT(mutex_owned(&sc->sc_lock));
- return bus->bus_bit(bus->bus_cookie, value);
+ return bus->bus_read_bit(bus->bus_cookie);
+}
+
+void
+onewire_write_bit(void *arg, int value)
+{
+ struct onewire_softc *sc = arg;
+ struct onewire_bus *bus = sc->sc_bus;
+
+ KASSERT(mutex_owned(&sc->sc_lock));
+
+ bus->bus_write_bit(bus->bus_cookie, value);
}
int
@@ -226,7 +266,7 @@ onewire_read_byte(void *arg)
return bus->bus_read_byte(bus->bus_cookie);
for (i = 0; i < 8; i++)
- value |= (bus->bus_bit(bus->bus_cookie, 1) << i);
+ value |= (bus->bus_read_bit(bus->bus_cookie) << i);
return value;
}
@@ -244,7 +284,7 @@ onewire_write_byte(void *arg, int value)
return bus->bus_write_byte(bus->bus_cookie, value);
for (i = 0; i < 8; i++)
- bus->bus_bit(bus->bus_cookie, (value >> i) & 0x1);
+ bus->bus_write_bit(bus->bus_cookie, (value >> i) & 0x1);
}
int
@@ -259,19 +299,19 @@ onewire_triplet(void *arg, int dir)
if (bus->bus_triplet != NULL)
return bus->bus_triplet(bus->bus_cookie, dir);
- rv = bus->bus_bit(bus->bus_cookie, 1);
+ rv = bus->bus_read_bit(bus->bus_cookie);
rv <<= 1;
- rv |= bus->bus_bit(bus->bus_cookie, 1);
+ rv |= bus->bus_read_bit(bus->bus_cookie);
switch (rv) {
case 0x0:
- bus->bus_bit(bus->bus_cookie, dir);
+ bus->bus_write_bit(bus->bus_cookie, dir);
break;
case 0x1:
- bus->bus_bit(bus->bus_cookie, 0);
+ bus->bus_write_bit(bus->bus_cookie, 0);
break;
default:
- bus->bus_bit(bus->bus_cookie, 1);
+ bus->bus_write_bit(bus->bus_cookie, 1);
}
return rv;
@@ -318,6 +358,18 @@ static void
onewire_thread(void *arg)
{
struct onewire_softc *sc = arg;
+ int unit, dly;
+
+ /*
+ * There can be many onewire busses, potentially funneled through
+ * few GPIO controllers. To avoid a thundering herd of kthreads and
+ * resulting contention for the GPIO controller, spread the probes
+ * out across an 8 second window. The kthreads could converge later
+ * due to timing effects.
+ */
+ unit = device_unit(sc->sc_dev);
+ dly = (unit & 0x07) * hz + ((unit >> 3) * hz >> 3) + 1;
+ (void)kpause("owdly", false, dly, NULL);
mutex_enter(&sc->sc_lock);
while (!sc->sc_dying) {
@@ -354,13 +406,17 @@ onewire_scan(struct onewire_softc *sc)
while (search && count++ < onewire_maxdevs) {
/*
- * Reset the bus. If there's no presence pulse
- * don't search for any devices.
+ * Reset the bus, allowing for one retry if reset fails. If
+ * there's no presence pulse don't search for any devices.
*/
if (onewire_reset(sc) != 0) {
DPRINTF(("%s: scan: no presence pulse\n",
device_xname(sc->sc_dev)));
- break;
+ if (onewire_reset(sc) != 0) {
+ DPRINTF(("%s: scan: retry failed\n",
+ device_xname(sc->sc_dev)));
+ break;
+ }
}
/*
@@ -405,6 +461,12 @@ onewire_scan(struct onewire_softc *sc)
}
lastd = i0;
+ /*
+ * Yield processor, but continue to hold the lock
+ * so that scan is not interrupted.
+ */
+ (void)kpause("owscan", false, 1, NULL);
+
if (rom == 0)
continue;
@@ -437,12 +499,6 @@ onewire_scan(struct onewire_softc *sc)
nd->d_present = true;
TAILQ_INSERT_TAIL(&sc->sc_devs, nd, d_list);
}
-
- /*
- * Yield processor, but continue to hold the lock
- * so that scan is not interrupted.
- */
- kpause("owscan", false, 1, NULL);
}
/*
Index: src/sys/dev/onewire/onewire_bitbang.c
diff -u src/sys/dev/onewire/onewire_bitbang.c:1.1 src/sys/dev/onewire/onewire_bitbang.c:1.2
--- src/sys/dev/onewire/onewire_bitbang.c:1.1 Fri Apr 7 18:55:22 2006
+++ src/sys/dev/onewire/onewire_bitbang.c Sat Nov 30 23:04:12 2019
@@ -1,6 +1,35 @@
-/* $NetBSD: onewire_bitbang.c,v 1.1 2006/04/07 18:55:22 riz Exp $ */
+/* $NetBSD: onewire_bitbang.c,v 1.2 2019/11/30 23:04:12 ad Exp $ */
/* $OpenBSD: onewire_bitbang.c,v 1.1 2006/03/04 16:27:03 grange Exp $ */
+/*-
+ * Copyright (c) 2019 The NetBSD Foundation, Inc.
+ * All rights reserved.
+ *
+ * This code is derived from software contributed to The NetBSD Foundation
+ * by Andrew Doran.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
+ * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+ * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
+ * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
+ * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+ * POSSIBILITY OF SUCH DAMAGE.
+ */
+
/*
* Copyright (c) 2006 Alexander Yurchenko <[email protected]>
*
@@ -18,7 +47,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: onewire_bitbang.c,v 1.1 2006/04/07 18:55:22 riz Exp $");
+__KERNEL_RCSID(0, "$NetBSD: onewire_bitbang.c,v 1.2 2019/11/30 23:04:12 ad Exp $");
/*
* 1-Wire bus bit-banging routines.
@@ -27,55 +56,131 @@ __KERNEL_RCSID(0, "$NetBSD: onewire_bitb
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/device.h>
+#include <sys/proc.h>
#include <dev/onewire/onewirevar.h>
+ /*
+ * Reset the bus. Sequence from DS18B20 datasheet:
+ *
+ * 1: Master pulls bus low for a minimum of 480us.
+ * 2: Bus pulled up by resistor. DS18B20 detects rising edge, waits 15-60us.
+ * 3: DS18B20 pulls bus low for 60-240us.
+ * 4: Bus pulled up by resistor. Master must wait at least 450us.
+ *
+ * 111111111112222233333444444444
+ *
+ * Vpu | +-+ +----->
+ * | / | /
+ * GND +----------+ +-----+
+ */
int
onewire_bb_reset(const struct onewire_bbops *ops, void *arg)
{
- int s, rv = 0, i;
+ int s, rv, i;
+ rv = 0;
s = splhigh();
ops->bb_tx(arg);
ops->bb_set(arg, 0);
- DELAY(480);
+ delay(500);
ops->bb_set(arg, 1);
ops->bb_rx(arg);
- DELAY(30);
- for (i = 0; i < 6; i++) {
+ for (i = 0; i < 240 / 5; i++) {
+ delay(5);
if ((rv = ops->bb_get(arg)) == 0)
break;
- DELAY(20);
}
- DELAY(450);
+ splx(s);
+
+ /*
+ * After a bus reset, we must wait for at least 450us before any
+ * further device access. There is no upper bound on this time, so
+ * rather than burning CPU, sleep for 1 tick.
+ */
+ KASSERT(2001 > hz);
+ (void)kpause("owreset", false, 1, NULL);
+
+ /*
+ * With a push-pull GPIO, bring the bus high to supply
+ * parasite-powered devices. With either PP or open drain,
+ * past this point on entry to onewire_bb_write_bit() and
+ * onewire_bb_read_bit() we assume that the line is set to
+ * output and not being held low.
+ */
+ s = splhigh();
+ ops->bb_tx(arg);
+ ops->bb_set(arg, 1);
splx(s);
- return (rv);
+ return rv;
}
+/*
+ * Onewire bit write.
+ *
+ * Method: pull the bus low. Then let the pull up resistor settle the bus.
+ * ZERO is signalled by the bus being held low for minimum 60us.
+ * ONE is signalled by the hold being much shorter (minimum 1us).
+ *
+ * In any eventuality, pad the entire transaction to the minimum 60us, plus
+ * an additional bit of recovery time before the next transaction
+ */
+void
+onewire_bb_write_bit(const struct onewire_bbops *ops, void *arg, int value)
+{
+ int s, d1, d2;
+
+ if (value) {
+ d1 = 2;
+ d2 = 62;
+ } else {
+ d1 = 62;
+ d2 = 2;
+ }
+
+ s = splhigh();
+ ops->bb_set(arg, 0);
+ delay(d1);
+ ops->bb_set(arg, 1);
+ splx(s);
+ /* Timing no longer critical. */
+ delay(d2);
+}
+
+/*
+ * Onewire bit read.
+ *
+ * Method: pull the bus low for at least 1us. Then let the pull up resistor
+ * settle the bus. ZERO is signalled by the bus being pulled low again by
+ * the slave at some point between 15-45us of transaction start. ONE is
+ * signalled by the bus not being pulled low.
+ *
+ * In any eventuality, pad the entire transaction to the minimum 60us, plus
+ * an additional bit of recovery time before the next transaction.
+ */
int
-onewire_bb_bit(const struct onewire_bbops *ops, void *arg, int value)
+onewire_bb_read_bit(const struct onewire_bbops *ops, void *arg)
{
- int s, rv = 0, i;
+ int s, rv, us;
s = splhigh();
- ops->bb_tx(arg);
ops->bb_set(arg, 0);
- DELAY(2);
- if (value) {
- ops->bb_set(arg, 1);
- ops->bb_rx(arg);
- for (i = 0; i < 15; i++) {
- if ((rv = ops->bb_get(arg)) == 0)
- break;
- DELAY(2);
+ delay(2);
+ ops->bb_set(arg, 1);
+ ops->bb_rx(arg);
+ for (us = 62; us >= 60 - 45; us -= 5) {
+ delay(5);
+ if ((rv = ops->bb_get(arg)) == 0) {
+ break;
}
- ops->bb_tx(arg);
}
- DELAY(60);
- ops->bb_set(arg, 1);
- DELAY(5);
splx(s);
-
- return (rv);
+ /* Timing no longer critical, and no further need to poll. */
+ if (us > 0) {
+ delay(us);
+ }
+ ops->bb_tx(arg);
+ ops->bb_set(arg, 1);
+ return rv;
}
Index: src/sys/dev/onewire/onewirevar.h
diff -u src/sys/dev/onewire/onewirevar.h:1.5 src/sys/dev/onewire/onewirevar.h:1.6
--- src/sys/dev/onewire/onewirevar.h:1.5 Wed Sep 5 15:39:22 2007
+++ src/sys/dev/onewire/onewirevar.h Sat Nov 30 23:04:12 2019
@@ -1,4 +1,4 @@
-/* $NetBSD: onewirevar.h,v 1.5 2007/09/05 15:39:22 xtraeme Exp $ */
+/* $NetBSD: onewirevar.h,v 1.6 2019/11/30 23:04:12 ad Exp $ */
/* $OpenBSD: onewirevar.h,v 1.1 2006/03/04 16:27:03 grange Exp $ */
/*
@@ -29,7 +29,8 @@ struct onewire_bus {
void * bus_cookie;
int (*bus_reset)(void *);
- int (*bus_bit)(void *, int);
+ int (*bus_read_bit)(void *);
+ void (*bus_write_bit)(void *, int);
int (*bus_read_byte)(void *);
void (*bus_write_byte)(void *, int);
int (*bus_triplet)(void *, int);
@@ -39,7 +40,8 @@ struct onewire_bus {
void onewire_lock(void *);
void onewire_unlock(void *);
int onewire_reset(void *);
-int onewire_bit(void *, int);
+int onewire_read_bit(void *);
+void onewire_write_bit(void *, int);
int onewire_read_byte(void *);
void onewire_write_byte(void *, int);
int onewire_triplet(void *, int);
@@ -80,6 +82,7 @@ struct onewire_bbops {
};
int onewire_bb_reset(const struct onewire_bbops *, void *);
-int onewire_bb_bit(const struct onewire_bbops *, void *, int);
+int onewire_bb_read_bit(const struct onewire_bbops *, void *);
+void onewire_bb_write_bit(const struct onewire_bbops *, void *, int);
#endif /* !_DEV_ONEWIRE_ONEWIREVAR_H_ */