1 /* $NetBSD: am79900.c,v 1.10 2001/07/07 15:53:16 thorpej Exp $ */ 2 3 /*- 4 * Copyright (c) 1998 5 * Matthias Drochner. All rights reserved. 6 * Copyright (c) 1997 Jason R. Thorpe. All rights reserved. 7 * Copyright (c) 1995 Charles M. Hannum. All rights reserved. 8 * Copyright (c) 1992, 1993 9 * The Regents of the University of California. All rights reserved. 10 * 11 * This code is derived from software contributed to Berkeley by 12 * Ralph Campbell and Rick Macklem. 13 * 14 * Redistribution and use in source and binary forms, with or without 15 * modification, are permitted provided that the following conditions 16 * are met: 17 * 1. Redistributions of source code must retain the above copyright 18 * notice, this list of conditions and the following disclaimer. 19 * 2. Redistributions in binary form must reproduce the above copyright 20 * notice, this list of conditions and the following disclaimer in the 21 * documentation and/or other materials provided with the distribution. 22 * 3. All advertising materials mentioning features or use of this software 23 * must display the following acknowledgement: 24 * This product includes software developed by the University of 25 * California, Berkeley and its contributors. 26 * 4. Neither the name of the University nor the names of its contributors 27 * may be used to endorse or promote products derived from this software 28 * without specific prior written permission. 29 * 30 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 31 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 32 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 33 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 34 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 35 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 36 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 37 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 38 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 39 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 40 * SUCH DAMAGE. 41 * 42 * @(#)if_le.c 8.2 (Berkeley) 11/16/93 43 */ 44 45 #include "bpfilter.h" 46 #include "rnd.h" 47 48 #include <sys/param.h> 49 #include <sys/systm.h> 50 #include <sys/mbuf.h> 51 #include <sys/syslog.h> 52 #include <sys/socket.h> 53 #include <sys/device.h> 54 #include <sys/malloc.h> 55 #include <sys/ioctl.h> 56 #include <sys/errno.h> 57 #if NRND > 0 58 #include <sys/rnd.h> 59 #endif 60 61 #include <net/if.h> 62 #include <net/if_dl.h> 63 #include <net/if_ether.h> 64 #include <net/if_media.h> 65 66 #if NBPFILTER > 0 67 #include <net/bpf.h> 68 #include <net/bpfdesc.h> 69 #endif 70 71 #include <dev/ic/lancereg.h> 72 #include <dev/ic/lancevar.h> 73 #include <dev/ic/am79900reg.h> 74 #include <dev/ic/am79900var.h> 75 76 void am79900_meminit __P((struct lance_softc *)); 77 void am79900_start __P((struct ifnet *)); 78 79 #if defined(_KERNEL_OPT) 80 #include "opt_ddb.h" 81 #endif 82 83 #ifdef DDB 84 #define integrate 85 #define hide 86 #else 87 #define integrate static __inline 88 #define hide static 89 #endif 90 91 integrate void am79900_rint __P((struct lance_softc *)); 92 integrate void am79900_tint __P((struct lance_softc *)); 93 94 #ifdef LEDEBUG 95 void am79900_recv_print __P((struct lance_softc *, int)); 96 void am79900_xmit_print __P((struct lance_softc *, int)); 97 #endif 98 99 #define ifp (&sc->sc_ethercom.ec_if) 100 101 void 102 am79900_config(sc) 103 struct am79900_softc *sc; 104 { 105 int mem, i; 106 107 sc->lsc.sc_meminit = am79900_meminit; 108 sc->lsc.sc_start = am79900_start; 109 110 lance_config(&sc->lsc); 111 112 mem = 0; 113 sc->lsc.sc_initaddr = mem; 114 mem += sizeof(struct leinit); 115 sc->lsc.sc_rmdaddr = mem; 116 mem += sizeof(struct lermd) * sc->lsc.sc_nrbuf; 117 sc->lsc.sc_tmdaddr = mem; 118 mem += sizeof(struct letmd) * sc->lsc.sc_ntbuf; 119 for (i = 0; i < sc->lsc.sc_nrbuf; i++, mem += LEBLEN) 120 sc->lsc.sc_rbufaddr[i] = mem; 121 for (i = 0; i < sc->lsc.sc_ntbuf; i++, mem += LEBLEN) 122 sc->lsc.sc_tbufaddr[i] = mem; 123 124 if (mem > sc->lsc.sc_memsize) 125 panic("%s: memsize", sc->lsc.sc_dev.dv_xname); 126 } 127 128 /* 129 * Set up the initialization block and the descriptor rings. 130 */ 131 void 132 am79900_meminit(sc) 133 struct lance_softc *sc; 134 { 135 u_long a; 136 int bix; 137 struct leinit init; 138 struct lermd rmd; 139 struct letmd tmd; 140 u_int8_t *myaddr; 141 142 #if NBPFILTER > 0 143 if (ifp->if_flags & IFF_PROMISC) 144 init.init_mode = LE_MODE_NORMAL | LE_MODE_PROM; 145 else 146 #endif 147 init.init_mode = LE_MODE_NORMAL; 148 if (sc->sc_initmodemedia == 1) 149 init.init_mode |= LE_MODE_PSEL0; 150 151 init.init_mode |= ((ffs(sc->sc_ntbuf) - 1) << 28) 152 | ((ffs(sc->sc_nrbuf) - 1) << 20); 153 154 /* 155 * Update our private copy of the Ethernet address. 156 * We NEED the copy so we can ensure its alignment! 157 */ 158 memcpy(sc->sc_enaddr, LLADDR(ifp->if_sadl), ETHER_ADDR_LEN); 159 myaddr = sc->sc_enaddr; 160 161 init.init_padr[0] = myaddr[0] | (myaddr[1] << 8) 162 | (myaddr[2] << 16) | (myaddr[3] << 24); 163 init.init_padr[1] = myaddr[4] | (myaddr[5] << 8); 164 lance_setladrf(&sc->sc_ethercom, init.init_ladrf); 165 166 sc->sc_last_rd = 0; 167 sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0; 168 169 a = sc->sc_addr + LE_RMDADDR(sc, 0); 170 init.init_rdra = a; 171 172 a = sc->sc_addr + LE_TMDADDR(sc, 0); 173 init.init_tdra = a; 174 175 (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init)); 176 177 /* 178 * Set up receive ring descriptors. 179 */ 180 for (bix = 0; bix < sc->sc_nrbuf; bix++) { 181 a = sc->sc_addr + LE_RBUFADDR(sc, bix); 182 rmd.rmd0 = a; 183 rmd.rmd1 = LE_R1_OWN | LE_R1_ONES | (-LEBLEN & 0xfff); 184 rmd.rmd2 = 0; 185 rmd.rmd3 = 0; 186 (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix), 187 sizeof(rmd)); 188 } 189 190 /* 191 * Set up transmit ring descriptors. 192 */ 193 for (bix = 0; bix < sc->sc_ntbuf; bix++) { 194 a = sc->sc_addr + LE_TBUFADDR(sc, bix); 195 tmd.tmd0 = a; 196 tmd.tmd1 = LE_T1_ONES; 197 tmd.tmd2 = 0; 198 tmd.tmd3 = 0; 199 (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix), 200 sizeof(tmd)); 201 } 202 } 203 204 integrate void 205 am79900_rint(sc) 206 struct lance_softc *sc; 207 { 208 int bix; 209 int rp; 210 struct lermd rmd; 211 212 bix = sc->sc_last_rd; 213 214 /* Process all buffers with valid data. */ 215 for (;;) { 216 rp = LE_RMDADDR(sc, bix); 217 (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd)); 218 219 if (rmd.rmd1 & LE_R1_OWN) 220 break; 221 222 if (rmd.rmd1 & LE_R1_ERR) { 223 if (rmd.rmd1 & LE_R1_ENP) { 224 #ifdef LEDEBUG 225 if ((rmd.rmd1 & LE_R1_OFLO) == 0) { 226 if (rmd.rmd1 & LE_R1_FRAM) 227 printf("%s: framing error\n", 228 sc->sc_dev.dv_xname); 229 if (rmd.rmd1 & LE_R1_CRC) 230 printf("%s: crc mismatch\n", 231 sc->sc_dev.dv_xname); 232 } 233 #endif 234 } else { 235 if (rmd.rmd1 & LE_R1_OFLO) 236 printf("%s: overflow\n", 237 sc->sc_dev.dv_xname); 238 } 239 if (rmd.rmd1 & LE_R1_BUFF) 240 printf("%s: receive buffer error\n", 241 sc->sc_dev.dv_xname); 242 ifp->if_ierrors++; 243 } else if ((rmd.rmd1 & (LE_R1_STP | LE_R1_ENP)) != 244 (LE_R1_STP | LE_R1_ENP)) { 245 printf("%s: dropping chained buffer\n", 246 sc->sc_dev.dv_xname); 247 ifp->if_ierrors++; 248 } else { 249 #ifdef LEDEBUG 250 if (sc->sc_debug) 251 am79900_recv_print(sc, sc->sc_last_rd); 252 #endif 253 lance_read(sc, LE_RBUFADDR(sc, bix), 254 (rmd.rmd2 & 0xfff) - 4); 255 } 256 257 rmd.rmd1 = LE_R1_OWN | LE_R1_ONES | (-LEBLEN & 0xfff); 258 rmd.rmd2 = 0; 259 rmd.rmd3 = 0; 260 (*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd)); 261 262 #ifdef LEDEBUG 263 if (sc->sc_debug) 264 printf("sc->sc_last_rd = %x, rmd: " 265 "adr %08x, flags/blen %08x\n", 266 sc->sc_last_rd, 267 rmd.rmd0, rmd.rmd1); 268 #endif 269 270 if (++bix == sc->sc_nrbuf) 271 bix = 0; 272 } 273 274 sc->sc_last_rd = bix; 275 } 276 277 integrate void 278 am79900_tint(sc) 279 struct lance_softc *sc; 280 { 281 int bix; 282 struct letmd tmd; 283 284 bix = sc->sc_first_td; 285 286 for (;;) { 287 if (sc->sc_no_td <= 0) 288 break; 289 290 (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix), 291 sizeof(tmd)); 292 293 #ifdef LEDEBUG 294 if (sc->sc_debug) 295 printf("trans tmd: " 296 "adr %08x, flags/blen %08x\n", 297 tmd.tmd0, tmd.tmd1); 298 #endif 299 300 if (tmd.tmd1 & LE_T1_OWN) 301 break; 302 303 ifp->if_flags &= ~IFF_OACTIVE; 304 305 if (tmd.tmd1 & LE_T1_ERR) { 306 if (tmd.tmd2 & LE_T2_BUFF) 307 printf("%s: transmit buffer error\n", 308 sc->sc_dev.dv_xname); 309 else if (tmd.tmd2 & LE_T2_UFLO) 310 printf("%s: underflow\n", sc->sc_dev.dv_xname); 311 if (tmd.tmd2 & (LE_T2_BUFF | LE_T2_UFLO)) { 312 lance_reset(sc); 313 return; 314 } 315 if (tmd.tmd2 & LE_T2_LCAR) { 316 sc->sc_havecarrier = 0; 317 if (sc->sc_nocarrier) 318 (*sc->sc_nocarrier)(sc); 319 else 320 printf("%s: lost carrier\n", 321 sc->sc_dev.dv_xname); 322 } 323 if (tmd.tmd2 & LE_T2_LCOL) 324 ifp->if_collisions++; 325 if (tmd.tmd2 & LE_T2_RTRY) { 326 #ifdef LEDEBUG 327 printf("%s: excessive collisions\n", 328 sc->sc_dev.dv_xname); 329 #endif 330 ifp->if_collisions += 16; 331 } 332 ifp->if_oerrors++; 333 } else { 334 if (tmd.tmd1 & LE_T1_ONE) 335 ifp->if_collisions++; 336 else if (tmd.tmd1 & LE_T1_MORE) 337 /* Real number is unknown. */ 338 ifp->if_collisions += 2; 339 ifp->if_opackets++; 340 } 341 342 if (++bix == sc->sc_ntbuf) 343 bix = 0; 344 345 --sc->sc_no_td; 346 } 347 348 sc->sc_first_td = bix; 349 350 am79900_start(ifp); 351 352 if (sc->sc_no_td == 0) 353 ifp->if_timer = 0; 354 } 355 356 /* 357 * Controller interrupt. 358 */ 359 int 360 am79900_intr(arg) 361 void *arg; 362 { 363 struct lance_softc *sc = arg; 364 u_int16_t isr; 365 366 isr = (*sc->sc_rdcsr)(sc, LE_CSR0) | sc->sc_saved_csr0; 367 sc->sc_saved_csr0 = 0; 368 #if defined(LEDEBUG) && LEDEBUG > 1 369 if (sc->sc_debug) 370 printf("%s: am79900_intr entering with isr=%04x\n", 371 sc->sc_dev.dv_xname, isr); 372 #endif 373 if ((isr & LE_C0_INTR) == 0) 374 return (0); 375 376 (*sc->sc_wrcsr)(sc, LE_CSR0, 377 isr & (LE_C0_INEA | LE_C0_BABL | LE_C0_MISS | LE_C0_MERR | 378 LE_C0_RINT | LE_C0_TINT | LE_C0_IDON)); 379 if (isr & LE_C0_ERR) { 380 if (isr & LE_C0_BABL) { 381 #ifdef LEDEBUG 382 printf("%s: babble\n", sc->sc_dev.dv_xname); 383 #endif 384 ifp->if_oerrors++; 385 } 386 #if 0 387 if (isr & LE_C0_CERR) { 388 printf("%s: collision error\n", sc->sc_dev.dv_xname); 389 ifp->if_collisions++; 390 } 391 #endif 392 if (isr & LE_C0_MISS) { 393 #ifdef LEDEBUG 394 printf("%s: missed packet\n", sc->sc_dev.dv_xname); 395 #endif 396 ifp->if_ierrors++; 397 } 398 if (isr & LE_C0_MERR) { 399 printf("%s: memory error\n", sc->sc_dev.dv_xname); 400 lance_reset(sc); 401 return (1); 402 } 403 } 404 405 if ((isr & LE_C0_RXON) == 0) { 406 printf("%s: receiver disabled\n", sc->sc_dev.dv_xname); 407 ifp->if_ierrors++; 408 lance_reset(sc); 409 return (1); 410 } 411 if ((isr & LE_C0_TXON) == 0) { 412 printf("%s: transmitter disabled\n", sc->sc_dev.dv_xname); 413 ifp->if_oerrors++; 414 lance_reset(sc); 415 return (1); 416 } 417 418 /* 419 * Pretend we have carrier; if we don't this will be cleared 420 * shortly. 421 */ 422 sc->sc_havecarrier = 1; 423 424 if (isr & LE_C0_RINT) 425 am79900_rint(sc); 426 if (isr & LE_C0_TINT) 427 am79900_tint(sc); 428 429 #if NRND > 0 430 rnd_add_uint32(&sc->rnd_source, isr); 431 #endif 432 433 return (1); 434 } 435 436 #undef ifp 437 438 /* 439 * Setup output on interface. 440 * Get another datagram to send off of the interface queue, and map it to the 441 * interface before starting the output. 442 * Called only at splnet or interrupt level. 443 */ 444 void 445 am79900_start(ifp) 446 struct ifnet *ifp; 447 { 448 struct lance_softc *sc = ifp->if_softc; 449 int bix; 450 struct mbuf *m; 451 struct letmd tmd; 452 int rp; 453 int len; 454 455 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING) 456 return; 457 458 bix = sc->sc_last_td; 459 460 for (;;) { 461 rp = LE_TMDADDR(sc, bix); 462 (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd)); 463 464 if (tmd.tmd1 & LE_T1_OWN) { 465 ifp->if_flags |= IFF_OACTIVE; 466 printf("missing buffer, no_td = %d, last_td = %d\n", 467 sc->sc_no_td, sc->sc_last_td); 468 } 469 470 IFQ_DEQUEUE(&ifp->if_snd, m); 471 if (m == 0) 472 break; 473 474 #if NBPFILTER > 0 475 /* 476 * If BPF is listening on this interface, let it see the packet 477 * before we commit it to the wire. 478 */ 479 if (ifp->if_bpf) 480 bpf_mtap(ifp->if_bpf, m); 481 #endif 482 483 /* 484 * Copy the mbuf chain into the transmit buffer. 485 */ 486 len = lance_put(sc, LE_TBUFADDR(sc, bix), m); 487 488 #ifdef LEDEBUG 489 if (len > ETHERMTU + sizeof(struct ether_header)) 490 printf("packet length %d\n", len); 491 #endif 492 493 ifp->if_timer = 5; 494 495 /* 496 * Init transmit registers, and set transmit start flag. 497 */ 498 tmd.tmd1 = LE_T1_OWN | LE_T1_STP | LE_T1_ENP | LE_T1_ONES | (-len & 0xfff); 499 tmd.tmd2 = 0; 500 tmd.tmd3 = 0; 501 502 (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd)); 503 504 #ifdef LEDEBUG 505 if (sc->sc_debug) 506 am79900_xmit_print(sc, sc->sc_last_td); 507 #endif 508 509 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD); 510 511 if (++bix == sc->sc_ntbuf) 512 bix = 0; 513 514 if (++sc->sc_no_td == sc->sc_ntbuf) { 515 ifp->if_flags |= IFF_OACTIVE; 516 break; 517 } 518 519 } 520 521 sc->sc_last_td = bix; 522 } 523 524 #ifdef LEDEBUG 525 void 526 am79900_recv_print(sc, no) 527 struct lance_softc *sc; 528 int no; 529 { 530 struct lermd rmd; 531 u_int16_t len; 532 struct ether_header eh; 533 534 (*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd)); 535 len = (rmd.rmd2 & 0xfff) - 4; 536 printf("%s: receive buffer %d, len = %d\n", sc->sc_dev.dv_xname, no, 537 len); 538 printf("%s: status %04x\n", sc->sc_dev.dv_xname, 539 (*sc->sc_rdcsr)(sc, LE_CSR0)); 540 printf("%s: adr %08x, flags/blen %08x\n", 541 sc->sc_dev.dv_xname, rmd.rmd0, rmd.rmd1); 542 if (len >= sizeof(eh)) { 543 (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh)); 544 printf("%s: dst %s", sc->sc_dev.dv_xname, 545 ether_sprintf(eh.ether_dhost)); 546 printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost), 547 ntohs(eh.ether_type)); 548 } 549 } 550 551 void 552 am79900_xmit_print(sc, no) 553 struct lance_softc *sc; 554 int no; 555 { 556 struct letmd tmd; 557 u_int16_t len; 558 struct ether_header eh; 559 560 (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd)); 561 len = -(tmd.tmd1 & 0xfff); 562 printf("%s: transmit buffer %d, len = %d\n", sc->sc_dev.dv_xname, no, 563 len); 564 printf("%s: status %04x\n", sc->sc_dev.dv_xname, 565 (*sc->sc_rdcsr)(sc, LE_CSR0)); 566 printf("%s: adr %08x, flags/blen %08x\n", 567 sc->sc_dev.dv_xname, tmd.tmd0, tmd.tmd1); 568 if (len >= sizeof(eh)) { 569 (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh)); 570 printf("%s: dst %s", sc->sc_dev.dv_xname, 571 ether_sprintf(eh.ether_dhost)); 572 printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost), 573 ntohs(eh.ether_type)); 574 } 575 } 576 #endif /* LEDEBUG */ 577