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