xref: /original-bsd/sys/news3400/if/if_lance.c (revision 6c394c2f)
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.2 (Berkeley) 06/25/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
108 #if NEN > 2
109       {	(Lance_reg *)LANCE_PORT2,
110 	(caddr_t)LANCE_MEMORY2,
111 	(caddr_t)ETHER_ID2 },
112 #endif
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 	if (RECV_ERR(rmd)) {
243 		recv_error(lance, rmd);
244 		RELEASE_RECV_BUF(rmd);
245 		goto next;
246 	}
247 
248 	return (RECV_BUF(lance, rmd));
249 }
250 
251 get_recv_length(chan)
252 	int chan;
253 {
254 
255 	return (RECV_CNT(lancesw[chan].lance_last_rmd));
256 }
257 
258 free_recv_buffer(chan)
259 	int chan;
260 {
261 	register recv_msg_desc *rmd = lancesw[chan].lance_last_rmd;
262 
263 	RELEASE_RECV_BUF(rmd);
264 }
265 
266 #define	GET_XMIT_BUF(lance, tmd)	{ \
267 	(tmd) = (lance)->lance_last_tmd + 1; \
268 	if ((tmd) >= (lance)->lance_tmd + XMIT_BUFFERS) \
269 		(tmd) = (lance)->lance_tmd; \
270 	if ((tmd)->tmd_stat & TMD_OWN) \
271 		(tmd) = NULL; \
272 	else \
273 		(lance)->lance_last_tmd = (tmd); \
274 }
275 #define	XMIT_BUF(lance, tmd)	(char *)((tmd)->tmd_ladr \
276 					+ (((tmd)->tmd_stat & TMD_HADR) << 16) \
277 					+ (lance)->lance_memory)
278 #define	XMIT_ERR(tmd)		((tmd)->tmd_stat & TMD_ERR)
279 #define	TRANSMIT(lance, tmd, count)	{ \
280 	(tmd)->tmd_bcnt = -(count); \
281 	(tmd)->tmd_error = 0; \
282 	(tmd)->tmd_stat = ((tmd)->tmd_stat & TMD_HADR) | (TMD_OWN|TMD_STP|TMD_ENP); \
283 	(lance)->lance_addr->rap = CSR0; \
284 	(lance)->lance_addr->rdp = (CSR_INEA|CSR_TDMD); \
285 }
286 
287 caddr_t
288 get_xmit_buffer(chan)
289 	int chan;
290 {
291 	register Lance_chan *lance = &lancesw[chan];
292 	register xmit_msg_desc *tmd;
293 
294 	GET_XMIT_BUF(lance, tmd);
295 	if (tmd == NULL)
296 		return (NULL);
297 	return (XMIT_BUF(lance, tmd));
298 }
299 
300 lance_transmit(chan, count)
301 	int chan;
302 	int count;
303 {
304 	register Lance_chan *lance = &lancesw[chan];
305 	register xmit_msg_desc *tmd;
306 
307 	tmd = lance->lance_last_tmd;
308 	TRANSMIT(lance, tmd, count);
309 }
310 
311 lance_xmit_error(chan)
312 	int chan;
313 {
314 	register Lance_chan *lance = &lancesw[chan];
315 	register xmit_msg_desc *tmd;
316 
317 	tmd = lance->lance_last_tmd;
318 	if (XMIT_ERR(tmd)) {
319 		xmit_error(lance, tmd);
320 		return (1);
321 	}
322 
323 	return (0);
324 }
325 
326 lance_collision(chan)
327 	int chan;
328 {
329 	register Lance_chan *lance = &lancesw[chan];
330 
331 	if (lance->lance_last_tmd->tmd_stat & (TMD_MORE|TMD_ONE)) {
332 		lance->lance_stats.ens_collis++;
333 		return (1);
334 	}
335 
336 	return (0);
337 }
338 
339 lance_get_addr(chan, addr)
340 	int chan;
341 	caddr_t addr;
342 {
343 	register Lance_chan *lance = &lancesw[chan];
344 
345 	bcopy(lance->lance_stats.ens_addr, addr,
346 		sizeof(lance->lance_stats.ens_addr));
347 }
348 
349 lance_prom_mode(chan, cmd)
350 	int chan;
351 {
352 	register Lance_chan *lance = &lancesw[chan];
353 
354 	lance_close(chan);
355 	if (cmd)
356 		lance->lance_flags |= LANCE_PROM;
357 	else
358 		lance->lance_flags &= ~LANCE_PROM;
359 	lance_open(chan);
360 }
361 
362 lance_get_status(chan, addr)
363 	int chan;
364 	caddr_t addr;
365 {
366 	register Lance_chan *lance = &lancesw[chan];
367 	register int s;
368 
369 	s = splimp();
370 	bcopy(&lance->lance_stats.ens_frames, addr,
371 	    sizeof(lance->lance_stats) - sizeof (lance->lance_stats.ens_addr));
372 	bzero(&lance->lance_stats.ens_frames,
373 	    sizeof(lance->lance_stats) - sizeof (lance->lance_stats.ens_addr));
374 	(void) splx(s);
375 }
376 
377 lance_intr()
378 {
379 	register Lance_chan *lance;
380 	register Lance_reg *reg;
381 	register int stat, chan;
382 	int retval = 0;
383 
384 	LED_ON;
385 
386 	for (chan = 0, lance = lancesw; chan < NEN ; lance++, chan++) {
387 		if ((lance->lance_flags & LANCE_ACTIVE) == 0)
388 			continue;
389 
390 		reg = lance->lance_addr;
391 		reg->rap = CSR0;
392 		stat = reg->rdp & ~CSR_INEA;
393 		if ((stat & CSR_INTR) == 0)
394 			continue;
395 
396 		retval = 1;
397 		reg->rdp = stat;
398 		reg->rdp = CSR_INEA;
399 
400 		if (stat & CSR_ERR) {
401 			if (stat & CSR_BABL)
402 				printf("lance %d error: babl\n", chan);
403 			if (stat & CSR_MISS)
404 				lance->lance_stats.ens_lost++;
405 			if (stat & CSR_MERR)
406 				printf("lance %d error: merr\n", chan);
407 		}
408 		if (stat & CSR_RINT) {
409 			lance->lance_stats.ens_frames++;
410 			enrint(chan);
411 		}
412 		if (stat & CSR_TINT) {
413 			lance->lance_stats.ens_xmit++;
414 			enxint(chan);
415 		}
416 		if (stat & CSR_IDON)
417 			lance->lance_flags |= LANCE_IDON;
418 	}
419 
420 	LED_OFF;
421 
422 	return (retval);
423 }
424 
425 lance_init(chan)
426 	int chan;
427 {
428 	register Lance_chan *lance = &lancesw[chan];
429 	register int s;
430 
431 	s = splimp();
432 	lance_write_reg(chan, CSR1, INIT_BLOCK & 0xffff);
433 	lance_write_reg(chan, CSR2, INIT_BLOCK >> 16);
434 	lance_write_reg(chan, CSR3, CSR_BSWP|CSR_BCON);
435 
436 	lance_write_reg(chan, CSR0, CSR_INEA|CSR_STRT|CSR_INIT);
437 	(void) splx(s);
438 
439 	while ((lance->lance_flags & LANCE_IDON) == 0)
440 		;
441 }
442 
443 recv_error(lance, rmd)
444 	register Lance_chan *lance;
445 	register recv_msg_desc *rmd;
446 {
447 	register int status = rmd->rmd_stat;
448 	register int chan = lance - lancesw;
449 
450 	if (status & RMD_FRAM)
451 		lance->lance_stats.ens_align++;
452 	if (status & RMD_OFLO)
453 		printf("lance %d recv error: overflow\n", chan);
454 	if (status & RMD_CRC)
455 		lance->lance_stats.ens_crc++;
456 	if (status & RMD_BUFF)
457 		printf("lance %d:recv error: buffer\n", chan);
458 }
459 
460 xmit_error(lance, tmd)
461 	register Lance_chan *lance;
462 	register xmit_msg_desc *tmd;
463 {
464 	register int status = tmd->tmd_error;
465 	register int chan = lance - lancesw;
466 
467 	if (status & TMD_BUFF)
468 		printf("lance %d: xmit error: buffer\n", chan);
469 	if (status & TMD_UFLO)
470 		printf("lance %d: xmit error: underflow\n", chan);
471 	if (status & TMD_LCOL) {
472 		printf("lance %d: xmit error: late collision\n", chan);
473 		lance->lance_stats.ens_owcollis++;
474 	}
475 	if (status & TMD_LCAR)
476 		printf("lance %d: xmit error: loss of carrier\n", chan);
477 	if (status & TMD_RTRY) {
478 		printf("lance %d: xmit error: retry tdr=%d\n",
479 		    chan, status & TMD_TDR);
480 		lance->lance_stats.ens_xcollis++;
481 	}
482 }
483 
484 lance_write_reg(chan, reg, data)
485 	int chan, reg, data;
486 {
487 	register Lance_reg *lance = lancesw[chan].lance_addr;
488 	register int s;
489 
490 	s = spl7();
491 	lance->rap = reg;
492 	lance->rdp = data;
493 	(void) splx(s);
494 }
495 
496 lance_read_reg(chan, reg)
497 	int chan, reg;
498 {
499 	register Lance_reg *lance = lancesw[chan].lance_addr;
500 	register int s, d;
501 
502 	s = spl7();
503 	lance->rap = reg;
504 	d = lance->rdp;
505 	(void) splx(s);
506 
507 	return (d);
508 }
509 
510 get_hard_addr(chan, addr)
511 	int chan;
512 	u_short *addr;
513 {
514 	register unsigned char *p, *q;
515 	register int i;
516 	register Lance_chan *lance = &lancesw[chan];
517 	unsigned char hard_addr[6];
518 
519 	p = (unsigned char *)lance->lance_rom + 16;
520 	q = hard_addr;
521 	for (i = 0; i < 6; i++) {
522 		*q = (*p++ & 0xf) << 4;
523 		*q++ |= *p++ & 0xf;
524 	}
525 
526 	bcopy(hard_addr, (char *)addr, 6);
527 }
528 
529 #if defined(mips) && defined(CPU_SINGLE)
530 bxcopy(s, d, n)
531 	caddr_t s, d;
532 	int n;
533 {
534 
535 	if (n <= 0)
536 		return;
537 	switch ((((int)s & 03) << 2) + ((int)d & 03)) {
538 
539 	case 0x0:
540 		blcopy((long *)s, (long *)d, n);
541 		return;
542 
543 	case 0x5:
544 		*(char *)d = *(char *)s;
545 		blcopy((long *)(s + 1), (long *)(d + 1), n - 1);
546 		return;
547 
548 	case 0xa:
549 		switch (n) {
550 
551 		case 1:
552 			*(char *)d = *(char *)s;
553 			return;
554 
555 		case 2:
556 			*(short *)d = *(short *)s;
557 			return;
558 
559 		default:
560 			*(short *)d = *(short *)s;
561 			blcopy((long *)(s + 2), (long *)(d + 2), n - 2);
562 			return;
563 		}
564 
565 	case 0xf:
566 		switch (n) {
567 
568 		case 1:
569 			*(char *)d = *(char *)s;
570 			return;
571 
572 		case 2:
573 			*(char *)d = *(char *)s;
574 			*(char *)(d + 1) = *(char *)(s + 1);
575 			return;
576 
577 		case 3:
578 			*(char *)d = *(char *)s;
579 			*(short *)(d + 1) = *(short *)(s + 1);
580 			return;
581 
582 		default:
583 			*(char *)d = *(char *)s;
584 			*(short *)(d + 1) = *(short *)(s + 1);
585 			blcopy((long *)(s + 3), (long *)(d + 3), n - 3);
586 			return;
587 		}
588 
589 	case 0x7:
590 	case 0xd:
591 		switch (n) {
592 
593 		case 1:
594 			*(char *)d = *(char *)s;
595 			return;
596 
597 		case 2:
598 			*(char *)d = *(char *)s;
599 			*(char *)(d + 1) = *(char *)(s + 1);
600 			return;
601 
602 		default:
603 			*(char *)d = *(char *)s;
604 			bwcopy((short *)(s + 1), (short *)(d + 1), n);
605 			return;
606 		}
607 
608 	case 0x2:
609 	case 0x8:
610 		bwcopy((short *)s, (short *)d, n);
611 		return;
612 
613 	default:
614 		bbcopy((char *)s, (char *)d, n);
615 		return;
616 	}
617 }
618 
619 #define	COPY(s, d, n, t) \
620 	while ((n) >= 8 * sizeof (t)) { \
621 		int t0, t1, t2, t3, t4, t5, t6, t7; \
622 		t0 = (s)[0]; \
623 		t1 = (s)[1]; \
624 		t2 = (s)[2]; \
625 		t3 = (s)[3]; \
626 		t4 = (s)[4]; \
627 		t5 = (s)[5]; \
628 		t6 = (s)[6]; \
629 		t7 = (s)[7]; \
630 		(d)[0] = t0; \
631 		(d)[1] = t1; \
632 		(d)[2] = t2; \
633 		(d)[3] = t3; \
634 		(d)[4] = t4; \
635 		(d)[5] = t5; \
636 		(d)[6] = t6; \
637 		(d)[7] = t7; \
638 		(s) += 8; \
639 		(d) += 8; \
640 		(n) -= 8 * sizeof (t); \
641 	} \
642 	while ((n) >= sizeof (t)) { \
643 		(d)[0] = (s)[0]; \
644 		(s)++; \
645 		(d)++; \
646 		(n) -= sizeof (t); \
647 	}
648 
649 blcopy(s, d, n)
650 	long *s, *d;
651 	int n;
652 {
653 
654 	COPY(s, d, n, long);
655 	switch (n) {
656 
657 	case 0:
658 		return;
659 
660 	case 1:
661 		*(char *)d = *(char *)s;
662 		return;
663 
664 	case 2:
665 		*(short *)d = *(short *)s;
666 		return;
667 
668 	case 3:
669 		*(short *)d = *(short *)s;
670 		*((char *)d + 2) = *((char *)s + 2);
671 		return;
672 	}
673 }
674 
675 bwcopy(s, d, n)
676 	short *s, *d;
677 	int n;
678 {
679 
680 	COPY(s, d, n, short);
681 	if (n == 1)
682 		*(char *)d = *(char *)s;
683 }
684 
685 bbcopy(s, d, n)
686 	char *s, *d;
687 	int n;
688 {
689 
690 	COPY(s, d, n, char);
691 }
692 #endif /* defined(mips) && defined(CPU_SINGLE) */
693 
694 #endif /* NEN > 0 */
695