xref: /netbsd/sys/arch/hp300/stand/common/if_le.c (revision bf9ec67e)
1 /*	$NetBSD: if_le.c,v 1.4 1999/04/09 09:34:13 drochner Exp $	*/
2 
3 /*
4  * Copyright (c) 1993 Adam Glass
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  * 3. All advertising materials mentioning features or use of this software
16  *    must display the following acknowledgement:
17  *	This product includes software developed by Adam Glass.
18  * 4. The name of the Author may not be used to endorse or promote products
19  *    derived from this software without specific prior written permission.
20  *
21  * THIS SOFTWARE IS PROVIDED BY Adam Glass ``AS IS'' AND
22  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
31  * SUCH DAMAGE.
32  */
33 
34 #include <sys/param.h>
35 #include <sys/types.h>
36 
37 #include <net/if_ether.h>
38 #include <netinet/in.h>
39 #include <netinet/in_systm.h>
40 
41 #include <lib/libsa/netif.h>
42 
43 #include <hp300/stand/common/device.h>
44 #include <hp300/stand/common/if_lereg.h>
45 #include <hp300/stand/common/samachdep.h>
46 
47 #ifndef NLE
48 #define NLE 1
49 #endif
50 
51 #ifdef LE_DEBUG
52 int le_debug = 0;
53 #endif
54 
55 int le_probe();
56 int le_match();
57 void le_init();
58 int le_get();
59 int le_put();
60 void le_end();
61 
62 struct le_sel {
63         int	le_id;
64         int	le_regs;
65         int	le_mem;
66         int	le_nvram;
67         int	le_heat;
68         int	le_bonus;
69 } le0conf[] = {
70 /* offsets for:	   ID   REGS     MEM   NVRAM	le_heat	le_bonus*/
71 {		    0,	0x4000, 0x8000, 0xC008,	1,	10   }
72 };
73 
74 extern struct netif_stats	le_stats[];
75 
76 struct netif_dif le_ifs[] = {
77 /*	dif_unit	dif_nsel	dif_stats	dif_private	*/
78 {	0,		NENTS(le0conf),	&le_stats[0],	le0conf,	},
79 };
80 
81 struct netif_stats le_stats[NENTS(le_ifs)];
82 
83 struct netif_driver le_driver = {
84 	"le",			/* netif_bname */
85 	le_match,		/* netif_match */
86 	le_probe,		/* netif_probe */
87 	le_init,		/* netif_init */
88 	le_get,			/* netif_get */
89 	le_put,			/* netif_put */
90 	le_end,			/* netif_end */
91 	le_ifs,			/* netif_ifs */
92 	NENTS(le_ifs)		/* netif_nifs */
93 };
94 
95 struct le_softc {
96 	struct	lereg0 *sc_r0;	/* DIO registers */
97 	struct	lereg1 *sc_r1;	/* LANCE registers */
98 	void	*sc_mem;
99 	struct	init_block *sc_init;
100 	struct	mds *sc_rd, *sc_td;
101 	u_char	*sc_rbuf, *sc_tbuf;
102 	int	sc_next_rd, sc_next_td;
103 	u_char	sc_addr[ETHER_ADDR_LEN];
104 } le_softc[NLE];
105 
106 static inline void
107 lewrcsr(sc, port, val)
108 	struct le_softc *sc;
109 	register u_short port;
110 	register u_short val;
111 {
112 	register struct lereg0 *ler0 = sc->sc_r0;
113 	register struct lereg1 *ler1 = sc->sc_r1;
114 
115 	do {
116 		ler1->ler1_rap = port;
117 	} while ((ler0->ler0_status & LE_ACK) == 0);
118 	do {
119 		ler1->ler1_rdp = val;
120 	} while ((ler0->ler0_status & LE_ACK) == 0);
121 }
122 
123 static inline u_short
124 lerdcsr(sc, port)
125 	struct le_softc *sc;
126 	register u_short port;
127 {
128 	register struct lereg0 *ler0 = sc->sc_r0;
129 	register struct lereg1 *ler1 = sc->sc_r1;
130 	register u_short val;
131 
132 	do {
133 		ler1->ler1_rap = port;
134 	} while ((ler0->ler0_status & LE_ACK) == 0);
135 	do {
136 		val = ler1->ler1_rdp;
137 	} while ((ler0->ler0_status & LE_ACK) == 0);
138 	return (val);
139 }
140 
141 leinit()
142 {
143 	extern struct hp_hw sc_table[];
144 	register struct hp_hw *hw;
145 	struct le_softc *sc;
146 	struct le_sel *sels;
147 	register int i, n;
148 	char *cp;
149 
150 	i = 0;
151 
152 	for (hw = sc_table; i < NLE && hw < &sc_table[MAXCTLRS]; hw++) {
153 #ifdef LE_DEBUG
154 		if (le_debug)
155 			printf("found type %x\n", hw->hw_type);
156 #endif
157 
158 #if 0
159 		if (!HW_ISDEV(hw, D_LAN))
160 			continue;
161 #endif
162 
163                 sels = (struct le_sel *)le_ifs[i].dif_private;
164 
165 		sc = &le_softc[i];
166                 sc->sc_r0 = (struct lereg0 *)(sels->le_id + (int)hw->hw_kva);
167 
168                 if (sc->sc_r0->ler0_id != LEID)
169                         continue;
170 
171                 sc->sc_r1 = (struct lereg1 *)(sels->le_regs + (int)hw->hw_kva);
172                 sc->sc_mem = (struct lereg2 *)(sels->le_mem + (int)hw->hw_kva);
173 
174 #ifdef LE_DEBUG
175 		if (le_debug)
176 			printf("le%d: DIO=%x regs=%x mem=%x\n",
177 				i, sc->sc_r0, sc->sc_r1, sc->sc_mem);
178 #endif
179 
180 		/*
181 		 * Read the ethernet address off the board, one nibble at a time.
182 		 */
183 		cp = (char *)(sels->le_nvram + (int)hw->hw_kva);
184 		for (n = 0; n < sizeof(sc->sc_addr); n++) {
185 		    sc->sc_addr[n] = (*++cp & 0xF) << 4;
186 		    cp++;
187 		    sc->sc_addr[n] |= *++cp & 0xF;
188 		    cp++;
189 		}
190 #ifdef LE_DEBUG
191 		if (le_debug)
192 			printf("le%d at sc%d physical address %s\n",
193 				i, hw->hw_sc, ether_sprintf(sc->sc_addr));
194 #endif
195 		hw->hw_pa = (caddr_t) i;	/* XXX for autoconfig */
196 		i++;
197 	}
198 }
199 
200 int
201 le_match(nif, machdep_hint)
202 	struct netif *nif;
203 	void *machdep_hint;
204 {
205 	struct le_sel *sels;
206 	char *name = machdep_hint;
207 	int rv = 0;
208 
209 	if (nif->nif_sel < le_ifs[nif->nif_unit].dif_nsel) {
210 		sels = (struct le_sel *)le_ifs[nif->nif_unit].dif_private;
211 		rv = sels[nif->nif_sel].le_heat;
212 		if (name && !strncmp(le_driver.netif_bname, name, 2))
213 			rv += sels[nif->nif_sel].le_bonus;
214 	}
215 #ifdef LE_DEBUG
216 	if (le_debug)
217 		printf("le%d: sel %d --> %d\n", nif->nif_unit, nif->nif_sel,
218 		    rv);
219 #endif
220 	return rv;
221 }
222 
223 le_probe(nif, machdep_hint)
224 	struct netif *nif;
225 	void *machdep_hint;
226 {
227 	char *cp;
228 	int i;
229 
230 	/* the set unit is the current unit */
231 #ifdef LE_DEBUG
232 	if (le_debug)
233 		printf("le%d.%d: le_probe called\n", nif->nif_unit, nif->nif_sel);
234 #endif
235 	/* XXX reset controller */
236 	return 0;
237 }
238 
239 #ifdef MEM_SUMMARY
240 void le_mem_summary(unit)
241 {
242 	struct lereg1 *ler1 = le_softc.sc_r1;
243 	struct lereg2 *ler2 = le_softc.sc_r2;
244 	register int i;
245 
246 	printf("le%d: ler1 = %x\n", unit, ler1);
247 	printf("le%d: ler2 = %x\n", unit, ler2);
248 
249 #if 0
250 	ler1->ler1_rap = LE_CSR0;
251 	ler1->ler1_rdp = LE_STOP;
252 	printf("le%d: csr0 = %x\n", unit, ler1->ler1_rdp);
253 	ler1->ler1_rap = LE_CSR1;
254 	printf("le%d: csr1 = %x\n", unit, ler1->ler1_rdp);
255 	ler1->ler1_rap = LE_CSR2;
256 	printf("le%d: csr2 = %x\n", unit, ler1->ler1_rdp);
257 	ler1->ler1_rap = LE_CSR3;
258 	printf("le%d: csr3 = %x\n", unit, ler1->ler1_rdp);
259 #endif
260 	printf("le%d: ladrf[0] = %x\n", unit, ler2->ler2_ladrf[0]);
261 	printf("le%d: ladrf[1] = %x\n", unit, ler2->ler2_ladrf[1]);
262 	printf("le%d: ler2_rdra = %x\n", unit, ler2->ler2_rdra);
263 	printf("le%d: ler2_rlen = %x\n", unit, ler2->ler2_rlen);
264 	printf("le%d: ler2_tdra = %x\n", unit, ler2->ler2_tdra);
265 	printf("le%d: ler2_tlen = %x\n", unit, ler2->ler2_tlen);
266 
267 	for (i = 0; i < LERBUF; i++) {
268 		printf("le%d: ler2_rmd[%d].rmd0 (ladr) = %x\n", unit, i,
269 			ler2->ler2_rmd[i].rmd0);
270 		printf("le%d: ler2_rmd[%d].rmd1 = %x\n", unit, i,
271 			ler2->ler2_rmd[i].rmd1);
272 		printf("le%d: ler2_rmd[%d].rmd2 (-bcnt) = %x\n", unit, i,
273 			ler2->ler2_rmd[i].rmd2);
274 		printf("le%d: ler2_rmd[%d].rmd3 (mcnt) = %x\n", unit, i,
275 			ler2->ler2_rmd[i].rmd3);
276 		printf("le%d: ler2_rbuf[%d] addr = %x\n", unit, i,
277 			&ler2->ler2_rbuf[i]);
278 	}
279 	for (i = 0; i < LETBUF; i++) {
280 		printf("le%d: ler2_tmd[%d].tmd0 = %x\n", unit, i,
281 			ler2->ler2_tmd[i].tmd0);
282 		printf("le%d: ler2_tmd[%d].tmd1 = %x\n", unit, i,
283 			ler2->ler2_tmd[i].tmd1);
284 		printf("le%d: ler2_tmd[%d].tmd2 (bcnt) = %x\n", unit, i,
285 			ler2->ler2_tmd[i].tmd2);
286 		printf("le%d: ler2_tmd[%d].tmd3 = %x\n", unit, i,
287 			ler2->ler2_tmd[i].tmd3);
288 		printf("le%d: ler2_tbuf[%d] addr = %x\n", unit, i,
289 			&ler2->ler2_tbuf[i]);
290 	}
291 }
292 #else
293 #define le_mem_summary(u)
294 #endif
295 
296 void
297 le_error(unit, str, stat)
298 	int unit;
299 	char *str;
300 	u_short stat;
301 {
302 
303 	if (stat & LE_BABL)
304 		panic("le%d: been babbling, found by '%s'\n", unit, str);
305 	if (stat & LE_CERR)
306 		le_stats[unit].collision_error++;
307 	if (stat & LE_MISS)
308 		le_stats[unit].missed++;
309 	if (stat & LE_MERR) {
310 		printf("le%d: memory error in '%s'\n", unit, str);
311 		le_mem_summary(unit);
312 		panic("bye");
313 	}
314 }
315 
316 #define	LANCE_ADDR(sc, a) \
317 	((u_long)(a) - (u_long)sc->sc_mem)
318 
319 /* LANCE initialization block set up. */
320 void
321 lememinit(sc)
322 	register struct le_softc *sc;
323 {
324 	int i;
325 	void *mem;
326 	u_long a;
327 
328 	/*
329 	 * At this point we assume that the memory allocated to the Lance is
330 	 * quadword aligned.  If it isn't then the initialisation is going
331 	 * fail later on.
332 	 */
333 	mem = sc->sc_mem;
334 
335 	sc->sc_init = mem;
336 	sc->sc_init->mode = LE_NORMAL;
337 	for (i = 0; i < ETHER_ADDR_LEN; i++)
338 		sc->sc_init->padr[i] = sc->sc_addr[i^1];
339 	sc->sc_init->ladrf[0] = sc->sc_init->ladrf[1] = 0;
340 	mem += sizeof(struct init_block);
341 
342 	sc->sc_rd = mem;
343 	a = LANCE_ADDR(sc, mem);
344 	sc->sc_init->rdra = a;
345 	sc->sc_init->rlen = ((a >> 16) & 0xff) | (RLEN << 13);
346 	mem += NRBUF * sizeof(struct mds);
347 
348 	sc->sc_td = mem;
349 	a = LANCE_ADDR(sc, mem);
350 	sc->sc_init->tdra = a;
351 	sc->sc_init->tlen = ((a >> 16) & 0xff) | (TLEN << 13);
352 	mem += NTBUF * sizeof(struct mds);
353 
354 	/*
355 	 * Set up receive ring descriptors.
356 	 */
357 	sc->sc_rbuf = mem;
358 	for (i = 0; i < NRBUF; i++) {
359 		a = LANCE_ADDR(sc, mem);
360 		sc->sc_rd[i].addr = a;
361 		sc->sc_rd[i].flags = ((a >> 16) & 0xff) | LE_OWN;
362 		sc->sc_rd[i].bcnt = -BUFSIZE;
363 		sc->sc_rd[i].mcnt = 0;
364 		mem += BUFSIZE;
365 	}
366 
367 	/*
368 	 * Set up transmit ring descriptors.
369 	 */
370 	sc->sc_tbuf = mem;
371 	for (i = 0; i < NTBUF; i++) {
372 		a = LANCE_ADDR(sc, mem);
373 		sc->sc_td[i].addr = a;
374 		sc->sc_td[i].flags = ((a >> 16) & 0xff);
375 		sc->sc_td[i].bcnt = 0xf000;
376 		sc->sc_td[i].mcnt = 0;
377 		mem += BUFSIZE;
378 	}
379 }
380 
381 void
382 le_reset(unit, myea)
383 	int unit;
384 	u_char *myea;
385 {
386 	struct le_softc *sc = &le_softc[unit];
387 	u_long a;
388 	int timo = 100000, stat, i;
389 
390 #ifdef LE_DEBUG
391 	if (le_debug) {
392 		printf("le%d: le_reset called\n", unit);
393 		printf("     r0=%x, r1=%x, mem=%x, addr=%x:%x:%x:%x:%x:%x\n",
394 		       sc->sc_r0, sc->sc_r1, sc->sc_mem,
395 		       sc->sc_addr[0], sc->sc_addr[1], sc->sc_addr[2],
396 		       sc->sc_addr[3], sc->sc_addr[4], sc->sc_addr[5]);
397 	}
398 #endif
399 	lewrcsr(sc, 0, LE_STOP);
400 	for (timo = 1000; timo; timo--);
401 
402 	sc->sc_next_rd = sc->sc_next_td = 0;
403 
404 	/* Set up LANCE init block. */
405 	lememinit(sc);
406 
407 	if (myea)
408 		bcopy(sc->sc_addr, myea, ETHER_ADDR_LEN);
409 
410 	/* Turn on byte swapping. */
411 	lewrcsr(sc, 3, LE_BSWP);
412 
413 	/* Give LANCE the physical address of its init block. */
414 	a = LANCE_ADDR(sc, sc->sc_init);
415 	lewrcsr(sc, 1, a);
416 	lewrcsr(sc, 2, (a >> 16) & 0xff);
417 
418 #ifdef LE_DEBUG
419 	if (le_debug)
420 		printf("le%d: before init\n", unit);
421 #endif
422 
423 	/* Try to initialize the LANCE. */
424 	lewrcsr(sc, 0, LE_INIT);
425 
426 	/* Wait for initialization to finish. */
427 	for (timo = 100000; timo; timo--)
428 		if (lerdcsr(sc, 0) & LE_IDON)
429 			break;
430 
431 	if (lerdcsr(sc, 0) & LE_IDON) {
432 		/* Start the LANCE. */
433 		lewrcsr(sc, 0, LE_INEA | LE_STRT | LE_IDON);
434 	} else
435 		printf("le%d: card failed to initialize\n", unit);
436 
437 #ifdef LE_DEBUG
438 	if (le_debug)
439 		printf("le%d: after init\n", unit);
440 #endif
441 
442 	le_mem_summary(unit);
443 }
444 
445 int
446 le_poll(desc, pkt, len)
447 	struct iodesc *desc;
448 	void *pkt;
449 	int len;
450 {
451 	struct netif *nif = desc->io_netif;
452 	int unit = /*nif->nif_unit*/0;
453 	struct le_softc *sc = &le_softc[unit];
454 	volatile struct lereg0 *ler0 = sc->sc_r0;
455 	volatile struct lereg1 *ler1 = sc->sc_r1;
456 	int length;
457 	volatile struct mds *cdm;
458 	register int stat;
459 
460 #ifdef LE_DEBUG
461 	if (/*le_debug*/0)
462 		printf("le%d: le_poll called. next_rd=%d\n", unit, sc->sc_next_rd);
463 #endif
464 	stat = lerdcsr(sc, 0);
465 	lewrcsr(sc, 0, stat & (LE_BABL | LE_MISS | LE_MERR | LE_RINT));
466 	cdm = &sc->sc_rd[sc->sc_next_rd];
467 	if (cdm->flags & LE_OWN)
468 		return 0;
469 #ifdef LE_DEBUG
470 	if (le_debug) {
471 		printf("next_rd %d\n", sc->sc_next_rd);
472 		printf("cdm->flags %x\n", cdm->flags);
473 		printf("cdm->bcnt %x, cdm->mcnt %x\n", cdm->bcnt, cdm->mcnt);
474 		printf("cdm->rbuf msg %d buf %d\n", cdm->mcnt, -cdm->bcnt );
475 	}
476 #endif
477 	if (stat & (LE_BABL | LE_CERR | LE_MISS | LE_MERR))
478 		le_error(unit, "le_poll", stat);
479 	if (cdm->flags & (LE_FRAM | LE_OFLO | LE_CRC | LE_RBUFF)) {
480 		printf("le%d_poll: rmd status 0x%x\n", unit, cdm->flags);
481 		length = 0;
482 		goto cleanup;
483 	}
484 	if ((cdm->flags & (LE_STP|LE_ENP)) != (LE_STP|LE_ENP))
485 		panic("le_poll: chained packet\n");
486 
487 	length = cdm->mcnt;
488 #ifdef LE_DEBUG
489 	if (le_debug)
490 		printf("le_poll: length %d\n", length);
491 #endif
492 	if (length >= BUFSIZE) {
493 		length = 0;
494 		panic("csr0 when bad things happen: %x\n", stat);
495 		goto cleanup;
496 	}
497 	if (!length)
498 		goto cleanup;
499 	length -= 4;
500 
501 	if (length > 0) {
502 		/*
503 		 * If the length of the packet is greater than the size of the
504 		 * buffer, we have to truncate it, to avoid Bad Things.
505 		 * XXX Is this the right thing to do?
506 		 */
507 		if (length > len)
508 			length = len;
509 
510 		bcopy(sc->sc_rbuf + (BUFSIZE * sc->sc_next_rd), pkt, length);
511 	}
512 
513 cleanup:
514 	cdm->mcnt = 0;
515 	cdm->flags |= LE_OWN;
516 	if (++sc->sc_next_rd >= NRBUF)
517 		sc->sc_next_rd = 0;
518 #ifdef LE_DEBUG
519 	if (le_debug)
520 		printf("new next_rd %d\n", sc->sc_next_rd);
521 #endif
522 
523 	return length;
524 }
525 
526 int
527 le_put(desc, pkt, len)
528 	struct iodesc *desc;
529 	void *pkt;
530 	int len;
531 {
532 	struct netif *nif = desc->io_netif;
533 	int unit = /*nif->nif_unit*/0;
534 	struct le_softc *sc = &le_softc[unit];
535 	volatile struct lereg0 *ler0 = sc->sc_r0;
536 	volatile struct lereg1 *ler1 = sc->sc_r1;
537 	volatile struct mds *cdm;
538 	int timo, i, stat;
539 
540  le_put_loop:
541 	timo = 100000;
542 
543 #ifdef LE_DEBUG
544 	if (le_debug)
545 		printf("le%d: le_put called. next_td=%d\n", unit, sc->sc_next_td);
546 #endif
547 	stat = lerdcsr(sc, 0);
548 	lewrcsr(sc, 0, stat & (LE_BABL | LE_MISS | LE_MERR | LE_TINT));
549 	if (stat & (LE_BABL | LE_CERR | LE_MISS | LE_MERR))
550 		le_error(unit, "le_put(way before xmit)", stat);
551 	cdm = &sc->sc_td[sc->sc_next_td];
552         i = 0;
553 #if 0
554 	while (cdm->flags & LE_OWN) {
555 		if ((i % 100) == 0)
556 			printf("le%d: output buffer busy - flags=%x\n",
557 				unit, cdm->flags);
558 		if (i++ > 500) break;
559 	}
560 	if (cdm->flags & LE_OWN)
561 		getchar();
562 #else
563 	while (cdm->flags & LE_OWN);
564 #endif
565 	bcopy(pkt, sc->sc_tbuf + (BUFSIZE * sc->sc_next_td), len);
566 	if (len < ETHER_MIN_LEN)
567 		cdm->bcnt = -ETHER_MIN_LEN;
568 	else
569 		cdm->bcnt = -len;
570 	cdm->mcnt = 0;
571 	cdm->flags |= LE_OWN | LE_STP | LE_ENP;
572 	stat = lerdcsr(sc, 0);
573 	if (stat & (LE_BABL | LE_CERR | LE_MISS | LE_MERR))
574 		le_error(unit, "le_put(before xmit)", stat);
575 	lewrcsr(sc, 0, LE_TDMD);
576 	stat = lerdcsr(sc, 0);
577 	if (stat & (LE_BABL | LE_CERR | LE_MISS | LE_MERR))
578 		le_error(unit, "le_put(after xmit)", stat);
579 	do {
580 		if (--timo == 0) {
581 			printf("le%d: transmit timeout, stat = 0x%x\n",
582 				unit, stat);
583 			if (stat & LE_SERR)
584 				le_error(unit, "le_put(timeout)", stat);
585 			if (stat & LE_INIT) {
586 				printf("le%d: reset and retry packet\n");
587 				lewrcsr(sc, 0, LE_TINT);	/* sanity */
588 				le_init();
589 				goto le_put_loop;
590 			}
591 			break;
592 		}
593 		stat = lerdcsr(sc, 0);
594 	} while ((stat & LE_TINT) == 0);
595 	lewrcsr(sc, 0, LE_TINT);
596 	if (stat & (LE_BABL |/* LE_CERR |*/ LE_MISS | LE_MERR)) {
597 		printf("le_put: xmit error, buf %d\n", sc->sc_next_td);
598 		le_error(unit, "le_put(xmit error)", stat);
599 	}
600 	if (++sc->sc_next_td >= NTBUF)
601 		sc->sc_next_td = 0;
602 	if (cdm->flags & LE_DEF)
603 		le_stats[unit].deferred++;
604 	if (cdm->flags & LE_ONE)
605 		le_stats[unit].collisions++;
606 	if (cdm->flags & LE_MORE)
607 		le_stats[unit].collisions += 2;
608 	if (cdm->flags & LE_ERR) {
609 		if (cdm->mcnt & LE_UFLO)
610 			printf("le%d: transmit underflow\n", unit);
611 		if (cdm->mcnt & LE_LCOL)
612 			le_stats[unit].collisions++;
613 		if (cdm->mcnt & LE_LCAR)
614 			printf("le%d: lost carrier\n", unit);
615 		if (cdm->mcnt & LE_RTRY)
616 			le_stats[unit].collisions += 16;
617 		return -1;
618 	}
619 #ifdef LE_DEBUG
620 	if (le_debug) {
621 		printf("le%d: le_put() successful: sent %d\n", unit, len);
622 		printf("le%d: le_put(): flags: %x mcnt: %x\n", unit,
623 			(unsigned int) cdm->flags,
624 			(unsigned int) cdm->mcnt);
625 	}
626 #endif
627 	return len;
628 }
629 
630 
631 int
632 le_get(desc, pkt, len, timeout)
633 	struct iodesc *desc;
634 	void *pkt;
635 	int len;
636 	time_t timeout;
637 {
638 	time_t t;
639 	int cc;
640 
641 	t = getsecs();
642 	cc = 0;
643 	while (((getsecs() - t) < timeout) && !cc) {
644 		cc = le_poll(desc, pkt, len);
645 	}
646 	return cc;
647 }
648 
649 void
650 le_init(desc, machdep_hint)
651 	struct iodesc *desc;
652 	void *machdep_hint;
653 {
654 	struct netif *nif = desc->io_netif;
655 	int unit = nif->nif_unit;
656 
657 	/* Get machine's common ethernet interface. This is done in leinit() */
658 	/* machdep_common_ether(myea); */
659 	leinit();
660 
661 #ifdef LE_DEBUG
662 	if (le_debug)
663 		printf("le%d: le_init called\n", unit);
664 #endif
665 	unit = 0;
666 	le_reset(unit, desc->myea);
667 }
668 
669 void
670 le_end(nif)
671 	struct netif *nif;
672 {
673 	int unit = nif->nif_unit;
674 
675 #ifdef LE_DEBUG
676 	if (le_debug)
677 		printf("le%d: le_end called\n", unit);
678 #endif
679 
680 	lewrcsr(&le_softc[unit], 0, LE_STOP);
681 }
682