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 <gra...@openbsd.org>
  *
@@ -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 <gra...@openbsd.org>
  *
@@ -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_ */

Reply via email to