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