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