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
lance_probe(chan)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
lance_open(chan)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
lance_close(chan)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
get_recv_buffer(chan)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
get_recv_length(chan)250 get_recv_length(chan)
251 int chan;
252 {
253
254 return (RECV_CNT(lancesw[chan].lance_last_rmd));
255 }
256
free_recv_buffer(chan)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
get_xmit_buffer(chan)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
lance_transmit(chan,count)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
lance_xmit_error(chan)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
lance_collision(chan)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
lance_get_addr(chan,addr)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
lance_prom_mode(chan,cmd)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
lance_get_status(chan,addr)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
lance_intr()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
lance_init(chan)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
recv_error(lance,rmd)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
xmit_error(lance,tmd)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
lance_write_reg(chan,reg,data)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
lance_read_reg(chan,reg)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
get_hard_addr(chan,addr)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)
bxcopy(s,d,n)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
blcopy(s,d,n)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
bwcopy(s,d,n)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
bbcopy(s,d,n)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