xref: /openbsd-src/sys/dev/ic/lance.c (revision 50b7afb2c2c0993b0894d4e34bf857cb13ed9c80)
1 /*	$OpenBSD: lance.c,v 1.3 2014/07/13 23:10:23 deraadt Exp $	*/
2 /*	$NetBSD: lance.c,v 1.46 2012/02/02 19:43:03 tls Exp $	*/
3 
4 /*-
5  * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
6  * All rights reserved.
7  *
8  * This code is derived from software contributed to The NetBSD Foundation
9  * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
10  * Simulation Facility, NASA Ames Research Center.
11  *
12  * Redistribution and use in source and binary forms, with or without
13  * modification, are permitted provided that the following conditions
14  * are met:
15  * 1. Redistributions of source code must retain the above copyright
16  *    notice, this list of conditions and the following disclaimer.
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
31  * POSSIBILITY OF SUCH DAMAGE.
32  */
33 
34 /*-
35  * Copyright (c) 1992, 1993
36  *	The Regents of the University of California.  All rights reserved.
37  *
38  * This code is derived from software contributed to Berkeley by
39  * Ralph Campbell and Rick Macklem.
40  *
41  * Redistribution and use in source and binary forms, with or without
42  * modification, are permitted provided that the following conditions
43  * are met:
44  * 1. Redistributions of source code must retain the above copyright
45  *    notice, this list of conditions and the following disclaimer.
46  * 2. Redistributions in binary form must reproduce the above copyright
47  *    notice, this list of conditions and the following disclaimer in the
48  *    documentation and/or other materials provided with the distribution.
49  * 3. Neither the name of the University nor the names of its contributors
50  *    may be used to endorse or promote products derived from this software
51  *    without specific prior written permission.
52  *
53  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
54  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
55  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
56  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
57  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
58  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
59  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
60  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
61  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
62  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
63  * SUCH DAMAGE.
64  *
65  *	@(#)if_le.c	8.2 (Berkeley) 11/16/93
66  */
67 
68 #include "bpfilter.h"
69 
70 #include <sys/param.h>
71 #include <sys/systm.h>
72 #include <sys/mbuf.h>
73 #include <sys/syslog.h>
74 #include <sys/socket.h>
75 #include <sys/device.h>
76 #include <sys/malloc.h>
77 #include <sys/ioctl.h>
78 #include <sys/errno.h>
79 
80 #include <net/if.h>
81 #include <net/if_media.h>
82 
83 #ifdef INET
84 #include <netinet/in.h>
85 #include <netinet/if_ether.h>
86 #include <netinet/in_systm.h>
87 #include <netinet/ip.h>
88 #endif
89 
90 #if NBPFILTER > 0
91 #include <net/bpf.h>
92 #endif
93 
94 #include <dev/ic/lancereg.h>
95 #include <dev/ic/lancevar.h>
96 
97 #ifdef DDB
98 #define	integrate
99 #define hide
100 #else
101 #define	integrate	static inline
102 #define hide		static
103 #endif
104 
105 integrate struct mbuf *lance_get(struct lance_softc *, int, int);
106 
107 int lance_mediachange(struct ifnet *);
108 void lance_mediastatus(struct ifnet *, struct ifmediareq *);
109 
110 static inline u_int16_t ether_cmp(void *, void *);
111 
112 void lance_stop(struct ifnet *, int);
113 int lance_ioctl(struct ifnet *, u_long, caddr_t);
114 void lance_watchdog(struct ifnet *);
115 
116 struct cfdriver le_cd = {
117 	NULL, "le", DV_IFNET
118 };
119 
120 /*
121  * Compare two Ether/802 addresses for equality, inlined and
122  * unrolled for speed.  Use this like memcmp().
123  *
124  * XXX: Add <machine/inlines.h> for stuff like this?
125  * XXX: or maybe add it to libkern.h instead?
126  *
127  * "I'd love to have an inline assembler version of this."
128  * XXX: Who wanted that? mycroft?  I wrote one, but this
129  * version in C is as good as hand-coded assembly. -gwr
130  *
131  * Please do NOT tweak this without looking at the actual
132  * assembly code generated before and after your tweaks!
133  */
134 static inline uint16_t
135 ether_cmp(void *one, void *two)
136 {
137 	uint16_t *a = (uint16_t *)one;
138 	uint16_t *b = (uint16_t *)two;
139 	uint16_t diff;
140 
141 #ifdef	__m68k__
142 	/*
143 	 * The post-increment-pointer form produces the best
144 	 * machine code for m68k.  This was carefully tuned
145 	 * so it compiles to just 8 short (2-byte) op-codes!
146 	 */
147 	diff  = *a++ - *b++;
148 	diff |= *a++ - *b++;
149 	diff |= *a++ - *b++;
150 #else
151 	/*
152 	 * Most modern CPUs do better with a single expresion.
153 	 * Note that short-cut evaluation is NOT helpful here,
154 	 * because it just makes the code longer, not faster!
155 	 */
156 	diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
157 #endif
158 
159 	return (diff);
160 }
161 
162 #define ETHER_CMP	ether_cmp
163 
164 #ifdef LANCE_REVC_BUG
165 /* Make sure this is short-aligned, for ether_cmp(). */
166 static uint16_t bcast_enaddr[3] = { ~0, ~0, ~0 };
167 #endif
168 
169 void
170 lance_config(struct lance_softc *sc)
171 {
172 	int i, nbuf;
173 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
174 
175 	/* Initialize ifnet structure. */
176 	strlcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ);
177 	ifp->if_softc = sc;
178 	ifp->if_start = sc->sc_start;
179 	ifp->if_ioctl = lance_ioctl;
180 	ifp->if_watchdog = lance_watchdog;
181 	ifp->if_flags =
182 	    IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
183 #ifdef LANCE_REVC_BUG
184 	ifp->if_flags &= ~IFF_MULTICAST;
185 #endif
186 	ifp->if_baudrate = IF_Mbps(10);
187 	IFQ_SET_READY(&ifp->if_snd);
188 
189 	/* Initialize ifmedia structures. */
190 	ifmedia_init(&sc->sc_ifmedia, 0, lance_mediachange, lance_mediastatus);
191 	if (sc->sc_supmedia != NULL) {
192 		for (i = 0; i < sc->sc_nsupmedia; i++)
193 			ifmedia_add(&sc->sc_ifmedia, sc->sc_supmedia[i],
194 			   0, NULL);
195 		ifmedia_set(&sc->sc_ifmedia, sc->sc_defaultmedia);
196 	} else {
197 		ifmedia_add(&sc->sc_ifmedia, IFM_ETHER|IFM_MANUAL, 0, NULL);
198 		ifmedia_set(&sc->sc_ifmedia, IFM_ETHER|IFM_MANUAL);
199 	}
200 
201 	if (sc->sc_memsize > 262144)
202 		sc->sc_memsize = 262144;
203 
204 	switch (sc->sc_memsize) {
205 	case 8192:
206 		sc->sc_nrbuf = 4;
207 		sc->sc_ntbuf = 1;
208 		break;
209 	case 16384:
210 		sc->sc_nrbuf = 8;
211 		sc->sc_ntbuf = 2;
212 		break;
213 	case 32768:
214 		sc->sc_nrbuf = 16;
215 		sc->sc_ntbuf = 4;
216 		break;
217 	case 65536:
218 		sc->sc_nrbuf = 32;
219 		sc->sc_ntbuf = 8;
220 		break;
221 	case 131072:
222 		sc->sc_nrbuf = 64;
223 		sc->sc_ntbuf = 16;
224 		break;
225 	case 262144:
226 		sc->sc_nrbuf = 128;
227 		sc->sc_ntbuf = 32;
228 		break;
229 	default:
230 		/* weird memory size; cope with it */
231 		nbuf = sc->sc_memsize / LEBLEN;
232 		sc->sc_ntbuf = nbuf / 5;
233 		sc->sc_nrbuf = nbuf - sc->sc_ntbuf;
234 	}
235 
236 	printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
237 	printf("%s: %d receive buffers, %d transmit buffers\n",
238 	    sc->sc_dev.dv_xname, sc->sc_nrbuf, sc->sc_ntbuf);
239 
240 	/* Make sure the chip is stopped. */
241 	lance_stop(ifp, 0);
242 
243 	/* claim 802.1q capability */
244 	ifp->if_capabilities = IFCAP_VLAN_MTU;
245 
246 	/* Attach the interface. */
247 	if_attach(ifp);
248 	ether_ifattach(ifp);
249 
250 	sc->sc_rbufaddr = mallocarray(sc->sc_nrbuf, sizeof(int), M_DEVBUF,
251 	    M_WAITOK);
252 	sc->sc_tbufaddr = mallocarray(sc->sc_ntbuf, sizeof(int), M_DEVBUF,
253 	    M_WAITOK);
254 }
255 
256 void
257 lance_reset(struct lance_softc *sc)
258 {
259 	int s;
260 
261 	s = splnet();
262 	lance_init(sc);
263 	splx(s);
264 }
265 
266 void
267 lance_stop(struct ifnet *ifp, int disable)
268 {
269 	struct lance_softc *sc = ifp->if_softc;
270 
271 	(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
272 }
273 
274 /*
275  * Initialization of interface; set up initialization block
276  * and transmit/receive descriptor rings.
277  */
278 int
279 lance_init(struct lance_softc *sc)
280 {
281 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
282 	int timo;
283 	u_long a;
284 
285 	(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
286 	DELAY(100);
287 
288 	/* Newer LANCE chips have a reset register */
289 	if (sc->sc_hwreset)
290 		(*sc->sc_hwreset)(sc);
291 
292 	/* Set the correct byte swapping mode, etc. */
293 	(*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
294 
295 	/* Set up LANCE init block. */
296 	(*sc->sc_meminit)(sc);
297 
298 	/* Give LANCE the physical address of its init block. */
299 	a = sc->sc_addr + LE_INITADDR(sc);
300 	(*sc->sc_wrcsr)(sc, LE_CSR1, a);
301 	(*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
302 
303 	/* Try to initialize the LANCE. */
304 	DELAY(100);
305 	(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
306 
307 	/* Wait for initialization to finish. */
308 	for (timo = 100000; timo; timo--)
309 		if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
310 			break;
311 
312 	if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
313 		/* Start the LANCE. */
314 		(*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT);
315 		ifp->if_flags |= IFF_RUNNING;
316 		ifp->if_flags &= ~IFF_OACTIVE;
317 		ifp->if_timer = 0;
318 		(*sc->sc_start)(ifp);
319 	} else
320 		printf("%s: controller failed to initialize\n",
321 		     sc->sc_dev.dv_xname);
322 	if (sc->sc_hwinit)
323 		(*sc->sc_hwinit)(sc);
324 
325 	return (0);
326 }
327 
328 /*
329  * Routine to copy from mbuf chain to transmit buffer in
330  * network buffer memory.
331  */
332 int
333 lance_put(struct lance_softc *sc, int boff, struct mbuf *m)
334 {
335 	struct mbuf *n;
336 	int len, tlen = 0;
337 
338 	for (; m; m = n) {
339 		len = m->m_len;
340 		if (len == 0) {
341 			MFREE(m, n);
342 			continue;
343 		}
344 		(*sc->sc_copytobuf)(sc, mtod(m, void *), boff, len);
345 		boff += len;
346 		tlen += len;
347 		MFREE(m, n);
348 	}
349 	if (tlen < LEMINSIZE) {
350 		(*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
351 		tlen = LEMINSIZE;
352 	}
353 	return (tlen);
354 }
355 
356 /*
357  * Pull data off an interface.
358  * Len is length of data, with local net header stripped.
359  * We copy the data into mbufs.  When full cluster sized units are present
360  * we copy into clusters.
361  */
362 integrate struct mbuf *
363 lance_get(struct lance_softc *sc, int boff, int totlen)
364 {
365 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
366 	struct mbuf *m, *top, **mp;
367 	int len, pad;
368 
369 	MGETHDR(m, M_DONTWAIT, MT_DATA);
370 	if (m == NULL)
371 		return (NULL);
372 	m->m_pkthdr.rcvif = ifp;
373 	m->m_pkthdr.len = totlen;
374 	pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
375 	m->m_data += pad;
376 	len = MHLEN - pad;
377 	top = NULL;
378 	mp = &top;
379 
380 	while (totlen > 0) {
381 		if (top) {
382 			MGET(m, M_DONTWAIT, MT_DATA);
383 			if (m == NULL) {
384 				m_freem(top);
385 				return NULL;
386 			}
387 			len = MLEN;
388 		}
389 		if (totlen >= MINCLSIZE) {
390 			MCLGET(m, M_DONTWAIT);
391 			if (m->m_flags & M_EXT) {
392 				len = MCLBYTES;
393 				if (!top) {
394 					m->m_data += pad;
395 					len -= pad;
396 				}
397 			}
398 		}
399 		m->m_len = len = min(totlen, len);
400 		(*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
401 		boff += len;
402 		totlen -= len;
403 		*mp = m;
404 		mp = &m->m_next;
405 	}
406 
407 	return (top);
408 }
409 
410 /*
411  * Pass a packet to the higher levels.
412  */
413 void
414 lance_read(struct lance_softc *sc, int boff, int len)
415 {
416 	struct mbuf *m;
417 	struct ifnet *ifp = &sc->sc_arpcom.ac_if;
418 	struct ether_header *eh;
419 
420 	if (len <= sizeof(struct ether_header) ||
421 	    len > ((ifp->if_capabilities & IFCAP_VLAN_MTU) ?
422 		ETHER_VLAN_ENCAP_LEN + ETHERMTU + sizeof(struct ether_header) :
423 		ETHERMTU + sizeof(struct ether_header))) {
424 #ifdef LEDEBUG
425 		printf("%s: invalid packet size %d; dropping\n",
426 		    sc->sc_dev.dv_xnam, len);
427 #endif
428 		ifp->if_ierrors++;
429 		return;
430 	}
431 
432 	/* Pull packet off interface. */
433 	m = lance_get(sc, boff, len);
434 	if (m == NULL) {
435 		ifp->if_ierrors++;
436 		return;
437 	}
438 
439 	ifp->if_ipackets++;
440 
441 	eh = mtod(m, struct ether_header *);
442 
443 #ifdef LANCE_REVC_BUG
444 	/*
445 	 * The old LANCE (Rev. C) chips have a bug which causes
446 	 * garbage to be inserted in front of the received packet.
447 	 * The work-around is to ignore packets with an invalid
448 	 * destination address (garbage will usually not match).
449 	 * Of course, this precludes multicast support...
450 	 */
451 	if (ETHER_CMP(eh->ether_dhost, sc->sc_arpcom.ac_enaddr) &&
452 	    ETHER_CMP(eh->ether_dhost, bcast_enaddr)) {
453 		m_freem(m);
454 		return;
455 	}
456 #endif
457 
458 	/*
459 	 * Some lance device does not present IFF_SIMPLEX behavior on multicast
460 	 * packets.  Make sure to drop it if it is from ourselves.
461 	 */
462 	if (!ETHER_CMP(eh->ether_shost, sc->sc_arpcom.ac_enaddr)) {
463 		m_freem(m);
464 		return;
465 	}
466 
467 #if NBPFILTER > 0
468 	/*
469 	 * Check if there's a BPF listener on this interface.
470 	 * If so, hand off the raw packet to BPF.
471 	 */
472 	if (ifp->if_bpf)
473 		bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
474 #endif
475 
476 	/* Pass the packet up. */
477 	ether_input_mbuf(ifp, m);
478 }
479 
480 void
481 lance_watchdog(struct ifnet *ifp)
482 {
483 	struct lance_softc *sc = ifp->if_softc;
484 
485 	log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
486 	++ifp->if_oerrors;
487 
488 	lance_reset(sc);
489 }
490 
491 int
492 lance_mediachange(struct ifnet *ifp)
493 {
494 	struct lance_softc *sc = ifp->if_softc;
495 
496 	if (sc->sc_mediachange)
497 		return ((*sc->sc_mediachange)(sc));
498 	return (0);
499 }
500 
501 void
502 lance_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
503 {
504 	struct lance_softc *sc = ifp->if_softc;
505 
506 	if ((ifp->if_flags & IFF_UP) == 0)
507 		return;
508 
509 	ifmr->ifm_status = IFM_AVALID;
510 	if (sc->sc_havecarrier)
511 		ifmr->ifm_status |= IFM_ACTIVE;
512 
513 	if (sc->sc_mediastatus)
514 		(*sc->sc_mediastatus)(sc, ifmr);
515 }
516 
517 /*
518  * Process an ioctl request.
519  */
520 int
521 lance_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
522 {
523 	struct lance_softc *sc = ifp->if_softc;
524 	struct ifaddr *ifa = (struct ifaddr *)data;
525 	struct ifreq *ifr = (struct ifreq *)data;
526 	int s, error = 0;
527 
528 	s = splnet();
529 
530 	switch (cmd) {
531 	case SIOCSIFADDR:
532 		ifp->if_flags |= IFF_UP;
533 		if (!(ifp->if_flags & IFF_RUNNING))
534 			lance_init(sc);
535 #ifdef INET
536 		if (ifa->ifa_addr->sa_family == AF_INET)
537 			arp_ifinit(&sc->sc_arpcom, ifa);
538 #endif
539 		break;
540 
541 	case SIOCSIFFLAGS:
542 		if (ifp->if_flags & IFF_UP) {
543 			if (ifp->if_flags & IFF_RUNNING)
544 				error = ENETRESET;
545 			else
546 				lance_init(sc);
547 		} else {
548 			if (ifp->if_flags & IFF_RUNNING) {
549 				lance_stop(ifp, 0);
550 				ifp->if_flags &= ~IFF_RUNNING;
551 			}
552 		}
553 
554 #ifdef LEDEBUG
555 		if (ifp->if_flags & IFF_DEBUG)
556 			sc->sc_debug = 1;
557 		else
558 			sc->sc_debug = 0;
559 #endif
560 		break;
561 
562 	case SIOCGIFMEDIA:
563 	case SIOCSIFMEDIA:
564 		error = ifmedia_ioctl(ifp, ifr, &sc->sc_ifmedia, cmd);
565 		break;
566 
567 	default:
568 		error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data);
569 		break;
570 	}
571 
572 	if (error == ENETRESET) {
573 		if (ifp->if_flags & IFF_RUNNING) {
574 			/*
575 			 * Multicast list has changed; set the hardware filter
576 			 * accordingly.
577 			 */
578 			lance_reset(sc);
579 		}
580 		error = 0;
581 	}
582 
583 	splx(s);
584 	return (error);
585 }
586 
587 /*
588  * Set up the logical address filter.
589  */
590 void
591 lance_setladrf(struct arpcom *ac, uint16_t *af)
592 {
593 	struct ifnet *ifp = &ac->ac_if;
594 	struct ether_multi *enm;
595 	uint32_t crc;
596 	struct ether_multistep step;
597 
598 	/*
599 	 * Set up multicast address filter by passing all multicast addresses
600 	 * through a crc generator, and then using the high order 6 bits as an
601 	 * index into the 64 bit logical address filter.  The high order bit
602 	 * selects the word, while the rest of the bits select the bit within
603 	 * the word.
604 	 */
605 
606 	if (ifp->if_flags & IFF_PROMISC || ac->ac_multirangecnt > 0)
607 		goto allmulti;
608 
609 	af[0] = af[1] = af[2] = af[3] = 0x0000;
610 	ETHER_FIRST_MULTI(step, ac, enm);
611 	while (enm != NULL) {
612 		crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
613 
614 		/* Just want the 6 most significant bits. */
615 		crc >>= 26;
616 
617 		/* Set the corresponding bit in the filter. */
618 		af[crc >> 4] |= 1 << (crc & 0xf);
619 
620 		ETHER_NEXT_MULTI(step, enm);
621 	}
622 	ifp->if_flags &= ~IFF_ALLMULTI;
623 	return;
624 
625 allmulti:
626 	ifp->if_flags |= IFF_ALLMULTI;
627 	af[0] = af[1] = af[2] = af[3] = 0xffff;
628 }
629 
630 /*
631  * Routines for accessing the transmit and receive buffers.
632  * The various CPU and adapter configurations supported by this
633  * driver require three different access methods for buffers
634  * and descriptors:
635  *	(1) contig (contiguous data; no padding),
636  *	(2) gap2 (two bytes of data followed by two bytes of padding),
637  *	(3) gap16 (16 bytes of data followed by 16 bytes of padding).
638  */
639 
640 /*
641  * contig: contiguous data with no padding.
642  *
643  * Buffers may have any alignment.
644  */
645 
646 void
647 lance_copytobuf_contig(struct lance_softc *sc, void *from, int boff, int len)
648 {
649 	uint8_t *buf = sc->sc_mem;
650 
651 	/*
652 	 * Just call memcpy() to do the work.
653 	 */
654 	memcpy(buf + boff, from, len);
655 }
656 
657 void
658 lance_copyfrombuf_contig(struct lance_softc *sc, void *to, int boff, int len)
659 {
660 	uint8_t *buf = sc->sc_mem;
661 
662 	/*
663 	 * Just call memcpy() to do the work.
664 	 */
665 	memcpy(to, buf + boff, len);
666 }
667 
668 void
669 lance_zerobuf_contig(struct lance_softc *sc, int boff, int len)
670 {
671 	uint8_t *buf = sc->sc_mem;
672 
673 	/*
674 	 * Just let memset() do the work
675 	 */
676 	memset(buf + boff, 0, len);
677 }
678 
679 #if 0
680 /*
681  * Examples only; duplicate these and tweak (if necessary) in
682  * machine-specific front-ends.
683  */
684 
685 /*
686  * gap2: two bytes of data followed by two bytes of pad.
687  *
688  * Buffers must be 4-byte aligned.  The code doesn't worry about
689  * doing an extra byte.
690  */
691 
692 void
693 lance_copytobuf_gap2(struct lance_softc *sc, void *fromv, int boff, int len)
694 {
695 	volatile void *buf = sc->sc_mem;
696 	void *from = fromv;
697 	volatile uint16_t *bptr;
698 
699 	if (boff & 0x1) {
700 		/* handle unaligned first byte */
701 		bptr = ((volatile uint16_t *)buf) + (boff - 1);
702 		*bptr = (*from++ << 8) | (*bptr & 0xff);
703 		bptr += 2;
704 		len--;
705 	} else
706 		bptr = ((volatile uint16_t *)buf) + boff;
707 	while (len > 1) {
708 		*bptr = (from[1] << 8) | (from[0] & 0xff);
709 		bptr += 2;
710 		from += 2;
711 		len -= 2;
712 	}
713 	if (len == 1)
714 		*bptr = (uint16_t)*from;
715 }
716 
717 void
718 lance_copyfrombuf_gap2(struct lance_softc *sc, void *tov, int boff, int len)
719 {
720 	volatile void *buf = sc->sc_mem;
721 	void *to = tov;
722 	volatile uint16_t *bptr;
723 	uint16_t tmp;
724 
725 	if (boff & 0x1) {
726 		/* handle unaligned first byte */
727 		bptr = ((volatile uint16_t *)buf) + (boff - 1);
728 		*to++ = (*bptr >> 8) & 0xff;
729 		bptr += 2;
730 		len--;
731 	} else
732 		bptr = ((volatile uint16_t *)buf) + boff;
733 	while (len > 1) {
734 		tmp = *bptr;
735 		*to++ = tmp & 0xff;
736 		*to++ = (tmp >> 8) & 0xff;
737 		bptr += 2;
738 		len -= 2;
739 	}
740 	if (len == 1)
741 		*to = *bptr & 0xff;
742 }
743 
744 void
745 lance_zerobuf_gap2(struct lance_softc *sc, int boff, int len)
746 {
747 	volatile void *buf = sc->sc_mem;
748 	volatile uint16_t *bptr;
749 
750 	if ((unsigned int)boff & 0x1) {
751 		bptr = ((volatile uint16_t *)buf) + (boff - 1);
752 		*bptr &= 0xff;
753 		bptr += 2;
754 		len--;
755 	} else
756 		bptr = ((volatile uint16_t *)buf) + boff;
757 	while (len > 0) {
758 		*bptr = 0;
759 		bptr += 2;
760 		len -= 2;
761 	}
762 }
763 
764 /*
765  * gap16: 16 bytes of data followed by 16 bytes of pad.
766  *
767  * Buffers must be 32-byte aligned.
768  */
769 
770 void
771 lance_copytobuf_gap16(struct lance_softc *sc, void *fromv, int boff, int len)
772 {
773 	volatile uint8_t *buf = sc->sc_mem;
774 	void *from = fromv;
775 	uint8_t *bptr;
776 	int xfer;
777 
778 	bptr = buf + ((boff << 1) & ~0x1f);
779 	boff &= 0xf;
780 	xfer = min(len, 16 - boff);
781 	while (len > 0) {
782 		memcpy(bptr + boff, from, xfer);
783 		from += xfer;
784 		bptr += 32;
785 		boff = 0;
786 		len -= xfer;
787 		xfer = min(len, 16);
788 	}
789 }
790 
791 void
792 lance_copyfrombuf_gap16(struct lance_softc *sc, void *tov, int boff, int len)
793 {
794 	volatile uint8_t *buf = sc->sc_mem;
795 	void *to = tov;
796 	uint8_t *bptr;
797 	int xfer;
798 
799 	bptr = buf + ((boff << 1) & ~0x1f);
800 	boff &= 0xf;
801 	xfer = min(len, 16 - boff);
802 	while (len > 0) {
803 		memcpy(to, bptr + boff, xfer);
804 		to += xfer;
805 		bptr += 32;
806 		boff = 0;
807 		len -= xfer;
808 		xfer = min(len, 16);
809 	}
810 }
811 
812 void
813 lance_zerobuf_gap16(struct lance_softc *sc, int boff, int len)
814 {
815 	volatile uint8_t *buf = sc->sc_mem;
816 	uint8_t *bptr;
817 	int xfer;
818 
819 	bptr = buf + ((boff << 1) & ~0x1f);
820 	boff &= 0xf;
821 	xfer = min(len, 16 - boff);
822 	while (len > 0) {
823 		memset(bptr + boff, 0, xfer);
824 		bptr += 32;
825 		boff = 0;
826 		len -= xfer;
827 		xfer = min(len, 16);
828 	}
829 }
830 #endif /* Example only */
831