xref: /netbsd/sys/arch/acorn32/podulebus/if_ie.c (revision cadc7d22)
1 /* $NetBSD: if_ie.c,v 1.53 2022/09/17 18:58:49 thorpej Exp $ */
2 
3 /*
4  * Copyright (c) 1995 Melvin Tang-Richardson.
5  * All rights reserved.
6  *
7  * This driver is a major hash up of src/sys/dev/isa/if_ie.c and
8  * src/sys/arch/acorn32/podulebus/kgdb_ie.c  Please refer to copyright
9  * notices from them too.
10  *
11  * Redistribution and use in source and binary forms, with or without
12  * modification, are permitted provided that the following conditions
13  * are met:
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  * 2. Redistributions in binary form must reproduce the above copyright
17  *    notice, this list of conditions and the following disclaimer in the
18  *    documentation and/or other materials provided with the distribution.
19  * 3. All advertising materials mentioning features or use of this software
20  *    must display the following acknowledgement:
21  *	This product includes software developed by RiscBSD.
22  * 4. The name of the company nor the name of the author may be used to
23  *    endorse or promote products derived from this software without specific
24  *    prior written permission.
25  *
26  * THIS SOFTWARE IS PROVIDED BY RISCBSD ``AS IS'' AND ANY EXPRESS OR IMPLIED
27  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
28  * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29  * IN NO EVENT SHALL RISCBSD OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
31  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
32  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
33  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
34  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
35  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36  * SUCH DAMAGE.
37  *
38  * RiscBSD kernel project
39  *
40  * if_ie.c
41  *
42  * Ether 1 podule driver
43  *
44  * Created      : 26/06/95
45  */
46 
47 /*
48  *	This driver is at its last beta release.  It should not cause
49  *	any problems (Touch wood)
50  *
51  * 	If it passes field tests again.  This will constitute the realse
52  *	version.
53  */
54 
55 #include <sys/cdefs.h>
56 __KERNEL_RCSID(0, "$NetBSD: if_ie.c,v 1.53 2022/09/17 18:58:49 thorpej Exp $");
57 
58 #define IGNORE_ETHER1_IDROM_CHECKSUM
59 
60 /* Standard podule includes */
61 
62 #include "opt_inet.h"
63 #include "opt_ns.h"
64 
65 #include <sys/param.h>
66 
67 #include <sys/systm.h>
68 #include <sys/kernel.h>
69 #include <sys/conf.h>
70 #include <sys/malloc.h>
71 #include <sys/device.h>
72 #include <machine/io.h>
73 #include <machine/intr.h>
74 #include <acorn32/podulebus/podulebus.h>
75 #include <dev/podulebus/podules.h>
76 
77 /* Include for interface to the net and ethernet subsystems */
78 
79 #include <sys/socket.h>
80 #include <sys/syslog.h>
81 #include <sys/ioctl.h>
82 #include <sys/mbuf.h>
83 
84 #include <net/if.h>
85 #include <net/if_types.h>
86 #include <net/if_dl.h>
87 #include <net/if_ether.h>
88 
89 #ifdef INET
90 #include <netinet/in.h>
91 #include <netinet/in_systm.h>
92 #include <netinet/in_var.h>
93 #include <netinet/ip.h>
94 #include <netinet/if_inarp.h>
95 #endif
96 
97 /* Import our data structures */
98 
99 #include "if_iereg.h"
100 
101 /* BPF support */
102 
103 #include <net/bpf.h>
104 
105 /* Some useful defines and macros */
106 
107 #define PODULE_IRQ_PENDING (1)
108 #define NFRAMES	(16)		/* number of frame to allow for receive */
109 #define NRXBUF	(48)		/* number of receive buffers to allocate */
110 #define IE_RXBUF_SIZE (256) 	/* receive buf size */
111 #define NTXBUF  (2)		/* number of transmit buffers to allocate */
112 #define IE_TXBUF_SIZE (1522) 	/* size of tx buffer */
113 
114 #define PWriteShort(a,b)	WriteWord(a,(b)<<16|(b))
115 
116 #define	xoffsetof(type, member)	(offsetof(type, member) << 1)
117 
118 /* Some data structures local to this file */
119 
120 struct ie_softc {
121 	device_t	sc_dev;
122 	int 		sc_podule_number;
123 	podule_t	*sc_podule;
124 	irqhandler_t 	sc_ih;
125 	int		sc_flags;
126 #define IE_BROKEN	1
127 	int		sc_iobase;
128 	int		sc_fastbase;
129 	int		sc_rom;
130 	int		sc_ram;
131 	int		sc_control;
132 	struct ethercom	sc_ethercom;
133 	u_short		promisc;
134 	int		sc_irqmode;
135 
136 	u_long	rframes[NFRAMES];
137 	u_long	rbuffs[NRXBUF];
138 	u_long	cbuffs[NRXBUF];
139 	int 	rfhead, rftail, rbhead, rbtail;
140 
141 	u_long 	xmit_cmds[NTXBUF];
142 	u_long 	xmit_buffs[NTXBUF];
143 	u_long 	xmit_cbuffs[NTXBUF];
144 	int	xmit_count;
145 	int	xmit_free;
146 	int	xchead;
147 	int 	xctail;
148 };
149 
150 /* Function and data prototypes */
151 
152 static void host2ie( struct ie_softc *sc, void *src, u_long dest, int size );
153 static void ie2host( struct ie_softc *sc, u_long src, void *dest, int size );
154 static void iezero( struct ie_softc *sc, u_long p, int size );
155 void        iereset( struct ie_softc *sc );
156 void        iewatchdog( struct ifnet *ifp );
157 int         ieioctl( struct ifnet *ifp, u_long cmd, void *data );
158 void        iestart( struct ifnet *ifp );
159 int 	    iestop( struct ie_softc *sc );
160 int         ieinit( struct ie_softc *sc );
161 int 	    ieintr( void *arg );
162 void 	    ietint( struct ie_softc *sc );
163 
164 /* A whopper of a function */
165 static int command_and_wait( struct ie_softc *sc, u_short cmd,
166 			      struct ie_sys_ctl_block *pscb,
167 			      void *pcmd, int ocmd, int scmd, int mask );
168 
169 int ieprobe(device_t, cfdata_t, void *);
170 void ieattach(device_t, device_t, void *);
171 
172 static inline void ie_cli(struct ie_softc *);
173 static inline void ieattn(struct ie_softc *);
174 static inline void setpage(struct ie_softc *, u_long);
175 static void ie_ack(struct ie_softc *, u_short);
176 void PWriteShorts(char *, char *, int);
177 void ReadShorts(char *, char *, int);
178 static void run_tdr(struct ie_softc *);
179 u_long setup_rfa(struct ie_softc *, u_long);
180 static inline int ie_buflen(struct ie_softc *, int);
181 static inline int ie_packet_len(struct ie_softc *);
182 struct mbuf *ieget(struct ie_softc *, int *);
183 void ie_drop_packet_buffer(struct ie_softc *);
184 void ie_read_frame(struct ie_softc *, int num);
185 void ierint(struct ie_softc *);
186 void iexmit(struct ie_softc *);
187 static void start_receiver(struct ie_softc *);
188 
189 
190 /*
191  * Our cfattach structure for the autoconfig system to chew on
192  */
193 
194 CFATTACH_DECL_NEW(ie, sizeof(struct ie_softc),
195     ieprobe, ieattach, NULL, NULL);
196 
197 /* Let's go! */
198 
199 /*
200  * Clear all pending interrupts from the i82586 chip
201  */
202 
203 static inline void
ie_cli(struct ie_softc * sc)204 ie_cli(struct ie_softc *sc)
205 {
206 	WriteByte(sc->sc_fastbase + (IE_CONTROL<<2), IE_CONT_CLI);
207 }
208 
209 /*
210  * Wake the i82586 chip up and get it to do something
211  */
212 
213 static inline void
ieattn(struct ie_softc * sc)214 ieattn(struct ie_softc *sc)
215 {
216 	WriteByte ( sc->sc_control + (IE_CONTROL<<2), IE_CONT_ATTN );
217 }
218 
219 /*
220  * Set the podule page register to bring a given address into view
221  */
222 
223 static inline void
setpage(struct ie_softc * sc,u_long off)224 setpage(struct ie_softc *sc, u_long off)
225 {
226 	WriteByte ( sc->sc_control + (IE_PAGE<<2), IE_COFF2PAGE(off) );
227 }
228 
229 /*
230  * Ack the i82586
231  */
232 
233 static void
ie_ack(struct ie_softc * sc,u_short mask)234 ie_ack(struct ie_softc *sc, u_short mask)
235 {
236 	u_short stat;
237 	int i;
238 	setpage(sc, IE_IBASE + IE_SCB_OFF );
239 
240 	stat = ReadShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
241 		(xoffsetof(struct ie_sys_ctl_block, ie_status)) );
242 
243 	PWriteShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
244 		(xoffsetof(struct ie_sys_ctl_block, ie_command)),
245 		stat & mask );
246 
247 	ieattn(sc);
248 
249 	for ( i=4000; --i>=0; ) {
250 		if ( !ReadShort(sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
251 		    (xoffsetof(struct ie_sys_ctl_block, ie_command))) )
252 			break;
253 		delay(100);
254 	}
255 
256 	if ( i<=0 )
257 		printf ( "ie: command timed out\n" );
258 	ie_cli(sc);
259 }
260 
261 /*
262  * This routine does the checksumming for the idrom
263  */
264 
265 #ifndef IGNORE_ETHER1_IDROM_CHECKSUM
266 static u_long
crc32(u_char * p,int l)267 crc32(u_char *p, int l)
268 {
269 	u_long crc=-1;
270 	int i, b;
271 	while ( --l >= 0 ) {
272 		b = *p++;
273 		for ( i=8; --i >= 0; b>>=1 )
274 			if ((b&1)^(crc>>31))
275 				crc=(crc<<1)^0x4c11db7;
276 			else
277 				crc<<=1;
278 	}
279 	return crc;
280 }
281 #endif
282 
283 /*
284  * Probe for the ether1 card.  return 1 on success 0 on failure
285  */
286 
287 int
ieprobe(device_t parent,cfdata_t cf,void * aux)288 ieprobe(device_t parent, cfdata_t cf, void *aux)
289 {
290 	struct podule_attach_args *pa = aux;
291 
292 /* Look for a network slot interface */
293 
294 	return (pa->pa_product == PODULE_ETHER1);
295 }
296 
297 /*
298  * Attach our driver to the interfaces it uses
299  */
300 
301 void
ieattach(device_t parent,device_t self,void * aux)302 ieattach(device_t parent, device_t self, void *aux)
303 {
304 	struct ie_softc *sc = device_private(self);
305 	struct podule_attach_args *pa = aux;
306 	struct ifnet *ifp = &sc->sc_ethercom.ec_if;
307 	int i;
308 	char idrom[32];
309 	uint8_t hwaddr[ETHER_ADDR_LEN];
310 
311 	/* Check a few things about the attach args */
312 
313 	if (pa->pa_podule_number == -1)
314 		panic("Podule has disappeared !");
315 
316 	sc->sc_dev = self;
317 	sc->sc_podule_number = pa->pa_podule_number;
318 	sc->sc_podule = pa->pa_podule;
319 	podules[sc->sc_podule_number].attached = 1;
320 
321 	/*
322 	 * MESS MESS MESS
323 	 *
324 	 * This needs a serious clean up. Alot of this code was in the probe function
325 	 * but required the softc structure. As a temporary measure until I rewrite it
326 	 * I have just bolted in the probe code here.
327 	 */
328 
329 	/* Index some podule areas */
330 	sc->sc_iobase   = sc->sc_podule->sync_base;	/* OBSOLETE */
331 	sc->sc_fastbase = sc->sc_podule->fast_base;	/* OBSOLETE */
332 	sc->sc_rom      = sc->sc_podule->sync_base;
333 	sc->sc_control  = sc->sc_podule->fast_base;
334 	sc->sc_ram      = sc->sc_podule->fast_base + IE_MEMOFF;
335 
336 	/* Set the page mask to something know and neutral */
337 	setpage(sc, IE_SCB_OFF);
338 
339 	/* Fetch the first part of the idrom */
340 	for ( i=0; i<16; i++ )
341 		idrom[i] = ReadByte ( sc->sc_rom + (i<<2) );
342 
343 	/* Verify the podulebus probe incase RiscOS lied */
344         if ( ReadByte ( sc->sc_rom + (3<<2) ) != 0x03 ) {
345 		printf(": Ether1 ROM probably broken.  ECID corrupt\n");
346 		sc->sc_flags |= IE_BROKEN;
347 		return;
348 	}
349 
350 	/* Reset the 82586 */
351 	WriteByte ( sc->sc_fastbase + (IE_CONTROL<<2), IE_CONT_RESET );
352  	delay(1000);
353 	WriteByte ( sc->sc_fastbase + (IE_CONTROL<<2), 0 );
354 	delay(10000);
355 
356 	/* Clear pending interrupts */
357 	ie_cli (sc);
358 
359 	/* Setup SCP */
360 	{
361 		struct ie_sys_conf_ptr scp;
362 		bzero (&scp, sizeof(scp) );
363 		scp.ie_iscp_ptr = (void *)IE_ISCP_ADDR;
364 		host2ie(sc, &scp, IE_SCP_ADDR, sizeof (scp) );
365 	}
366 
367 	/* Setup ISCP */
368 	{
369 		struct ie_int_sys_conf_ptr iscp;
370 		bzero ( &iscp, sizeof(iscp) );
371 		iscp.ie_busy = 1;
372 		iscp.ie_base = (void *)IE_IBASE;
373 		iscp.ie_scb_offset = IE_SCB_OFF;
374 		host2ie(sc, &iscp, IE_ISCP_ADDR, sizeof(iscp) );
375 	}
376 
377 	/* Initialise the control block */
378 	iezero ( sc, IE_IBASE + IE_SCB_OFF, sizeof(struct ie_sys_ctl_block) );
379 	ieattn(sc);
380 
381 	/* Wait for not busy */
382 	setpage ( sc, IE_ISCP_ADDR );
383 	for ( i=10000; --i>=0; ) {
384 		if ( !ReadShort( sc->sc_ram + IE_COFF2POFF(IE_ISCP_ADDR) +
385 		    ( xoffsetof(struct ie_int_sys_conf_ptr, ie_busy)) ) )
386 			break;
387 		delay (10);
388 	}
389 
390 	/* If the busy didn't go low, the i82586 is broken or too slow */
391         if ( i<=0 ) {
392 		printf ( ": ether1 chipset didn't respond\n" );
393 		sc->sc_flags |= IE_BROKEN;
394 		return;
395 	}
396 
397 	/* Ensure that the podule sends interrupts */
398         for ( i=1000; --i>=0 ; ) {
399 		if ( ReadByte(sc->sc_rom + 0) & PODULE_IRQ_PENDING )
400 			break;
401 		delay (10);
402 	}
403 
404 	/* If we didn't see the interrupt then the IRQ line is broken */
405 	if ( i<=0 ) {
406 		printf ( ": interrupt from chipset didn't reach host\n" );
407 		sc->sc_flags |= IE_BROKEN;
408 		return;
409 	}
410 
411 	/* Ack our little test operation */
412 	ie_ack(sc,IE_ST_WHENCE);
413         ie_cli (sc);
414 
415 	/* Get second part of idrom */
416 	for ( i=16; i<32; i++ )
417 		idrom[i] = ReadByte ( sc->sc_rom + (i<<2) );
418 
419 	/* This checksum always fails.  For some reason the first 16 */
420 	/* bytes are duplicated in the second 16 bytes, the checksum */
421 	/* should be at location 28 it is clearly not		     */
422 
423 	/* It is possible that this ether1 card is buggered	     */
424 
425 #ifndef IGNORE_ETHER1_IDROM_CHECKSUM
426 	if ( crc32(idrom,28) != *(u_long *)(idrom+28) )
427 	{
428 	    printf ( "ie: ether1 idrom failed checksum %08x!=%08x\n",
429 					crc32(idrom,28), *(u_long *)(idrom+28));
430             for ( i=0; i<32; i+=8 ) {
431 	        printf ( "IDROM: %02x %02x %02x %02x %02x %02x %02x %02x\n",
432 		    idrom[0+i], idrom[1+i], idrom[2+i], idrom[3+i],
433 		    idrom[4+i], idrom[5+i], idrom[6+i], idrom[7+i] );
434 	    }
435 	    printf ( "ie: I'll ignore this fact for now!\n" );
436 	}
437 #endif
438 
439 	/* Get our ethernet address.  Do explicit copy */
440 	for ( i=0; i<ETHER_ADDR_LEN; i++ )
441 	    hwaddr[i] = idrom[9+i];
442 
443 	/* Fill in my application form to attach to the inet system */
444 
445 	memcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
446 	ifp->if_softc = sc;
447 	ifp->if_start = iestart;
448 	ifp->if_ioctl = ieioctl;
449 	ifp->if_watchdog = iewatchdog;
450 	ifp->if_flags = IFF_BROADCAST;
451 
452 	/* Signed, dated then sent */
453         if_attach (ifp);
454 	if_deferred_start_init(ifp, NULL);
455 	ether_ifattach(ifp, hwaddr);
456 
457 	/* "Hmm," said nuts, "what if the attach fails" */
458 
459 	/* Write some pretty things on the announcement line */
460 	printf ( ": %s using %dk card ram",
461 	    ether_sprintf(hwaddr),
462 	    ((NRXBUF*IE_RXBUF_SIZE)+(NTXBUF*IE_TXBUF_SIZE))/1024 );
463 
464 	sc->sc_ih.ih_func = ieintr;
465 	sc->sc_ih.ih_arg = sc;
466 	sc->sc_ih.ih_level = IPL_NET;
467 	sc->sc_ih.ih_name = "net: ie";
468 	sc->sc_ih.ih_maskaddr = sc->sc_podule->irq_addr;
469 	sc->sc_ih.ih_maskbits = sc->sc_podule->irq_mask;
470 
471 	if (irq_claim(sc->sc_podule->interrupt, &sc->sc_ih)) {
472 		sc->sc_irqmode = 0;
473 		printf(" POLLED");
474 		panic("%s: Cannot install IRQ handler", device_xname(sc->sc_dev));
475 	} else {
476 		sc->sc_irqmode = 1;
477 		printf(" IRQ");
478 	}
479 
480 	printf("\n");
481 }
482 
483 
484 /*
485  * Oh no!! Where's my shorts!!! I'm sure I put them on this morning
486  */
487 
488 void
PWriteShorts(char * src,char * dest,int cnt)489 PWriteShorts(char *src, char *dest, int cnt)
490 {
491 	for (cnt /= 2; --cnt >= 0; ) {
492 		PWriteShort(dest, *(u_short *)src);
493 		src+=2;
494 		dest+=4;
495 	}
496 }
497 
498 void
ReadShorts(char * src,char * dest,int cnt)499 ReadShorts(char *src, char *dest, int cnt)
500 {
501 	for (cnt /= 2; --cnt >= 0; ) {
502 		*(u_short *)dest = ReadShort(src);
503 		src+=4;
504 		dest+=2;
505 	}
506 }
507 
508 /*
509  * A bcopy or memcpy to adapter ram.  It handles the page register for you
510  * so you dont have to worry about the ram windowing
511  */
512 
513 static void
host2ie(struct ie_softc * sc,void * src,u_long dest,int size)514 host2ie(struct ie_softc *sc, void *src, u_long dest, int size)
515 {
516 	int cnt;
517 	char *sptr = src;
518 
519 #ifdef DIAGNOSTIC
520 	if (size & 1)
521 		panic("host2ie");
522 #endif
523 
524 	while (size > 0) {
525 		cnt = IE_PAGESIZE - dest % IE_PAGESIZE;
526 		if (cnt > size)
527 			cnt = size;
528 		setpage(sc, dest);
529 		PWriteShorts(sptr, (char *)sc->sc_ram + IE_COFF2POFF(dest), cnt);
530 		sptr+=cnt;
531 		dest+=cnt;
532 		size-=cnt;
533 	}
534 }
535 
536 static void
ie2host(struct ie_softc * sc,u_long src,void * dest,int size)537 ie2host(struct ie_softc *sc, u_long src, void *dest, int size)
538 {
539 	int cnt;
540 	char *dptr = dest;
541 
542 #ifdef DIAGNOSTIC
543 	if (size & 1)
544 		panic ( "ie2host" );
545 #endif
546 
547 	while (size > 0) {
548 		cnt = IE_PAGESIZE - src % IE_PAGESIZE;
549 		if (cnt > size)
550 			cnt = size;
551 		setpage(sc, src);
552 		ReadShorts((char *)sc->sc_ram + IE_COFF2POFF(src), dptr, cnt);
553 		src+=cnt;
554 		dptr+=cnt;
555 		size-=cnt;
556 	}
557 }
558 
559 /*
560  * Like a bzero or memset 0 for adapter memory.  It handles the page
561  * register so you dont have to worry about it
562  */
563 
564 static void
iezero(struct ie_softc * sc,u_long p,int size)565 iezero(struct ie_softc *sc, u_long p, int size)
566 {
567 	int cnt;
568 
569 	while (size > 0) {
570 		cnt = IE_PAGESIZE - p % IE_PAGESIZE;
571 		if (cnt > size)
572 			cnt=size;
573 		setpage(sc, p);
574 		memset((char *)sc->sc_ram + IE_COFF2POFF(p), 0, 2*cnt);
575 		p += cnt;
576 		size -= cnt;
577 	}
578 }
579 
580 /*
581  * I/O Control interface to the kernel, entry point here
582  */
583 
584 int
ieioctl(struct ifnet * ifp,unsigned long cmd,void * data)585 ieioctl(struct ifnet *ifp, unsigned long cmd, void *data)
586 {
587     struct ie_softc *sc = ifp->if_softc;
588     struct ifaddr *ifa = (struct ifaddr *)data;
589     int s;
590     int error=0;
591 
592     s=splnet();
593 
594     switch ( cmd )
595     {
596 	case SIOCINITIFADDR:
597 	    ifp->if_flags |= IFF_UP;
598 	    switch (ifa->ifa_addr->sa_family ) {
599 #ifdef INET
600 		case AF_INET:
601 		    ieinit(sc);
602 		    arp_ifinit(ifp, ifa );
603 		    break;
604 #endif
605 		default:
606 		    ieinit(sc);
607 		    break;
608 	    }
609 	    break;
610 
611 #define IZSET(a,b) ((a->if_flags&b)!=0)
612 #define IZCLR(a,b) ((a->if_flags&b)==0)
613 #define DOSET(a,b) (a->if_flags|=b)
614 #define DOCLR(a,b) (a->if_flags&=~b)
615 
616 	case SIOCSIFFLAGS:
617 	    if ((error = ifioctl_common(ifp, cmd, data)) != 0)
618 		break;
619 	    sc->promisc = ifp->if_flags & ( IFF_PROMISC | IFF_ALLMULTI );
620 
621 	    if ( IZCLR(ifp,IFF_UP) && IZSET(ifp,IFF_RUNNING) )
622 	    {
623 		/* Interface was marked down and its running so stop it */
624 		iestop(sc);
625 		DOCLR(ifp,IFF_RUNNING);
626 	    }
627 	    else if ( IZSET(ifp,IFF_UP) && IZCLR(ifp,IFF_RUNNING) )
628 	    {
629 		/* Just marked up and we're not running so start it */
630 		ieinit(sc);
631 	    }
632 	    else
633 	    {
634 		/* else reset to invoke changes in other registers */
635 		iestop(sc);
636 		ieinit(sc);
637             }
638 
639 	default:
640 	    error = ether_ioctl(ifp, cmd, data);
641 	    break;
642     }
643     (void)splx(s);
644     return error;
645 }
646 
647 /*
648  * Reset the card.  Completely.
649  */
650 
651 void
iereset(struct ie_softc * sc)652 iereset(struct ie_softc *sc)
653 {
654 	struct ie_sys_ctl_block scb;
655 	int s = splnet();
656 
657 	iestop(sc);
658 
659 	ie2host(sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb);
660 
661 	if (command_and_wait(sc, IE_RU_ABORT|IE_CU_ABORT, 0, 0, 0, 0, 0))
662 	        printf("ie0: abort commands timed out\n");
663 
664 	if (command_and_wait(sc, IE_RU_DISABLE|IE_CU_STOP, 0, 0, 0, 0, 0))
665 	        printf("ie0: abort commands timed out\n");
666 
667 	ieinit(sc);
668 
669 	(void)splx(s);
670 }
671 
672 /*
673  * Watchdog entry point.  This is the entry for the kernel to call us
674  */
675 
676 void
iewatchdog(struct ifnet * ifp)677 iewatchdog(struct ifnet *ifp)
678 {
679 	struct ie_softc *sc = ifp->if_softc;
680 
681 	log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev));
682 	if_statinc(ifp, if_oerrors);
683 	iereset(sc);
684 }
685 
686 /*
687  * Start the time-domain-refloctometer running
688  */
689 
690 static void
run_tdr(struct ie_softc * sc)691 run_tdr(struct ie_softc *sc)
692 {
693     struct ie_sys_ctl_block scb;
694     u_long ptr = IE_IBASE + IE_SCB_OFF + sizeof scb;
695     struct ie_tdr_cmd cmd;
696     int result;
697 
698     bzero ( &scb, sizeof(scb) );
699     bzero ( &cmd, sizeof(cmd) );
700 
701     cmd.com.ie_cmd_status = 0;
702     cmd.com.ie_cmd_cmd = IE_CMD_TDR | IE_CMD_LAST;
703     cmd.com.ie_cmd_link = 0xffff;
704     cmd.ie_tdr_time = 0;
705 
706     scb.ie_command_list = (u_short)ptr;
707 
708     result=0;
709     if ( command_and_wait(sc, IE_CU_START, &scb, &cmd, ptr, sizeof cmd,
710 	IE_STAT_COMPL) )
711     {
712 	    result = 0x10000;
713     }
714     else if ( !(cmd.com.ie_cmd_status & IE_STAT_OK) )
715     {
716 	result = 0x10000;
717     }
718 
719     if ( result==0 )
720 	result = cmd.ie_tdr_time;
721 
722     ie_ack ( sc, IE_ST_WHENCE );
723 
724     if (result & IE_TDR_SUCCESS )
725 	return;
726 
727     /* Very messy.  I'll tidy it later */
728 
729     if ( result & 0x10000 )
730     {
731 	printf ( "ie: TDR command failed\n" );
732     }
733     else if ( result & IE_TDR_XCVR )
734     {
735 	printf ( "ie: tranceiver problem. Is it plugged in?\n" );
736     }
737     else if ( result & IE_TDR_OPEN )
738     {
739 	if ((result & IE_TDR_TIME)>0)
740 	    printf ( "ie: TDR detected an open %d clocks away.\n",
741 			result & IE_TDR_TIME );
742     }
743     else if ( result & IE_TDR_SHORT )
744     {
745 	if ((result & IE_TDR_TIME)>0)
746 	    printf ( "ie: TDR detected a short %d clock away.\n",
747 			result & IE_TDR_TIME );
748     }
749     else
750     {
751 	printf ( "ie: TDR returned unknown status %x\n", result );
752     }
753 }
754 
755 u_long
setup_rfa(struct ie_softc * sc,u_long ptr)756 setup_rfa(struct ie_softc *sc, u_long ptr)
757 {
758     int i;
759     {
760 	/* Receive frame descriptors */
761         struct ie_recv_frame_desc rfd;
762 	memset( &rfd, 0, sizeof rfd );
763 	for ( i=0; i<NFRAMES; i++ )
764 	{
765 	    sc->rframes[i] = ptr;
766 	    rfd.ie_fd_next = ptr + sizeof rfd;
767 	    host2ie(sc, (char *)&rfd, ptr, sizeof rfd);
768 	    ptr += sizeof rfd;
769 	}
770 	rfd.ie_fd_next = sc->rframes[0];
771 	rfd.ie_fd_last |= IE_FD_LAST;
772 	host2ie(sc, (char *)&rfd, sc->rframes[NFRAMES-1], sizeof rfd );
773 
774 	ie2host(sc, sc->rframes[0], (char *)&rfd, sizeof rfd );
775 	rfd.ie_fd_buf_desc = (u_short) ptr;
776 	host2ie(sc, (char *)&rfd, sc->rframes[0], sizeof rfd );
777     }
778 
779     {
780 	/* Receive frame descriptors */
781 	struct ie_recv_buf_desc rbd;
782 	memset(&rbd, 0, sizeof rbd);
783 	for ( i=0; i<NRXBUF; i++ )
784 	{
785 	    sc->rbuffs[i] = ptr;
786 	    rbd.ie_rbd_length = IE_RXBUF_SIZE;
787 	    rbd.ie_rbd_buffer = (void *)(ptr + sizeof rbd);
788 	    rbd.ie_rbd_next = (u_short)(ptr + sizeof rbd + IE_RXBUF_SIZE);
789 	    host2ie(sc, &rbd, ptr, sizeof rbd);
790 	    ptr+=sizeof rbd;
791 
792 	    sc->cbuffs[i] = ptr;
793 	    ptr+=IE_RXBUF_SIZE;
794 	}
795 	rbd.ie_rbd_next = sc->rbuffs[0];
796 	rbd.ie_rbd_length |= IE_RBD_LAST;
797 	host2ie(sc, &rbd, sc->rbuffs[NRXBUF-1], sizeof rbd);
798     }
799 
800     sc->rfhead = 0;
801     sc->rftail = NFRAMES-1;
802     sc->rbhead = 0;
803     sc->rbtail = NRXBUF-1;
804 
805     {
806 	struct ie_sys_ctl_block scb;
807 	bzero ( &scb, sizeof scb );
808 	scb.ie_recv_list = (u_short)sc->rframes[0];
809 	host2ie(sc, (char *)&scb, (IE_IBASE + IE_SCB_OFF), sizeof scb );
810     }
811     return ptr;
812 }
813 
814 static void
start_receiver(struct ie_softc * sc)815 start_receiver(struct ie_softc *sc)
816 {
817     struct ie_sys_ctl_block scb;
818     ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb );
819     scb.ie_recv_list = (u_short)sc->rframes[0];
820     command_and_wait(sc, IE_RU_START, &scb, 0, 0, 0, 0);
821     ie_ack(sc, IE_ST_WHENCE );
822 }
823 
824 /*
825  * Take our configuration and update all the other data structures that
826  * require information from the driver.
827  *
828  * CALL AT SPLIMP OR HIGHER
829  */
830 
831 int
ieinit(struct ie_softc * sc)832 ieinit(struct ie_softc *sc)
833 {
834     struct ifnet *ifp;
835     struct ie_sys_ctl_block scb;
836     struct ie_config_cmd cmd;
837     struct ie_iasetup_cmd iasetup_cmd;
838     u_long ptr = IE_IBASE + IE_SCB_OFF + sizeof scb;
839     int n;
840 
841     ifp = &sc->sc_ethercom.ec_if;
842 
843     bzero ( &scb, sizeof(scb) );
844 
845     /* Send the configure command */
846 
847     cmd.com.ie_cmd_status = 0;
848     cmd.com.ie_cmd_cmd = IE_CMD_CONFIG | IE_CMD_LAST;
849     cmd.com.ie_cmd_link = 0xffff;
850 
851     cmd.ie_config_count = 0x0c;
852     cmd.ie_fifo = 8;
853     cmd.ie_save_bad = 0x40;
854     cmd.ie_addr_len = 0x2e;
855     cmd.ie_priority = 0;
856     cmd.ie_ifs = 0x60;
857     cmd.ie_slot_low = 0;
858     cmd.ie_slot_high = 0xf2;
859     cmd.ie_promisc = 0;		/* Hey nuts, look at this! */
860     cmd.ie_crs_cdt = 0;
861     cmd.ie_min_len = 64;
862     cmd.ie_junk = 0xff;
863 
864     scb.ie_command_list = (u_short)ptr;
865 
866     if ( command_and_wait(sc, IE_CU_START, &scb, &cmd, ptr, sizeof cmd,
867 	IE_STAT_COMPL) )
868     {
869 	printf ( "%s: command failed: timeout\n", device_xname(sc->sc_dev));
870 	return 0;
871     }
872 
873     if ( !(cmd.com.ie_cmd_status & IE_STAT_OK) )
874     {
875 	printf ( "%s: command failed: !IE_STAT_OK\n", device_xname(sc->sc_dev));
876 	return 0;
877     }
878 
879     /* Individual address setup command */
880 
881     iasetup_cmd.com.ie_cmd_status = 0;
882     iasetup_cmd.com.ie_cmd_cmd = IE_CMD_IASETUP | IE_CMD_LAST;
883     iasetup_cmd.com.ie_cmd_link = 0xffff;
884 
885     bcopy ( CLLADDR(ifp->if_sadl), (void *) &iasetup_cmd.ie_address,
886 	 	sizeof (iasetup_cmd.ie_address) );
887 
888     if ( command_and_wait(sc, IE_CU_START, &scb, &iasetup_cmd, ptr, sizeof cmd,
889 	IE_STAT_COMPL) )
890     {
891 	printf ( "%s: iasetup failed : timeout\n", device_xname(sc->sc_dev));
892 	return 0;
893     }
894 
895     if ( !(cmd.com.ie_cmd_status & IE_STAT_OK) )
896     {
897 	printf ( "%s: iasetup failed : !IE_STAT_OK\n", device_xname(sc->sc_dev));
898 	return 0;
899     }
900 
901     ie_ack ( sc, IE_ST_WHENCE );
902 
903     /* Run the time-domain refloctometer */
904     run_tdr ( sc );
905 
906     ie_ack ( sc, IE_ST_WHENCE );
907 
908     /* meminit */
909     ptr = setup_rfa(sc, ptr);
910 
911     ifp->if_flags |= IFF_RUNNING;
912 
913     /* Setup transmit buffers */
914 
915     for ( n=0; n<NTXBUF; n++ ) {
916 	sc->xmit_cmds[n] = ptr;
917 	iezero(sc, ptr, sizeof(struct ie_xmit_cmd) );
918 	ptr += sizeof(struct ie_xmit_cmd);
919 
920 	sc->xmit_buffs[n] = ptr;
921 	iezero(sc, ptr, sizeof(struct ie_xmit_buf));
922 	ptr += sizeof(struct ie_xmit_buf);
923     }
924 
925     for ( n=0; n<NTXBUF; n++ ) {
926 	sc->xmit_cbuffs[n] = ptr;
927 	ptr += IE_TXBUF_SIZE;
928     }
929 
930     sc->xmit_free = NTXBUF;
931     sc->xchead = sc->xctail = 0;
932 
933     {
934 	struct ie_xmit_cmd xmcmd;
935 	bzero ( &xmcmd, sizeof xmcmd );
936 	xmcmd.ie_xmit_status = IE_STAT_COMPL;
937 	host2ie(sc, &xmcmd, sc->xmit_cmds[0], sizeof xmcmd);
938     }
939 
940     start_receiver (sc);
941 
942     return 0;
943 }
944 
945 int
iestop(struct ie_softc * sc)946 iestop(struct ie_softc *sc)
947 {
948     struct ie_sys_ctl_block scb;
949     int s = splnet();
950 
951     ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb );
952 
953     if ( command_and_wait(sc, IE_RU_DISABLE, &scb, 0, 0, 0, 0) )
954         printf ( "ie0: abort commands timed out\n" );
955 
956     (void)splx(s);
957     return(0);
958 }
959 
960 /*
961  * Send a command to the card and await its completion.
962  * Timeout if it's taking too long
963  */
964 
965 /*CAW*/
966 
967 static int
command_and_wait(struct ie_softc * sc,u_short cmd,struct ie_sys_ctl_block * pscb,void * pcmd,int ocmd,int scmd,int mask)968 command_and_wait(struct ie_softc *sc, u_short cmd, struct ie_sys_ctl_block *pscb, void *pcmd, int ocmd, int scmd, int mask)
969 {
970     int i=0;
971 
972     /* Copy the command to the card */
973 
974     if ( pcmd )
975 	host2ie(sc, pcmd, ocmd, scmd); /* transfer the command to the card */
976 
977     /* Copy the scb to the card */
978 
979     if ( pscb ) {
980 	pscb->ie_command = cmd;
981 	host2ie(sc, pscb, IE_IBASE + IE_SCB_OFF, sizeof *pscb);
982     }
983     else
984     {
985 	setpage ( sc, IE_IBASE + IE_SCB_OFF );
986 	PWriteShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
987 		(xoffsetof(struct ie_sys_ctl_block, ie_command)), cmd );
988     }
989 
990     /* Prod the card to act on the newly loaded command */
991     ieattn(sc);
992 
993     /* Wait for the command to complete */
994     if ( IE_ACTION_COMMAND(cmd) && pcmd )
995     {
996 	setpage(sc,ocmd);
997 	for ( i=4000; --i>=0; ) {
998 	    if ( ReadShort(sc->sc_ram + IE_COFF2POFF(ocmd) +
999 		(xoffsetof(struct ie_config_cmd, ie_config_status))) & mask)
1000 		break;
1001 	    delay(100);
1002 	}
1003     }
1004     else
1005     {
1006 	for ( i=4000; --i>=0; ) {
1007 	    if ( !ReadShort(sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
1008 		(xoffsetof(struct ie_sys_ctl_block, ie_command))) )
1009 		break;
1010 	    delay(100);
1011 	}
1012     }
1013 
1014     /* Update the host structures to reflect the state on the card */
1015     if ( pscb )
1016 	ie2host(sc, IE_IBASE + IE_SCB_OFF, pscb, sizeof *pscb );
1017     if ( pcmd )
1018 	ie2host(sc, ocmd, pcmd, scmd);
1019 
1020     return i < 0;
1021 }
1022 
1023 #define READ_MEMBER(sc,type,member,ptr,dest)			\
1024 	setpage(sc, ptr);					\
1025 	dest = ReadShort(sc->sc_ram + IE_COFF2POFF(ptr) +	\
1026 	       (xoffsetof(type, member)) );
1027 
1028 #define WRITE_MEMBER(sc,type,member,ptr,dest)			\
1029 	setpage(sc, ptr);					\
1030 	PWriteShort(sc->sc_ram + IE_COFF2POFF(ptr) +	\
1031 	       (xoffsetof(type, member)), dest );
1032 
1033 static inline int
ie_buflen(struct ie_softc * sc,int head)1034 ie_buflen(struct ie_softc *sc, int head)
1035 {
1036 	int actual;
1037 
1038 	READ_MEMBER(sc,struct ie_recv_buf_desc, ie_rbd_actual,
1039 	    sc->rbuffs[head], actual );
1040 
1041 	return(actual & (IE_RXBUF_SIZE | (IE_RXBUF_SIZE-1))) ;
1042 }
1043 
1044 static inline int
ie_packet_len(struct ie_softc * sc)1045 ie_packet_len(struct ie_softc *sc)
1046 {
1047     int i;
1048     int actual;
1049     int head = sc->rbhead;
1050     int acc=0;
1051 
1052     do {
1053 	READ_MEMBER(sc,struct ie_recv_buf_desc, ie_rbd_actual,
1054 			sc->rbuffs[sc->rbhead], actual );
1055 	if (!(actual&IE_RBD_USED))
1056 	{
1057 	    return (-1);
1058 	}
1059 
1060 	READ_MEMBER(sc,struct ie_recv_buf_desc, ie_rbd_actual,
1061 			sc->rbuffs[head], i );
1062         i = i & IE_RBD_LAST;
1063 
1064 	acc += ie_buflen(sc, head);
1065 	head = (head+1) % NRXBUF;
1066     } while (!i);
1067 
1068     return acc;
1069 }
1070 
1071 struct mbuf *
ieget(struct ie_softc * sc,int * to_bpf)1072 ieget(struct ie_softc *sc, int *to_bpf )
1073 {
1074     struct mbuf *top, **mp, *m;
1075     int head;
1076     int resid, totlen, thisrboff, thismboff;
1077     int len;
1078     struct ether_header eh;
1079 
1080     totlen = ie_packet_len(sc);
1081 
1082     if ( totlen > ETHER_MAX_LEN )
1083     {
1084 	printf ( "ie: Gosh that packet was s-o-o-o big.\n" );
1085 	return 0;
1086     }
1087 
1088     if ( totlen<=0 )
1089 	return 0;
1090 
1091     head = sc->rbhead;
1092 
1093     /* Read the ethernet header */
1094     ie2host ( sc, sc->cbuffs[head], (void *)&eh, sizeof eh );
1095 
1096     /* Check if the packet is for us */
1097 
1098     resid = totlen;
1099 
1100     MGETHDR ( m, M_DONTWAIT, MT_DATA );
1101     if ( m==0 )
1102 	return 0;
1103 
1104     m_set_rcvif(m, &sc->sc_ethercom.ec_if);
1105     m->m_pkthdr.len = totlen;
1106     len = MHLEN;
1107     top = 0;
1108     mp = &top;
1109 
1110     /*
1111      * This loop goes through and allocates mbufs for all the data we will
1112      * be copying in.  It does not actually do the copying yet.
1113      */
1114     while (totlen > 0) {
1115 	if (top) {
1116 	    MGET(m, M_DONTWAIT, MT_DATA);
1117 	    if (m == 0) {
1118 		m_freem(top);
1119 		return 0;
1120 	    }
1121 	    len = MLEN;
1122 	}
1123 	if (totlen >= MINCLSIZE) {
1124 	    MCLGET(m, M_DONTWAIT);
1125 	    if (m->m_flags & M_EXT)
1126 		len = MCLBYTES;
1127 	}
1128 
1129 	if (mp == &top) {
1130 		void *newdata = (void *)
1131 		    ALIGN(m->m_data + sizeof(struct ether_header)) -
1132 		    sizeof(struct ether_header);
1133 		len -= newdata - m->m_data;
1134 		m->m_data = newdata;
1135 	}
1136 
1137         m->m_len = len = min(totlen, len);
1138 
1139         totlen -= len;
1140         *mp = m;
1141         mp = &m->m_next;
1142     }
1143 
1144     m = top;
1145     thismboff = 0;
1146 
1147     /*
1148      * Copy the Ethernet header into the mbuf chain.
1149      */
1150     memcpy(mtod(m, void *), &eh, sizeof(struct ether_header));
1151     thismboff = sizeof(struct ether_header);
1152     thisrboff = sizeof(struct ether_header);
1153     resid -= sizeof(struct ether_header);
1154 
1155     /*
1156      * Now we take the mbuf chain (hopefully only one mbuf most of the
1157      * time) and stuff the data into it.  There are no possible failures at
1158      * or after this point.
1159      */
1160     while (resid > 0) {
1161 	int thisrblen = ie_buflen(sc, head) - thisrboff,
1162 	    thismblen = m->m_len - thismboff;
1163 	len = min(thisrblen, thismblen);
1164 
1165 /*      bcopy((void *)(sc->cbuffs[head] + thisrboff),
1166 	    mtod(m, void *) + thismboff, (u_int)len);	 */
1167 
1168 
1169 	if ( len&1 )
1170 	{
1171  	    ie2host(sc, sc->cbuffs[head]+thisrboff,
1172 		mtod(m, void *) + thismboff, (u_int)len+1);
1173   	}
1174 	else
1175 	{
1176  	    ie2host(sc, sc->cbuffs[head]+thisrboff,
1177 		mtod(m, void *) + thismboff, (u_int)len);
1178 	}
1179 
1180 	resid -= len;
1181 
1182 	if (len == thismblen) {
1183 		m = m->m_next;
1184 		thismboff = 0;
1185 	} else
1186 		thismboff += len;
1187 
1188 	if (len == thisrblen) {
1189 		head = (head + 1) % NRXBUF;
1190 		thisrboff = 0;
1191 	} else
1192 		thisrboff += len;
1193     }
1194 
1195 
1196     return top;
1197 }
1198 
1199 void
ie_drop_packet_buffer(struct ie_softc * sc)1200 ie_drop_packet_buffer(struct ie_softc *sc)
1201 {
1202     int i, actual, last;
1203 
1204     do {
1205 	READ_MEMBER(sc,struct ie_recv_buf_desc, ie_rbd_actual,
1206 			sc->rbuffs[sc->rbhead], actual );
1207 	if (!(actual&IE_RBD_USED))
1208 	{
1209 	    iereset(sc);
1210 	    return;
1211 	}
1212 
1213 	i = actual & IE_RBD_LAST;
1214 
1215         READ_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_length,
1216 			sc->rbuffs[sc->rbhead], last );
1217         last |= IE_RBD_LAST;
1218         WRITE_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_length,
1219 			sc->rbuffs[sc->rbhead], last );
1220 
1221         WRITE_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_actual,
1222 			sc->rbuffs[sc->rbhead], 0 );
1223 
1224 	sc->rbhead = ( sc->rbhead + 1 ) % NRXBUF;
1225 
1226         READ_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_length,
1227 			sc->rbuffs[sc->rbtail], last );
1228         last &= ~IE_RBD_LAST;
1229         WRITE_MEMBER(sc,struct ie_recv_buf_desc,ie_rbd_length,
1230 			sc->rbuffs[sc->rbtail], last );
1231 
1232 	sc->rbtail = ( sc->rbtail + 1 ) % NRXBUF;
1233     } while (!i);
1234 }
1235 
1236 void
ie_read_frame(struct ie_softc * sc,int num)1237 ie_read_frame(struct ie_softc *sc, int num)
1238 {
1239     int status;
1240     struct ie_recv_frame_desc rfd;
1241     struct mbuf *m=0;
1242     struct ifnet *ifp;
1243     int last;
1244 
1245     ifp = &sc->sc_ethercom.ec_if;
1246 
1247     ie2host(sc, sc->rframes[num], &rfd, sizeof rfd );
1248     status = rfd.ie_fd_status;
1249 
1250     /* Advance the RFD list, since we're done with this descriptor */
1251 
1252     WRITE_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_status,
1253 			sc->rframes[num], 0 );
1254 
1255     READ_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_last,
1256 			sc->rframes[num], last );
1257     last |= IE_FD_LAST;
1258     WRITE_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_last,
1259 			sc->rframes[num], last );
1260 
1261     READ_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_last,
1262 			sc->rframes[sc->rftail], last );
1263     last &= ~IE_FD_LAST;
1264     WRITE_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_last,
1265 			sc->rframes[sc->rftail], last );
1266 
1267     sc->rftail = ( sc->rftail + 1 ) % NFRAMES;
1268     sc->rfhead = ( sc->rfhead + 1 ) % NFRAMES;
1269 
1270     if ( status & IE_FD_OK ) {
1271 	m = ieget(sc, 0);
1272 	ie_drop_packet_buffer(sc);
1273     }
1274 
1275     if ( m==0 ) {
1276 	if_statinc(ifp, if_ierrors);
1277 	return;
1278     }
1279 
1280     if_percpuq_enqueue(ifp->if_percpuq, m);
1281 }
1282 
1283 void
ierint(struct ie_softc * sc)1284 ierint(struct ie_softc *sc)
1285 {
1286     int i;
1287     int times_thru = 1024;
1288     struct ie_sys_ctl_block scb;
1289     int status;
1290     int safety_catch = 0;
1291 
1292     i = sc->rfhead;
1293     for (;;) {
1294 
1295 	if ( (safety_catch++)>100 )
1296 	{
1297 	    printf ( "ie: ierint safety catch tripped\n" );
1298 	    iereset(sc);
1299 	    return;
1300 	}
1301 
1302 	READ_MEMBER(sc,struct ie_recv_frame_desc,ie_fd_status,
1303 				sc->rframes[i],status);
1304 
1305 	if ((status&IE_FD_COMPLETE)&&(status&IE_FD_OK)) {
1306 	    if ( !--times_thru ) {
1307 		printf ( "IERINT: Uh oh. Nuts, look at this bit!!!\n" );
1308     		ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb );
1309 		sc->sc_ethercom.ec_if.if_ierrors += scb.ie_err_crc +
1310 						  scb.ie_err_align +
1311 						  scb.ie_err_resource +
1312 						  scb.ie_err_overrun;
1313 		scb.ie_err_crc      = scb.ie_err_align   = 0;
1314 		scb.ie_err_resource = scb.ie_err_overrun = 0;
1315 	        host2ie(sc, &scb, IE_SCP_ADDR, sizeof (scb) );
1316 	    }
1317 	    ie_read_frame(sc, i);
1318 	} else {
1319     	    ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb );
1320 
1321 	    if ( ((status&IE_FD_RNR)!=0) && ((scb.ie_status&IE_RU_READY)==0) )
1322 	    {
1323 		WRITE_MEMBER(sc,struct ie_recv_frame_desc, ie_fd_buf_desc,
1324 				sc->rframes[0], sc->rbuffs[0] );
1325 
1326 		scb.ie_recv_list = sc->rframes[0];
1327 	        host2ie(sc, (char *)&scb, IE_IBASE + IE_SCB_OFF, sizeof (scb) );
1328     		command_and_wait(sc, IE_RU_START, &scb, 0, 0, 0, 0);
1329 	    }
1330 	    break;
1331 	}
1332 	i = (i + 1) % NFRAMES;
1333     }
1334 }
1335 
1336 static int in_intr = 0;
1337 
1338 int
ieintr(void * arg)1339 ieintr(void *arg)
1340 {
1341     struct ie_softc *sc = arg;
1342     u_short status;
1343     int safety_catch = 0;
1344     static int safety_net = 0;
1345 
1346     if (in_intr == 1)
1347 	panic ( "ie: INTERRUPT REENTERED\n" );
1348 
1349     /* Clear the interrrupt */
1350     ie_cli (sc);
1351 
1352     setpage(sc, IE_IBASE + IE_SCB_OFF );
1353     status = ReadShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
1354 		(xoffsetof(struct ie_sys_ctl_block, ie_status)) );
1355 
1356     status = status & IE_ST_WHENCE;
1357 
1358     if (status == 0) {
1359 	in_intr = 0;
1360 	return(0);
1361     }
1362 
1363 loop:
1364 
1365     ie_ack(sc, status);
1366 
1367     if (status & (IE_ST_FR | IE_ST_RNR))
1368 	ierint(sc);
1369 
1370     if (status & IE_ST_CX)
1371 	ietint(sc);
1372 
1373     if (status & IE_ST_RNR) {
1374 	printf ( "ie: receiver not ready\n" );
1375 	sc->sc_ethercom.ec_if.if_ierrors++;
1376 	iereset(sc);
1377     }
1378 
1379     setpage(sc, IE_IBASE + IE_SCB_OFF );
1380     status = ReadShort ( sc->sc_ram + IE_COFF2POFF(IE_IBASE+IE_SCB_OFF) +
1381 		(xoffsetof(struct ie_sys_ctl_block, ie_status)) );
1382     status = status & IE_ST_WHENCE;
1383 
1384     ie_cli(sc);
1385 
1386     if (status == 0) {
1387 	in_intr = 0;
1388 	return(0);
1389     }
1390 
1391     /* This is prehaps a little over cautious */
1392     if ( safety_catch++ > 10 )
1393     {
1394 	printf ( "ie: Interrupt couldn't be cleared\n" );
1395 	delay ( 1000 );
1396 	ie_cli(sc);
1397 	if ( safety_net++ > 50 )
1398 	{
1399 /*	    printf ( "ie: safety net catches driver, shutting down\n" );
1400 	    disable_irq ( IRQ_PODULE );*/
1401 	}
1402 	in_intr = 0;
1403 	return(0);
1404     }
1405 
1406     goto loop;
1407 }
1408 
1409 void
iexmit(struct ie_softc * sc)1410 iexmit(struct ie_softc *sc)
1411 {
1412 /*    int actual;*/
1413     struct ie_sys_ctl_block scb;
1414 
1415     struct ie_xmit_cmd xc;
1416     struct ie_xmit_buf xb;
1417 
1418     ie2host(sc, sc->xmit_buffs[sc->xctail], (char *)&xb, sizeof xb );
1419     xb.ie_xmit_flags |= IE_XMIT_LAST;
1420     xb.ie_xmit_next = 0xffff;
1421     xb.ie_xmit_buf = (void *)sc->xmit_cbuffs[sc->xctail];
1422     host2ie(sc, &xb, sc->xmit_buffs[sc->xctail], sizeof xb );
1423 
1424     bzero ( &xc, sizeof xc );
1425     xc.com.ie_cmd_link = 0xffff;
1426     xc.com.ie_cmd_cmd = IE_CMD_XMIT | IE_CMD_INTR | IE_CMD_LAST;
1427     xc.ie_xmit_status = 0x0000;
1428     xc.ie_xmit_desc = sc->xmit_buffs[sc->xctail];
1429     host2ie(sc, (char *)&xc, sc->xmit_cmds[sc->xctail], sizeof xc );
1430 
1431     ie2host ( sc, IE_IBASE + IE_SCB_OFF, &scb, sizeof scb );
1432     scb.ie_command_list = sc->xmit_cmds[sc->xctail];
1433     host2ie(sc, (char *)&scb, (IE_IBASE + IE_SCB_OFF), sizeof scb );
1434 
1435     command_and_wait(sc, IE_CU_START, &scb, &xc, sc->xmit_cmds[sc->xctail]
1436 			, sizeof xc, IE_STAT_COMPL);
1437 
1438     sc->sc_ethercom.ec_if.if_timer = 5;
1439 }
1440 /*
1441  * Start sending all the queued buffers.
1442  */
1443 
1444 void
iestart(struct ifnet * ifp)1445 iestart(struct ifnet *ifp)
1446 {
1447 	struct ie_softc *sc = ifp->if_softc;
1448 	struct mbuf *m0, *m;
1449 	u_char *buffer;
1450 	u_short len;
1451 	char txbuf[IE_TXBUF_SIZE];
1452 	int safety_catch = 0;
1453 
1454 	while (sc->xmit_free != 0) {
1455 		if ( (safety_catch++)>100 )
1456 		{
1457 		    printf ( "ie: iestart safety catch tripped\n" );
1458 		    iereset(sc);
1459 		    return;
1460 		}
1461 
1462 		IF_DEQUEUE(&ifp->if_snd, m);
1463 		if (!m)
1464 			break;
1465 
1466 		/* TODO: Write directly to the card */
1467 		len = 0;
1468 		/* buffer = sc->xmit_cbuffs[sc->xchead]; */
1469 		buffer = txbuf;
1470 
1471 		for (m0 = m; m && (len + m->m_len) < IE_TXBUF_SIZE;
1472 		     m = m->m_next) {
1473 			memcpy(buffer, mtod(m, void *), m->m_len);
1474 			buffer += m->m_len;
1475 			len += m->m_len;
1476 		}
1477 
1478 		bpf_mtap(ifp, m0, BPF_D_OUT);
1479 
1480 		m_freem(m0);
1481 		if (len < ETHER_MIN_LEN - ETHER_CRC_LEN) {
1482 			memset(buffer, 0, ETHER_MIN_LEN - ETHER_CRC_LEN - len);
1483 			len = ETHER_MIN_LEN - ETHER_CRC_LEN;
1484 			buffer += ETHER_MIN_LEN - ETHER_CRC_LEN;
1485 		}
1486 
1487 		/* When we write directly to the card we dont need this */
1488     		if (len&1)
1489    		    host2ie(sc, txbuf, sc->xmit_cbuffs[sc->xchead], len+1 );
1490 		else
1491    		    host2ie(sc, txbuf, sc->xmit_cbuffs[sc->xchead], len );
1492 
1493 		/* sc->xmit_buffs[sc->xchead]->ie_xmit_flags = len; */
1494 
1495 		WRITE_MEMBER(sc,struct ie_xmit_buf, ie_xmit_flags,
1496 				sc->xmit_buffs[sc->xchead], len)
1497 
1498 		/* Start the first packet transmitting. */
1499 		if (sc->xmit_free == NTXBUF)
1500 			iexmit(sc);
1501 
1502 		sc->xchead = (sc->xchead + 1) % NTXBUF;
1503 		sc->xmit_free--;
1504 	}
1505 }
1506 
1507 void
ietint(struct ie_softc * sc)1508 ietint(struct ie_softc *sc)
1509 {
1510     struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1511 
1512     int status;
1513 
1514     ifp->if_timer=0;
1515 
1516     READ_MEMBER(sc,struct ie_xmit_cmd, ie_xmit_status,
1517 	sc->xmit_cmds[sc->xctail], status );
1518 
1519     if (!(status&IE_STAT_COMPL) || (status & IE_STAT_BUSY) )
1520 	printf ( "ietint: command still busy!\n" );
1521 
1522     if ( status & IE_STAT_OK ) {
1523 	if_statinc(ifp, if_opackets);
1524 	if_statadd(ifp, if_collisions, status & IE_XS_MAXCOLL);
1525     } else {
1526 	if_statinc(ifp, if_oerrors);
1527 	if ( status & IE_STAT_ABORT )
1528 	    printf ( "ie: send aborted\n" );
1529 	if ( status & IE_XS_LATECOLL )
1530 	    printf ( "ie: late collision\n" );
1531 	if ( status & IE_XS_NOCARRIER )
1532 	    printf ( "ie: no carrier\n" );
1533 	if ( status & IE_XS_LOSTCTS )
1534 	    printf ( "ie: lost CTS\n" );
1535 	if ( status & IE_XS_UNDERRUN )
1536 	    printf ( "ie: DMA underrun\n" );
1537 	if ( status & IE_XS_EXCMAX )
1538 	    printf ( "ie: too many collisions\n" );
1539 	if_statadd(ifp, if_collisions, 16);
1540     }
1541     /* Done with the buffer */
1542     sc->xmit_free++;
1543     sc->xctail = (sc->xctail + 1 ) % NTXBUF;
1544 
1545     /* Start the next packet transmitting, if any */
1546     if ( sc->xmit_free<NTXBUF )
1547 	iexmit(sc);
1548 
1549     if_schedule_deferred_start(ifp);
1550 }
1551 
1552 /* End of if_ie.c */
1553