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