xref: /netbsd-src/sys/dev/qbus/if_de.c (revision 4b2769fe52b586c4d7d9e7cc506c2247ed060a04)
1*4b2769feSandvar /*	$NetBSD: if_de.c,v 1.36 2021/08/01 15:29:30 andvar Exp $	*/
2944b6966Sragge 
389955057Sragge /*
489955057Sragge  * Copyright (c) 1982, 1986, 1989 Regents of the University of California.
5aad01611Sagc  * All rights reserved.
6aad01611Sagc  *
7aad01611Sagc  *
8aad01611Sagc  * Redistribution and use in source and binary forms, with or without
9aad01611Sagc  * modification, are permitted provided that the following conditions
10aad01611Sagc  * are met:
11aad01611Sagc  * 1. Redistributions of source code must retain the above copyright
12aad01611Sagc  *    notice, this list of conditions and the following disclaimer.
13aad01611Sagc  * 2. Redistributions in binary form must reproduce the above copyright
14aad01611Sagc  *    notice, this list of conditions and the following disclaimer in the
15aad01611Sagc  *    documentation and/or other materials provided with the distribution.
16aad01611Sagc  * 3. Neither the name of the University nor the names of its contributors
17aad01611Sagc  *    may be used to endorse or promote products derived from this software
18aad01611Sagc  *    without specific prior written permission.
19aad01611Sagc  *
20aad01611Sagc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
21aad01611Sagc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22aad01611Sagc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
23aad01611Sagc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
24aad01611Sagc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25aad01611Sagc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
26aad01611Sagc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
27aad01611Sagc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
28aad01611Sagc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
29aad01611Sagc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30aad01611Sagc  * SUCH DAMAGE.
31aad01611Sagc  *
32aad01611Sagc  *	@(#)if_de.c	7.12 (Berkeley) 12/16/90
33aad01611Sagc  */
34aad01611Sagc 
35aad01611Sagc /*
3689955057Sragge  * Copyright (c) 2000 Ludd, University of Lule}, Sweden.
3789955057Sragge  * All rights reserved.
3889955057Sragge  *
3989955057Sragge  *
4089955057Sragge  * Redistribution and use in source and binary forms, with or without
4189955057Sragge  * modification, are permitted provided that the following conditions
4289955057Sragge  * are met:
4389955057Sragge  * 1. Redistributions of source code must retain the above copyright
4489955057Sragge  *    notice, this list of conditions and the following disclaimer.
4589955057Sragge  * 2. Redistributions in binary form must reproduce the above copyright
4689955057Sragge  *    notice, this list of conditions and the following disclaimer in the
4789955057Sragge  *    documentation and/or other materials provided with the distribution.
4889955057Sragge  *
4989955057Sragge  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
5089955057Sragge  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
5189955057Sragge  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
5289955057Sragge  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
5389955057Sragge  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
5489955057Sragge  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
5589955057Sragge  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
5689955057Sragge  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
5789955057Sragge  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
5889955057Sragge  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
5989955057Sragge  * SUCH DAMAGE.
6089955057Sragge  */
6189955057Sragge 
6289955057Sragge /*
6389955057Sragge  * DEC DEUNA interface
6489955057Sragge  *
6589955057Sragge  *	Lou Salkind
6689955057Sragge  *	New York University
6789955057Sragge  *
6816f02724Sragge  *	Rewritten by Ragge 30 April 2000 to match new world.
6989955057Sragge  *
7089955057Sragge  * TODO:
7189955057Sragge  *	timeout routine (get statistics)
7289955057Sragge  */
7389955057Sragge 
74a3746e00Slukem #include <sys/cdefs.h>
75*4b2769feSandvar __KERNEL_RCSID(0, "$NetBSD: if_de.c,v 1.36 2021/08/01 15:29:30 andvar Exp $");
76a3746e00Slukem 
7789955057Sragge #include "opt_inet.h"
7889955057Sragge 
7989955057Sragge #include <sys/param.h>
8089955057Sragge #include <sys/systm.h>
8189955057Sragge #include <sys/mbuf.h>
8289955057Sragge #include <sys/buf.h>
8389955057Sragge #include <sys/protosw.h>
8489955057Sragge #include <sys/socket.h>
8589955057Sragge #include <sys/ioctl.h>
8689955057Sragge #include <sys/errno.h>
8789955057Sragge #include <sys/syslog.h>
8889955057Sragge #include <sys/device.h>
8989955057Sragge 
9089955057Sragge #include <net/if.h>
9189955057Sragge #include <net/if_ether.h>
9289955057Sragge #include <net/if_dl.h>
934b508fb1Smsaitoh #include <net/bpf.h>
9489955057Sragge 
9589955057Sragge #ifdef INET
9689955057Sragge #include <netinet/in.h>
9789955057Sragge #include <netinet/if_inarp.h>
9889955057Sragge #endif
9989955057Sragge 
100a2a38285Sad #include <sys/bus.h>
10189955057Sragge 
10289955057Sragge #include <dev/qbus/ubavar.h>
10389955057Sragge #include <dev/qbus/if_dereg.h>
10493011fb5Sragge #include <dev/qbus/if_uba.h>
10589955057Sragge 
10689955057Sragge #include "ioconf.h"
10789955057Sragge 
10889955057Sragge /*
10989955057Sragge  * Be careful with transmit/receive buffers, each entry steals 4 map
11089955057Sragge  * registers, and there is only 496 on one unibus...
11189955057Sragge  */
11293011fb5Sragge #define NRCV	7	/* number of receive buffers (must be > 1) */
11393011fb5Sragge #define NXMT	3	/* number of transmit buffers */
11489955057Sragge 
11589955057Sragge /*
11689955057Sragge  * Structure containing the elements that must be in DMA-safe memory.
11789955057Sragge  */
11889955057Sragge struct	de_cdata {
11989955057Sragge 	/* the following structures are always mapped in */
12089955057Sragge 	struct	de_pcbb dc_pcbb;	/* port control block */
12189955057Sragge 	struct	de_ring dc_xrent[NXMT]; /* transmit ring entrys */
12289955057Sragge 	struct	de_ring dc_rrent[NRCV]; /* receive ring entrys */
12389955057Sragge 	struct	de_udbbuf dc_udbbuf;	/* UNIBUS data buffer */
12489955057Sragge 	/* end mapped area */
12589955057Sragge };
12689955057Sragge 
12789955057Sragge /*
12889955057Sragge  * Ethernet software status per interface.
12989955057Sragge  *
13089955057Sragge  * Each interface is referenced by a network interface structure,
13189955057Sragge  * ds_if, which the routing code uses to locate the interface.
13289955057Sragge  * This structure contains the output queue for the interface, its address, ...
13389955057Sragge  * We also have, for each interface, a UBA interface structure, which
13489955057Sragge  * contains information about the UNIBUS resources held by the interface:
13589955057Sragge  * map registers, buffered data paths, etc.  Information is cached in this
13689955057Sragge  * structure for use by the if_uba.c routines in running the interface
13789955057Sragge  * efficiently.
13889955057Sragge  */
13989955057Sragge struct	de_softc {
140dfba8166Smatt 	device_t sc_dev;		/* Configuration common part */
141dfba8166Smatt 	struct uba_softc *sc_uh;	/* our parent */
1420bd304e5Smatt 	struct evcnt sc_intrcnt;	/* Interrupt counting */
14389955057Sragge 	struct ethercom sc_ec;		/* Ethernet common part */
14489955057Sragge #define sc_if	sc_ec.ec_if		/* network-visible interface */
14589955057Sragge 	bus_space_tag_t sc_iot;
14689955057Sragge 	bus_addr_t sc_ioh;
14789955057Sragge 	bus_dma_tag_t sc_dmat;
14893011fb5Sragge 	int sc_flags;
14993011fb5Sragge #define	DSF_MAPPED	1
1506bfb730eSragge 	struct ubinfo sc_ui;
15189955057Sragge 	struct de_cdata *sc_dedata;	/* Control structure */
15289955057Sragge 	struct de_cdata *sc_pdedata;	/* Bus-mapped control structure */
15393011fb5Sragge 	struct ifubinfo sc_ifuba;	/* UNIBUS resources */
15493011fb5Sragge 	struct ifrw sc_ifr[NRCV];	/* UNIBUS receive buffer maps */
15593011fb5Sragge 	struct ifxmt sc_ifw[NXMT];	/* UNIBUS receive buffer maps */
15693011fb5Sragge 
157944b6966Sragge 	int sc_xindex;			/* UNA index into transmit chain */
158944b6966Sragge 	int sc_rindex;			/* UNA index into receive chain */
159944b6966Sragge 	int sc_xfree;			/* index for next transmit buffer */
160944b6966Sragge 	int sc_nxmit;			/* # of transmits in progress */
16116f02724Sragge 	void *sc_sh;			/* shutdownhook cookie */
16289955057Sragge };
16389955057Sragge 
164dfba8166Smatt static	int dematch(device_t, cfdata_t, void *);
165dfba8166Smatt static	void deattach(device_t, device_t, void *);
166a4a700a7Sragge static	void dewait(struct de_softc *, const char *);
16793011fb5Sragge static	int deinit(struct ifnet *);
16853524e44Schristos static	int deioctl(struct ifnet *, u_long, void *);
169dfba8166Smatt static	void dereset(device_t);
17093011fb5Sragge static	void destop(struct ifnet *, int);
17189955057Sragge static	void destart(struct ifnet *);
17289955057Sragge static	void derecv(struct de_softc *);
17389955057Sragge static	void deintr(void *);
17416f02724Sragge static	void deshutdown(void *);
17589955057Sragge 
176dfba8166Smatt CFATTACH_DECL_NEW(de, sizeof(struct de_softc),
177b75a007dSthorpej     dematch, deattach, NULL, NULL);
17889955057Sragge 
17989955057Sragge #define DE_WCSR(csr, val) \
18089955057Sragge 	bus_space_write_2(sc->sc_iot, sc->sc_ioh, csr, val)
18189955057Sragge #define DE_WLOW(val) \
18289955057Sragge 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, DE_PCSR0, val)
18389955057Sragge #define DE_WHIGH(val) \
18489955057Sragge 	bus_space_write_1(sc->sc_iot, sc->sc_ioh, DE_PCSR0 + 1, val)
18589955057Sragge #define DE_RCSR(csr) \
18689955057Sragge 	bus_space_read_2(sc->sc_iot, sc->sc_ioh, csr)
18789955057Sragge 
18889955057Sragge #define LOWORD(x)	((int)(x) & 0xffff)
18989955057Sragge #define HIWORD(x)	(((int)(x) >> 16) & 0x3)
19089955057Sragge /*
19189955057Sragge  * Interface exists: make available by filling in network interface
19289955057Sragge  * record.  System will initialize the interface when it is ready
19389955057Sragge  * to accept packets.  We get the ethernet address here.
19489955057Sragge  */
19589955057Sragge void
deattach(device_t parent,device_t self,void * aux)196dfba8166Smatt deattach(device_t parent, device_t self, void *aux)
19789955057Sragge {
19889955057Sragge 	struct uba_attach_args *ua = aux;
199ceb94256Sthorpej 	struct de_softc *sc = device_private(self);
20089955057Sragge 	struct ifnet *ifp = &sc->sc_if;
20189955057Sragge 	u_int8_t myaddr[ETHER_ADDR_LEN];
20293011fb5Sragge 	int csr1, error;
203a4a700a7Sragge 	const char *c;
20489955057Sragge 
205dfba8166Smatt 	sc->sc_dev = self;
206dfba8166Smatt 	sc->sc_uh = device_private(parent);
20789955057Sragge 	sc->sc_iot = ua->ua_iot;
20889955057Sragge 	sc->sc_ioh = ua->ua_ioh;
20989955057Sragge 	sc->sc_dmat = ua->ua_dmat;
21089955057Sragge 
21189955057Sragge 	/*
21289955057Sragge 	 * What kind of a board is this?
21389955057Sragge 	 * The error bits 4-6 in pcsr1 are a device id as long as
21489955057Sragge 	 * the high byte is zero.
21589955057Sragge 	 */
21689955057Sragge 	csr1 = DE_RCSR(DE_PCSR1);
21789955057Sragge 	if (csr1 & 0xff60)
21889955057Sragge 		c = "broken";
21989955057Sragge 	else if (csr1 & 0x10)
22089955057Sragge 		c = "delua";
22189955057Sragge 	else
22289955057Sragge 		c = "deuna";
22389955057Sragge 
22489955057Sragge 	/*
22589955057Sragge 	 * Reset the board and temporarily map
22689955057Sragge 	 * the pcbb buffer onto the Unibus.
22789955057Sragge 	 */
22889955057Sragge 	DE_WCSR(DE_PCSR0, 0);		/* reset INTE */
22989955057Sragge 	DELAY(100);
23089955057Sragge 	DE_WCSR(DE_PCSR0, PCSR0_RSET);
23116f02724Sragge 	dewait(sc, "reset");
23289955057Sragge 
2336bfb730eSragge 	sc->sc_ui.ui_size = sizeof(struct de_cdata);
234dfba8166Smatt 	if ((error = ubmemalloc(sc->sc_uh, &sc->sc_ui, 0)))
23593011fb5Sragge 		return printf(": failed ubmemalloc(), error = %d\n", error);
2366bfb730eSragge 	sc->sc_dedata = (struct de_cdata *)sc->sc_ui.ui_vaddr;
23716f02724Sragge 
23889955057Sragge 	/*
23989955057Sragge 	 * Tell the DEUNA about our PCB
24089955057Sragge 	 */
24193011fb5Sragge 	DE_WCSR(DE_PCSR2, LOWORD(sc->sc_ui.ui_baddr));
24293011fb5Sragge 	DE_WCSR(DE_PCSR3, HIWORD(sc->sc_ui.ui_baddr));
24389955057Sragge 	DE_WLOW(CMD_GETPCBB);
24416f02724Sragge 	dewait(sc, "pcbb");
24589955057Sragge 
24689955057Sragge 	sc->sc_dedata->dc_pcbb.pcbb0 = FC_RDPHYAD;
24789955057Sragge 	DE_WLOW(CMD_GETCMD);
24816f02724Sragge 	dewait(sc, "read addr ");
24989955057Sragge 
250e2cb8590Scegger 	memcpy(myaddr, (void *)&sc->sc_dedata->dc_pcbb.pcbb2, sizeof (myaddr));
251dfba8166Smatt 	printf(": %s, hardware address %s\n", c, ether_sprintf(myaddr));
25289955057Sragge 
253944b6966Sragge 	uba_intr_establish(ua->ua_icookie, ua->ua_cvec, deintr, sc,
254944b6966Sragge 	    &sc->sc_intrcnt);
255dfba8166Smatt 	uba_reset_establish(dereset, sc->sc_dev);
2562f85fe7aSmatt 	evcnt_attach_dynamic(&sc->sc_intrcnt, EVCNT_TYPE_INTR, ua->ua_evcnt,
257dfba8166Smatt 	    device_xname(sc->sc_dev), "intr");
25889955057Sragge 
259dfba8166Smatt 	strcpy(ifp->if_xname, device_xname(sc->sc_dev));
26089955057Sragge 	ifp->if_softc = sc;
261944b6966Sragge 	ifp->if_flags = IFF_BROADCAST|IFF_SIMPLEX|IFF_MULTICAST|IFF_ALLMULTI;
26289955057Sragge 	ifp->if_ioctl = deioctl;
26389955057Sragge 	ifp->if_start = destart;
26493011fb5Sragge 	ifp->if_init = deinit;
26593011fb5Sragge 	ifp->if_stop = destop;
266a64a0f81Sthorpej 	IFQ_SET_READY(&ifp->if_snd);
267a64a0f81Sthorpej 
26889955057Sragge 	if_attach(ifp);
26989955057Sragge 	ether_ifattach(ifp, myaddr);
270dfba8166Smatt 	ubmemfree(sc->sc_uh, &sc->sc_ui);
271b84f740bSthorpej 
27216f02724Sragge 	sc->sc_sh = shutdownhook_establish(deshutdown, sc);
27393011fb5Sragge }
27489955057Sragge 
27593011fb5Sragge void
destop(struct ifnet * ifp,int a)27693011fb5Sragge destop(struct ifnet *ifp, int a)
27793011fb5Sragge {
27893011fb5Sragge 	struct de_softc *sc = ifp->if_softc;
27993011fb5Sragge 
28093011fb5Sragge 	DE_WLOW(0);
28193011fb5Sragge 	DELAY(5000);
28293011fb5Sragge 	DE_WLOW(PCSR0_RSET);
28389955057Sragge }
28493011fb5Sragge 
28589955057Sragge 
28689955057Sragge /*
28789955057Sragge  * Reset of interface after UNIBUS reset.
28889955057Sragge  */
28989955057Sragge void
dereset(device_t dev)290dfba8166Smatt dereset(device_t dev)
29189955057Sragge {
29289955057Sragge 	struct de_softc *sc = (void *)dev;
29389955057Sragge 
29489955057Sragge 	sc->sc_if.if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
29593011fb5Sragge 	sc->sc_flags &= ~DSF_MAPPED;
296944b6966Sragge 	sc->sc_pdedata = NULL;	/* All mappings lost */
29789955057Sragge 	DE_WCSR(DE_PCSR0, PCSR0_RSET);
29816f02724Sragge 	dewait(sc, "reset");
29993011fb5Sragge 	deinit(&sc->sc_if);
30089955057Sragge }
30189955057Sragge 
30289955057Sragge /*
30389955057Sragge  * Initialization of interface; clear recorded pending
30489955057Sragge  * operations, and reinitialize UNIBUS usage.
30589955057Sragge  */
30693011fb5Sragge int
deinit(struct ifnet * ifp)30793011fb5Sragge deinit(struct ifnet *ifp)
30889955057Sragge {
30993011fb5Sragge 	struct de_softc *sc = ifp->if_softc;
31016f02724Sragge 	struct de_cdata *dc, *pdc;
31193011fb5Sragge 	struct ifrw *ifrw;
31293011fb5Sragge 	struct ifxmt *ifxp;
31393011fb5Sragge 	struct de_ring *rp;
31493011fb5Sragge 	int s, error;
31589955057Sragge 
31693011fb5Sragge 	if (ifp->if_flags & IFF_RUNNING)
31793011fb5Sragge 		return 0;
31893011fb5Sragge 	if ((sc->sc_flags & DSF_MAPPED) == 0) {
319dfba8166Smatt 		if (if_ubaminit(&sc->sc_ifuba, sc->sc_uh, MCLBYTES,
320dfba8166Smatt 				sc->sc_ifr, NRCV, sc->sc_ifw, NXMT)) {
321dfba8166Smatt 			aprint_error_dev(sc->sc_dev, " can't initialize\n");
32293011fb5Sragge 			ifp->if_flags &= ~IFF_UP;
32393011fb5Sragge 			return 0;
32493011fb5Sragge 		}
32593011fb5Sragge 		sc->sc_ui.ui_size = sizeof(struct de_cdata);
326dfba8166Smatt 		if ((error = ubmemalloc(sc->sc_uh, &sc->sc_ui, 0))) {
327dfba8166Smatt 			aprint_error(": unable to ubmemalloc(), error = %d\n",
328dfba8166Smatt 			    error);
32993011fb5Sragge 			return 0;
33093011fb5Sragge 		}
33193011fb5Sragge 		sc->sc_pdedata = (struct de_cdata *)sc->sc_ui.ui_baddr;
33293011fb5Sragge 		sc->sc_dedata = (struct de_cdata *)sc->sc_ui.ui_vaddr;
33393011fb5Sragge 		sc->sc_flags |= DSF_MAPPED;
33493011fb5Sragge 	}
33593011fb5Sragge 
33689955057Sragge 	/*
33789955057Sragge 	 * Tell the DEUNA about our PCB
33889955057Sragge 	 */
33989955057Sragge 	DE_WCSR(DE_PCSR2, LOWORD(sc->sc_pdedata));
34089955057Sragge 	DE_WCSR(DE_PCSR3, HIWORD(sc->sc_pdedata));
34189955057Sragge 	DE_WLOW(0);		/* reset INTE */
34289955057Sragge 	DELAY(500);
34389955057Sragge 	DE_WLOW(CMD_GETPCBB);
34416f02724Sragge 	dewait(sc, "pcbb");
34589955057Sragge 
34689955057Sragge 	dc = sc->sc_dedata;
34716f02724Sragge 	pdc = sc->sc_pdedata;
34889955057Sragge 	/* set the transmit and receive ring header addresses */
34989955057Sragge 	dc->dc_pcbb.pcbb0 = FC_WTRING;
35016f02724Sragge 	dc->dc_pcbb.pcbb2 = LOWORD(&pdc->dc_udbbuf);
35116f02724Sragge 	dc->dc_pcbb.pcbb4 = HIWORD(&pdc->dc_udbbuf);
35289955057Sragge 
35316f02724Sragge 	dc->dc_udbbuf.b_tdrbl = LOWORD(&pdc->dc_xrent[0]);
35416f02724Sragge 	dc->dc_udbbuf.b_tdrbh = HIWORD(&pdc->dc_xrent[0]);
35589955057Sragge 	dc->dc_udbbuf.b_telen = sizeof (struct de_ring) / sizeof(u_int16_t);
35689955057Sragge 	dc->dc_udbbuf.b_trlen = NXMT;
35716f02724Sragge 	dc->dc_udbbuf.b_rdrbl = LOWORD(&pdc->dc_rrent[0]);
35816f02724Sragge 	dc->dc_udbbuf.b_rdrbh = HIWORD(&pdc->dc_rrent[0]);
35989955057Sragge 	dc->dc_udbbuf.b_relen = sizeof (struct de_ring) / sizeof(u_int16_t);
36089955057Sragge 	dc->dc_udbbuf.b_rrlen = NRCV;
36189955057Sragge 
36289955057Sragge 	DE_WLOW(CMD_GETCMD);
36316f02724Sragge 	dewait(sc, "wtring");
36489955057Sragge 
365944b6966Sragge 	sc->sc_dedata->dc_pcbb.pcbb0 = FC_WTMODE;
366944b6966Sragge 	sc->sc_dedata->dc_pcbb.pcbb2 = MOD_TPAD|MOD_HDX|MOD_DRDC|MOD_ENAL;
367944b6966Sragge 	DE_WLOW(CMD_GETCMD);
368944b6966Sragge 	dewait(sc, "wtmode");
36989955057Sragge 
370944b6966Sragge 	/* set up the receive and transmit ring entries */
37193011fb5Sragge 	ifxp = &sc->sc_ifw[0];
37293011fb5Sragge 	for (rp = &dc->dc_xrent[0]; rp < &dc->dc_xrent[NXMT]; rp++) {
37393011fb5Sragge 		rp->r_segbl = LOWORD(ifxp->ifw_info);
37493011fb5Sragge 		rp->r_segbh = HIWORD(ifxp->ifw_info);
37593011fb5Sragge 		rp->r_flags = 0;
37693011fb5Sragge 		ifxp++;
37793011fb5Sragge 	}
37893011fb5Sragge 	ifrw = &sc->sc_ifr[0];
37993011fb5Sragge 	for (rp = &dc->dc_rrent[0]; rp < &dc->dc_rrent[NRCV]; rp++) {
38093011fb5Sragge 		rp->r_slen = MCLBYTES - 2;
38193011fb5Sragge 		rp->r_segbl = LOWORD(ifrw->ifrw_info);
38293011fb5Sragge 		rp->r_segbh = HIWORD(ifrw->ifrw_info);
38393011fb5Sragge 		rp->r_flags = RFLG_OWN;
38493011fb5Sragge 		ifrw++;
38593011fb5Sragge 	}
38689955057Sragge 
38789955057Sragge 	/* start up the board (rah rah) */
38889955057Sragge 	s = splnet();
389944b6966Sragge 	sc->sc_rindex = sc->sc_xindex = sc->sc_xfree = sc->sc_nxmit = 0;
39089955057Sragge 	sc->sc_if.if_flags |= IFF_RUNNING;
391944b6966Sragge 	DE_WLOW(PCSR0_INTE);			/* avoid interlock */
392944b6966Sragge 	destart(&sc->sc_if);		/* queue output packets */
39389955057Sragge 	DE_WLOW(CMD_START|PCSR0_INTE);
39489955057Sragge 	splx(s);
39593011fb5Sragge 	return 0;
39689955057Sragge }
39789955057Sragge 
39889955057Sragge /*
39989955057Sragge  * Setup output on interface.
40089955057Sragge  * Get another datagram to send off of the interface queue,
40189955057Sragge  * and map it to the interface before starting the output.
40289955057Sragge  * Must be called from ipl >= our interrupt level.
40389955057Sragge  */
40489955057Sragge void
destart(struct ifnet * ifp)40589955057Sragge destart(struct ifnet *ifp)
40689955057Sragge {
40789955057Sragge 	struct de_softc *sc = ifp->if_softc;
40816f02724Sragge 	struct de_cdata *dc;
40993011fb5Sragge 	struct de_ring *rp;
41016f02724Sragge 	struct mbuf *m;
41193011fb5Sragge 	int nxmit, len;
41289955057Sragge 
41389955057Sragge 	/*
41489955057Sragge 	 * the following test is necessary, since
41589955057Sragge 	 * the code is not reentrant and we have
41689955057Sragge 	 * multiple transmission buffers.
41789955057Sragge 	 */
418944b6966Sragge 	if (sc->sc_if.if_flags & IFF_OACTIVE)
41989955057Sragge 		return;
42016f02724Sragge 	dc = sc->sc_dedata;
421944b6966Sragge 	for (nxmit = sc->sc_nxmit; nxmit < NXMT; nxmit++) {
422a64a0f81Sthorpej 		IFQ_DEQUEUE(&ifp->if_snd, m);
42389955057Sragge 		if (m == 0)
424944b6966Sragge 			break;
42593011fb5Sragge 
42693011fb5Sragge 		rp = &dc->dc_xrent[sc->sc_xfree];
427944b6966Sragge 		if (rp->r_flags & XFLG_OWN)
428944b6966Sragge 			panic("deuna xmit in progress");
4293cd62456Smsaitoh 		bpf_mtap(ifp, m, BPF_D_OUT);
430944b6966Sragge 
43193011fb5Sragge 		len = if_ubaput(&sc->sc_ifuba, &sc->sc_ifw[sc->sc_xfree], m);
43293011fb5Sragge 		rp->r_slen = len;
43393011fb5Sragge 		rp->r_tdrerr = 0;
43493011fb5Sragge 		rp->r_flags = XFLG_STP|XFLG_ENP|XFLG_OWN;
43593011fb5Sragge 
436944b6966Sragge 		sc->sc_xfree++;
437944b6966Sragge 		if (sc->sc_xfree == NXMT)
438944b6966Sragge 			sc->sc_xfree = 0;
43989955057Sragge 	}
44093011fb5Sragge 	if (sc->sc_nxmit != nxmit) {
441944b6966Sragge 		sc->sc_nxmit = nxmit;
442944b6966Sragge 		if (ifp->if_flags & IFF_RUNNING)
44389955057Sragge 			DE_WLOW(PCSR0_INTE|CMD_PDMD);
44416f02724Sragge 	}
44589955057Sragge }
44689955057Sragge 
44789955057Sragge /*
44889955057Sragge  * Command done interrupt.
44989955057Sragge  */
45089955057Sragge void
deintr(void * arg)45189955057Sragge deintr(void *arg)
45289955057Sragge {
45393011fb5Sragge 	struct ifxmt *ifxp;
454944b6966Sragge 	struct de_cdata *dc;
45589955057Sragge 	struct de_softc *sc = arg;
456944b6966Sragge 	struct de_ring *rp;
457944b6966Sragge 	short csr0;
45889955057Sragge 
45989955057Sragge 	/* save flags right away - clear out interrupt bits */
46089955057Sragge 	csr0 = DE_RCSR(DE_PCSR0);
46189955057Sragge 	DE_WHIGH(csr0 >> 8);
46289955057Sragge 
463944b6966Sragge 
464944b6966Sragge 	sc->sc_if.if_flags |= IFF_OACTIVE;	/* prevent entering destart */
465944b6966Sragge 	/*
466944b6966Sragge 	 * if receive, put receive buffer on mbuf
467944b6966Sragge 	 * and hang the request again
468944b6966Sragge 	 */
46989955057Sragge 	derecv(sc);
47089955057Sragge 
47189955057Sragge 	/*
47289955057Sragge 	 * Poll transmit ring and check status.
473944b6966Sragge 	 * Be careful about loopback requests.
47489955057Sragge 	 * Then free buffer space and check for
47589955057Sragge 	 * more transmit requests.
47689955057Sragge 	 */
477944b6966Sragge 	dc = sc->sc_dedata;
478944b6966Sragge 	for ( ; sc->sc_nxmit > 0; sc->sc_nxmit--) {
479944b6966Sragge 		rp = &dc->dc_xrent[sc->sc_xindex];
480944b6966Sragge 		if (rp->r_flags & XFLG_OWN)
48116f02724Sragge 			break;
48293011fb5Sragge 
483d18dc548Sthorpej 		if_statinc(&sc->sc_if, if_opackets);
48493011fb5Sragge 		ifxp = &sc->sc_ifw[sc->sc_xindex];
485944b6966Sragge 		/* check for unusual conditions */
48689955057Sragge 		if (rp->r_flags & (XFLG_ERRS|XFLG_MTCH|XFLG_ONE|XFLG_MORE)) {
48789955057Sragge 			if (rp->r_flags & XFLG_ERRS) {
488944b6966Sragge 				/* output error */
489d18dc548Sthorpej 				if_statinc(&sc->sc_if, if_oerrors);
49089955057Sragge 			} else if (rp->r_flags & XFLG_ONE) {
491944b6966Sragge 				/* one collision */
492d18dc548Sthorpej 				if_statinc(&sc->sc_if, if_collisions);
49389955057Sragge 			} else if (rp->r_flags & XFLG_MORE) {
494d18dc548Sthorpej 				/* more than one collision (guess...) */
495d18dc548Sthorpej 				if_statadd(&sc->sc_if, if_collisions, 2);
49689955057Sragge 			}
49789955057Sragge 		}
49893011fb5Sragge 		if_ubaend(&sc->sc_ifuba, ifxp);
499944b6966Sragge 		/* check if next transmit buffer also finished */
500944b6966Sragge 		sc->sc_xindex++;
501944b6966Sragge 		if (sc->sc_xindex == NXMT)
502944b6966Sragge 			sc->sc_xindex = 0;
50389955057Sragge 	}
504944b6966Sragge 	sc->sc_if.if_flags &= ~IFF_OACTIVE;
505944b6966Sragge 	destart(&sc->sc_if);
506944b6966Sragge 
507944b6966Sragge 	if (csr0 & PCSR0_RCBI) {
508944b6966Sragge 		DE_WLOW(PCSR0_INTE|CMD_PDMD);
509944b6966Sragge 	}
51089955057Sragge }
51189955057Sragge 
51289955057Sragge /*
51389955057Sragge  * Ethernet interface receiver interface.
51489955057Sragge  * If input error just drop packet.
51589955057Sragge  * Otherwise purge input buffered data path and examine
51689955057Sragge  * packet to determine type.  If can't determine length
517*4b2769feSandvar  * from type, then have to drop packet.	 Otherwise decapsulate
51889955057Sragge  * packet based on type and pass to type specific higher-level
51989955057Sragge  * input routine.
52089955057Sragge  */
52189955057Sragge void
derecv(struct de_softc * sc)52289955057Sragge derecv(struct de_softc *sc)
52389955057Sragge {
52489955057Sragge 	struct ifnet *ifp = &sc->sc_if;
52589955057Sragge 	struct de_ring *rp;
526944b6966Sragge 	struct de_cdata *dc;
52789955057Sragge 	struct mbuf *m;
52889955057Sragge 	int len;
52989955057Sragge 
530944b6966Sragge 	dc = sc->sc_dedata;
531944b6966Sragge 	rp = &dc->dc_rrent[sc->sc_rindex];
53289955057Sragge 	while ((rp->r_flags & RFLG_OWN) == 0) {
533944b6966Sragge 		len = (rp->r_lenerr&RERR_MLEN) - ETHER_CRC_LEN;
53489955057Sragge 		/* check for errors */
53589955057Sragge 		if ((rp->r_flags & (RFLG_ERRS|RFLG_FRAM|RFLG_OFLO|RFLG_CRC)) ||
53616f02724Sragge 		    (rp->r_lenerr & (RERR_BUFL|RERR_UBTO))) {
537d18dc548Sthorpej 			if_statinc(&sc->sc_if, if_ierrors);
53889955057Sragge 			goto next;
53989955057Sragge 		}
54093011fb5Sragge 		m = if_ubaget(&sc->sc_ifuba, &sc->sc_ifr[sc->sc_rindex],
54193011fb5Sragge 		    ifp, len);
54293011fb5Sragge 		if (m == 0) {
543d18dc548Sthorpej 			if_statinc(&sc->sc_if, if_ierrors);
54493011fb5Sragge 			goto next;
54593011fb5Sragge 		}
546944b6966Sragge 
5479c4cd063Sozaki-r 		if_percpuq_enqueue(ifp->if_percpuq, m);
54889955057Sragge 
54989955057Sragge 		/* hang the receive buffer again */
55089955057Sragge next:		rp->r_lenerr = 0;
55189955057Sragge 		rp->r_flags = RFLG_OWN;
55289955057Sragge 
55389955057Sragge 		/* check next receive buffer */
554944b6966Sragge 		sc->sc_rindex++;
555944b6966Sragge 		if (sc->sc_rindex == NRCV)
556944b6966Sragge 			sc->sc_rindex = 0;
557944b6966Sragge 		rp = &dc->dc_rrent[sc->sc_rindex];
55889955057Sragge 	}
55989955057Sragge }
56089955057Sragge 
56189955057Sragge /*
56289955057Sragge  * Process an ioctl request.
56389955057Sragge  */
56489955057Sragge int
deioctl(struct ifnet * ifp,u_long cmd,void * data)56553524e44Schristos deioctl(struct ifnet *ifp, u_long cmd, void *data)
56689955057Sragge {
56793011fb5Sragge 	int s, error = 0;
56889955057Sragge 
56993011fb5Sragge 	s = splnet();
57089955057Sragge 
57193011fb5Sragge 	error = ether_ioctl(ifp, cmd, data);
57293011fb5Sragge 	if (error == ENETRESET)
57316f02724Sragge 		error = 0;
57489955057Sragge 
57589955057Sragge 	splx(s);
57689955057Sragge 	return (error);
57789955057Sragge }
57889955057Sragge 
57989955057Sragge /*
58089955057Sragge  * Await completion of the named function
58189955057Sragge  * and check for errors.
58289955057Sragge  */
58316f02724Sragge void
dewait(struct de_softc * sc,const char * fn)584a4a700a7Sragge dewait(struct de_softc *sc, const char *fn)
58589955057Sragge {
586dfba8166Smatt 	int csr0, csr1;
58789955057Sragge 
58889955057Sragge 	while ((DE_RCSR(DE_PCSR0) & PCSR0_INTR) == 0)
58989955057Sragge 		;
59089955057Sragge 	csr0 = DE_RCSR(DE_PCSR0);
59189955057Sragge 	DE_WHIGH(csr0 >> 8);
59289955057Sragge 	if (csr0 & PCSR0_PCEI) {
593dfba8166Smatt 		char bits0[64];
594dfba8166Smatt 		char bits1[64];
595dfba8166Smatt 		csr1 = DE_RCSR(DE_PCSR1);
5969a5d3f28Schristos 		snprintb(bits0, sizeof(bits0), PCSR0_BITS, csr0);
5979a5d3f28Schristos 		snprintb(bits1, sizeof(bits1), PCSR1_BITS, csr1);
598dfba8166Smatt 		aprint_error_dev(sc->sc_dev, "%s failed, csr0=%s csr1=%s\n",
5999a5d3f28Schristos 		    fn, bits0, bits1);
60089955057Sragge 	}
60189955057Sragge }
60289955057Sragge 
60389955057Sragge int
dematch(device_t parent,cfdata_t cf,void * aux)604dfba8166Smatt dematch(device_t parent, cfdata_t cf, void *aux)
60589955057Sragge {
60689955057Sragge 	struct uba_attach_args *ua = aux;
60789955057Sragge 	struct de_softc ssc;
60889955057Sragge 	struct de_softc *sc = &ssc;
60989955057Sragge 	int i;
61089955057Sragge 
61189955057Sragge 	sc->sc_iot = ua->ua_iot;
61289955057Sragge 	sc->sc_ioh = ua->ua_ioh;
61389955057Sragge 	/*
61489955057Sragge 	 * Make sure self-test is finished before we screw with the board.
61589955057Sragge 	 * Self-test on a DELUA can take 15 seconds (argh).
61689955057Sragge 	 */
61789955057Sragge 	for (i = 0;
61889955057Sragge 	    (i < 160) &&
61989955057Sragge 	    (DE_RCSR(DE_PCSR0) & PCSR0_FATI) == 0 &&
62089955057Sragge 	    (DE_RCSR(DE_PCSR1) & PCSR1_STMASK) == STAT_RESET;
62189955057Sragge 	    ++i)
62289955057Sragge 		DELAY(50000);
62389955057Sragge 	if (((DE_RCSR(DE_PCSR0) & PCSR0_FATI) != 0) ||
62489955057Sragge 	    (((DE_RCSR(DE_PCSR1) & PCSR1_STMASK) != STAT_READY) &&
62589955057Sragge 	    ((DE_RCSR(DE_PCSR1) & PCSR1_STMASK) != STAT_RUN)))
62689955057Sragge 		return(0);
62789955057Sragge 
62889955057Sragge 	DE_WCSR(DE_PCSR0, 0);
62989955057Sragge 	DELAY(5000);
63089955057Sragge 	DE_WCSR(DE_PCSR0, PCSR0_RSET);
63189955057Sragge 	while ((DE_RCSR(DE_PCSR0) & PCSR0_INTR) == 0)
63289955057Sragge 		;
63389955057Sragge 	/* make board interrupt by executing a GETPCBB command */
63489955057Sragge 	DE_WCSR(DE_PCSR0, PCSR0_INTE);
63589955057Sragge 	DE_WCSR(DE_PCSR2, 0);
63689955057Sragge 	DE_WCSR(DE_PCSR3, 0);
63789955057Sragge 	DE_WCSR(DE_PCSR0, PCSR0_INTE|CMD_GETPCBB);
63889955057Sragge 	DELAY(50000);
63989955057Sragge 
64089955057Sragge 	return 1;
64189955057Sragge }
64216f02724Sragge 
64316f02724Sragge void
deshutdown(void * arg)64416f02724Sragge deshutdown(void *arg)
64516f02724Sragge {
64616f02724Sragge 	struct de_softc *sc = arg;
64716f02724Sragge 
648944b6966Sragge 	DE_WCSR(DE_PCSR0, 0);
649944b6966Sragge 	DELAY(1000);
65016f02724Sragge 	DE_WCSR(DE_PCSR0, PCSR0_RSET);
65116f02724Sragge 	dewait(sc, "shutdown");
65216f02724Sragge }
653