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