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