1 /* $NetBSD: lance.c,v 1.34 2005/12/24 20:27:30 perry Exp $ */ 2 3 /*- 4 * SPDX-License-Identifier: BSD-2-Clause 5 * 6 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc. 7 * All rights reserved. 8 * 9 * This code is derived from software contributed to The NetBSD Foundation 10 * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace 11 * Simulation Facility, NASA Ames Research Center. 12 * 13 * Redistribution and use in source and binary forms, with or without 14 * modification, are permitted provided that the following conditions 15 * are met: 16 * 1. Redistributions of source code must retain the above copyright 17 * notice, this list of conditions and the following disclaimer. 18 * 2. Redistributions in binary form must reproduce the above copyright 19 * notice, this list of conditions and the following disclaimer in the 20 * documentation and/or other materials provided with the distribution. 21 * 22 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS 23 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED 24 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 25 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS 26 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 27 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 28 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 29 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 30 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 31 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 32 * POSSIBILITY OF SUCH DAMAGE. 33 */ 34 35 /*- 36 * Copyright (c) 1992, 1993 37 * The Regents of the University of California. All rights reserved. 38 * 39 * This code is derived from software contributed to Berkeley by 40 * Ralph Campbell and Rick Macklem. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 3. Neither the name of the University nor the names of its contributors 51 * may be used to endorse or promote products derived from this software 52 * without specific prior written permission. 53 * 54 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 55 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 56 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 57 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 58 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 59 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 60 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 61 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 62 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 63 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 64 * SUCH DAMAGE. 65 */ 66 67 #include <sys/cdefs.h> 68 #include <sys/param.h> 69 #include <sys/bus.h> 70 #include <sys/endian.h> 71 #include <sys/lock.h> 72 #include <sys/kernel.h> 73 #include <sys/malloc.h> 74 #include <sys/mbuf.h> 75 #include <sys/mutex.h> 76 #include <sys/socket.h> 77 #include <sys/sockio.h> 78 79 #include <net/ethernet.h> 80 #include <net/if.h> 81 #include <net/if_var.h> 82 #include <net/if_arp.h> 83 #include <net/if_dl.h> 84 #include <net/if_media.h> 85 #include <net/if_types.h> 86 #include <net/if_vlan_var.h> 87 88 #include <machine/bus.h> 89 90 #include <dev/le/lancereg.h> 91 #include <dev/le/lancevar.h> 92 93 static void lance_start(if_t); 94 static void lance_stop(struct lance_softc *); 95 static void lance_init(void *); 96 static void lance_watchdog(void *s); 97 static int lance_mediachange(if_t); 98 static void lance_mediastatus(if_t, struct ifmediareq *); 99 static int lance_ioctl(if_t, u_long, caddr_t); 100 101 int 102 lance_config(struct lance_softc *sc, const char* name, int unit) 103 { 104 if_t ifp; 105 int i, nbuf; 106 107 if (LE_LOCK_INITIALIZED(sc) == 0) 108 return (ENXIO); 109 110 ifp = sc->sc_ifp = if_alloc(IFT_ETHER); 111 if (ifp == NULL) 112 return (ENOSPC); 113 114 callout_init_mtx(&sc->sc_wdog_ch, &sc->sc_mtx, 0); 115 116 /* Initialize ifnet structure. */ 117 if_setsoftc(ifp, sc); 118 if_initname(ifp, name, unit); 119 if_setstartfn(ifp, lance_start); 120 if_setioctlfn(ifp, lance_ioctl); 121 if_setinitfn(ifp, lance_init); 122 if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST); 123 #ifdef LANCE_REVC_BUG 124 if_setflagsbit(ifp, 0, IFF_MULTICAST); 125 #endif 126 if_setbaudrate(ifp, IF_Mbps(10)); 127 if_setsendqlen(ifp, ifqmaxlen); 128 if_setsendqready(ifp); 129 130 /* Initialize ifmedia structures. */ 131 ifmedia_init(&sc->sc_media, 0, lance_mediachange, lance_mediastatus); 132 if (sc->sc_supmedia != NULL) { 133 for (i = 0; i < sc->sc_nsupmedia; i++) 134 ifmedia_add(&sc->sc_media, sc->sc_supmedia[i], 0, NULL); 135 ifmedia_set(&sc->sc_media, sc->sc_defaultmedia); 136 } else { 137 ifmedia_add(&sc->sc_media, 138 IFM_MAKEWORD(IFM_ETHER, IFM_MANUAL, 0, 0), 0, NULL); 139 ifmedia_set(&sc->sc_media, 140 IFM_MAKEWORD(IFM_ETHER, IFM_MANUAL, 0, 0)); 141 } 142 143 switch (sc->sc_memsize) { 144 case 8192: 145 sc->sc_nrbuf = 4; 146 sc->sc_ntbuf = 1; 147 break; 148 case 16384: 149 sc->sc_nrbuf = 8; 150 sc->sc_ntbuf = 2; 151 break; 152 case 32768: 153 sc->sc_nrbuf = 16; 154 sc->sc_ntbuf = 4; 155 break; 156 case 65536: 157 sc->sc_nrbuf = 32; 158 sc->sc_ntbuf = 8; 159 break; 160 case 131072: 161 sc->sc_nrbuf = 64; 162 sc->sc_ntbuf = 16; 163 break; 164 case 262144: 165 sc->sc_nrbuf = 128; 166 sc->sc_ntbuf = 32; 167 break; 168 default: 169 /* weird memory size; cope with it */ 170 nbuf = sc->sc_memsize / LEBLEN; 171 sc->sc_ntbuf = nbuf / 5; 172 sc->sc_nrbuf = nbuf - sc->sc_ntbuf; 173 } 174 175 if_printf(ifp, "%d receive buffers, %d transmit buffers\n", 176 sc->sc_nrbuf, sc->sc_ntbuf); 177 178 /* Make sure the chip is stopped. */ 179 LE_LOCK(sc); 180 lance_stop(sc); 181 LE_UNLOCK(sc); 182 183 return (0); 184 } 185 186 void 187 lance_attach(struct lance_softc *sc) 188 { 189 if_t ifp = sc->sc_ifp; 190 191 /* Attach the interface. */ 192 ether_ifattach(ifp, sc->sc_enaddr); 193 194 /* Claim 802.1q capability. */ 195 if_setifheaderlen(ifp, sizeof(struct ether_vlan_header)); 196 if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0); 197 if_setcapenablebit(ifp, IFCAP_VLAN_MTU, 0); 198 199 gone_in(15, "le: 10/100 NIC no longer needed for Qemu/MIPS"); 200 } 201 202 void 203 lance_detach(struct lance_softc *sc) 204 { 205 if_t ifp = sc->sc_ifp; 206 207 LE_LOCK(sc); 208 lance_stop(sc); 209 LE_UNLOCK(sc); 210 callout_drain(&sc->sc_wdog_ch); 211 ether_ifdetach(ifp); 212 if_free(ifp); 213 } 214 215 void 216 lance_suspend(struct lance_softc *sc) 217 { 218 219 LE_LOCK(sc); 220 lance_stop(sc); 221 LE_UNLOCK(sc); 222 } 223 224 void 225 lance_resume(struct lance_softc *sc) 226 { 227 228 LE_LOCK(sc); 229 if (if_getflags(sc->sc_ifp) & IFF_UP) 230 lance_init_locked(sc); 231 LE_UNLOCK(sc); 232 } 233 234 static void 235 lance_start(if_t ifp) 236 { 237 struct lance_softc *sc = if_getsoftc(ifp); 238 239 LE_LOCK(sc); 240 (*sc->sc_start_locked)(sc); 241 LE_UNLOCK(sc); 242 } 243 244 static void 245 lance_stop(struct lance_softc *sc) 246 { 247 if_t ifp = sc->sc_ifp; 248 249 LE_LOCK_ASSERT(sc, MA_OWNED); 250 251 /* 252 * Mark the interface down and cancel the watchdog timer. 253 */ 254 if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)); 255 callout_stop(&sc->sc_wdog_ch); 256 sc->sc_wdog_timer = 0; 257 258 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP); 259 } 260 261 static void 262 lance_init(void *xsc) 263 { 264 struct lance_softc *sc = (struct lance_softc *)xsc; 265 266 LE_LOCK(sc); 267 lance_init_locked(sc); 268 LE_UNLOCK(sc); 269 } 270 271 /* 272 * Initialization of interface; set up initialization block 273 * and transmit/receive descriptor rings. 274 */ 275 void 276 lance_init_locked(struct lance_softc *sc) 277 { 278 if_t ifp = sc->sc_ifp; 279 u_long a; 280 int timo; 281 282 LE_LOCK_ASSERT(sc, MA_OWNED); 283 284 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP); 285 DELAY(100); 286 287 /* Newer LANCE chips have a reset register. */ 288 if (sc->sc_hwreset) 289 (*sc->sc_hwreset)(sc); 290 291 /* Set the correct byte swapping mode, etc. */ 292 (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3); 293 294 /* Set the current media. This may require the chip to be stopped. */ 295 if (sc->sc_mediachange) 296 (void)(*sc->sc_mediachange)(sc); 297 298 /* 299 * Update our private copy of the Ethernet address. 300 * We NEED the copy so we can ensure its alignment! 301 */ 302 memcpy(sc->sc_enaddr, if_getlladdr(ifp), ETHER_ADDR_LEN); 303 304 /* Set up LANCE init block. */ 305 (*sc->sc_meminit)(sc); 306 307 /* Give LANCE the physical address of its init block. */ 308 a = sc->sc_addr + LE_INITADDR(sc); 309 (*sc->sc_wrcsr)(sc, LE_CSR1, a & 0xffff); 310 (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16); 311 312 /* Try to initialize the LANCE. */ 313 DELAY(100); 314 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT); 315 316 /* Wait for initialization to finish. */ 317 for (timo = 100000; timo; timo--) 318 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) 319 break; 320 321 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) { 322 /* Start the LANCE. */ 323 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT); 324 if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0); 325 if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE); 326 sc->sc_wdog_timer = 0; 327 callout_reset(&sc->sc_wdog_ch, hz, lance_watchdog, sc); 328 (*sc->sc_start_locked)(sc); 329 } else 330 if_printf(ifp, "controller failed to initialize\n"); 331 332 if (sc->sc_hwinit) 333 (*sc->sc_hwinit)(sc); 334 } 335 336 /* 337 * Routine to copy from mbuf chain to transmit buffer in 338 * network buffer memory. 339 */ 340 int 341 lance_put(struct lance_softc *sc, int boff, struct mbuf *m) 342 { 343 struct mbuf *n; 344 int len, tlen = 0; 345 346 LE_LOCK_ASSERT(sc, MA_OWNED); 347 348 for (; m; m = n) { 349 len = m->m_len; 350 if (len == 0) { 351 n = m_free(m); 352 m = NULL; 353 continue; 354 } 355 (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len); 356 boff += len; 357 tlen += len; 358 n = m_free(m); 359 m = NULL; 360 } 361 if (tlen < LEMINSIZE) { 362 (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen); 363 tlen = LEMINSIZE; 364 } 365 return (tlen); 366 } 367 368 /* 369 * Pull data off an interface. 370 * Len is length of data, with local net header stripped. 371 * We copy the data into mbufs. When full cluster sized units are present 372 * we copy into clusters. 373 */ 374 struct mbuf * 375 lance_get(struct lance_softc *sc, int boff, int totlen) 376 { 377 if_t ifp = sc->sc_ifp; 378 struct mbuf *m, *m0, *newm; 379 caddr_t newdata; 380 int len; 381 382 if (totlen <= ETHER_HDR_LEN || totlen > LEBLEN - ETHER_CRC_LEN) { 383 #ifdef LEDEBUG 384 if_printf(ifp, "invalid packet size %d; dropping\n", totlen); 385 #endif 386 return (NULL); 387 } 388 389 MGETHDR(m0, M_NOWAIT, MT_DATA); 390 if (m0 == NULL) 391 return (NULL); 392 m0->m_pkthdr.rcvif = ifp; 393 m0->m_pkthdr.len = totlen; 394 len = MHLEN; 395 m = m0; 396 397 while (totlen > 0) { 398 if (totlen >= MINCLSIZE) { 399 if (!(MCLGET(m, M_NOWAIT))) 400 goto bad; 401 len = MCLBYTES; 402 } 403 404 if (m == m0) { 405 newdata = (caddr_t) 406 ALIGN(m->m_data + ETHER_HDR_LEN) - ETHER_HDR_LEN; 407 len -= newdata - m->m_data; 408 m->m_data = newdata; 409 } 410 411 m->m_len = len = min(totlen, len); 412 (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len); 413 boff += len; 414 415 totlen -= len; 416 if (totlen > 0) { 417 MGET(newm, M_NOWAIT, MT_DATA); 418 if (newm == NULL) 419 goto bad; 420 len = MLEN; 421 m = m->m_next = newm; 422 } 423 } 424 425 return (m0); 426 427 bad: 428 m_freem(m0); 429 return (NULL); 430 } 431 432 static void 433 lance_watchdog(void *xsc) 434 { 435 struct lance_softc *sc = (struct lance_softc *)xsc; 436 if_t ifp = sc->sc_ifp; 437 438 LE_LOCK_ASSERT(sc, MA_OWNED); 439 440 if (sc->sc_wdog_timer == 0 || --sc->sc_wdog_timer != 0) { 441 callout_reset(&sc->sc_wdog_ch, hz, lance_watchdog, sc); 442 return; 443 } 444 445 if_printf(ifp, "device timeout\n"); 446 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1); 447 lance_init_locked(sc); 448 } 449 450 static int 451 lance_mediachange(if_t ifp) 452 { 453 struct lance_softc *sc = if_getsoftc(ifp); 454 455 if (sc->sc_mediachange) { 456 /* 457 * For setting the port in LE_CSR15 the PCnet chips must 458 * be powered down or stopped and unlike documented may 459 * not take effect without an initialization. So don't 460 * invoke (*sc_mediachange) directly here but go through 461 * lance_init_locked(). 462 */ 463 LE_LOCK(sc); 464 lance_stop(sc); 465 lance_init_locked(sc); 466 if (!if_sendq_empty(ifp)) 467 (*sc->sc_start_locked)(sc); 468 LE_UNLOCK(sc); 469 } 470 return (0); 471 } 472 473 static void 474 lance_mediastatus(if_t ifp, struct ifmediareq *ifmr) 475 { 476 struct lance_softc *sc = if_getsoftc(ifp); 477 478 LE_LOCK(sc); 479 if (!(if_getflags(ifp) & IFF_UP)) { 480 LE_UNLOCK(sc); 481 return; 482 } 483 484 ifmr->ifm_status = IFM_AVALID; 485 if (sc->sc_flags & LE_CARRIER) 486 ifmr->ifm_status |= IFM_ACTIVE; 487 488 if (sc->sc_mediastatus) 489 (*sc->sc_mediastatus)(sc, ifmr); 490 LE_UNLOCK(sc); 491 } 492 493 /* 494 * Process an ioctl request. 495 */ 496 static int 497 lance_ioctl(if_t ifp, u_long cmd, caddr_t data) 498 { 499 struct lance_softc *sc = if_getsoftc(ifp); 500 struct ifreq *ifr = (struct ifreq *)data; 501 int error = 0; 502 503 switch (cmd) { 504 case SIOCSIFFLAGS: 505 LE_LOCK(sc); 506 if (if_getflags(ifp) & IFF_PROMISC) { 507 if (!(sc->sc_flags & LE_PROMISC)) { 508 sc->sc_flags |= LE_PROMISC; 509 lance_init_locked(sc); 510 } 511 } else if (sc->sc_flags & LE_PROMISC) { 512 sc->sc_flags &= ~LE_PROMISC; 513 lance_init_locked(sc); 514 } 515 516 if ((if_getflags(ifp) & IFF_ALLMULTI) && 517 !(sc->sc_flags & LE_ALLMULTI)) { 518 sc->sc_flags |= LE_ALLMULTI; 519 lance_init_locked(sc); 520 } else if (!(if_getflags(ifp) & IFF_ALLMULTI) && 521 (sc->sc_flags & LE_ALLMULTI)) { 522 sc->sc_flags &= ~LE_ALLMULTI; 523 lance_init_locked(sc); 524 } 525 526 if (!(if_getflags(ifp) & IFF_UP) && 527 if_getdrvflags(ifp) & IFF_DRV_RUNNING) { 528 /* 529 * If interface is marked down and it is running, then 530 * stop it. 531 */ 532 lance_stop(sc); 533 } else if (if_getflags(ifp) & IFF_UP && 534 !(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) { 535 /* 536 * If interface is marked up and it is stopped, then 537 * start it. 538 */ 539 lance_init_locked(sc); 540 } 541 #ifdef LEDEBUG 542 if (if_getflags(ifp) & IFF_DEBUG) 543 sc->sc_flags |= LE_DEBUG; 544 else 545 sc->sc_flags &= ~LE_DEBUG; 546 #endif 547 LE_UNLOCK(sc); 548 break; 549 550 case SIOCADDMULTI: 551 case SIOCDELMULTI: 552 /* 553 * Multicast list has changed; set the hardware filter 554 * accordingly. 555 */ 556 LE_LOCK(sc); 557 if (if_getdrvflags(ifp) & IFF_DRV_RUNNING) 558 lance_init_locked(sc); 559 LE_UNLOCK(sc); 560 break; 561 562 case SIOCGIFMEDIA: 563 case SIOCSIFMEDIA: 564 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd); 565 break; 566 567 default: 568 error = ether_ioctl(ifp, cmd, data); 569 break; 570 } 571 572 return (error); 573 } 574 575 struct lance_hash_maddr_ctx { 576 struct lance_softc *sc; 577 uint16_t *af; 578 }; 579 580 static u_int 581 lance_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt) 582 { 583 struct lance_hash_maddr_ctx *ctx = arg; 584 struct lance_softc *sc = ctx->sc; 585 uint32_t crc; 586 587 crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN); 588 /* Just want the 6 most significant bits. */ 589 crc >>= 26; 590 /* Set the corresponding bit in the filter. */ 591 ctx->af[crc >> 4] |= LE_HTOLE16(1 << (crc & 0xf)); 592 593 return (1); 594 } 595 596 /* 597 * Set up the logical address filter. 598 */ 599 void 600 lance_setladrf(struct lance_softc *sc, uint16_t *af) 601 { 602 if_t ifp = sc->sc_ifp; 603 struct lance_hash_maddr_ctx ctx = { sc, af }; 604 605 /* 606 * Set up multicast address filter by passing all multicast addresses 607 * through a crc generator, and then using the high order 6 bits as an 608 * index into the 64 bit logical address filter. The high order bit 609 * selects the word, while the rest of the bits select the bit within 610 * the word. 611 */ 612 613 if (if_getflags(ifp) & IFF_PROMISC || sc->sc_flags & LE_ALLMULTI) { 614 af[0] = af[1] = af[2] = af[3] = 0xffff; 615 return; 616 } 617 618 af[0] = af[1] = af[2] = af[3] = 0x0000; 619 if_foreach_llmaddr(ifp, lance_hash_maddr, &ctx); 620 } 621 622 /* 623 * Routines for accessing the transmit and receive buffers. 624 * The various CPU and adapter configurations supported by this 625 * driver require three different access methods for buffers 626 * and descriptors: 627 * (1) contig (contiguous data; no padding), 628 * (2) gap2 (two bytes of data followed by two bytes of padding), 629 * (3) gap16 (16 bytes of data followed by 16 bytes of padding). 630 */ 631 632 /* 633 * contig: contiguous data with no padding. 634 * 635 * Buffers may have any alignment. 636 */ 637 638 void 639 lance_copytobuf_contig(struct lance_softc *sc, void *from, int boff, int len) 640 { 641 volatile caddr_t buf = sc->sc_mem; 642 643 /* 644 * Just call memcpy() to do the work. 645 */ 646 memcpy(buf + boff, from, len); 647 } 648 649 void 650 lance_copyfrombuf_contig(struct lance_softc *sc, void *to, int boff, int len) 651 { 652 volatile caddr_t buf = sc->sc_mem; 653 654 /* 655 * Just call memcpy() to do the work. 656 */ 657 memcpy(to, buf + boff, len); 658 } 659 660 void 661 lance_zerobuf_contig(struct lance_softc *sc, int boff, int len) 662 { 663 volatile caddr_t buf = sc->sc_mem; 664 665 /* 666 * Just let memset() do the work 667 */ 668 memset(buf + boff, 0, len); 669 } 670 671 #if 0 672 /* 673 * Examples only; duplicate these and tweak (if necessary) in 674 * machine-specific front-ends. 675 */ 676 677 /* 678 * gap2: two bytes of data followed by two bytes of pad. 679 * 680 * Buffers must be 4-byte aligned. The code doesn't worry about 681 * doing an extra byte. 682 */ 683 684 static void 685 lance_copytobuf_gap2(struct lance_softc *sc, void *fromv, int boff, int len) 686 { 687 volatile caddr_t buf = sc->sc_mem; 688 caddr_t from = fromv; 689 volatile uint16_t *bptr; 690 691 if (boff & 0x1) { 692 /* Handle unaligned first byte. */ 693 bptr = ((volatile uint16_t *)buf) + (boff - 1); 694 *bptr = (*from++ << 8) | (*bptr & 0xff); 695 bptr += 2; 696 len--; 697 } else 698 bptr = ((volatile uint16_t *)buf) + boff; 699 while (len > 1) { 700 *bptr = (from[1] << 8) | (from[0] & 0xff); 701 bptr += 2; 702 from += 2; 703 len -= 2; 704 } 705 if (len == 1) 706 *bptr = (uint16_t)*from; 707 } 708 709 static void 710 lance_copyfrombuf_gap2(struct lance_softc *sc, void *tov, int boff, int len) 711 { 712 volatile caddr_t buf = sc->sc_mem; 713 caddr_t to = tov; 714 volatile uint16_t *bptr; 715 uint16_t tmp; 716 717 if (boff & 0x1) { 718 /* Handle unaligned first byte. */ 719 bptr = ((volatile uint16_t *)buf) + (boff - 1); 720 *to++ = (*bptr >> 8) & 0xff; 721 bptr += 2; 722 len--; 723 } else 724 bptr = ((volatile uint16_t *)buf) + boff; 725 while (len > 1) { 726 tmp = *bptr; 727 *to++ = tmp & 0xff; 728 *to++ = (tmp >> 8) & 0xff; 729 bptr += 2; 730 len -= 2; 731 } 732 if (len == 1) 733 *to = *bptr & 0xff; 734 } 735 736 static void 737 lance_zerobuf_gap2(struct lance_softc *sc, int boff, int len) 738 { 739 volatile caddr_t buf = sc->sc_mem; 740 volatile uint16_t *bptr; 741 742 if ((unsigned)boff & 0x1) { 743 bptr = ((volatile uint16_t *)buf) + (boff - 1); 744 *bptr &= 0xff; 745 bptr += 2; 746 len--; 747 } else 748 bptr = ((volatile uint16_t *)buf) + boff; 749 while (len > 0) { 750 *bptr = 0; 751 bptr += 2; 752 len -= 2; 753 } 754 } 755 756 /* 757 * gap16: 16 bytes of data followed by 16 bytes of pad. 758 * 759 * Buffers must be 32-byte aligned. 760 */ 761 762 static void 763 lance_copytobuf_gap16(struct lance_softc *sc, void *fromv, int boff, int len) 764 { 765 volatile caddr_t buf = sc->sc_mem; 766 caddr_t bptr, from = fromv; 767 int xfer; 768 769 bptr = buf + ((boff << 1) & ~0x1f); 770 boff &= 0xf; 771 xfer = min(len, 16 - boff); 772 while (len > 0) { 773 memcpy(bptr + boff, from, xfer); 774 from += xfer; 775 bptr += 32; 776 boff = 0; 777 len -= xfer; 778 xfer = min(len, 16); 779 } 780 } 781 782 static void 783 lance_copyfrombuf_gap16(struct lance_softc *sc, void *tov, int boff, int len) 784 { 785 volatile caddr_t buf = sc->sc_mem; 786 caddr_t bptr, to = tov; 787 int xfer; 788 789 bptr = buf + ((boff << 1) & ~0x1f); 790 boff &= 0xf; 791 xfer = min(len, 16 - boff); 792 while (len > 0) { 793 memcpy(to, bptr + boff, xfer); 794 to += xfer; 795 bptr += 32; 796 boff = 0; 797 len -= xfer; 798 xfer = min(len, 16); 799 } 800 } 801 802 static void 803 lance_zerobuf_gap16(struct lance_softc *sc, int boff, int len) 804 { 805 volatile caddr_t buf = sc->sc_mem; 806 caddr_t bptr; 807 int xfer; 808 809 bptr = buf + ((boff << 1) & ~0x1f); 810 boff &= 0xf; 811 xfer = min(len, 16 - boff); 812 while (len > 0) { 813 memset(bptr + boff, 0, xfer); 814 bptr += 32; 815 boff = 0; 816 len -= xfer; 817 xfer = min(len, 16); 818 } 819 } 820 #endif /* Example only */ 821