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