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