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