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