Module Name:    src
Committed By:   thorpej
Date:           Tue May 18 23:48:16 UTC 2021

Modified Files:
        src/sys/dev/fdt [thorpej-i2c-spi-conf]: fdt_spi.c
        src/sys/dev/ofw [thorpej-i2c-spi-conf]: ofw_spi_subr.c
        src/sys/dev/spi [thorpej-i2c-spi-conf]: spi.c spivar.h

Log Message:
Define a "spi-enumerate-devices" device call and use it for direct
configuration of SPI devices, rather than slinging arrays of dictionaries
around.  Implement this device call for OpenFirmware / FDT, following
the SPI bindings for Device Tree.


To generate a diff of this commit:
cvs rdiff -u -r1.2 -r1.2.2.1 src/sys/dev/fdt/fdt_spi.c
cvs rdiff -u -r1.1 -r1.1.6.1 src/sys/dev/ofw/ofw_spi_subr.c
cvs rdiff -u -r1.17 -r1.17.2.1 src/sys/dev/spi/spi.c
cvs rdiff -u -r1.10 -r1.10.6.1 src/sys/dev/spi/spivar.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/fdt/fdt_spi.c
diff -u src/sys/dev/fdt/fdt_spi.c:1.2 src/sys/dev/fdt/fdt_spi.c:1.2.2.1
--- src/sys/dev/fdt/fdt_spi.c:1.2	Sat Apr 24 23:36:53 2021
+++ src/sys/dev/fdt/fdt_spi.c	Tue May 18 23:48:16 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: fdt_spi.c,v 1.2 2021/04/24 23:36:53 thorpej Exp $ */
+/* $NetBSD: fdt_spi.c,v 1.2.2.1 2021/05/18 23:48:16 thorpej Exp $ */
 
 /*
  * Copyright (c) 2019 The NetBSD Foundation, Inc.
@@ -30,7 +30,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: fdt_spi.c,v 1.2 2021/04/24 23:36:53 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: fdt_spi.c,v 1.2.2.1 2021/05/18 23:48:16 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
@@ -84,33 +84,17 @@ device_t
 fdtbus_attach_spibus(device_t dev, int phandle, cfprint_t print)
 {
 	struct spi_controller *spi;
-	struct spibus_attach_args sba;
-	prop_dictionary_t devs;
-	device_t ret;
-	u_int address_cells;
-
-	devs = prop_dictionary_create();
-	if (of_getprop_uint32(phandle, "#address-cells", &address_cells))
-		address_cells = 1;
-	of_enter_spi_devs(devs, phandle, address_cells * 4);
 
 	spi = fdtbus_get_spi_controller(phandle);
 	KASSERT(spi != NULL);
-	memset(&sba, 0, sizeof(sba));
-	sba.sba_controller = spi;
 
-	sba.sba_child_devices = prop_dictionary_get(devs, "spi-child-devices");
-	if (sba.sba_child_devices)
-		prop_object_retain(sba.sba_child_devices);
-	prop_object_release(devs);
-
-	ret = config_found(dev, &sba, print,
+	struct spibus_attach_args sba = {
+		.sba_controller = spi,
+	};
+	return config_found(dev, &sba, print,
 	    CFARG_IATTR, "spibus",
+	    CFARG_DEVHANDLE, device_handle(dev),
 	    CFARG_EOL);
-	if (sba.sba_child_devices)
-		prop_object_release(sba.sba_child_devices);
-
-	return ret;
 }
 
 

Index: src/sys/dev/ofw/ofw_spi_subr.c
diff -u src/sys/dev/ofw/ofw_spi_subr.c:1.1 src/sys/dev/ofw/ofw_spi_subr.c:1.1.6.1
--- src/sys/dev/ofw/ofw_spi_subr.c:1.1	Thu Feb  4 20:19:09 2021
+++ src/sys/dev/ofw/ofw_spi_subr.c	Tue May 18 23:48:16 2021
@@ -1,100 +1,96 @@
-/*	$NetBSD: ofw_spi_subr.c,v 1.1 2021/02/04 20:19:09 thorpej Exp $	*/
+/*	$NetBSD: ofw_spi_subr.c,v 1.1.6.1 2021/05/18 23:48:16 thorpej Exp $	*/
 
 /*
- * Copyright 1998
- * Digital Equipment Corporation. All rights reserved.
+ * Copyright (c) 2021 The NetBSD Foundation, Inc.
+ * All rights reserved.
  *
- * This software is furnished under license and may be used and
- * copied only in accordance with the following terms and conditions.
- * Subject to these conditions, you may download, copy, install,
- * use, modify and distribute this software in source and/or binary
- * form. No title or ownership is transferred hereby.
+ * 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.
  *
- * 1) Any source code used, modified or distributed must reproduce
- *    and retain this copyright notice and list of conditions as
- *    they appear in the source file.
- *
- * 2) No right is granted to use any trade name, trademark, or logo of
- *    Digital Equipment Corporation. Neither the "Digital Equipment
- *    Corporation" name nor any trademark or logo of Digital Equipment
- *    Corporation may be used to endorse or promote products derived
- *    from this software without the prior written permission of
- *    Digital Equipment Corporation.
- *
- * 3) This software is provided "AS-IS" and any express or implied
- *    warranties, including but not limited to, any implied warranties
- *    of merchantability, fitness for a particular purpose, or
- *    non-infringement are disclaimed. In no event shall DIGITAL be
- *    liable for any damages whatsoever, and in particular, DIGITAL
- *    shall not be liable for special, indirect, consequential, or
- *    incidental damages or damages for lost profits, loss of
- *    revenue or loss of use, whether such damages arise in contract,
- *    negligence, tort, under statute, in equity, at law or otherwise,
- *    even if advised of the possibility of such damage.
+ * 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.
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: ofw_spi_subr.c,v 1.1 2021/02/04 20:19:09 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: ofw_spi_subr.c,v 1.1.6.1 2021/05/18 23:48:16 thorpej Exp $");
 
 #include <sys/param.h>
 #include <sys/device.h>
 #include <sys/kmem.h>
 #include <sys/systm.h>
 #include <dev/ofw/openfirm.h>
+#include <dev/spi/spivar.h>
 
-void
-of_enter_spi_devs(prop_dictionary_t props, int ofnode, size_t cell_size)
+static int
+of_spi_enumerate_devices(device_t dev, devhandle_t call_handle, void *v)
 {
-	int node, len;
-	char name[32];
-	uint64_t reg64;
-	uint32_t reg32;
-	uint32_t slave;
-	u_int32_t maxfreq;
-	prop_array_t array = NULL;
-	prop_dictionary_t dev;
-	int mode;
+	struct spi_enumerate_devices_args *args = v;
+	int spi_node, node;
+	char name[32], compat_buf[32];
+	uint32_t chip_select;
+	char *clist;
+	int clist_size;
+	bool cbrv;
+
+	spi_node = devhandle_to_of(call_handle);
 
-	for (node = OF_child(ofnode); node; node = OF_peer(node)) {
-		if (OF_getprop(node, "name", name, sizeof(name)) <= 0)
+	for (node = OF_child(spi_node); node != 0; node = OF_peer(node)) {
+		if (OF_getprop(node, "name", name, sizeof(name)) <= 0) {
 			continue;
-		len = OF_getproplen(node, "reg");
-		slave = 0;
-		if (cell_size == 8 && len >= sizeof(reg64)) {
-			if (OF_getprop(node, "reg", &reg64, sizeof(reg64))
-			    < sizeof(reg64))
-				continue;
-			slave = be64toh(reg64);
-		} else if (cell_size == 4 && len >= sizeof(reg32)) {
-			if (OF_getprop(node, "reg", &reg32, sizeof(reg32))
-			    < sizeof(reg32))
-				continue;
-			slave = be32toh(reg32);
-		} else {
+		}
+
+		if (of_getprop_uint32(node, "reg", &chip_select) != 0) {
 			continue;
 		}
-		if (of_getprop_uint32(node, "spi-max-frequency", &maxfreq)) {
-			maxfreq = 0;
+
+		/* Device Tree bindings specify a max chip select of 256. */
+		if (chip_select > 256) {
+			continue;
 		}
-		mode = ((int)of_hasprop(node, "cpol") << 1) | (int)of_hasprop(node, "cpha");
 
-		if (array == NULL)
-			array = prop_array_create();
+		clist_size = OF_getproplen(node, "compatible");
+		if (clist_size <= 0) {
+			continue;
+		}
 
-		dev = prop_dictionary_create();
-		prop_dictionary_set_string(dev, "name", name);
-		prop_dictionary_set_uint32(dev, "slave", slave);
-		prop_dictionary_set_uint32(dev, "mode", mode);
-		if (maxfreq > 0)
-			prop_dictionary_set_uint32(dev, "spi-max-frequency", maxfreq);
-		prop_dictionary_set_uint64(dev, "cookie", node);
-		of_to_dataprop(dev, node, "compatible", "compatible");
-		prop_array_add(array, dev);
-		prop_object_release(dev);
-	}
+		clist = kmem_tmpbuf_alloc(clist_size,
+		    compat_buf, sizeof(compat_buf), KM_SLEEP);
+		if (OF_getprop(node, "compatible", clist, clist_size) <
+		    clist_size) {
+			kmem_tmpbuf_free(clist, clist_size, compat_buf);
+			continue;
+		}
+
+		args->chip_select = (int)chip_select;
+		args->sa->sa_name = name;
+		args->sa->sa_clist = clist;
+		args->sa->sa_clist_size = clist_size;
+		args->sa->sa_devhandle = devhandle_from_of(node);
 
-	if (array != NULL) {
-		prop_dictionary_set(props, "spi-child-devices", array);
-		prop_object_release(array);
+		cbrv = args->callback(dev, args);
+
+		kmem_tmpbuf_free(clist, clist_size, compat_buf);
+
+		if (!cbrv) {
+			break;
+		}
 	}
+
+	return 0;
 }
+OF_DEVICE_CALL_REGISTER("spi-enumerate-devices", of_spi_enumerate_devices);

Index: src/sys/dev/spi/spi.c
diff -u src/sys/dev/spi/spi.c:1.17 src/sys/dev/spi/spi.c:1.17.2.1
--- src/sys/dev/spi/spi.c:1.17	Sat Apr 24 23:36:59 2021
+++ src/sys/dev/spi/spi.c	Tue May 18 23:48:16 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: spi.c,v 1.17 2021/04/24 23:36:59 thorpej Exp $ */
+/* $NetBSD: spi.c,v 1.17.2.1 2021/05/18 23:48:16 thorpej Exp $ */
 
 /*-
  * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
@@ -42,7 +42,7 @@
  */
 
 #include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: spi.c,v 1.17 2021/04/24 23:36:59 thorpej Exp $");
+__KERNEL_RCSID(0, "$NetBSD: spi.c,v 1.17.2.1 2021/05/18 23:48:16 thorpej Exp $");
 
 #include "locators.h"
 
@@ -50,7 +50,7 @@ __KERNEL_RCSID(0, "$NetBSD: spi.c,v 1.17
 #include <sys/systm.h>
 #include <sys/device.h>
 #include <sys/conf.h>
-#include <sys/malloc.h>
+#include <sys/kmem.h>
 #include <sys/mutex.h>
 #include <sys/condvar.h>
 #include <sys/errno.h>
@@ -62,12 +62,14 @@ __KERNEL_RCSID(0, "$NetBSD: spi.c,v 1.17
 #include "locators.h"
 
 struct spi_softc {
+	device_t		sc_dev;
 	struct spi_controller	sc_controller;
 	int			sc_mode;
 	int			sc_speed;
 	int			sc_slave;
 	int			sc_nslaves;
 	struct spi_handle	*sc_slaves;
+	kmutex_t		sc_slave_state_lock;
 	kmutex_t		sc_lock;
 	kcondvar_t		sc_cv;
 	int			sc_flags;
@@ -97,13 +99,14 @@ const struct cdevsw spi_cdevsw = {
  * SPI slave device.  We have one of these per slave.
  */
 struct spi_handle {
-	struct spi_softc	*sh_sc;
-	struct spi_controller	*sh_controller;
-	int			sh_slave;
-	int			sh_mode;
-	int			sh_speed;
-	int			sh_flags;
-#define SPIH_ATTACHED		1
+	struct spi_softc	*sh_sc;		/* static */
+	struct spi_controller	*sh_controller;	/* static */
+	int			sh_slave;	/* static */
+	int			sh_mode;	/* locked by owning child */
+	int			sh_speed;	/* locked by owning child */
+	int			sh_flags;	/* ^^ slave_state_lock ^^ */
+#define SPIH_ATTACHED		__BIT(0)
+#define SPIH_DIRECT		__BIT(1)
 };
 
 #define SPI_MAXDATA 4096
@@ -131,152 +134,143 @@ spi_match(device_t parent, cfdata_t cf, 
 }
 
 static int
-spi_print(void *aux, const char *pnp)
+spi_print_direct(void *aux, const char *pnp)
 {
 	struct spi_attach_args *sa = aux;
 
-	if (sa->sa_handle->sh_slave != -1)
+	if (pnp != NULL) {
+		aprint_normal("%s%s%s%s at %s slave %d",
+		    sa->sa_name ? sa->sa_name : "(unknown)",
+		    sa->sa_clist ? " (" : "",
+		    sa->sa_clist ? sa->sa_clist : "",
+		    sa->sa_clist ? ")" : "",
+		    pnp, sa->sa_handle->sh_slave);
+	} else {
 		aprint_normal(" slave %d", sa->sa_handle->sh_slave);
+	}
 
-	return (UNCONF);
+	return UNCONF;
 }
 
 static int
-spi_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
+spi_print(void *aux, const char *pnp)
 {
-	struct spi_softc *sc = device_private(parent);
-	struct spi_attach_args sa;
-	int addr;
-
-	addr = cf->cf_loc[SPICF_SLAVE];
-	if ((addr < 0) || (addr >= sc->sc_controller.sct_nslaves)) {
-		return -1;
-	}
-
-	memset(&sa, 0, sizeof sa);
-	sa.sa_handle = &sc->sc_slaves[addr];
-	if (ISSET(sa.sa_handle->sh_flags, SPIH_ATTACHED))
-		return -1;
+	struct spi_attach_args *sa = aux;
 
-	if (config_probe(parent, cf, &sa)) {
-		SET(sa.sa_handle->sh_flags, SPIH_ATTACHED);
-		config_attach(parent, cf, &sa, spi_print, CFARG_EOL);
-	}
+	aprint_normal(" slave %d", sa->sa_handle->sh_slave);
 
-	return 0;
+	return UNCONF;
 }
 
 /*
- * XXX this is the same as i2c_fill_compat. It could be refactored into a
- * common fill_compat function with pointers to compat & ncompat instead
- * of attach_args as the first parameter.
+ * Direct and indrect for SPI are pretty similar, so we can collapse
+ * them into a single function.
  */
 static void
-spi_fill_compat(struct spi_attach_args *sa, const char *compat, size_t len,
-	char **buffer)
+spi_attach_child(struct spi_softc *sc, struct spi_attach_args *sa,
+    int chip_select, cfdata_t cf)
 {
-	int count, i;
-	const char *c, *start, **ptr;
+	struct spi_handle *sh;
+	device_t newdev = NULL;
+	bool is_direct = cf == NULL;
+	const int skip_flags = is_direct ? SPIH_ATTACHED
+					 : (SPIH_ATTACHED | SPIH_DIRECT);
+	const int claim_flags = skip_flags ^ SPIH_DIRECT;
+	int locs[SPICF_NLOCS] = { 0 };
 
-	*buffer = NULL;
-	for (i = count = 0, c = compat; i < len; i++, c++)
-		if (*c == 0)
-			count++;
-	count += 2;
-	ptr = malloc(sizeof(char*)*count, M_TEMP, M_WAITOK);
-	if (!ptr)
+	if (chip_select < 0 ||
+	    chip_select >= sc->sc_controller.sct_nslaves) {
 		return;
+	}
 
-	for (i = count = 0, start = c = compat; i < len; i++, c++) {
-		if (*c == 0) {
-			ptr[count++] = start;
-			start = c + 1;
-		}
+	sh = &sc->sc_slaves[chip_select];
+
+	mutex_enter(&sc->sc_slave_state_lock);
+	if (ISSET(sh->sh_flags, skip_flags)) {
+		mutex_exit(&sc->sc_slave_state_lock);
+		return;
 	}
-	if (start < compat + len) {
-		/* last string not 0 terminated */
-		size_t l = c - start;
-		*buffer = malloc(l + 1, M_TEMP, M_WAITOK);
-		memcpy(*buffer, start, l);
-		(*buffer)[l] = 0;
-		ptr[count++] = *buffer;
+
+	/* Keep others off of this chip select. */
+	SET(sh->sh_flags, claim_flags);
+	mutex_exit(&sc->sc_slave_state_lock);
+
+	locs[SPICF_SLAVE] = chip_select;
+	sa->sa_handle = sh;
+
+	if (is_direct) {
+		newdev = config_found(sc->sc_dev, sa, spi_print_direct,
+		    /* CFARG_SUBMATCH, config_stdsubmatch, XXX */
+		    CFARG_LOCATORS, locs,
+		    CFARG_DEVHANDLE, sa->sa_devhandle,
+		    CFARG_EOL);
+	} else {
+		if (config_probe(sc->sc_dev, cf, &sa)) {
+			newdev = config_attach(sc->sc_dev, cf, &sa, spi_print,
+			    CFARG_LOCATORS, locs,
+			    CFARG_EOL);
+		}
 	}
-	ptr[count] = NULL;
 
-	sa->sa_compat = ptr;
-	sa->sa_ncompat = count;
+	if (newdev == NULL) {
+		/*
+		 * Clear our claim on this chip select (yes, just
+		 * the ATTACHED flag; we want to keep indirects off
+		 * of chip selects for which there is a device tree
+		 * node).
+		 */
+		mutex_enter(&sc->sc_slave_state_lock);
+		CLR(sh->sh_flags, SPIH_ATTACHED);
+		mutex_exit(&sc->sc_slave_state_lock);
+	}
 }
 
-static void
-spi_direct_attach_child_devices(device_t parent, struct spi_softc *sc,
-    prop_array_t child_devices)
+static int
+spi_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux)
 {
-	unsigned int count;
-	prop_dictionary_t child;
-	prop_data_t cdata;
-	uint32_t slave;
-	uint64_t cookie;
+	struct spi_softc *sc = device_private(parent);
 	struct spi_attach_args sa;
-	int loc[SPICF_NLOCS];
-	char *buf;
-	int i;
-
-	memset(loc, 0, sizeof loc);
-	count = prop_array_count(child_devices);
-	for (i = 0; i < count; i++) {
-		child = prop_array_get(child_devices, i);
-		if (!child)
-			continue;
-		if (!prop_dictionary_get_uint32(child, "slave", &slave))
-			continue;
-		if(slave >= sc->sc_controller.sct_nslaves)
-			continue;
-		if (!prop_dictionary_get_uint64(child, "cookie", &cookie))
-			continue;
-		if (!(cdata = prop_dictionary_get(child, "compatible")))
-			continue;
-		loc[SPICF_SLAVE] = slave;
-
-		memset(&sa, 0, sizeof sa);
-		sa.sa_handle = &sc->sc_slaves[i];
-		sa.sa_prop = child;
-		sa.sa_cookie = cookie;
-		if (ISSET(sa.sa_handle->sh_flags, SPIH_ATTACHED))
-			continue;
-		SET(sa.sa_handle->sh_flags, SPIH_ATTACHED);
-
-		buf = NULL;
-		spi_fill_compat(&sa,
-				prop_data_value(cdata),
-				prop_data_size(cdata), &buf);
-		config_found(parent, &sa, spi_print,
-		    CFARG_LOCATORS, loc,
-		    CFARG_EOL);
 
-		if (sa.sa_compat)
-			free(sa.sa_compat, M_TEMP);
-		if (buf)
-			free(buf, M_TEMP);
+	if (cf->cf_loc[SPICF_SLAVE] == SPICF_SLAVE_DEFAULT) {
+		/* No wildcards for indirect on SPI. */
+		return 0;
 	}
+
+	memset(&sa, 0, sizeof(sa));
+	spi_attach_child(sc, &sa, cf->cf_loc[SPICF_SLAVE], cf);
+
+	return 0;
+}
+
+static bool
+spi_enumerate_devices_callback(device_t self,
+    struct spi_enumerate_devices_args *args)
+{
+	struct spi_softc *sc = device_private(self);
+
+	spi_attach_child(sc, args->sa, args->chip_select, NULL);
+
+	return true;				/* keep enumerating */
 }
 
 int
 spi_compatible_match(const struct spi_attach_args *sa, const cfdata_t cf,
 		     const struct device_compatible_entry *compats)
 {
-	if (sa->sa_ncompat > 0)
-		return device_compatible_match(sa->sa_compat, sa->sa_ncompat,
-					       compats);
+	if (sa->sa_clist != NULL) {
+		return device_compatible_match_strlist(sa->sa_clist,
+		    sa->sa_clist_size, compats);
+	}
 
+	/*
+	 * In this case, we're using indirect configuration, but SPI
+	 * has no real addressing system, and we've filtered out
+	 * wildcarded chip selects in spi_search(), so we have no
+	 * choice but to trust the user-specified config.
+	 */
 	return 1;
 }
 
-/*
- * API for device drivers.
- *
- * We provide wrapper routines to decouple the ABI for the SPI
- * device drivers from the ABI for the SPI bus drivers.
- */
 static void
 spi_attach(device_t parent, device_t self, void *aux)
 {
@@ -284,17 +278,21 @@ spi_attach(device_t parent, device_t sel
 	struct spibus_attach_args *sba = aux;
 	int i;
 
+	sc->sc_dev = self;
+
 	aprint_naive(": SPI bus\n");
 	aprint_normal(": SPI bus\n");
 
 	mutex_init(&sc->sc_lock, MUTEX_DEFAULT, IPL_VM);
+	mutex_init(&sc->sc_slave_state_lock, MUTEX_DEFAULT, IPL_NONE);
 	cv_init(&sc->sc_cv, "spictl");
 
 	sc->sc_controller = *sba->sba_controller;
 	sc->sc_nslaves = sba->sba_controller->sct_nslaves;
+
 	/* allocate slave structures */
-	sc->sc_slaves = malloc(sizeof (struct spi_handle) * sc->sc_nslaves,
-	    M_DEVBUF, M_WAITOK | M_ZERO);
+	sc->sc_slaves = kmem_zalloc(sizeof(*sc->sc_slaves) * sc->sc_nslaves,
+	    KM_SLEEP);
 
 	sc->sc_speed = 0;
 	sc->sc_mode = -1;
@@ -309,16 +307,26 @@ spi_attach(device_t parent, device_t sel
 		sc->sc_slaves[i].sh_controller = &sc->sc_controller;
 	}
 
-	/* First attach devices known to be present via fdt */
-	if (sba->sba_child_devices) {
-		spi_direct_attach_child_devices(self, sc, sba->sba_child_devices);
-	}
+	/*
+	 * Attempt to enumerate the devices on the bus using the
+	 * platform device tree.
+	 */
+	struct spi_attach_args sa = { 0 };
+	struct spi_enumerate_devices_args enumargs = {
+		.sa = &sa,
+		.callback = spi_enumerate_devices_callback,
+	};
+	device_call(self, "spi-enumerate-devices", &enumargs);
+
 	/* Then do any other devices the user may have manually wired */
 	config_search(self, NULL,
 	    CFARG_SEARCH, spi_search,
 	    CFARG_EOL);
 }
 
+CFATTACH_DECL_NEW(spi, sizeof(struct spi_softc),
+    spi_match, spi_attach, NULL, NULL);
+
 static int
 spi_open(dev_t dev, int flag, int fmt, lwp_t *l)
 {
@@ -375,11 +383,11 @@ spi_ioctl(dev_t dev, u_long cmd, void *d
 		sbuf = rbuf = NULL;
 		error = 0;
 		if (sit->sit_send && sit->sit_sendlen <= SPI_MAXDATA) {
-			sbuf = malloc(sit->sit_sendlen, M_DEVBUF, M_WAITOK);
+			sbuf = kmem_alloc(sit->sit_sendlen, KM_SLEEP);
 			error = copyin(sit->sit_send, sbuf, sit->sit_sendlen);
 		}
 		if (sit->sit_recv && sit->sit_recvlen <= SPI_MAXDATA) {
-			rbuf = malloc(sit->sit_recvlen, M_DEVBUF, M_WAITOK);
+			rbuf = kmem_alloc(sit->sit_recvlen, KM_SLEEP);
 		}
 		if (error == 0) {
 			if (sbuf && rbuf)
@@ -397,10 +405,10 @@ spi_ioctl(dev_t dev, u_long cmd, void *d
 			if (error == 0)
 				error = copyout(rbuf, sit->sit_recv,
 						sit->sit_recvlen);
-			free(rbuf, M_DEVBUF);
+			kmem_free(rbuf, sit->sit_recvlen);
 		}
 		if (sbuf) {
-			free(sbuf, M_DEVBUF);
+			kmem_free(sbuf, sit->sit_sendlen);
 		}
 		break;
 	default:
@@ -411,8 +419,12 @@ spi_ioctl(dev_t dev, u_long cmd, void *d
 	return error;
 }
 
-CFATTACH_DECL_NEW(spi, sizeof(struct spi_softc),
-    spi_match, spi_attach, NULL, NULL);
+/*
+ * API for device drivers.
+ *
+ * We provide wrapper routines to decouple the ABI for the SPI
+ * device drivers from the ABI for the SPI bus drivers.
+ */
 
 /*
  * Configure.  This should be the first thing that the SPI driver
@@ -662,4 +674,3 @@ spi_send_recv(struct spi_handle *sh, int
 
 	return 0;
 }
-

Index: src/sys/dev/spi/spivar.h
diff -u src/sys/dev/spi/spivar.h:1.10 src/sys/dev/spi/spivar.h:1.10.6.1
--- src/sys/dev/spi/spivar.h:1.10	Tue Aug  4 13:20:45 2020
+++ src/sys/dev/spi/spivar.h	Tue May 18 23:48:16 2021
@@ -1,4 +1,4 @@
-/* $NetBSD: spivar.h,v 1.10 2020/08/04 13:20:45 kardel Exp $ */
+/* $NetBSD: spivar.h,v 1.10.6.1 2021/05/18 23:48:16 thorpej Exp $ */
 
 /*-
  * Copyright (c) 2006 Urbana-Champaign Independent Media Center.
@@ -77,18 +77,30 @@ int spibus_print(void *, const char *);
 /* one per chip select */
 struct spibus_attach_args {
 	struct spi_controller	*sba_controller;
-	prop_array_t		sba_child_devices;
 };
 
 struct spi_attach_args {
 	struct spi_handle	*sa_handle;
+
 	/* only set if using direct config */
-	int		sa_ncompat;	/* number of pointers in the
-					   ia_compat array */
-	const char **	sa_compat;	/* chip names */
-	prop_dictionary_t sa_prop;	/* dictionary for this device */
+	const char	*sa_name;	/* name of the device */
+	const char	*sa_clist;	/* compatible strlist */
+	size_t		sa_clist_size;	/* size of compatible strlist */
+	devhandle_t	sa_devhandle;	/* device handle for the device */
+};
 
-	uintptr_t	sa_cookie;	/* OF node in openfirmware machines */
+/*
+ * spi-enumerate-devices device call
+ *
+ *	Enumerates the devices connected to the SPI bus, filling out
+ *	the spi_attach_args and invoking the callback for each one.
+ *	If the callback returns true, then enumeration continues.  If
+ *	the callback returns false, enumeration is stopped.
+ */
+struct spi_enumerate_devices_args {
+	struct spi_attach_args *sa;
+	bool (*callback)(device_t, struct spi_enumerate_devices_args *);
+	int chip_select;
 };
 
 /*

Reply via email to