Subject: LAN adapter driver (port-dreamcast/17493)
To: None <port-dreamcast@netbsd.org>
From: Izumi Tsutsui <tsutsui@ceres.dti.ne.jp>
List: port-dreamcast
Date: 12/24/2002 22:59:53
Hi,

MI mb86960 driver has been cleaned up enough and Christian Groessler
sent me a new patch for the SEGA LAN adapter so I think it's time
to commit it, but I'd like to ask how to implement bus_space(9)
functions for sparse address space.

In his original patch, MD attachment for the adapter has
its own bus space tag and bus_space functions in it are overridden
in the attachment, but I change them and implement a set of
bus_space(9) functions for sparse address space in g2bus_bus_mem.c.
The functions are switched by calling g2bus_set_bus_mem_sparse()
with bus_space_tag in the attachment. I guess it is not so smart
to use a function to switch bus_space_tag, but I think it's acceptable.

If there is no objection, I'll commit it on Thurseday,
but any suggestions are appreciated.
---
Izumi Tsutsui
tsutsui@ceres.dti.ne.jp

Index: conf/GENERIC
===================================================================
RCS file: /cvsroot/src/sys/arch/dreamcast/conf/GENERIC,v
retrieving revision 1.29
diff -u -r1.29 GENERIC
--- conf/GENERIC	2002/11/15 14:15:36	1.29
+++ conf/GENERIC	2002/12/23 10:00:09
@@ -166,6 +166,8 @@
 rtk*		at pci? dev ? function ?	# SEGA Broadband Adapter
 ukphy*		at mii? phy ?
 
+mbe*		at g2bus?			# SEGA LAN Adapter
+
 #pseudo-device	cgd		2	# cryptographic disk devices
 pseudo-device	md		1	# memory disk device (ramdisk)
 pseudo-device	vnd		2	# disk-like interface to files
Index: conf/files.dreamcast
===================================================================
RCS file: /cvsroot/src/sys/arch/dreamcast/conf/files.dreamcast,v
retrieving revision 1.22
diff -u -r1.22 files.dreamcast
--- conf/files.dreamcast	2002/11/19 09:37:25	1.22
+++ conf/files.dreamcast	2002/12/23 10:00:09
@@ -91,4 +91,8 @@
 file	arch/dreamcast/dev/g2/gapspci_dma.c		gapspci
 file	arch/dreamcast/dev/g2/gapspci_pci.c		gapspci
 
+# LAN Adapter
+attach	mbe at g2bus with mbe_g2bus
+file	arch/dreamcast/dev/g2/if_mbe_g2.c		mbe_g2bus
+
 include "arch/dreamcast/conf/majors.dreamcast"
Index: dev/g2/g2bus_bus_mem.c
===================================================================
RCS file: /cvsroot/src/sys/arch/dreamcast/dev/g2/g2bus_bus_mem.c,v
retrieving revision 1.5
diff -u -r1.5 g2bus_bus_mem.c
--- dev/g2/g2bus_bus_mem.c	2002/03/03 14:31:29	1.5
+++ dev/g2/g2bus_bus_mem.c	2002/12/23 10:00:09
@@ -77,6 +77,29 @@
 void	g2bus_bus_mem_write_region_1(void *, bus_space_handle_t, bus_size_t,
 	    const u_int8_t *, bus_size_t);
 
+u_int8_t g2bus_sparse_bus_mem_read_1(void *, bus_space_handle_t, bus_size_t);
+u_int16_t g2bus_sparse_bus_mem_read_2(void *, bus_space_handle_t, bus_size_t);
+u_int32_t g2bus_sparse_bus_mem_read_4(void *, bus_space_handle_t, bus_size_t);
+
+void	g2bus_sparse_bus_mem_write_1(void *, bus_space_handle_t, bus_size_t,
+	    u_int8_t);
+void	g2bus_sparse_bus_mem_write_2(void *, bus_space_handle_t, bus_size_t,
+	    u_int16_t);
+void	g2bus_sparse_bus_mem_write_4(void *, bus_space_handle_t, bus_size_t,
+	    u_int32_t);
+
+void	g2bus_sparse_bus_mem_read_region_1(void *, bus_space_handle_t,
+	    bus_size_t, u_int8_t *, bus_size_t);
+
+void	g2bus_sparse_bus_mem_write_region_1(void *, bus_space_handle_t,
+	    bus_size_t, const u_int8_t *, bus_size_t);
+
+void	g2bus_sparse_bus_mem_read_multi_1(void *, bus_space_handle_t,
+	    bus_size_t, u_int8_t *, bus_size_t);
+
+void	g2bus_sparse_bus_mem_write_multi_1(void *, bus_space_handle_t,
+	    bus_size_t, const u_int8_t *, bus_size_t);
+
 void
 g2bus_bus_mem_init(struct g2bus_softc *sc)
 {
@@ -240,6 +263,165 @@
 
 	while (len--)
 		*baddr++ = *addr++;
+
+	G2_UNLOCK;
+}
+
+void
+g2bus_set_bus_mem_sparse(bus_space_tag_t memt)
+{
+
+	memt->dbs_r_1 = g2bus_sparse_bus_mem_read_1;
+	memt->dbs_r_2 = g2bus_sparse_bus_mem_read_2;
+	memt->dbs_r_4 = g2bus_sparse_bus_mem_read_4;
+
+	memt->dbs_w_1 = g2bus_sparse_bus_mem_write_1;
+	memt->dbs_w_2 = g2bus_sparse_bus_mem_write_2;
+	memt->dbs_w_4 = g2bus_sparse_bus_mem_write_4;
+
+	memt->dbs_rr_1 = g2bus_sparse_bus_mem_read_region_1;
+
+	memt->dbs_wr_1 = g2bus_sparse_bus_mem_write_region_1;
+
+	memt->dbs_rm_1 = g2bus_sparse_bus_mem_read_multi_1;
+
+	memt->dbs_wm_1 = g2bus_sparse_bus_mem_write_multi_1;
+}
+
+u_int8_t
+g2bus_sparse_bus_mem_read_1(void *v, bus_space_handle_t sh, bus_size_t off)
+{
+	u_int8_t rv;
+
+	G2_LOCK;
+
+	rv = *(__volatile u_int8_t *)(sh + (off * 4));
+
+	G2_UNLOCK;
+
+	return (rv);
+}
+
+u_int16_t
+g2bus_sparse_bus_mem_read_2(void *v, bus_space_handle_t sh, bus_size_t off)
+{
+	u_int16_t rv;
+
+	G2_LOCK;
+
+	rv = *(__volatile u_int16_t *)(sh + (off * 4));
+
+	G2_UNLOCK;
+
+	return (rv);
+}
+
+u_int32_t
+g2bus_sparse_bus_mem_read_4(void *v, bus_space_handle_t sh, bus_size_t off)
+{
+	u_int32_t rv;
+
+	G2_LOCK;
+
+	rv = *(__volatile u_int32_t *)(sh + (off * 4));
+
+	G2_UNLOCK;
+
+	return (rv);
+}
+
+void
+g2bus_sparse_bus_mem_write_1(void *v, bus_space_handle_t sh, bus_size_t off,
+    u_int8_t val)
+{
+
+	G2_LOCK;
+
+	*(__volatile u_int8_t *)(sh + (off * 4)) = val;
+
+	G2_UNLOCK;
+}
+
+void
+g2bus_sparse_bus_mem_write_2(void *v, bus_space_handle_t sh, bus_size_t off,
+    u_int16_t val)
+{
+
+	G2_LOCK;
+
+	*(__volatile u_int16_t *)(sh + (off * 4)) = val;
+
+	G2_UNLOCK;
+}
+
+void
+g2bus_sparse_bus_mem_write_4(void *v, bus_space_handle_t sh, bus_size_t off,
+    u_int32_t val)
+{
+
+	G2_LOCK;
+
+	*(__volatile u_int32_t *)(sh + (off * 4)) = val;
+
+	G2_UNLOCK;
+}
+
+void
+g2bus_sparse_bus_mem_read_region_1(void *v, bus_space_handle_t sh,
+    bus_size_t off, u_int8_t *addr, bus_size_t len)
+{
+	__volatile const u_int8_t *baddr = (u_int8_t *)(sh + (off * 4));
+
+	G2_LOCK;
+
+	while (len--) {
+		*addr++ = *baddr;
+		baddr += 4;
+	}
+
+	G2_UNLOCK;
+}
+
+void
+g2bus_sparse_bus_mem_write_region_1(void *v, bus_space_handle_t sh,
+    bus_size_t off, const u_int8_t *addr, bus_size_t len)
+{
+	__volatile u_int8_t *baddr = (u_int8_t *)(sh + (off * 4));
+
+	G2_LOCK;
+
+	while (len--) {
+		*baddr = *addr++;
+		baddr += 4;
+	}
+
+	G2_UNLOCK;
+}
+
+void
+g2bus_sparse_bus_mem_read_multi_1(void *v, bus_space_handle_t sh,
+    bus_size_t off, u_int8_t *addr, bus_size_t len)
+{
+	__volatile const u_int8_t *baddr = (u_int8_t *)(sh + (off * 4));
+
+	G2_LOCK;
+
+	while (len--)
+		*addr++ = *baddr;
+
+	G2_UNLOCK;
+}
+
+void
+g2bus_sparse_bus_mem_write_multi_1(void *v, bus_space_handle_t sh,
+    bus_size_t off, const u_int8_t *addr, bus_size_t len)
+{
+	__volatile u_int8_t *baddr = (u_int8_t *)(sh + (off * 4));
+
+	G2_LOCK;
+
+	while (len--)
+		*baddr = *addr++;
 
 	G2_UNLOCK;
 }
Index: dev/g2/g2busvar.h
===================================================================
RCS file: /cvsroot/src/sys/arch/dreamcast/dev/g2/g2busvar.h,v
retrieving revision 1.3
diff -u -r1.3 g2busvar.h
--- dev/g2/g2busvar.h	2002/12/23 09:59:25	1.3
+++ dev/g2/g2busvar.h	2002/12/23 10:00:09
@@ -64,5 +64,6 @@
 };
 
 void	g2bus_bus_mem_init(struct g2bus_softc *);
+void	g2bus_set_bus_mem_sparse(bus_space_tag_t);
 
 #endif /* _DREAMCAST_G2BUSVAR_H_ */
Index: include/sysasicvar.h
===================================================================
RCS file: /cvsroot/src/sys/arch/dreamcast/include/sysasicvar.h,v
retrieving revision 1.3
diff -u -r1.3 sysasicvar.h
--- include/sysasicvar.h	2002/11/15 13:29:27	1.3
+++ include/sysasicvar.h	2002/12/23 10:00:10
@@ -43,6 +43,7 @@
 #define SYSASIC_EVENT_MAPLE_ERROR	13
 #define SYSASIC_EVENT_GDROM		32
 #define SYSASIC_EVENT_AICA		33
+#define SYSASIC_EVENT_8BIT		34
 #define SYSASIC_EVENT_EXT		35
 #define SYSASIC_EVENT_MAX		65
 

--- /dev/null	Tue Dec 24 02:11:01 2002
+++ dev/g2/if_mbe_g2.c	Tue Dec 24 22:32:57 2002
@@ -0,0 +1,239 @@
+/*	$NetBSD$	*/
+
+/*
+ * Copyright (c) 2002 Christian Groessler
+ * All rights reserved.
+ *
+ * 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.
+ * 3. The name of the author may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 AUTHOR 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.
+ */
+
+/*
+ * All Rights Reserved, Copyright (C) Fujitsu Limited 1995
+ *
+ * This software may be used, modified, copied, distributed, and sold, in
+ * both source and binary form provided that the above copyright, these
+ * terms and the following disclaimer are retained.  The name of the author
+ * and/or the contributor may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``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 AUTHOR OR THE CONTRIBUTOR 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.
+ */
+
+/*
+ * Portions copyright (C) 1993, David Greenman.	 This software may be used,
+ * modified, copied, distributed, and sold, in both source and binary form
+ * provided that the above copyright and these terms are retained.  Under no
+ * circumstances is the author responsible for the proper functioning of this
+ * software, nor does the author assume any responsibility for damages
+ * incurred with its use.
+ */
+
+/*
+ * Driver for Sega LAN Adapter (HIT-0300)
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/device.h>
+
+#include <net/if.h>
+#include <net/if_ether.h>
+#include <net/if_media.h>
+
+#include <machine/bus.h>
+#include <machine/intr.h>
+#include <machine/sysasicvar.h>
+#include <machine/cpu.h>
+
+#include <dev/ic/mb86960reg.h>
+#include <dev/ic/mb86960var.h>
+
+#include <dreamcast/dev/g2/g2busvar.h>
+
+
+int	mbe_g2_match(struct device *, struct cfdata *, void *);
+void	mbe_g2_attach(struct device *, struct device *, void *);
+static int mbe_g2_detect(bus_space_tag_t, bus_space_handle_t, u_int8_t *);
+
+struct mbe_g2_softc {
+	struct	mb86960_softc sc_mb86960;	/* real "mb86960" softc */
+};
+
+CFATTACH_DECL(mbe_g2bus, sizeof(struct mbe_g2_softc),
+    mbe_g2_match, mbe_g2_attach, NULL, NULL);
+
+#define LANA_NPORTS (0x20 * 4)
+
+static struct dreamcast_bus_space mbe_g2_dbs;
+
+/*
+ * Determine if the device is present.
+ */
+int
+mbe_g2_match(struct device *parent, struct cfdata *cf, void *aux)
+{
+	struct g2bus_attach_args *ga = aux;
+	bus_space_handle_t memh;
+	struct dreamcast_bus_space dbs;
+	bus_space_tag_t memt = &dbs;
+	static int lanafound;
+	int rv;
+	u_int8_t myea[ETHER_ADDR_LEN];
+
+	if (lanafound)
+		return (0);
+
+	if (strcmp("mbe", cf->cf_name))
+		return (0);
+
+	memcpy(memt, ga->ga_memt, sizeof(struct dreamcast_bus_space));
+	g2bus_set_bus_mem_sparse(memt);
+
+	/* Map i/o ports. */
+	if (bus_space_map(memt, 0x00600400, LANA_NPORTS, 0, &memh)) {
+#ifdef LANA_DEBUG
+		printf("mbe_g2_match: couldn't map iospace 0x%x\n",
+		       0x00600400);
+#endif
+		return (0);
+	}
+
+	rv = 0;
+	if (mbe_g2_detect(memt, memh, myea) == 0) {
+#ifdef LANA_DEBUG
+		printf("mbe_g2_match: LAN Adapter detection failed\n");
+#endif
+		goto out;
+	}
+
+	rv = 1;
+	lanafound = 1;
+ out:
+	bus_space_unmap(memt, memh, LANA_NPORTS);
+	return (rv);
+}
+
+
+/*
+ * Determine type and ethernet address.
+ */
+static int
+mbe_g2_detect(iot, ioh, enaddr)
+	bus_space_tag_t iot;
+	bus_space_handle_t ioh;
+	u_int8_t *enaddr;
+{
+	u_int8_t eeprom[FE_EEPROM_SIZE];
+
+	memset(eeprom, 0, FE_EEPROM_SIZE);
+
+	/* Get our station address from EEPROM. */
+	mb86965_read_eeprom(iot, ioh, eeprom);
+	memcpy(enaddr, eeprom, ETHER_ADDR_LEN);
+
+#if LANA_DEBUG > 1
+	printf("Ethernet address: %s\n", ether_sprintf(enaddr));
+#endif
+
+	/* Make sure we got a valid station address. */
+	if ((enaddr[0] & 0x03) != 0x00 ||
+	    (enaddr[0] == 0x00 && enaddr[1] == 0x00 && enaddr[2] == 0x00)) {
+#ifdef LANA_DEBUG
+		printf("mbe_g2_detect: invalid ethernet address\n");
+#endif
+		return (0);
+	}
+
+	/* Read the chip type */
+	if ((bus_space_read_1(iot, ioh, FE_DLCR7) & FE_D7_IDENT) !=
+	    FE_D7_IDENT_86967) {
+#ifdef LANA_DEBUG
+		printf("mbe_g2_detect: unknown chip type\n");
+#endif
+		return (0);
+	}
+
+	return (1);
+}
+
+void
+mbe_g2_attach(parent, self, aux)
+	struct device *parent, *self;
+	void *aux;
+{
+	struct g2bus_attach_args *ga = aux;
+	struct mbe_g2_softc *isc = (struct mbe_g2_softc *)self;
+	struct mb86960_softc *sc = &isc->sc_mb86960;
+	bus_space_tag_t memt = &mbe_g2_dbs;
+	bus_space_handle_t memh;
+	u_int8_t myea[ETHER_ADDR_LEN];
+
+	memcpy(memt, ga->ga_memt, sizeof(struct dreamcast_bus_space));
+	g2bus_set_bus_mem_sparse(memt);
+
+	/* Map i/o ports. */
+	if (bus_space_map(memt, 0x00600400, LANA_NPORTS, 0, &memh)) {
+		printf(": can't map i/o space\n");
+		return;
+	}
+
+	sc->sc_bst = memt;
+	sc->sc_bsh = memh;
+
+	/* Determine the card type. */
+	if (mbe_g2_detect(memt, memh, myea) == 0) {
+		printf(": where did the card go?!\n");
+		panic("unknown card");
+	}
+
+	printf(": Sega LAN-Adapter Ethernet\n");
+
+	/* This interface is always enabled. */
+	sc->sc_stat |= FE_STAT_ENABLED;
+
+	/* The LAN-Adapter uses 8 bit bus mode. */
+	sc->sc_flags |= FE_FLAGS_SBW_BYTE;
+
+	/*
+	 * Do generic MB86960 attach.
+	 */
+	mb86960_attach(sc, myea);
+
+	mb86960_config(sc, NULL, 0, 0);
+
+	sysasic_intr_establish(SYSASIC_EVENT_8BIT, IPL_NET, mb86960_intr, sc);
+}