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