xref: /original-bsd/sys/news3400/if/if_lance.c (revision 3705696b)
1 /*
2  * Copyright (c) 1992, 1993
3  *	The Regents of the University of California.  All rights reserved.
4  *
5  * This code is derived from software contributed to Berkeley by
6  * Sony Corp. and Kazumasa Utashiro of Software Research Associates, Inc.
7  *
8  * %sccs.include.redist.c%
9  *
10  * from: $Hdr: if_lance.c,v 4.300 91/06/09 06:25:58 root Rel41 $ SONY
11  *
12  *	@(#)if_lance.c	8.1 (Berkeley) 06/11/93
13  */
14 
15 /*
16  * if_lance: Am7990 LANCE driver
17  *
18  * This driver is available only for single CPU machine.
19  */
20 
21 #define	LANCE_LED
22 
23 #include "en.h"
24 
25 #if NEN > 0
26 
27 #include <machine/adrsmap.h>
28 
29 #include <sys/param.h>
30 
31 #include <news3400/if/lancereg.h>
32 #include <news3400/if/if_lance.h>
33 
34 #ifdef mips
35 #define	VOLATILE	volatile
36 #else
37 #define	VOLATILE
38 #endif
39 
40 #ifdef LANCE_LED
41 #ifdef news3400
42 #define	LED_ON	{ \
43 	VOLATILE u_char *p = (u_char *)DEBUG_PORT; \
44 	*p = DP_WRITE | (*p & ~DP_LED2); \
45 }
46 #define	LED_OFF	{ \
47 	VOLATILE u_char *p = (u_char *)DEBUG_PORT; \
48 	*p = DP_WRITE | (*p | DP_LED2); \
49 }
50 #else /* news3400 */
51 #define	LED_ON
52 #define	LED_OFF
53 #endif /* news3400 */
54 #else /* LANCE_LED */
55 #define	LED_ON
56 #define	LED_OFF
57 #endif /* LANCE_LED */
58 
59 /*
60  *	LANCE memory configuration
61  */
62 #define	INIT_BLOCK		0x000000
63 #define	RECV_MSG_DESC		0x000100
64 #define	XMIT_MSG_DESC		0x000200
65 #ifdef mips
66 #define	RECV_BUFFER		(0x000300 + 2)
67 				/* for data alignment to long word */
68 #else /* mips */
69 #define	RECV_BUFFER		0x000300
70 #endif /* mips */
71 #define	XMIT_BUFFER		(RECV_BUFFER+(RECV_BUFFER_SIZE*RECV_BUFFERS))
72 
73 #define	RECV_RING_LEN		3	/* log2(8) */
74 #define	XMIT_RING_LEN		1	/* log2(2) */
75 
76 #define	RECV_BUFFER_SIZE	0x600
77 #define	XMIT_BUFFER_SIZE	0x600
78 
79 #define	RECV_BUFFERS		(1 << RECV_RING_LEN)
80 #define	XMIT_BUFFERS		(1 << XMIT_RING_LEN)
81 
82 /*
83  *	Initialization block
84  */
85 struct init_block init_block = {
86 	0,
87 	0, 0, 0, 0, 0, 0,
88 	0, 0, 0, 0, 0, 0, 0, 0,
89 	RECV_MSG_DESC & 0xffff,
90 	(RECV_RING_LEN << 13) | (RECV_MSG_DESC >> 16),
91 	XMIT_MSG_DESC & 0xffff,
92 	(XMIT_RING_LEN << 13) | (XMIT_MSG_DESC >> 16)
93 };
94 
95 /*
96  *	LANCE control block
97  */
98 Lance_chan lancesw[NEN] = {
99       {	(Lance_reg *)LANCE_PORT,
100 	(caddr_t)LANCE_MEMORY,
101 	(caddr_t)ETHER_ID },
102 #if NEN > 1
103       {	(Lance_reg *)LANCE_PORT1,
104 	(caddr_t)LANCE_MEMORY1,
105 	(caddr_t)ETHER_ID1 },
106 #endif
107 #if NEN > 2
108       {	(Lance_reg *)LANCE_PORT2,
109 	(caddr_t)LANCE_MEMORY2,
110 	(caddr_t)ETHER_ID2 },
111 #endif
112 };
113 
114 lance_probe(chan)
115 	int chan;
116 {
117 	register Lance_chan *lance = &lancesw[chan];
118 	VOLATILE int *p = (VOLATILE int *)lance->lance_memory;
119 
120 	if (badaddr(lance->lance_addr, 1))
121 		return (0);
122 
123 	*p = 0x12345678;
124 
125 	return (*p == 0x12345678);
126 }
127 
128 lance_open(chan)
129 	int chan;
130 {
131 	register Lance_chan *lance = &lancesw[chan];
132 	register recv_msg_desc *rmd;
133 	register xmit_msg_desc *tmd;
134 	register struct init_block *ib;
135 	register int buffer, i;
136 
137 	if ((lance->lance_flags & LANCE_ACTIVE) == 0) {
138 		if (lance->lance_addr == (Lance_reg *)0)
139 			return (-1);
140 
141 		lance_write_reg(chan, CSR0, CSR_STOP);
142 
143 		rmd = (recv_msg_desc *)
144 		    (RECV_MSG_DESC + lance->lance_memory);
145 		lance->lance_last_rmd =
146 		    (lance->lance_rmd = rmd) + RECV_BUFFERS - 1;
147 		buffer = RECV_BUFFER;
148 		for (i = 0; i < RECV_BUFFERS; i++) {
149 			rmd->rmd_ladr = buffer & 0xffff;
150 			rmd->rmd_stat = RMD_OWN | (buffer >> 16);
151 			rmd->rmd_bcnt = -RECV_BUFFER_SIZE;
152 			rmd->rmd_mcnt = 0;
153 			rmd++;
154 			buffer += RECV_BUFFER_SIZE;
155 		}
156 
157 		tmd = (xmit_msg_desc *)
158 		    (XMIT_MSG_DESC + lance->lance_memory);
159 		lance->lance_last_tmd =
160 			(lance->lance_tmd = tmd) + XMIT_BUFFERS - 1;
161 		buffer = XMIT_BUFFER;
162 		for (i = 0; i < XMIT_BUFFERS; i++) {
163 			tmd->tmd_ladr = buffer & 0xffff;
164 			tmd->tmd_stat = buffer >> 16;
165 			tmd->tmd_bcnt = 0;
166 			tmd++;
167 			buffer += XMIT_BUFFER_SIZE;
168 		}
169 		get_hard_addr(chan, lance->lance_stats.ens_addr);
170 
171 		ib = (struct init_block *)(INIT_BLOCK + lance->lance_memory);
172 		lance->lance_ib = ib;
173 		*ib = init_block;
174 		ib->ib_padr[0] = lance->lance_stats.ens_addr[1];
175 		ib->ib_padr[1] = lance->lance_stats.ens_addr[0];
176 		ib->ib_padr[2] = lance->lance_stats.ens_addr[3];
177 		ib->ib_padr[3] = lance->lance_stats.ens_addr[2];
178 		ib->ib_padr[4] = lance->lance_stats.ens_addr[5];
179 		ib->ib_padr[5] = lance->lance_stats.ens_addr[4];
180 
181 		if (lance->lance_flags & LANCE_PROM)
182 			ib->ib_mode |= IB_PROM;
183 
184 		lance->lance_flags |= LANCE_ACTIVE;
185 		lance_init(chan);
186 
187 		if (lance_read_reg(chan, CSR0) !=
188 		    (CSR_INEA|CSR_RXON|CSR_TXON|CSR_STRT|CSR_INIT)) {
189 			lance->lance_flags &= ~LANCE_ACTIVE;
190 			return (-1);
191 		}
192 
193 	}
194 
195 	return (0);
196 }
197 
198 lance_close(chan)
199 	int chan;
200 {
201 	register Lance_chan *lance = &lancesw[chan];
202 
203 	lance_write_reg(chan, CSR0, CSR_STOP);
204 	lance->lance_flags &= ~LANCE_ACTIVE;
205 
206 }
207 
208 #define	RECEIVE(lance, rmd)	{ \
209 	register int i; \
210 	(rmd) = (lance)->lance_last_rmd + 1; \
211 	if ((rmd) >= (lance)->lance_rmd + RECV_BUFFERS) \
212 		(rmd) = (lance)->lance_rmd; \
213 	if (((rmd)->rmd_stat & RMD_OWN) == 0) \
214 		(lance)->lance_last_rmd = (rmd); \
215 	else \
216 		(rmd) = NULL; \
217 }
218 #define	RECV_BUF(lance, rmd)	(char *)((rmd)->rmd_ladr \
219 					+ (((rmd)->rmd_stat & RMD_HADR) << 16) \
220 					+ (lance)->lance_memory)
221 #define	RECV_CNT(rmd)		((rmd)->rmd_mcnt - 4)
222 #define	RECV_ERR(rmd)		((rmd)->rmd_stat & RMD_ERR)
223 #define	RELEASE_RECV_BUF(rmd)	{ \
224 	(rmd)->rmd_mcnt = 0; \
225 	(rmd)->rmd_stat = ((rmd)->rmd_stat & RMD_HADR) | RMD_OWN; \
226 }
227 
228 
229 caddr_t
230 get_recv_buffer(chan)
231 	int chan;
232 {
233 	register Lance_chan *lance = &lancesw[chan];
234 	register recv_msg_desc *rmd;
235 
236 next:
237 	RECEIVE(lance, rmd);
238 	if (rmd == NULL)
239 		return (NULL);
240 
241 	if (RECV_ERR(rmd)) {
242 		recv_error(lance, rmd);
243 		RELEASE_RECV_BUF(rmd);
244 		goto next;
245 	}
246 
247 	return (RECV_BUF(lance, rmd));
248 }
249 
250 get_recv_length(chan)
251 	int chan;
252 {
253 
254 	return (RECV_CNT(lancesw[chan].lance_last_rmd));
255 }
256 
257 free_recv_buffer(chan)
258 	int chan;
259 {
260 	register recv_msg_desc *rmd = lancesw[chan].lance_last_rmd;
261 
262 	RELEASE_RECV_BUF(rmd);
263 }
264 
265 #define	GET_XMIT_BUF(lance, tmd)	{ \
266 	(tmd) = (lance)->lance_last_tmd + 1; \
267 	if ((tmd) >= (lance)->lance_tmd + XMIT_BUFFERS) \
268 		(tmd) = (lance)->lance_tmd; \
269 	if ((tmd)->tmd_stat & TMD_OWN) \
270 		(tmd) = NULL; \
271 	else \
272 		(lance)->lance_last_tmd = (tmd); \
273 }
274 #define	XMIT_BUF(lance, tmd)	(char *)((tmd)->tmd_ladr \
275 					+ (((tmd)->tmd_stat & TMD_HADR) << 16) \
276 					+ (lance)->lance_memory)
277 #define	XMIT_ERR(tmd)		((tmd)->tmd_stat & TMD_ERR)
278 #define	TRANSMIT(lance, tmd, count)	{ \
279 	(tmd)->tmd_bcnt = -(count); \
280 	(tmd)->tmd_error = 0; \
281 	(tmd)->tmd_stat = ((tmd)->tmd_stat & TMD_HADR) | (TMD_OWN|TMD_STP|TMD_ENP); \
282 	(lance)->lance_addr->rap = CSR0; \
283 	(lance)->lance_addr->rdp = (CSR_INEA|CSR_TDMD); \
284 }
285 
286 caddr_t
287 get_xmit_buffer(chan)
288 	int chan;
289 {
290 	register Lance_chan *lance = &lancesw[chan];
291 	register xmit_msg_desc *tmd;
292 
293 	GET_XMIT_BUF(lance, tmd);
294 	if (tmd == NULL)
295 		return (NULL);
296 	return (XMIT_BUF(lance, tmd));
297 }
298 
299 lance_transmit(chan, count)
300 	int chan;
301 	int count;
302 {
303 	register Lance_chan *lance = &lancesw[chan];
304 	register xmit_msg_desc *tmd;
305 
306 	tmd = lance->lance_last_tmd;
307 	TRANSMIT(lance, tmd, count);
308 }
309 
310 lance_xmit_error(chan)
311 	int chan;
312 {
313 	register Lance_chan *lance = &lancesw[chan];
314 	register xmit_msg_desc *tmd;
315 
316 	tmd = lance->lance_last_tmd;
317 	if (XMIT_ERR(tmd)) {
318 		xmit_error(lance, tmd);
319 		return (1);
320 	}
321 
322 	return (0);
323 }
324 
325 lance_collision(chan)
326 	int chan;
327 {
328 	register Lance_chan *lance = &lancesw[chan];
329 
330 	if (lance->lance_last_tmd->tmd_stat & (TMD_MORE|TMD_ONE)) {
331 		lance->lance_stats.ens_collis++;
332 		return (1);
333 	}
334 
335 	return (0);
336 }
337 
338 lance_get_addr(chan, addr)
339 	int chan;
340 	caddr_t addr;
341 {
342 	register Lance_chan *lance = &lancesw[chan];
343 
344 	bcopy(lance->lance_stats.ens_addr, addr,
345 		sizeof(lance->lance_stats.ens_addr));
346 }
347 
348 lance_prom_mode(chan, cmd)
349 	int chan;
350 {
351 	register Lance_chan *lance = &lancesw[chan];
352 
353 	lance_close(chan);
354 	if (cmd)
355 		lance->lance_flags |= LANCE_PROM;
356 	else
357 		lance->lance_flags &= ~LANCE_PROM;
358 	lance_open(chan);
359 }
360 
361 lance_get_status(chan, addr)
362 	int chan;
363 	caddr_t addr;
364 {
365 	register Lance_chan *lance = &lancesw[chan];
366 	register int s;
367 
368 	s = splimp();
369 	bcopy(&lance->lance_stats.ens_frames, addr,
370 	    sizeof(lance->lance_stats) - sizeof (lance->lance_stats.ens_addr));
371 	bzero(&lance->lance_stats.ens_frames,
372 	    sizeof(lance->lance_stats) - sizeof (lance->lance_stats.ens_addr));
373 	(void) splx(s);
374 }
375 
376 lance_intr()
377 {
378 	register Lance_chan *lance;
379 	register Lance_reg *reg;
380 	register int stat, chan;
381 	int retval = 0;
382 
383 	LED_ON;
384 
385 	for (chan = 0, lance = lancesw; chan < NEN ; lance++, chan++) {
386 		if ((lance->lance_flags & LANCE_ACTIVE) == 0)
387 			continue;
388 
389 		reg = lance->lance_addr;
390 		reg->rap = CSR0;
391 		stat = reg->rdp & ~CSR_INEA;
392 		if ((stat & CSR_INTR) == 0)
393 			continue;
394 
395 		retval = 1;
396 		reg->rdp = stat;
397 		reg->rdp = CSR_INEA;
398 
399 		if (stat & CSR_ERR) {
400 			if (stat & CSR_BABL)
401 				printf("lance %d error: babl\n", chan);
402 			if (stat & CSR_MISS)
403 				lance->lance_stats.ens_lost++;
404 			if (stat & CSR_MERR)
405 				printf("lance %d error: merr\n", chan);
406 		}
407 		if (stat & CSR_RINT) {
408 			lance->lance_stats.ens_frames++;
409 			enrint(chan);
410 		}
411 		if (stat & CSR_TINT) {
412 			lance->lance_stats.ens_xmit++;
413 			enxint(chan);
414 		}
415 		if (stat & CSR_IDON)
416 			lance->lance_flags |= LANCE_IDON;
417 	}
418 
419 	LED_OFF;
420 
421 	return (retval);
422 }
423 
424 lance_init(chan)
425 	int chan;
426 {
427 	register Lance_chan *lance = &lancesw[chan];
428 	register int s;
429 
430 	s = splimp();
431 	lance_write_reg(chan, CSR1, INIT_BLOCK & 0xffff);
432 	lance_write_reg(chan, CSR2, INIT_BLOCK >> 16);
433 	lance_write_reg(chan, CSR3, CSR_BSWP|CSR_BCON);
434 
435 	lance_write_reg(chan, CSR0, CSR_INEA|CSR_STRT|CSR_INIT);
436 	(void) splx(s);
437 
438 	while ((lance->lance_flags & LANCE_IDON) == 0)
439 		;
440 }
441 
442 recv_error(lance, rmd)
443 	register Lance_chan *lance;
444 	register recv_msg_desc *rmd;
445 {
446 	register int status = rmd->rmd_stat;
447 	register int chan = lance - lancesw;
448 
449 	if (status & RMD_FRAM)
450 		lance->lance_stats.ens_align++;
451 	if (status & RMD_OFLO)
452 		printf("lance %d recv error: overflow\n", chan);
453 	if (status & RMD_CRC)
454 		lance->lance_stats.ens_crc++;
455 	if (status & RMD_BUFF)
456 		printf("lance %d:recv error: buffer\n", chan);
457 }
458 
459 xmit_error(lance, tmd)
460 	register Lance_chan *lance;
461 	register xmit_msg_desc *tmd;
462 {
463 	register int status = tmd->tmd_error;
464 	register int chan = lance - lancesw;
465 
466 	if (status & TMD_BUFF)
467 		printf("lance %d: xmit error: buffer\n", chan);
468 	if (status & TMD_UFLO)
469 		printf("lance %d: xmit error: underflow\n", chan);
470 	if (status & TMD_LCOL) {
471 		printf("lance %d: xmit error: late collision\n", chan);
472 		lance->lance_stats.ens_owcollis++;
473 	}
474 	if (status & TMD_LCAR)
475 		printf("lance %d: xmit error: loss of carrier\n", chan);
476 	if (status & TMD_RTRY) {
477 		printf("lance %d: xmit error: retry tdr=%d\n",
478 		    chan, status & TMD_TDR);
479 		lance->lance_stats.ens_xcollis++;
480 	}
481 }
482 
483 lance_write_reg(chan, reg, data)
484 	int chan, reg, data;
485 {
486 	register Lance_reg *lance = lancesw[chan].lance_addr;
487 	register int s;
488 
489 	s = spl7();
490 	lance->rap = reg;
491 	lance->rdp = data;
492 	(void) splx(s);
493 }
494 
495 lance_read_reg(chan, reg)
496 	int chan, reg;
497 {
498 	register Lance_reg *lance = lancesw[chan].lance_addr;
499 	register int s, d;
500 
501 	s = spl7();
502 	lance->rap = reg;
503 	d = lance->rdp;
504 	(void) splx(s);
505 
506 	return (d);
507 }
508 
509 get_hard_addr(chan, addr)
510 	int chan;
511 	u_short *addr;
512 {
513 	register unsigned char *p, *q;
514 	register int i;
515 	register Lance_chan *lance = &lancesw[chan];
516 	unsigned char hard_addr[6];
517 
518 	p = (unsigned char *)lance->lance_rom + 16;
519 	q = hard_addr;
520 	for (i = 0; i < 6; i++) {
521 		*q = (*p++ & 0xf) << 4;
522 		*q++ |= *p++ & 0xf;
523 	}
524 
525 	bcopy(hard_addr, (char *)addr, 6);
526 }
527 
528 #if defined(mips) && defined(CPU_SINGLE)
529 bxcopy(s, d, n)
530 	caddr_t s, d;
531 	int n;
532 {
533 
534 	if (n <= 0)
535 		return;
536 	switch ((((int)s & 03) << 2) + ((int)d & 03)) {
537 
538 	case 0x0:
539 		blcopy((long *)s, (long *)d, n);
540 		return;
541 
542 	case 0x5:
543 		*(char *)d = *(char *)s;
544 		blcopy((long *)(s + 1), (long *)(d + 1), n - 1);
545 		return;
546 
547 	case 0xa:
548 		switch (n) {
549 
550 		case 1:
551 			*(char *)d = *(char *)s;
552 			return;
553 
554 		case 2:
555 			*(short *)d = *(short *)s;
556 			return;
557 
558 		default:
559 			*(short *)d = *(short *)s;
560 			blcopy((long *)(s + 2), (long *)(d + 2), n - 2);
561 			return;
562 		}
563 
564 	case 0xf:
565 		switch (n) {
566 
567 		case 1:
568 			*(char *)d = *(char *)s;
569 			return;
570 
571 		case 2:
572 			*(char *)d = *(char *)s;
573 			*(char *)(d + 1) = *(char *)(s + 1);
574 			return;
575 
576 		case 3:
577 			*(char *)d = *(char *)s;
578 			*(short *)(d + 1) = *(short *)(s + 1);
579 			return;
580 
581 		default:
582 			*(char *)d = *(char *)s;
583 			*(short *)(d + 1) = *(short *)(s + 1);
584 			blcopy((long *)(s + 3), (long *)(d + 3), n - 3);
585 			return;
586 		}
587 
588 	case 0x7:
589 	case 0xd:
590 		switch (n) {
591 
592 		case 1:
593 			*(char *)d = *(char *)s;
594 			return;
595 
596 		case 2:
597 			*(char *)d = *(char *)s;
598 			*(char *)(d + 1) = *(char *)(s + 1);
599 			return;
600 
601 		default:
602 			*(char *)d = *(char *)s;
603 			bwcopy((short *)(s + 1), (short *)(d + 1), n);
604 			return;
605 		}
606 
607 	case 0x2:
608 	case 0x8:
609 		bwcopy((short *)s, (short *)d, n);
610 		return;
611 
612 	default:
613 		bbcopy((char *)s, (char *)d, n);
614 		return;
615 	}
616 }
617 
618 #define	COPY(s, d, n, t) \
619 	while ((n) >= 8 * sizeof (t)) { \
620 		int t0, t1, t2, t3, t4, t5, t6, t7; \
621 		t0 = (s)[0]; \
622 		t1 = (s)[1]; \
623 		t2 = (s)[2]; \
624 		t3 = (s)[3]; \
625 		t4 = (s)[4]; \
626 		t5 = (s)[5]; \
627 		t6 = (s)[6]; \
628 		t7 = (s)[7]; \
629 		(d)[0] = t0; \
630 		(d)[1] = t1; \
631 		(d)[2] = t2; \
632 		(d)[3] = t3; \
633 		(d)[4] = t4; \
634 		(d)[5] = t5; \
635 		(d)[6] = t6; \
636 		(d)[7] = t7; \
637 		(s) += 8; \
638 		(d) += 8; \
639 		(n) -= 8 * sizeof (t); \
640 	} \
641 	while ((n) >= sizeof (t)) { \
642 		(d)[0] = (s)[0]; \
643 		(s)++; \
644 		(d)++; \
645 		(n) -= sizeof (t); \
646 	}
647 
648 blcopy(s, d, n)
649 	long *s, *d;
650 	int n;
651 {
652 
653 	COPY(s, d, n, long);
654 	switch (n) {
655 
656 	case 0:
657 		return;
658 
659 	case 1:
660 		*(char *)d = *(char *)s;
661 		return;
662 
663 	case 2:
664 		*(short *)d = *(short *)s;
665 		return;
666 
667 	case 3:
668 		*(short *)d = *(short *)s;
669 		*((char *)d + 2) = *((char *)s + 2);
670 		return;
671 	}
672 }
673 
674 bwcopy(s, d, n)
675 	short *s, *d;
676 	int n;
677 {
678 
679 	COPY(s, d, n, short);
680 	if (n == 1)
681 		*(char *)d = *(char *)s;
682 }
683 
684 bbcopy(s, d, n)
685 	char *s, *d;
686 	int n;
687 {
688 
689 	COPY(s, d, n, char);
690 }
691 #endif /* defined(mips) && defined(CPU_SINGLE) */
692 
693 #endif /* NEN > 0 */
694