xref: /freebsd/sys/dev/le/lance.c (revision 0efd6615cd5f39b67cec82a7034e655f3b5801e3)
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, IFQ_MAXLEN);
137 	ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
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 	/*
303 	 * Update our private copy of the Ethernet address.
304 	 * We NEED the copy so we can ensure its alignment!
305 	 */
306 	memcpy(sc->sc_enaddr, IF_LLADDR(ifp), ETHER_ADDR_LEN);
307 
308 	/* Set up LANCE init block. */
309 	(*sc->sc_meminit)(sc);
310 
311 	/* Give LANCE the physical address of its init block. */
312 	a = sc->sc_addr + LE_INITADDR(sc);
313 	(*sc->sc_wrcsr)(sc, LE_CSR1, a & 0xffff);
314 	(*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
315 
316 	/* Try to initialize the LANCE. */
317 	DELAY(100);
318 	(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
319 
320 	/* Wait for initialization to finish. */
321 	for (timo = 100000; timo; timo--)
322 		if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
323 			break;
324 
325 	/* Set the current media. */
326 	if (sc->sc_mediachange)
327 		(void)(*sc->sc_mediachange)(sc);
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 	int error;
464 
465 	if (sc->sc_mediachange) {
466 		LE_LOCK(sc);
467 		error = (*sc->sc_mediachange)(sc);
468 		LE_UNLOCK(sc);
469 		return (error);
470 	}
471 	return (0);
472 }
473 
474 static void
475 lance_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
476 {
477 	struct lance_softc *sc = ifp->if_softc;
478 
479 	LE_LOCK(sc);
480 	if (!(ifp->if_flags & IFF_UP)) {
481 		LE_UNLOCK(sc);
482 		return;
483 	}
484 
485 	ifmr->ifm_status = IFM_AVALID;
486 	if (sc->sc_flags & LE_CARRIER)
487 		ifmr->ifm_status |= IFM_ACTIVE;
488 
489 	if (sc->sc_mediastatus)
490 		(*sc->sc_mediastatus)(sc, ifmr);
491 	LE_UNLOCK(sc);
492 }
493 
494 /*
495  * Process an ioctl request.
496  */
497 static int
498 lance_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
499 {
500 	struct lance_softc *sc = ifp->if_softc;
501 	struct ifreq *ifr = (struct ifreq *)data;
502 	int error = 0;
503 
504 	switch (cmd) {
505 	case SIOCSIFFLAGS:
506 		LE_LOCK(sc);
507 		if (ifp->if_flags & IFF_PROMISC) {
508 			if (!(sc->sc_flags & LE_PROMISC)) {
509 				sc->sc_flags |= LE_PROMISC;
510 				lance_init_locked(sc);
511 			}
512 		} else if (sc->sc_flags & LE_PROMISC) {
513 			sc->sc_flags &= ~LE_PROMISC;
514 			lance_init_locked(sc);
515 		}
516 
517 		if ((ifp->if_flags & IFF_ALLMULTI) &&
518 		    !(sc->sc_flags & LE_ALLMULTI)) {
519 			sc->sc_flags |= LE_ALLMULTI;
520 			lance_init_locked(sc);
521 		} else if (!(ifp->if_flags & IFF_ALLMULTI) &&
522 		    (sc->sc_flags & LE_ALLMULTI)) {
523 			sc->sc_flags &= ~LE_ALLMULTI;
524 			lance_init_locked(sc);
525 		}
526 
527 		if (!(ifp->if_flags & IFF_UP) &&
528 		    ifp->if_drv_flags & IFF_DRV_RUNNING) {
529 			/*
530 			 * If interface is marked down and it is running, then
531 			 * stop it.
532 			 */
533 			lance_stop(sc);
534 		} else if (ifp->if_flags & IFF_UP &&
535 		    !(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
536 			/*
537 			 * If interface is marked up and it is stopped, then
538 			 * start it.
539 			 */
540 			lance_init_locked(sc);
541 		}
542 #ifdef LEDEBUG
543 		if (ifp->if_flags & IFF_DEBUG)
544 			sc->sc_flags |= LE_DEBUG;
545 		else
546 			sc->sc_flags &= ~LE_DEBUG;
547 #endif
548 		LE_UNLOCK(sc);
549 		break;
550 
551 	case SIOCADDMULTI:
552 	case SIOCDELMULTI:
553 		/*
554 		 * Multicast list has changed; set the hardware filter
555 		 * accordingly.
556 		 */
557 		LE_LOCK(sc);
558 		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
559 			lance_init_locked(sc);
560 		LE_UNLOCK(sc);
561 		break;
562 
563 	case SIOCGIFMEDIA:
564 	case SIOCSIFMEDIA:
565 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
566 		break;
567 
568 	default:
569 		error = ether_ioctl(ifp, cmd, data);
570 		break;
571 	}
572 
573 	return (error);
574 }
575 
576 /*
577  * Set up the logical address filter.
578  */
579 void
580 lance_setladrf(struct lance_softc *sc, uint16_t *af)
581 {
582 	struct ifnet *ifp = sc->sc_ifp;
583 	struct ifmultiaddr *ifma;
584 	uint32_t crc;
585 
586 	/*
587 	 * Set up multicast address filter by passing all multicast addresses
588 	 * through a crc generator, and then using the high order 6 bits as an
589 	 * index into the 64 bit logical address filter.  The high order bit
590 	 * selects the word, while the rest of the bits select the bit within
591 	 * the word.
592 	 */
593 
594 	if (ifp->if_flags & IFF_PROMISC || sc->sc_flags & LE_ALLMULTI) {
595 		af[0] = af[1] = af[2] = af[3] = 0xffff;
596 		return;
597 	}
598 
599 	af[0] = af[1] = af[2] = af[3] = 0x0000;
600 	IF_ADDR_LOCK(ifp);
601 	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
602 		if (ifma->ifma_addr->sa_family != AF_LINK)
603 			continue;
604 
605 		crc = ether_crc32_le(LLADDR((struct sockaddr_dl *)
606 		    ifma->ifma_addr), ETHER_ADDR_LEN);
607 
608 		/* Just want the 6 most significant bits. */
609 		crc >>= 26;
610 
611 		/* Set the corresponding bit in the filter. */
612 		af[crc >> 4] |= LE_HTOLE16(1 << (crc & 0xf));
613 	}
614 	IF_ADDR_UNLOCK(ifp);
615 }
616 
617 /*
618  * Routines for accessing the transmit and receive buffers.
619  * The various CPU and adapter configurations supported by this
620  * driver require three different access methods for buffers
621  * and descriptors:
622  *	(1) contig (contiguous data; no padding),
623  *	(2) gap2 (two bytes of data followed by two bytes of padding),
624  *	(3) gap16 (16 bytes of data followed by 16 bytes of padding).
625  */
626 
627 /*
628  * contig: contiguous data with no padding.
629  *
630  * Buffers may have any alignment.
631  */
632 
633 void
634 lance_copytobuf_contig(struct lance_softc *sc, void *from, int boff, int len)
635 {
636 	volatile caddr_t buf = sc->sc_mem;
637 
638 	/*
639 	 * Just call memcpy() to do the work.
640 	 */
641 	memcpy(buf + boff, from, len);
642 }
643 
644 void
645 lance_copyfrombuf_contig(struct lance_softc *sc, void *to, int boff, int len)
646 {
647 	volatile caddr_t buf = sc->sc_mem;
648 
649 	/*
650 	 * Just call memcpy() to do the work.
651 	 */
652 	memcpy(to, buf + boff, len);
653 }
654 
655 void
656 lance_zerobuf_contig(struct lance_softc *sc, int boff, int len)
657 {
658 	volatile caddr_t buf = sc->sc_mem;
659 
660 	/*
661 	 * Just let memset() do the work
662 	 */
663 	memset(buf + boff, 0, len);
664 }
665 
666 #if 0
667 /*
668  * Examples only; duplicate these and tweak (if necessary) in
669  * machine-specific front-ends.
670  */
671 
672 /*
673  * gap2: two bytes of data followed by two bytes of pad.
674  *
675  * Buffers must be 4-byte aligned.  The code doesn't worry about
676  * doing an extra byte.
677  */
678 
679 static void
680 lance_copytobuf_gap2(struct lance_softc *sc, void *fromv, int boff, int len)
681 {
682 	volatile caddr_t buf = sc->sc_mem;
683 	caddr_t from = fromv;
684 	volatile uint16_t *bptr;
685 
686 	if (boff & 0x1) {
687 		/* Handle unaligned first byte. */
688 		bptr = ((volatile uint16_t *)buf) + (boff - 1);
689 		*bptr = (*from++ << 8) | (*bptr & 0xff);
690 		bptr += 2;
691 		len--;
692 	} else
693 		bptr = ((volatile uint16_t *)buf) + boff;
694 	while (len > 1) {
695 		*bptr = (from[1] << 8) | (from[0] & 0xff);
696 		bptr += 2;
697 		from += 2;
698 		len -= 2;
699 	}
700 	if (len == 1)
701 		*bptr = (uint16_t)*from;
702 }
703 
704 static void
705 lance_copyfrombuf_gap2(struct lance_softc *sc, void *tov, int boff, int len)
706 {
707 	volatile caddr_t buf = sc->sc_mem;
708 	caddr_t to = tov;
709 	volatile uint16_t *bptr;
710 	uint16_t tmp;
711 
712 	if (boff & 0x1) {
713 		/* Handle unaligned first byte. */
714 		bptr = ((volatile uint16_t *)buf) + (boff - 1);
715 		*to++ = (*bptr >> 8) & 0xff;
716 		bptr += 2;
717 		len--;
718 	} else
719 		bptr = ((volatile uint16_t *)buf) + boff;
720 	while (len > 1) {
721 		tmp = *bptr;
722 		*to++ = tmp & 0xff;
723 		*to++ = (tmp >> 8) & 0xff;
724 		bptr += 2;
725 		len -= 2;
726 	}
727 	if (len == 1)
728 		*to = *bptr & 0xff;
729 }
730 
731 static void
732 lance_zerobuf_gap2(struct lance_softc *sc, int boff, int len)
733 {
734 	volatile caddr_t buf = sc->sc_mem;
735 	volatile uint16_t *bptr;
736 
737 	if ((unsigned)boff & 0x1) {
738 		bptr = ((volatile uint16_t *)buf) + (boff - 1);
739 		*bptr &= 0xff;
740 		bptr += 2;
741 		len--;
742 	} else
743 		bptr = ((volatile uint16_t *)buf) + boff;
744 	while (len > 0) {
745 		*bptr = 0;
746 		bptr += 2;
747 		len -= 2;
748 	}
749 }
750 
751 /*
752  * gap16: 16 bytes of data followed by 16 bytes of pad.
753  *
754  * Buffers must be 32-byte aligned.
755  */
756 
757 static void
758 lance_copytobuf_gap16(struct lance_softc *sc, void *fromv, int boff, int len)
759 {
760 	volatile caddr_t buf = sc->sc_mem;
761 	caddr_t bptr, from = fromv;
762 	int xfer;
763 
764 	bptr = buf + ((boff << 1) & ~0x1f);
765 	boff &= 0xf;
766 	xfer = min(len, 16 - boff);
767 	while (len > 0) {
768 		memcpy(bptr + boff, from, xfer);
769 		from += xfer;
770 		bptr += 32;
771 		boff = 0;
772 		len -= xfer;
773 		xfer = min(len, 16);
774 	}
775 }
776 
777 static void
778 lance_copyfrombuf_gap16(struct lance_softc *sc, void *tov, int boff, int len)
779 {
780 	volatile caddr_t buf = sc->sc_mem;
781 	caddr_t bptr, to = tov;
782 	int xfer;
783 
784 	bptr = buf + ((boff << 1) & ~0x1f);
785 	boff &= 0xf;
786 	xfer = min(len, 16 - boff);
787 	while (len > 0) {
788 		memcpy(to, bptr + boff, xfer);
789 		to += xfer;
790 		bptr += 32;
791 		boff = 0;
792 		len -= xfer;
793 		xfer = min(len, 16);
794 	}
795 }
796 
797 static void
798 lance_zerobuf_gap16(struct lance_softc *sc, int boff, int len)
799 {
800 	volatile caddr_t buf = sc->sc_mem;
801 	caddr_t bptr;
802 	int xfer;
803 
804 	bptr = buf + ((boff << 1) & ~0x1f);
805 	boff &= 0xf;
806 	xfer = min(len, 16 - boff);
807 	while (len > 0) {
808 		memset(bptr + boff, 0, xfer);
809 		bptr += 32;
810 		boff = 0;
811 		len -= xfer;
812 		xfer = min(len, 16);
813 	}
814 }
815 #endif /* Example only */
816