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