if_es.c revision 1.62
1/*	$NetBSD: if_es.c,v 1.62 2019/05/29 05:06:39 msaitoh Exp $ */
2
3/*
4 * Copyright (c) 1995 Michael L. Hitch
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 * 1. Redistributions of source code must retain the above copyright
11 *    notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 *    notice, this list of conditions and the following disclaimer in the
14 *    documentation and/or other materials provided with the distribution.
15 *
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27
28/*
29 * SMC 91C90 Single-Chip Ethernet Controller
30 */
31#include "opt_ddb.h"
32#include "opt_inet.h"
33#include "opt_ns.h"
34
35#include <sys/cdefs.h>
36__KERNEL_RCSID(0, "$NetBSD: if_es.c,v 1.62 2019/05/29 05:06:39 msaitoh Exp $");
37
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/mbuf.h>
42#include <sys/buf.h>
43#include <sys/protosw.h>
44#include <sys/socket.h>
45#include <sys/syslog.h>
46#include <sys/ioctl.h>
47#include <sys/errno.h>
48#include <sys/device.h>
49
50#include <net/if.h>
51#include <net/if_dl.h>
52#include <net/if_ether.h>
53#include <net/if_media.h>
54#include <net/bpf.h>
55
56#ifdef INET
57#include <netinet/in.h>
58#include <netinet/in_systm.h>
59#include <netinet/in_var.h>
60#include <netinet/ip.h>
61#include <netinet/if_inarp.h>
62#endif
63
64#include <machine/cpu.h>
65#include <amiga/amiga/device.h>
66#include <amiga/amiga/isr.h>
67#include <amiga/dev/zbusvar.h>
68#include <amiga/dev/if_esreg.h>
69
70#define SWAP(x) (((x & 0xff) << 8) | ((x >> 8) & 0xff))
71
72#define	USEPKTBUF
73
74/*
75 * Ethernet software status per interface.
76 *
77 * Each interface is referenced by a network interface structure,
78 * es_if, which the routing code uses to locate the interface.
79 * This structure contains the output queue for the interface, its address, ...
80 */
81struct	es_softc {
82	device_t sc_dev;
83	struct	isr sc_isr;
84	struct	ethercom sc_ethercom;	/* common Ethernet structures */
85	struct	ifmedia sc_media;	/* our supported media */
86	void	*sc_base;		/* base address of board */
87	short	sc_iflags;
88	unsigned short sc_intctl;
89#ifdef ESDEBUG
90	int	sc_debug;
91	short	sc_intbusy;		/* counter for interrupt rentered */
92	short	sc_smcbusy;		/* counter for other rentry checks */
93#endif
94};
95
96#ifdef ESDEBUG
97/* console error messages */
98int	esdebug = 0;
99int	estxints = 0;	/* IST_TX with TX enabled */
100int	estxint2 = 0;	/* IST_TX active after IST_TX_EMPTY */
101int	estxint3 = 0;	/* IST_TX interrupt processed */
102int	estxint4 = 0;	/* ~TEMPTY counts */
103int	estxint5 = 0;	/* IST_TX_EMPTY interrupts */
104void	es_dump_smcregs(char *, union smcregs *);
105#endif
106
107int esintr(void *);
108void esstart(struct ifnet *);
109void eswatchdog(struct ifnet *);
110int esioctl(struct ifnet *, u_long, void *);
111void esrint(struct es_softc *);
112void estint(struct es_softc *);
113void esinit(struct es_softc *);
114void esreset(struct es_softc *);
115void esstop(struct es_softc *);
116int esmediachange(struct ifnet *);
117void esmediastatus(struct ifnet *, struct ifmediareq *);
118
119int esmatch(device_t, cfdata_t, void *);
120void esattach(device_t, device_t, void *);
121
122CFATTACH_DECL_NEW(es, sizeof(struct es_softc),
123    esmatch, esattach, NULL, NULL);
124
125int
126esmatch(device_t parent, cfdata_t cf, void *aux)
127{
128	struct zbus_args *zap = aux;
129
130	/* Ameristar A4066 ethernet card */
131	if (zap->manid == 1053 && zap->prodid == 10)
132		return (1);
133
134	return (0);
135}
136
137/*
138 * Interface exists: make available by filling in network interface
139 * record.  System will initialize the interface when it is ready
140 * to accept packets.
141 */
142void
143esattach(device_t parent, device_t self, void *aux)
144{
145	struct es_softc *sc = device_private(self);
146	struct zbus_args *zap = aux;
147	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
148	unsigned long ser;
149	u_int8_t myaddr[ETHER_ADDR_LEN];
150
151	sc->sc_dev = self;
152	sc->sc_base = zap->va;
153
154	/*
155	 * Manufacturer decides the 3 first bytes, i.e. ethernet vendor ID.
156	 * (Currently only Ameristar.)
157	 */
158	myaddr[0] = 0x00;
159	myaddr[1] = 0x00;
160	myaddr[2] = 0x9f;
161
162	/*
163	 * Serial number for board contains last 3 bytes.
164	 */
165	ser = (unsigned long) zap->serno;
166
167	myaddr[3] = (ser >> 16) & 0xff;
168	myaddr[4] = (ser >>  8) & 0xff;
169	myaddr[5] = (ser      ) & 0xff;
170
171	/* Initialize ifnet structure. */
172	memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
173	ifp->if_softc = sc;
174	ifp->if_ioctl = esioctl;
175	ifp->if_start = esstart;
176	ifp->if_watchdog = eswatchdog;
177	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
178
179	ifmedia_init(&sc->sc_media, 0, esmediachange, esmediastatus);
180	ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
181	ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
182
183	/* Attach the interface. */
184	if_attach(ifp);
185	if_deferred_start_init(ifp, NULL);
186	ether_ifattach(ifp, myaddr);
187
188	/* Print additional info when attached. */
189	printf(": address %s\n", ether_sprintf(myaddr));
190
191	sc->sc_isr.isr_intr = esintr;
192	sc->sc_isr.isr_arg = sc;
193	sc->sc_isr.isr_ipl = 2;
194	add_isr(&sc->sc_isr);
195}
196
197#ifdef ESDEBUG
198void
199es_dump_smcregs(char *where, union smcregs *smc)
200{
201	u_short cur_bank = smc->b0.bsr & BSR_MASK;
202
203	printf("SMC registers %p from %s bank %04x\n", smc, where,
204	    smc->b0.bsr);
205	smc->b0.bsr = BSR_BANK0;
206	printf("TCR %04x EPHSR %04x RCR %04x ECR %04x MIR %04x MCR %04x\n",
207	    SWAP(smc->b0.tcr), SWAP(smc->b0.ephsr), SWAP(smc->b0.rcr),
208	    SWAP(smc->b0.ecr), SWAP(smc->b0.mir), SWAP(smc->b0.mcr));
209	smc->b1.bsr = BSR_BANK1;
210	printf("CR %04x BAR %04x IAR %04x %04x %04x GPR %04x CTR %04x\n",
211	    SWAP(smc->b1.cr), SWAP(smc->b1.bar), smc->b1.iar[0], smc->b1.iar[1],
212	    smc->b1.iar[2], smc->b1.gpr, SWAP(smc->b1.ctr));
213	smc->b2.bsr = BSR_BANK2;
214	printf("MMUCR %04x PNR %02x ARR %02x FIFO %04x PTR %04x",
215	    SWAP(smc->b2.mmucr), smc->b2.pnr, smc->b2.arr, smc->b2.fifo,
216	    SWAP(smc->b2.ptr));
217	printf(" DATA %04x %04x IST %02x MSK %02x\n", smc->b2.data,
218	    smc->b2.datax, smc->b2.ist, smc->b2.msk);
219	smc->b3.bsr = BSR_BANK3;
220	printf("MT %04x %04x %04x %04x\n",
221	    smc->b3.mt[0], smc->b3.mt[1], smc->b3.mt[2], smc->b3.mt[3]);
222	smc->b3.bsr = cur_bank;
223}
224#endif
225
226void
227esstop(struct es_softc *sc)
228{
229	union smcregs *smc = sc->sc_base;
230
231	/*
232	 * Clear interrupt mask; disable all interrupts.
233	 */
234	smc->b2.bsr = BSR_BANK2;
235	smc->b2.msk = 0;
236
237	/*
238	 * Disable transmitter and receiver.
239	 */
240	smc->b0.bsr = BSR_BANK0;
241	smc->b0.rcr = 0;
242	smc->b0.tcr = 0;
243
244	/*
245	 * Cancel watchdog timer.
246	 */
247	sc->sc_ethercom.ec_if.if_timer = 0;
248}
249
250void
251esinit(struct es_softc *sc)
252{
253	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
254	union smcregs *smc = sc->sc_base;
255	int s;
256
257	s = splnet();
258
259#ifdef ESDEBUG
260	if (ifp->if_flags & IFF_RUNNING)
261		es_dump_smcregs("esinit", smc);
262#endif
263	smc->b0.bsr = BSR_BANK0;	/* Select bank 0 */
264	smc->b0.rcr = RCR_EPH_RST;
265	smc->b0.rcr = 0;
266	smc->b3.bsr = BSR_BANK3;	/* Select bank 3 */
267	smc->b3.mt[0] = 0;		/* clear Multicast table */
268	smc->b3.mt[1] = 0;
269	smc->b3.mt[2] = 0;
270	smc->b3.mt[3] = 0;
271	/* XXX set Multicast table from Multicast list */
272	smc->b1.bsr = BSR_BANK1;	/* Select bank 1 */
273	smc->b1.cr = CR_RAM32K | CR_NO_WAIT_ST | CR_SET_SQLCH;
274	smc->b1.ctr = CTR_AUTO_RLSE | CTR_TE_ENA;
275	smc->b1.iar[0] = *((const unsigned short *) &CLLADDR(ifp->if_sadl)[0]);
276	smc->b1.iar[1] = *((const unsigned short *) &CLLADDR(ifp->if_sadl)[2]);
277	smc->b1.iar[2] = *((const unsigned short *) &CLLADDR(ifp->if_sadl)[4]);
278	smc->b2.bsr = BSR_BANK2;	/* Select bank 2 */
279	smc->b2.mmucr = MMUCR_RESET;
280	smc->b0.bsr = BSR_BANK0;	/* Select bank 0 */
281	smc->b0.mcr = SWAP(0x0020);	/* reserve 8K for transmit buffers */
282	smc->b0.tcr = TCR_PAD_EN | (TCR_TXENA + TCR_MON_CSN);
283	smc->b0.rcr = RCR_FILT_CAR | RCR_STRIP_CRC | RCR_RXEN | RCR_ALLMUL;
284	/* XXX add promiscuous flags */
285	smc->b2.bsr = BSR_BANK2;	/* Select bank 2 */
286	smc->b2.msk = sc->sc_intctl = MSK_RX_OVRN | MSK_RX | MSK_EPHINT;
287
288	/* Interface is now 'running', with no output active. */
289	ifp->if_flags |= IFF_RUNNING;
290	ifp->if_flags &= ~IFF_OACTIVE;
291
292	/* Attempt to start output, if any. */
293	if_schedule_deferred_start(ifp);
294
295	splx(s);
296}
297
298int
299esintr(void *arg)
300{
301	struct es_softc *sc = arg;
302	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
303	u_short intsts, intact;
304	union smcregs *smc;
305	int s = splnet();
306
307	smc = sc->sc_base;
308#ifdef ESDEBUG
309	while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2 &&
310	    ifp->if_flags & IFF_RUNNING) {
311		printf("%s: intr BSR not 2: %04x\n", device_xname(sc->sc_dev),
312		    smc->b2.bsr);
313		smc->b2.bsr = BSR_BANK2;
314	}
315#endif
316	intsts = smc->b2.ist;
317	intact = smc->b2.msk & intsts;
318	if ((intact) == 0) {
319		splx(s);
320		return (0);
321	}
322#ifdef ESDEBUG
323	if (esdebug)
324		printf ("%s: esintr ist %02x msk %02x",
325		    device_xname(sc->sc_dev), intsts, smc->b2.msk);
326	if (sc->sc_intbusy++) {
327		printf("%s: esintr re-entered\n", device_xname(sc->sc_dev));
328		panic("esintr re-entered");
329	}
330	if (sc->sc_smcbusy)
331		printf("%s: esintr interrupted busy %d\n", device_xname(sc->sc_dev),
332		    sc->sc_smcbusy);
333#endif
334	smc->b2.msk = 0;
335#ifdef ESDEBUG
336	if (esdebug)
337		printf ("=>%02x%02x pnr %02x arr %02x fifo %04x\n",
338		    smc->b2.ist, smc->b2.ist, smc->b2.pnr, smc->b2.arr,
339		    smc->b2.fifo);
340#endif
341	if (intact & IST_ALLOC) {
342		sc->sc_intctl &= ~MSK_ALLOC;
343#ifdef ESDEBUG
344		if (esdebug || 1)
345			printf ("%s: ist %02x", device_xname(sc->sc_dev),
346			    intsts);
347#endif
348		if ((smc->b2.arr & ARR_FAILED) == 0) {
349			u_char save_pnr;
350#ifdef ESDEBUG
351			if (esdebug || 1)
352				printf (" arr %02x\n", smc->b2.arr);
353#endif
354			save_pnr = smc->b2.pnr;
355			smc->b2.pnr = smc->b2.arr;
356			smc->b2.mmucr = MMUCR_RLSPKT;
357			while (smc->b2.mmucr & MMUCR_BUSY)
358				;
359			smc->b2.pnr = save_pnr;
360			ifp->if_flags &= ~IFF_OACTIVE;
361			ifp->if_timer = 0;
362		}
363#ifdef ESDEBUG
364		else if (esdebug || 1)
365			printf (" IST_ALLOC with ARR_FAILED?\n");
366#endif
367	}
368#ifdef ESDEBUG
369	while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
370		printf("%s: intr+ BSR not 2: %04x\n", device_xname(sc->sc_dev),
371		    smc->b2.bsr);
372		smc->b2.bsr = BSR_BANK2;
373	}
374#endif
375	while ((smc->b2.fifo & FIFO_REMPTY) == 0) {
376		esrint(sc);
377	}
378#ifdef ESDEBUG
379	while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
380		printf("%s: intr++ BSR not 2: %04x\n", device_xname(sc->sc_dev),
381		    smc->b2.bsr);
382		smc->b2.bsr = BSR_BANK2;
383	}
384#endif
385	if (intact & IST_RX_OVRN) {
386		printf ("%s: Overrun ist %02x", device_xname(sc->sc_dev),
387		    intsts);
388		smc->b2.ist = ACK_RX_OVRN;
389		printf ("->%02x\n", smc->b2.ist);
390		ifp->if_ierrors++;
391	}
392	if (intact & IST_TX_EMPTY) {
393		u_short ecr;
394#ifdef ESDEBUG
395		if (esdebug)
396			printf ("%s: TX EMPTY %02x",
397			    device_xname(sc->sc_dev), intsts);
398		++estxint5;		/* count # IST_TX_EMPTY ints */
399#endif
400		smc->b2.ist = ACK_TX_EMPTY;
401		sc->sc_intctl &= ~(MSK_TX_EMPTY | MSK_TX);
402		ifp->if_timer = 0;
403#ifdef ESDEBUG
404		if (esdebug)
405			printf ("->%02x intcl %x pnr %02x arr %02x\n",
406			    smc->b2.ist, sc->sc_intctl, smc->b2.pnr,
407			    smc->b2.arr);
408#endif
409		if (smc->b2.ist & IST_TX) {
410			intact |= IST_TX;
411#ifdef ESDEBUG
412			++estxint2;		/* count # TX after TX_EMPTY */
413#endif
414		} else {
415			smc->b0.bsr = BSR_BANK0;
416			ecr = smc->b0.ecr;	/* Get error counters */
417			if (ecr & 0xff00)
418				ifp->if_collisions += ((ecr >> 8) & 15) +
419				    ((ecr >> 11) & 0x1e);
420			smc->b2.bsr = BSR_BANK2;
421#if 0
422			smc->b2.mmucr = MMUCR_RESET_TX; /* XXX reset TX FIFO */
423#endif
424		}
425	}
426	if (intact & IST_TX) {
427		u_char tx_pnr, save_pnr;
428		u_short save_ptr, ephsr, tcr;
429		int n = 0;
430#ifdef ESDEBUG
431		if (esdebug) {
432			printf ("%s: TX INT ist %02x",
433			    device_xname(sc->sc_dev), intsts);
434			printf ("->%02x\n", smc->b2.ist);
435		}
436		++estxint3;			/* count # IST_TX */
437#endif
438zzzz:
439#ifdef ESDEBUG
440		++estxint4;			/* count # ~TEMPTY */
441#endif
442		smc->b0.bsr = BSR_BANK0;
443		ephsr = smc->b0.ephsr;		/* get EPHSR */
444		__USE(ephsr);
445		tcr = smc->b0.tcr;		/* and TCR */
446		smc->b2.bsr = BSR_BANK2;
447		save_ptr = smc->b2.ptr;
448		save_pnr = smc->b2.pnr;
449		tx_pnr = smc->b2.fifo >> 8;	/* pktno from completion fifo */
450		smc->b2.pnr = tx_pnr;		/* set TX packet number */
451		smc->b2.ptr = PTR_READ;		/* point to status word */
452#if 0 /* XXXX */
453		printf("%s: esintr TXINT IST %02x PNR %02x(%d)",
454		    device_xname(sc->sc_dev), smc->b2.ist,
455		    tx_pnr, n);
456		printf(" Status %04x", smc->b2.data);
457		printf(" EPHSR %04x\n", ephsr);
458#endif
459		if ((smc->b2.data & EPHSR_TX_SUC) == 0 && (tcr & TCR_TXENA) == 0) {
460			/*
461			 * Transmitter was stopped for some error.  Enqueue
462			 * the packet again and restart the transmitter.
463			 * May need some check to limit the number of retries.
464			 */
465			smc->b2.mmucr = MMUCR_ENQ_TX;
466			smc->b0.bsr = BSR_BANK0;
467			smc->b0.tcr |= TCR_TXENA;
468			smc->b2.bsr = BSR_BANK2;
469			ifp->if_oerrors++;
470			sc->sc_intctl |= MSK_TX_EMPTY | MSK_TX;
471		} else {
472			/*
473			 * This shouldn't have happened:  IST_TX indicates
474			 * the TX completion FIFO is not empty, but the
475			 * status for the packet on the completion FIFO
476			 * shows that the transmit was successful.  Since
477			 * AutoRelease is being used, a successful transmit
478			 * should not result in a packet on the completion
479			 * FIFO.  Also, that packet doesn't seem to want
480			 * to be acknowledged.  If this occurs, just reset
481			 * the TX FIFOs.
482			 */
483#if 1
484			if (smc->b2.ist & IST_TX_EMPTY) {
485				smc->b2.mmucr = MMUCR_RESET_TX;
486				sc->sc_intctl &= ~(MSK_TX_EMPTY | MSK_TX);
487				ifp->if_timer = 0;
488			}
489#endif
490#ifdef ESDEBUG
491			++estxints;	/* count IST_TX with TX enabled */
492#endif
493		}
494		smc->b2.pnr = save_pnr;
495		smc->b2.ptr = save_ptr;
496		smc->b2.ist = ACK_TX;
497
498		if ((smc->b2.fifo & FIFO_TEMPTY) == 0 && n++ < 32) {
499#if 0 /* XXXX */
500			printf("%s: multiple TX int(%2d) pnr %02x ist %02x fifo %04x",
501			    device_xname(sc->sc_dev), n, tx_pnr, smc->b2.ist, smc->b2.fifo);
502			smc->w2.istmsk = ACK_TX << 8;
503			printf(" %04x\n", smc->b2.fifo);
504#endif
505			if (tx_pnr != (smc->b2.fifo >> 8))
506				goto zzzz;
507		}
508	}
509	if (intact & IST_EPHINT) {
510		ifp->if_oerrors++;
511		esreset(sc);
512	}
513	/* output packets */
514	estint(sc);
515#ifdef ESDEBUG
516	while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
517		printf("%s: intr+++ BSR not 2: %04x\n", device_xname(sc->sc_dev),
518		    smc->b2.bsr);
519		smc->b2.bsr = BSR_BANK2;
520	}
521#endif
522	smc->b2.msk = sc->sc_intctl;
523#ifdef ESDEBUG
524	if (--sc->sc_intbusy) {
525		printf("%s: esintr busy on exit\n", device_xname(sc->sc_dev));
526		panic("esintr busy on exit");
527	}
528#endif
529	splx(s);
530	return (1);
531}
532
533void
534esrint(struct es_softc *sc)
535{
536	union smcregs *smc = sc->sc_base;
537	u_short len;
538	short cnt;
539	u_short pktctlw, pktlen, *buf;
540	volatile u_short *data;
541#if 0
542	u_long *lbuf;
543	volatile u_long *ldata;
544#endif
545	struct ifnet *ifp;
546	struct mbuf *top, **mp, *m;
547#ifdef USEPKTBUF
548	u_char *b, pktbuf[1530];
549#endif
550#ifdef ESDEBUG
551	int i;
552#endif
553
554	ifp = &sc->sc_ethercom.ec_if;
555#ifdef ESDEBUG
556	if (esdebug)
557		printf ("%s: esrint fifo %04x", device_xname(sc->sc_dev),
558		    smc->b2.fifo);
559	if (sc->sc_smcbusy++) {
560		printf("%s: esrint re-entered\n", device_xname(sc->sc_dev));
561		panic("esrint re-entered");
562	}
563	while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
564		printf("%s: rint BSR not 2: %04x\n", device_xname(sc->sc_dev),
565		    smc->b2.bsr);
566		smc->b2.bsr = BSR_BANK2;
567	}
568#endif
569	data = (volatile u_short *)&smc->b2.data;
570	smc->b2.ptr = PTR_RCV | PTR_AUTOINCR | PTR_READ | SWAP(0x0002);
571	(void) smc->b2.mmucr;
572#ifdef ESDEBUG
573	if (esdebug)
574		printf ("->%04x", smc->b2.fifo);
575#endif
576	len = *data;
577	len = SWAP(len);	/* Careful of macro side-effects */
578#ifdef ESDEBUG
579	if (esdebug)
580		printf (" length %d", len);
581#endif
582	smc->b2.ptr = PTR_RCV | (PTR_AUTOINCR + PTR_READ) | SWAP(0x0000);
583	(void) smc->b2.mmucr;
584	pktctlw = *data;
585	pktlen = *data;
586	pktctlw = SWAP(pktctlw);
587	pktlen = SWAP(pktlen) - 6;
588	if (pktctlw & RFSW_ODDFRM)
589		pktlen++;
590	if (len > 1530) {
591		printf("%s: Corrupted packet length-sts %04x bytcnt %04x len %04x bank %04x\n",
592		    device_xname(sc->sc_dev), pktctlw, pktlen, len, smc->b2.bsr);
593		/* XXX ignore packet, or just truncate? */
594#if defined(ESDEBUG) && defined(DDB)
595		if ((smc->b2.bsr & BSR_MASK) != BSR_BANK2)
596			Debugger();
597#endif
598		smc->b2.bsr = BSR_BANK2;
599		smc->b2.mmucr = MMUCR_REMRLS_RX;
600		while (smc->b2.mmucr & MMUCR_BUSY)
601			;
602		++ifp->if_ierrors;
603#ifdef ESDEBUG
604		if (--sc->sc_smcbusy) {
605			printf("%s: esrintr busy on bad packet exit\n",
606			    device_xname(sc->sc_dev));
607			panic("esrintr busy on exit");
608		}
609#endif
610		return;
611	}
612#ifdef USEPKTBUF
613#if 0
614	lbuf = (u_long *) pktbuf;
615	ldata = (u_long *)data;
616	cnt = (len - 4) / 4;
617	while (cnt--)
618		*lbuf++ = *ldata;
619	if ((len - 4) & 2) {
620		buf = (u_short *) lbuf;
621		*buf = *data;
622	}
623#else
624	buf = (u_short *)pktbuf;
625	cnt = (len - 4) / 2;
626	while (cnt--)
627		*buf++ = *data;
628#endif
629	smc->b2.mmucr = MMUCR_REMRLS_RX;
630	while (smc->b2.mmucr & MMUCR_BUSY)
631		;
632#ifdef ESDEBUG
633	if (pktctlw & (RFSW_ALGNERR | RFSW_BADCRC | RFSW_TOOLNG | RFSW_TOOSHORT)) {
634		printf ("%s: Packet error %04x\n", device_xname(sc->sc_dev), pktctlw);
635		/* count input error? */
636	}
637	if (esdebug) {
638		printf (" pktctlw %04x pktlen %04x fifo %04x\n", pktctlw, pktlen,
639		    smc->b2.fifo);
640		for (i = 0; i < pktlen; ++i)
641			printf ("%02x%s", pktbuf[i], ((i & 31) == 31) ? "\n" :
642			    "");
643		if (i & 31)
644			printf ("\n");
645	}
646#endif
647#else	/* USEPKTBUF */
648	/* XXX copy directly from controller to mbuf */
649#ifdef ESDEBUG
650	if (pktctlw & (RFSW_ALGNERR | RFSW_BADCRC | RFSW_TOOLNG | RFSW_TOOSHORT)) {
651		printf ("%s: Packet error %04x\n", device_xname(sc->sc_dev), pktctlw);
652		/* count input error? */
653	}
654	if (esdebug) {
655		printf (" pktctlw %04x pktlen %04x fifo %04x\n", pktctlw, pktlen,
656		    smc->b2.fifo);
657	}
658#endif
659#endif /* USEPKTBUF */
660	MGETHDR(m, M_DONTWAIT, MT_DATA);
661	if (m == NULL)
662		return;
663	m_set_rcvif(m, ifp);
664	m->m_pkthdr.len = pktlen;
665	len = MHLEN;
666	top = NULL;
667	mp = &top;
668#ifdef USEPKTBUF
669	b = pktbuf;
670#endif
671	while (pktlen > 0) {
672		if (top) {
673			MGET(m, M_DONTWAIT, MT_DATA);
674			if (m == 0) {
675				m_freem(top);
676				return;
677			}
678			len = MLEN;
679		}
680		if (pktlen >= MINCLSIZE) {
681			MCLGET(m, M_DONTWAIT);
682			if (m->m_flags & M_EXT)
683				len = MCLBYTES;
684		}
685		m->m_len = len = uimin(pktlen, len);
686#ifdef USEPKTBUF
687		memcpy(mtod(m, void *), (void *)b, len);
688		b += len;
689#else	/* USEPKTBUF */
690		buf = mtod(m, u_short *);
691		cnt = len / 2;
692		while (cnt--)
693			*buf++ = *data;
694		if (len & 1)
695			*buf = *data;	/* XXX should be byte store */
696#ifdef ESDEBUG
697		if (esdebug) {
698			buf = mtod(m, u_short *);
699			for (i = 0; i < len; ++i)
700				printf ("%02x%s", ((u_char *)buf)[i],
701				    ((i & 31) == 31) ? "\n" : "");
702			if (i & 31)
703				printf ("\n");
704		}
705#endif
706#endif	/* USEPKTBUF */
707		pktlen -= len;
708		*mp = m;
709		mp = &m->m_next;
710	}
711#ifndef USEPKTBUF
712	smc->b2.mmucr = MMUCR_REMRLS_RX;
713	while (smc->b2.mmucr & MMUCR_BUSY)
714		;
715#endif
716	/*
717	 * Check if there's a BPF listener on this interface.  If so, hand off
718	 * the raw packet to bpf.
719	 */
720	if_percpuq_enqueue(ifp->if_percpuq, top);
721#ifdef ESDEBUG
722	if (--sc->sc_smcbusy) {
723		printf("%s: esintr busy on exit\n", device_xname(sc->sc_dev));
724		panic("esintr busy on exit");
725	}
726#endif
727}
728
729void
730estint(struct es_softc *sc)
731{
732
733	esstart(&sc->sc_ethercom.ec_if);
734}
735
736void
737esstart(struct ifnet *ifp)
738{
739	struct es_softc *sc = ifp->if_softc;
740	union smcregs *smc = sc->sc_base;
741	struct mbuf *m0, *m;
742#ifdef USEPKTBUF
743	u_short pktbuf[ETHERMTU + 2];
744#else
745	u_short oddbyte, needbyte;
746#endif
747	u_short pktctlw, pktlen;
748	u_short *buf;
749	volatile u_short *data;
750#if 0
751	u_long *lbuf;
752	volatile u_long *ldata;
753#endif
754	short cnt;
755	int i;
756	u_char active_pnr;
757
758	if ((sc->sc_ethercom.ec_if.if_flags & (IFF_RUNNING | IFF_OACTIVE)) !=
759	    IFF_RUNNING)
760		return;
761
762#ifdef ESDEBUG
763	if (sc->sc_smcbusy++) {
764		printf("%s: esstart re-entered\n", device_xname(sc->sc_dev));
765		panic("esstart re-entred");
766	}
767	while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
768		printf("%s: esstart BSR not 2: %04x\n", device_xname(sc->sc_dev),
769		    smc->b2.bsr);
770		smc->b2.bsr = BSR_BANK2;
771	}
772#endif
773	for (;;) {
774#ifdef ESDEBUG
775		u_short start_ptr, end_ptr;
776#endif
777		/*
778		 * Sneak a peek at the next packet to get the length
779		 * and see if the SMC 91C90 can accept it.
780		 */
781		m = sc->sc_ethercom.ec_if.if_snd.ifq_head;
782		if (!m)
783			break;
784#ifdef ESDEBUG
785		if (esdebug && (m->m_next || m->m_len & 1))
786			printf("%s: esstart m_next %p m_len %d\n",
787			    device_xname(sc->sc_dev), m->m_next, m->m_len);
788#endif
789		for (m0 = m, pktlen = 0; m0; m0 = m0->m_next)
790			pktlen += m0->m_len;
791		pktctlw = 0;
792		pktlen += 4;
793		if (pktlen & 1)
794			++pktlen;	/* control byte after last byte */
795		else
796			pktlen += 2;	/* control byte after pad byte */
797		smc->b2.mmucr = MMUCR_ALLOC | (pktlen & 0x0700);
798		for (i = 0; i <= 5; ++i)
799			if ((smc->b2.arr & ARR_FAILED) == 0)
800				break;
801		if (smc->b2.arr & ARR_FAILED) {
802			sc->sc_ethercom.ec_if.if_flags |= IFF_OACTIVE;
803			sc->sc_intctl |= MSK_ALLOC;
804			sc->sc_ethercom.ec_if.if_timer = 5;
805			break;
806		}
807		active_pnr = smc->b2.pnr = smc->b2.arr;
808
809#ifdef ESDEBUG
810		while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
811			printf("%s: esstart+ BSR not 2: %04x\n", device_xname(sc->sc_dev),
812			    smc->b2.bsr);
813			smc->b2.bsr = BSR_BANK2;
814		}
815#endif
816		IF_DEQUEUE(&sc->sc_ethercom.ec_if.if_snd, m);
817		smc->b2.ptr = PTR_AUTOINCR;
818		(void) smc->b2.mmucr;
819		data = (volatile u_short *)&smc->b2.data;
820		*data = SWAP(pktctlw);
821		*data = SWAP(pktlen);
822#ifdef ESDEBUG
823		while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
824			printf("%s: esstart++ BSR not 2: %04x\n", device_xname(sc->sc_dev),
825			    smc->b2.bsr);
826			smc->b2.bsr = BSR_BANK2;
827		}
828#endif
829#ifdef USEPKTBUF
830		i = 0;
831		for (m0 = m; m; m = m->m_next) {
832			memcpy((char *)pktbuf + i, mtod(m, void *), m->m_len);
833			i += m->m_len;
834		}
835
836		if (i & 1)	/* Figure out where to put control byte */
837			pktbuf[i/2] = (pktbuf[i/2] & 0xff00) | CTLB_ODD;
838		else
839			pktbuf[i/2] = 0;
840		pktlen -= 4;
841#ifdef ESDEBUG
842		if (pktlen > sizeof(pktbuf) && i > (sizeof(pktbuf) * 2))
843			printf("%s: esstart packet longer than pktbuf\n",
844			    device_xname(sc->sc_dev));
845#endif
846#if 0 /* doesn't quite work? */
847		lbuf = (u_long *)(pktbuf);
848		ldata = (u_long *)data;
849		cnt = pktlen / 4;
850		while (cnt--)
851			*ldata = *lbuf++;
852		if (pktlen & 2) {
853			buf = (u_short *)lbuf;
854			*data = *buf;
855		}
856#else
857#ifdef ESDEBUG
858		while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
859			printf("%s: esstart++2 BSR not 2: %04x\n", device_xname(sc->sc_dev),
860			    smc->b2.bsr);
861			smc->b2.bsr = BSR_BANK2;
862		}
863		start_ptr = SWAP(smc->b2.ptr);	/* save PTR before copy */
864#endif
865		buf = pktbuf;
866		cnt = pktlen / 2;
867		while (cnt--)
868			*data = *buf++;
869#ifdef ESDEBUG
870		end_ptr = SWAP(smc->b2.ptr);	/* save PTR after copy */
871#endif
872#endif
873#else	/* USEPKTBUF */
874		pktctlw = 0;
875		oddbyte = needbyte = 0;
876		for (m0 = m; m; m = m->m_next) {
877			buf = mtod(m, u_short *);
878			cnt = m->m_len / 2;
879			if (needbyte) {
880				oddbyte |= *buf >> 8;
881				*data = oddbyte;
882			}
883			while (cnt--)
884				*data = *buf++;
885			if (m->m_len & 1)
886				pktctlw = (*buf & 0xff00) | CTLB_ODD;
887			if (m->m_len & 1 && m->m_next)
888				printf("%s: esstart odd byte count in mbuf\n",
889				    device_xname(sc->sc_dev));
890		}
891		*data = pktctlw;
892#endif	/* USEPKTBUF */
893		while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
894			/*
895			 * The bank select register has changed.  This seems
896			 * to happen with my A2000/Zeus once in a while.  It
897			 * appears that the Ethernet chip resets while
898			 * copying the transmit buffer.  Requeue the current
899			 * transmit buffer and reinitialize the interface.
900			 * The initialize routine will take care of
901			 * retransmitting the buffer.  mhitch
902			 */
903#ifdef DIAGNOSTIC
904			printf("%s: esstart+++ BSR not 2: %04x\n",
905			    device_xname(sc->sc_dev), smc->b2.bsr);
906#endif
907			smc->b2.bsr = BSR_BANK2;
908#ifdef ESDEBUG
909			printf("start_ptr %04x end_ptr %04x cur ptr %04x\n",
910			    start_ptr, end_ptr, SWAP(smc->b2.ptr));
911			--sc->sc_smcbusy;
912#endif
913			IF_PREPEND(&sc->sc_ethercom.ec_if.if_snd, m0);
914			esinit(sc);	/* It's really hosed - reset */
915			return;
916		}
917		smc->b2.mmucr = MMUCR_ENQ_TX;
918		if (smc->b2.pnr != active_pnr)
919			printf("%s: esstart - PNR changed %x->%x\n",
920			    device_xname(sc->sc_dev), active_pnr, smc->b2.pnr);
921		bpf_mtap(&sc->sc_ethercom.ec_if, m0, BPF_D_OUT);
922		m_freem(m0);
923		sc->sc_ethercom.ec_if.if_opackets++;	/* move to interrupt? */
924		sc->sc_intctl |= MSK_TX_EMPTY | MSK_TX;
925		sc->sc_ethercom.ec_if.if_timer = 5;
926	}
927	smc->b2.msk = sc->sc_intctl;
928#ifdef ESDEBUG
929	while ((smc->b2.bsr & BSR_MASK) != BSR_BANK2) {
930		printf("%s: esstart++++ BSR not 2: %04x\n", device_xname(sc->sc_dev),
931		    smc->b2.bsr);
932		smc->b2.bsr = BSR_BANK2;
933	}
934	if (--sc->sc_smcbusy) {
935		printf("%s: esstart busy on exit\n", device_xname(sc->sc_dev));
936		panic("esstart busy on exit");
937	}
938#endif
939}
940
941int
942esioctl(struct ifnet *ifp, u_long cmd, void *data)
943{
944	struct es_softc *sc = ifp->if_softc;
945	register struct ifaddr *ifa = (struct ifaddr *)data;
946	struct ifreq *ifr = (struct ifreq *)data;
947	int s, error = 0;
948
949	s = splnet();
950
951	switch (cmd) {
952
953	case SIOCINITIFADDR:
954		ifp->if_flags |= IFF_UP;
955
956		switch (ifa->ifa_addr->sa_family) {
957#ifdef INET
958		case AF_INET:
959			esinit(sc);
960			arp_ifinit(ifp, ifa);
961			break;
962#endif
963		default:
964			esinit(sc);
965			break;
966		}
967		break;
968
969	case SIOCSIFFLAGS:
970		if ((error = ifioctl_common(ifp, cmd, data)) != 0)
971			break;
972		/* XXX see the comment in ed_ioctl() about code re-use */
973		/*
974		 * If interface is marked down and it is running, then stop it
975		 */
976		if ((ifp->if_flags & IFF_UP) == 0 &&
977		    (ifp->if_flags & IFF_RUNNING) != 0) {
978			/*
979			 * If interface is marked down and it is running, then
980			 * stop it.
981			 */
982			esstop(sc);
983			ifp->if_flags &= ~IFF_RUNNING;
984		} else if ((ifp->if_flags & IFF_UP) != 0 &&
985		    	   (ifp->if_flags & IFF_RUNNING) == 0) {
986			/*
987			 * If interface is marked up and it is stopped, then
988			 * start it.
989			 */
990			esinit(sc);
991		} else {
992			/*
993			 * Reset the interface to pick up changes in any other
994			 * flags that affect hardware registers.
995			 */
996			esstop(sc);
997			esinit(sc);
998		}
999#ifdef ESDEBUG
1000		if (ifp->if_flags & IFF_DEBUG)
1001			esdebug = sc->sc_debug = 1;
1002		else
1003			esdebug = sc->sc_debug = 0;
1004#endif
1005		break;
1006
1007	case SIOCADDMULTI:
1008	case SIOCDELMULTI:
1009		if ((error = ether_ioctl(ifp, cmd, data)) == ENETRESET) {
1010			/*
1011			 * Multicast list has changed; set the hardware filter
1012			 * accordingly.
1013			 */
1014			if (ifp->if_flags & IFF_RUNNING) {
1015				/* XXX */
1016			}
1017			error = 0;
1018		}
1019		break;
1020
1021	case SIOCGIFMEDIA:
1022	case SIOCSIFMEDIA:
1023		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
1024		break;
1025
1026	default:
1027		error = ether_ioctl(ifp, cmd, data);
1028		break;
1029	}
1030
1031	splx(s);
1032	return (error);
1033}
1034
1035/*
1036 * Reset the interface.
1037 */
1038void
1039esreset(struct es_softc *sc)
1040{
1041	int s;
1042
1043	s = splnet();
1044	esstop(sc);
1045	esinit(sc);
1046	splx(s);
1047}
1048
1049void
1050eswatchdog(struct ifnet *ifp)
1051{
1052	struct es_softc *sc = ifp->if_softc;
1053
1054	log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev));
1055	++ifp->if_oerrors;
1056
1057	esreset(sc);
1058}
1059
1060int
1061esmediachange(struct ifnet *ifp)
1062{
1063	return 0;
1064}
1065
1066void
1067esmediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
1068{
1069}
1070