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