1 /* $NetBSD: am7990.c,v 1.84 2022/09/25 18:43:32 thorpej 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.84 2022/09/25 18:43:32 thorpej 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/ioctl.h> 77 #include <sys/errno.h> 78 #include <sys/rndsource.h> 79 80 #include <net/if.h> 81 #include <net/if_dl.h> 82 #include <net/if_ether.h> 83 #include <net/if_media.h> 84 #include <net/bpf.h> 85 86 #include <dev/ic/lancereg.h> 87 #include <dev/ic/lancevar.h> 88 #include <dev/ic/am7990reg.h> 89 #include <dev/ic/am7990var.h> 90 91 static void am7990_meminit(struct lance_softc *); 92 static void am7990_start(struct ifnet *); 93 94 #if defined(_KERNEL_OPT) 95 #include "opt_ddb.h" 96 #endif 97 98 #ifdef LEDEBUG 99 static void am7990_recv_print(struct lance_softc *, int); 100 static void am7990_xmit_print(struct lance_softc *, int); 101 #endif 102 103 #define ifp (&sc->sc_ethercom.ec_if) 104 105 void 106 am7990_config(struct am7990_softc *sc) 107 { 108 int mem, i; 109 110 sc->lsc.sc_meminit = am7990_meminit; 111 sc->lsc.sc_start = am7990_start; 112 113 lance_config(&sc->lsc); 114 if_deferred_start_init(&sc->lsc.sc_ethercom.ec_if, NULL); 115 116 mem = 0; 117 sc->lsc.sc_initaddr = mem; 118 mem += sizeof(struct leinit); 119 sc->lsc.sc_rmdaddr = mem; 120 mem += sizeof(struct lermd) * sc->lsc.sc_nrbuf; 121 sc->lsc.sc_tmdaddr = mem; 122 mem += sizeof(struct letmd) * sc->lsc.sc_ntbuf; 123 for (i = 0; i < sc->lsc.sc_nrbuf; i++, mem += LEBLEN) 124 sc->lsc.sc_rbufaddr[i] = mem; 125 for (i = 0; i < sc->lsc.sc_ntbuf; i++, mem += LEBLEN) 126 sc->lsc.sc_tbufaddr[i] = mem; 127 #ifdef notyet 128 if (mem > ...) 129 panic(...); 130 #endif 131 } 132 133 /* 134 * Set up the initialization block and the descriptor rings. 135 */ 136 static void 137 am7990_meminit(struct lance_softc *sc) 138 { 139 u_long a; 140 int bix; 141 struct leinit init; 142 struct lermd rmd; 143 struct letmd tmd; 144 uint8_t *myaddr; 145 146 if (ifp->if_flags & IFF_PROMISC) 147 init.init_mode = LE_MODE_NORMAL | LE_MODE_PROM; 148 else 149 init.init_mode = LE_MODE_NORMAL; 150 if (sc->sc_initmodemedia == 1) 151 init.init_mode |= LE_MODE_PSEL0; 152 153 /* 154 * Update our private copy of the Ethernet address. 155 * We NEED the copy so we can ensure its alignment! 156 */ 157 memcpy(sc->sc_enaddr, CLLADDR(ifp->if_sadl), ETHER_ADDR_LEN); 158 myaddr = sc->sc_enaddr; 159 160 init.init_padr[0] = (myaddr[1] << 8) | myaddr[0]; 161 init.init_padr[1] = (myaddr[3] << 8) | myaddr[2]; 162 init.init_padr[2] = (myaddr[5] << 8) | myaddr[4]; 163 lance_setladrf(&sc->sc_ethercom, init.init_ladrf); 164 165 sc->sc_last_rd = 0; 166 sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0; 167 168 a = sc->sc_addr + LE_RMDADDR(sc, 0); 169 init.init_rdra = a; 170 init.init_rlen = (a >> 16) | ((ffs(sc->sc_nrbuf) - 1) << 13); 171 172 a = sc->sc_addr + LE_TMDADDR(sc, 0); 173 init.init_tdra = a; 174 init.init_tlen = (a >> 16) | ((ffs(sc->sc_ntbuf) - 1) << 13); 175 176 (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init)); 177 178 /* 179 * Set up receive ring descriptors. 180 */ 181 for (bix = 0; bix < sc->sc_nrbuf; bix++) { 182 a = sc->sc_addr + LE_RBUFADDR(sc, bix); 183 rmd.rmd0 = a; 184 rmd.rmd1_hadr = a >> 16; 185 rmd.rmd1_bits = LE_R1_OWN; 186 rmd.rmd2 = -LEBLEN | LE_XMD2_ONES; 187 rmd.rmd3 = 0; 188 (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix), 189 sizeof(rmd)); 190 } 191 192 /* 193 * Set up transmit ring descriptors. 194 */ 195 for (bix = 0; bix < sc->sc_ntbuf; bix++) { 196 a = sc->sc_addr + LE_TBUFADDR(sc, bix); 197 tmd.tmd0 = a; 198 tmd.tmd1_hadr = a >> 16; 199 tmd.tmd1_bits = 0; 200 tmd.tmd2 = 0 | LE_XMD2_ONES; 201 tmd.tmd3 = 0; 202 (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix), 203 sizeof(tmd)); 204 } 205 } 206 207 static void 208 am7990_rint(struct lance_softc *sc) 209 { 210 int bix; 211 int rp; 212 struct lermd rmd; 213 214 bix = sc->sc_last_rd; 215 216 /* Process all buffers with valid data. */ 217 for (;;) { 218 rp = LE_RMDADDR(sc, bix); 219 (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd)); 220 221 if (rmd.rmd1_bits & LE_R1_OWN) 222 break; 223 224 if (rmd.rmd1_bits & LE_R1_ERR) { 225 if (rmd.rmd1_bits & LE_R1_ENP) { 226 #ifdef LEDEBUG 227 if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) { 228 if (rmd.rmd1_bits & LE_R1_FRAM) 229 printf("%s: framing error\n", 230 device_xname(sc->sc_dev)); 231 if (rmd.rmd1_bits & LE_R1_CRC) 232 printf("%s: crc mismatch\n", 233 device_xname(sc->sc_dev)); 234 } 235 #endif 236 } else { 237 if (rmd.rmd1_bits & LE_R1_OFLO) 238 printf("%s: overflow\n", 239 device_xname(sc->sc_dev)); 240 } 241 if (rmd.rmd1_bits & LE_R1_BUFF) 242 printf("%s: receive buffer error\n", 243 device_xname(sc->sc_dev)); 244 if_statinc(ifp, if_ierrors); 245 } else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) != 246 (LE_R1_STP | LE_R1_ENP)) { 247 printf("%s: dropping chained buffer\n", 248 device_xname(sc->sc_dev)); 249 if_statinc(ifp, if_ierrors); 250 } else { 251 #ifdef LEDEBUG 252 if (sc->sc_debug > 1) 253 am7990_recv_print(sc, sc->sc_last_rd); 254 #endif 255 lance_read(sc, LE_RBUFADDR(sc, bix), 256 (int)rmd.rmd3 - 4); 257 } 258 259 rmd.rmd1_bits = LE_R1_OWN; 260 rmd.rmd2 = -LEBLEN | LE_XMD2_ONES; 261 rmd.rmd3 = 0; 262 (*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd)); 263 264 #ifdef LEDEBUG 265 if (sc->sc_debug) 266 printf("sc->sc_last_rd = %x, rmd: " 267 "ladr %04x, hadr %02x, flags %02x, " 268 "bcnt %04x, mcnt %04x\n", 269 sc->sc_last_rd, 270 rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, 271 rmd.rmd2, rmd.rmd3); 272 #endif 273 274 if (++bix == sc->sc_nrbuf) 275 bix = 0; 276 } 277 278 sc->sc_last_rd = bix; 279 } 280 281 static void 282 am7990_tint(struct lance_softc *sc) 283 { 284 int bix; 285 struct letmd tmd; 286 287 bix = sc->sc_first_td; 288 289 for (;;) { 290 if (sc->sc_no_td <= 0) 291 break; 292 293 (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix), 294 sizeof(tmd)); 295 296 #ifdef LEDEBUG 297 if (sc->sc_debug) 298 printf("trans tmd: " 299 "ladr %04x, hadr %02x, flags %02x, " 300 "bcnt %04x, mcnt %04x\n", 301 tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, 302 tmd.tmd2, tmd.tmd3); 303 #endif 304 305 if (tmd.tmd1_bits & LE_T1_OWN) 306 break; 307 308 if (tmd.tmd1_bits & LE_T1_ERR) { 309 if (tmd.tmd3 & LE_T3_BUFF) 310 printf("%s: transmit buffer error\n", 311 device_xname(sc->sc_dev)); 312 else if (tmd.tmd3 & LE_T3_UFLO) 313 printf("%s: underflow\n", 314 device_xname(sc->sc_dev)); 315 if (tmd.tmd3 & (LE_T3_BUFF | LE_T3_UFLO)) { 316 lance_reset(sc); 317 return; 318 } 319 if (tmd.tmd3 & LE_T3_LCAR) { 320 sc->sc_havecarrier = 0; 321 if (sc->sc_nocarrier) 322 (*sc->sc_nocarrier)(sc); 323 else 324 printf("%s: lost carrier\n", 325 device_xname(sc->sc_dev)); 326 } 327 if (tmd.tmd3 & LE_T3_LCOL) 328 if_statinc(ifp, if_collisions); 329 if (tmd.tmd3 & LE_T3_RTRY) { 330 #ifdef LEDEBUG 331 printf("%s: excessive collisions, tdr %d\n", 332 device_xname(sc->sc_dev), 333 tmd.tmd3 & LE_T3_TDR_MASK); 334 #endif 335 if_statadd(ifp, if_collisions, 16); 336 } 337 if_statinc(ifp, if_oerrors); 338 } else { 339 if (tmd.tmd1_bits & LE_T1_ONE) 340 if_statinc(ifp, if_collisions); 341 else if (tmd.tmd1_bits & LE_T1_MORE) 342 /* Real number is unknown. */ 343 if_statadd(ifp, if_collisions, 2); 344 if_statinc(ifp, if_opackets); 345 } 346 347 if (++bix == sc->sc_ntbuf) 348 bix = 0; 349 350 --sc->sc_no_td; 351 } 352 353 sc->sc_first_td = bix; 354 355 if_schedule_deferred_start(ifp); 356 357 if (sc->sc_no_td == 0) 358 ifp->if_timer = 0; 359 } 360 361 /* 362 * Controller interrupt. 363 */ 364 int 365 am7990_intr(void *arg) 366 { 367 struct lance_softc *sc = arg; 368 uint16_t isr; 369 370 isr = (*sc->sc_rdcsr)(sc, LE_CSR0) | sc->sc_saved_csr0; 371 sc->sc_saved_csr0 = 0; 372 #if defined(LEDEBUG) && LEDEBUG > 1 373 if (sc->sc_debug) 374 printf("%s: am7990_intr entering with isr=%04x\n", 375 device_xname(sc->sc_dev), isr); 376 #endif 377 if ((isr & LE_C0_INTR) == 0) 378 return (0); 379 380 #ifdef __vax__ 381 /* 382 * DEC needs this write order to the registers, don't know 383 * the results on other arch's. Ragge 991029 384 */ 385 isr &= ~LE_C0_INEA; 386 (*sc->sc_wrcsr)(sc, LE_CSR0, isr); 387 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA); 388 #else 389 (*sc->sc_wrcsr)(sc, LE_CSR0, 390 isr & (LE_C0_INEA | LE_C0_BABL | LE_C0_MISS | LE_C0_MERR | 391 LE_C0_RINT | LE_C0_TINT | LE_C0_IDON)); 392 #endif 393 if (isr & LE_C0_ERR) { 394 if (isr & LE_C0_BABL) { 395 #ifdef LEDEBUG 396 printf("%s: babble\n", device_xname(sc->sc_dev)); 397 #endif 398 if_statinc(ifp, if_oerrors); 399 } 400 #if 0 401 if (isr & LE_C0_CERR) { 402 printf("%s: collision error\n", 403 device_xname(sc->sc_dev)); 404 if_statinc(ifp, if_collisions); 405 } 406 #endif 407 if (isr & LE_C0_MISS) { 408 #ifdef LEDEBUG 409 printf("%s: missed packet\n", device_xname(sc->sc_dev)); 410 #endif 411 if_statinc(ifp, if_ierrors); 412 } 413 if (isr & LE_C0_MERR) { 414 printf("%s: memory error\n", device_xname(sc->sc_dev)); 415 lance_reset(sc); 416 return (1); 417 } 418 } 419 420 if ((isr & LE_C0_RXON) == 0) { 421 printf("%s: receiver disabled\n", device_xname(sc->sc_dev)); 422 if_statinc(ifp, if_ierrors); 423 lance_reset(sc); 424 return (1); 425 } 426 if ((isr & LE_C0_TXON) == 0) { 427 printf("%s: transmitter disabled\n", device_xname(sc->sc_dev)); 428 if_statinc(ifp, if_oerrors); 429 lance_reset(sc); 430 return (1); 431 } 432 433 /* 434 * Pretend we have carrier; if we don't this will be cleared 435 * shortly. 436 */ 437 const int ocarrier = sc->sc_havecarrier; 438 sc->sc_havecarrier = 1; 439 440 if (isr & LE_C0_RINT) 441 am7990_rint(sc); 442 if (isr & LE_C0_TINT) 443 am7990_tint(sc); 444 445 if (sc->sc_havecarrier != ocarrier) 446 if_link_state_change(ifp, 447 sc->sc_havecarrier ? LINK_STATE_UP : LINK_STATE_DOWN); 448 449 rnd_add_uint32(&sc->rnd_source, isr); 450 451 return (1); 452 } 453 454 #undef ifp 455 456 /* 457 * Setup output on interface. 458 * Get another datagram to send off of the interface queue, and map it to the 459 * interface before starting the output. 460 * Called only at splnet or interrupt level. 461 */ 462 static void 463 am7990_start(struct ifnet *ifp) 464 { 465 struct lance_softc *sc = ifp->if_softc; 466 int bix; 467 struct mbuf *m; 468 struct letmd tmd; 469 int rp; 470 int len; 471 472 if ((ifp->if_flags & IFF_RUNNING) != IFF_RUNNING) 473 return; 474 475 bix = sc->sc_last_td; 476 477 while (sc->sc_no_td < sc->sc_ntbuf) { 478 rp = LE_TMDADDR(sc, bix); 479 (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd)); 480 481 if (tmd.tmd1_bits & LE_T1_OWN) { 482 printf("%s: missing buffer, no_td = %d, last_td = %d\n", 483 device_xname(sc->sc_dev), sc->sc_no_td, 484 sc->sc_last_td); 485 break; 486 } 487 488 IFQ_DEQUEUE(&ifp->if_snd, m); 489 if (m == NULL) 490 break; 491 492 /* 493 * If BPF is listening on this interface, let it see the packet 494 * before we commit it to the wire. 495 */ 496 bpf_mtap(ifp, m, BPF_D_OUT); 497 498 /* 499 * Copy the mbuf chain into the transmit buffer. 500 */ 501 len = lance_put(sc, LE_TBUFADDR(sc, bix), m); 502 503 #ifdef LEDEBUG 504 if (len > ETHERMTU + sizeof(struct ether_header)) 505 printf("packet length %d\n", len); 506 #endif 507 508 ifp->if_timer = 5; 509 510 /* 511 * Init transmit registers, and set transmit start flag. 512 */ 513 tmd.tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP; 514 tmd.tmd2 = -len | LE_XMD2_ONES; 515 tmd.tmd3 = 0; 516 517 (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd)); 518 519 #ifdef LEDEBUG 520 if (sc->sc_debug > 1) 521 am7990_xmit_print(sc, sc->sc_last_td); 522 #endif 523 524 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD); 525 526 if (++bix == sc->sc_ntbuf) 527 bix = 0; 528 529 sc->sc_no_td++; 530 } 531 532 sc->sc_last_td = bix; 533 } 534 535 #ifdef LEDEBUG 536 static void 537 am7990_recv_print(struct lance_softc *sc, int no) 538 { 539 struct lermd rmd; 540 uint16_t len; 541 struct ether_header eh; 542 543 (*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd)); 544 len = rmd.rmd3; 545 printf("%s: receive buffer %d, len = %d\n", 546 device_xname(sc->sc_dev), no, len); 547 printf("%s: status %04x\n", device_xname(sc->sc_dev), 548 (*sc->sc_rdcsr)(sc, LE_CSR0)); 549 printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n", 550 device_xname(sc->sc_dev), 551 rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, rmd.rmd2, rmd.rmd3); 552 if (len >= sizeof(eh)) { 553 (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh)); 554 printf("%s: dst %s", device_xname(sc->sc_dev), 555 ether_sprintf(eh.ether_dhost)); 556 printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost), 557 ntohs(eh.ether_type)); 558 } 559 } 560 561 static void 562 am7990_xmit_print(struct lance_softc *sc, int no) 563 { 564 struct letmd tmd; 565 uint16_t len; 566 struct ether_header eh; 567 568 (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd)); 569 len = -tmd.tmd2; 570 printf("%s: transmit buffer %d, len = %d\n", 571 device_xname(sc->sc_dev), no, len); 572 printf("%s: status %04x\n", device_xname(sc->sc_dev), 573 (*sc->sc_rdcsr)(sc, LE_CSR0)); 574 printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n", 575 device_xname(sc->sc_dev), 576 tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, tmd.tmd2, tmd.tmd3); 577 if (len >= sizeof(eh)) { 578 (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh)); 579 printf("%s: dst %s", device_xname(sc->sc_dev), 580 ether_sprintf(eh.ether_dhost)); 581 printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost), 582 ntohs(eh.ether_type)); 583 } 584 } 585 #endif /* LEDEBUG */ 586