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