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