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