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