1 /* $NetBSD: lance.c,v 1.34 2005/12/24 20:27:30 perry Exp $ */
2
3 /*-
4 * SPDX-License-Identifier: BSD-2-Clause
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
67 #include <sys/param.h>
68 #include <sys/bus.h>
69 #include <sys/endian.h>
70 #include <sys/lock.h>
71 #include <sys/kernel.h>
72 #include <sys/malloc.h>
73 #include <sys/mbuf.h>
74 #include <sys/mutex.h>
75 #include <sys/socket.h>
76 #include <sys/sockio.h>
77
78 #include <net/ethernet.h>
79 #include <net/if.h>
80 #include <net/if_var.h>
81 #include <net/if_arp.h>
82 #include <net/if_dl.h>
83 #include <net/if_media.h>
84 #include <net/if_types.h>
85 #include <net/if_vlan_var.h>
86
87 #include <machine/bus.h>
88
89 #include <dev/le/lancereg.h>
90 #include <dev/le/lancevar.h>
91
92 static void lance_start(if_t);
93 static void lance_stop(struct lance_softc *);
94 static void lance_init(void *);
95 static void lance_watchdog(void *s);
96 static int lance_mediachange(if_t);
97 static void lance_mediastatus(if_t, struct ifmediareq *);
98 static int lance_ioctl(if_t, u_long, caddr_t);
99
100 int
lance_config(struct lance_softc * sc,const char * name,int unit)101 lance_config(struct lance_softc *sc, const char* name, int unit)
102 {
103 if_t ifp;
104 int i, nbuf;
105
106 if (LE_LOCK_INITIALIZED(sc) == 0)
107 return (ENXIO);
108
109 ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
110 if (ifp == NULL)
111 return (ENOSPC);
112
113 callout_init_mtx(&sc->sc_wdog_ch, &sc->sc_mtx, 0);
114
115 /* Initialize ifnet structure. */
116 if_setsoftc(ifp, sc);
117 if_initname(ifp, name, unit);
118 if_setstartfn(ifp, lance_start);
119 if_setioctlfn(ifp, lance_ioctl);
120 if_setinitfn(ifp, lance_init);
121 if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
122 #ifdef LANCE_REVC_BUG
123 if_setflagsbit(ifp, 0, IFF_MULTICAST);
124 #endif
125 if_setbaudrate(ifp, IF_Mbps(10));
126 if_setsendqlen(ifp, ifqmaxlen);
127 if_setsendqready(ifp);
128
129 /* Initialize ifmedia structures. */
130 ifmedia_init(&sc->sc_media, 0, lance_mediachange, lance_mediastatus);
131 if (sc->sc_supmedia != NULL) {
132 for (i = 0; i < sc->sc_nsupmedia; i++)
133 ifmedia_add(&sc->sc_media, sc->sc_supmedia[i], 0, NULL);
134 ifmedia_set(&sc->sc_media, sc->sc_defaultmedia);
135 } else {
136 ifmedia_add(&sc->sc_media,
137 IFM_MAKEWORD(IFM_ETHER, IFM_MANUAL, 0, 0), 0, NULL);
138 ifmedia_set(&sc->sc_media,
139 IFM_MAKEWORD(IFM_ETHER, IFM_MANUAL, 0, 0));
140 }
141
142 switch (sc->sc_memsize) {
143 case 8192:
144 sc->sc_nrbuf = 4;
145 sc->sc_ntbuf = 1;
146 break;
147 case 16384:
148 sc->sc_nrbuf = 8;
149 sc->sc_ntbuf = 2;
150 break;
151 case 32768:
152 sc->sc_nrbuf = 16;
153 sc->sc_ntbuf = 4;
154 break;
155 case 65536:
156 sc->sc_nrbuf = 32;
157 sc->sc_ntbuf = 8;
158 break;
159 case 131072:
160 sc->sc_nrbuf = 64;
161 sc->sc_ntbuf = 16;
162 break;
163 case 262144:
164 sc->sc_nrbuf = 128;
165 sc->sc_ntbuf = 32;
166 break;
167 default:
168 /* weird memory size; cope with it */
169 nbuf = sc->sc_memsize / LEBLEN;
170 sc->sc_ntbuf = nbuf / 5;
171 sc->sc_nrbuf = nbuf - sc->sc_ntbuf;
172 }
173
174 if_printf(ifp, "%d receive buffers, %d transmit buffers\n",
175 sc->sc_nrbuf, sc->sc_ntbuf);
176
177 /* Make sure the chip is stopped. */
178 LE_LOCK(sc);
179 lance_stop(sc);
180 LE_UNLOCK(sc);
181
182 return (0);
183 }
184
185 void
lance_attach(struct lance_softc * sc)186 lance_attach(struct lance_softc *sc)
187 {
188 if_t ifp = sc->sc_ifp;
189
190 /* Attach the interface. */
191 ether_ifattach(ifp, sc->sc_enaddr);
192
193 /* Claim 802.1q capability. */
194 if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
195 if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0);
196 if_setcapenablebit(ifp, IFCAP_VLAN_MTU, 0);
197
198 gone_in(15, "le: 10/100 NIC no longer needed for Qemu/MIPS");
199 }
200
201 void
lance_detach(struct lance_softc * sc)202 lance_detach(struct lance_softc *sc)
203 {
204 if_t ifp = sc->sc_ifp;
205
206 LE_LOCK(sc);
207 lance_stop(sc);
208 LE_UNLOCK(sc);
209 callout_drain(&sc->sc_wdog_ch);
210 ether_ifdetach(ifp);
211 if_free(ifp);
212 }
213
214 void
lance_suspend(struct lance_softc * sc)215 lance_suspend(struct lance_softc *sc)
216 {
217
218 LE_LOCK(sc);
219 lance_stop(sc);
220 LE_UNLOCK(sc);
221 }
222
223 void
lance_resume(struct lance_softc * sc)224 lance_resume(struct lance_softc *sc)
225 {
226
227 LE_LOCK(sc);
228 if (if_getflags(sc->sc_ifp) & IFF_UP)
229 lance_init_locked(sc);
230 LE_UNLOCK(sc);
231 }
232
233 static void
lance_start(if_t ifp)234 lance_start(if_t ifp)
235 {
236 struct lance_softc *sc = if_getsoftc(ifp);
237
238 LE_LOCK(sc);
239 (*sc->sc_start_locked)(sc);
240 LE_UNLOCK(sc);
241 }
242
243 static void
lance_stop(struct lance_softc * sc)244 lance_stop(struct lance_softc *sc)
245 {
246 if_t ifp = sc->sc_ifp;
247
248 LE_LOCK_ASSERT(sc, MA_OWNED);
249
250 /*
251 * Mark the interface down and cancel the watchdog timer.
252 */
253 if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE));
254 callout_stop(&sc->sc_wdog_ch);
255 sc->sc_wdog_timer = 0;
256
257 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
258 }
259
260 static void
lance_init(void * xsc)261 lance_init(void *xsc)
262 {
263 struct lance_softc *sc = (struct lance_softc *)xsc;
264
265 LE_LOCK(sc);
266 lance_init_locked(sc);
267 LE_UNLOCK(sc);
268 }
269
270 /*
271 * Initialization of interface; set up initialization block
272 * and transmit/receive descriptor rings.
273 */
274 void
lance_init_locked(struct lance_softc * sc)275 lance_init_locked(struct lance_softc *sc)
276 {
277 if_t ifp = sc->sc_ifp;
278 u_long a;
279 int timo;
280
281 LE_LOCK_ASSERT(sc, MA_OWNED);
282
283 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
284 DELAY(100);
285
286 /* Newer LANCE chips have a reset register. */
287 if (sc->sc_hwreset)
288 (*sc->sc_hwreset)(sc);
289
290 /* Set the correct byte swapping mode, etc. */
291 (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
292
293 /* Set the current media. This may require the chip to be stopped. */
294 if (sc->sc_mediachange)
295 (void)(*sc->sc_mediachange)(sc);
296
297 /*
298 * Update our private copy of the Ethernet address.
299 * We NEED the copy so we can ensure its alignment!
300 */
301 memcpy(sc->sc_enaddr, if_getlladdr(ifp), ETHER_ADDR_LEN);
302
303 /* Set up LANCE init block. */
304 (*sc->sc_meminit)(sc);
305
306 /* Give LANCE the physical address of its init block. */
307 a = sc->sc_addr + LE_INITADDR(sc);
308 (*sc->sc_wrcsr)(sc, LE_CSR1, a & 0xffff);
309 (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
310
311 /* Try to initialize the LANCE. */
312 DELAY(100);
313 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
314
315 /* Wait for initialization to finish. */
316 for (timo = 100000; timo; timo--)
317 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
318 break;
319
320 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
321 /* Start the LANCE. */
322 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT);
323 if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
324 if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
325 sc->sc_wdog_timer = 0;
326 callout_reset(&sc->sc_wdog_ch, hz, lance_watchdog, sc);
327 (*sc->sc_start_locked)(sc);
328 } else
329 if_printf(ifp, "controller failed to initialize\n");
330
331 if (sc->sc_hwinit)
332 (*sc->sc_hwinit)(sc);
333 }
334
335 /*
336 * Routine to copy from mbuf chain to transmit buffer in
337 * network buffer memory.
338 */
339 int
lance_put(struct lance_softc * sc,int boff,struct mbuf * m)340 lance_put(struct lance_softc *sc, int boff, struct mbuf *m)
341 {
342 struct mbuf *n;
343 int len, tlen = 0;
344
345 LE_LOCK_ASSERT(sc, MA_OWNED);
346
347 for (; m; m = n) {
348 len = m->m_len;
349 if (len == 0) {
350 n = m_free(m);
351 m = NULL;
352 continue;
353 }
354 (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
355 boff += len;
356 tlen += len;
357 n = m_free(m);
358 m = NULL;
359 }
360 if (tlen < LEMINSIZE) {
361 (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
362 tlen = LEMINSIZE;
363 }
364 return (tlen);
365 }
366
367 /*
368 * Pull data off an interface.
369 * Len is length of data, with local net header stripped.
370 * We copy the data into mbufs. When full cluster sized units are present
371 * we copy into clusters.
372 */
373 struct mbuf *
lance_get(struct lance_softc * sc,int boff,int totlen)374 lance_get(struct lance_softc *sc, int boff, int totlen)
375 {
376 if_t ifp = sc->sc_ifp;
377 struct mbuf *m, *m0, *newm;
378 caddr_t newdata;
379 int len;
380
381 if (totlen <= ETHER_HDR_LEN || totlen > LEBLEN - ETHER_CRC_LEN) {
382 #ifdef LEDEBUG
383 if_printf(ifp, "invalid packet size %d; dropping\n", totlen);
384 #endif
385 return (NULL);
386 }
387
388 MGETHDR(m0, M_NOWAIT, MT_DATA);
389 if (m0 == NULL)
390 return (NULL);
391 m0->m_pkthdr.rcvif = ifp;
392 m0->m_pkthdr.len = totlen;
393 len = MHLEN;
394 m = m0;
395
396 while (totlen > 0) {
397 if (totlen >= MINCLSIZE) {
398 if (!(MCLGET(m, M_NOWAIT)))
399 goto bad;
400 len = MCLBYTES;
401 }
402
403 if (m == m0) {
404 newdata = (caddr_t)
405 ALIGN(m->m_data + ETHER_HDR_LEN) - ETHER_HDR_LEN;
406 len -= newdata - m->m_data;
407 m->m_data = newdata;
408 }
409
410 m->m_len = len = min(totlen, len);
411 (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
412 boff += len;
413
414 totlen -= len;
415 if (totlen > 0) {
416 MGET(newm, M_NOWAIT, MT_DATA);
417 if (newm == NULL)
418 goto bad;
419 len = MLEN;
420 m = m->m_next = newm;
421 }
422 }
423
424 return (m0);
425
426 bad:
427 m_freem(m0);
428 return (NULL);
429 }
430
431 static void
lance_watchdog(void * xsc)432 lance_watchdog(void *xsc)
433 {
434 struct lance_softc *sc = (struct lance_softc *)xsc;
435 if_t ifp = sc->sc_ifp;
436
437 LE_LOCK_ASSERT(sc, MA_OWNED);
438
439 if (sc->sc_wdog_timer == 0 || --sc->sc_wdog_timer != 0) {
440 callout_reset(&sc->sc_wdog_ch, hz, lance_watchdog, sc);
441 return;
442 }
443
444 if_printf(ifp, "device timeout\n");
445 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
446 lance_init_locked(sc);
447 }
448
449 static int
lance_mediachange(if_t ifp)450 lance_mediachange(if_t ifp)
451 {
452 struct lance_softc *sc = if_getsoftc(ifp);
453
454 if (sc->sc_mediachange) {
455 /*
456 * For setting the port in LE_CSR15 the PCnet chips must
457 * be powered down or stopped and unlike documented may
458 * not take effect without an initialization. So don't
459 * invoke (*sc_mediachange) directly here but go through
460 * lance_init_locked().
461 */
462 LE_LOCK(sc);
463 lance_stop(sc);
464 lance_init_locked(sc);
465 if (!if_sendq_empty(ifp))
466 (*sc->sc_start_locked)(sc);
467 LE_UNLOCK(sc);
468 }
469 return (0);
470 }
471
472 static void
lance_mediastatus(if_t ifp,struct ifmediareq * ifmr)473 lance_mediastatus(if_t ifp, struct ifmediareq *ifmr)
474 {
475 struct lance_softc *sc = if_getsoftc(ifp);
476
477 LE_LOCK(sc);
478 if (!(if_getflags(ifp) & IFF_UP)) {
479 LE_UNLOCK(sc);
480 return;
481 }
482
483 ifmr->ifm_status = IFM_AVALID;
484 if (sc->sc_flags & LE_CARRIER)
485 ifmr->ifm_status |= IFM_ACTIVE;
486
487 if (sc->sc_mediastatus)
488 (*sc->sc_mediastatus)(sc, ifmr);
489 LE_UNLOCK(sc);
490 }
491
492 /*
493 * Process an ioctl request.
494 */
495 static int
lance_ioctl(if_t ifp,u_long cmd,caddr_t data)496 lance_ioctl(if_t ifp, u_long cmd, caddr_t data)
497 {
498 struct lance_softc *sc = if_getsoftc(ifp);
499 struct ifreq *ifr = (struct ifreq *)data;
500 int error = 0;
501
502 switch (cmd) {
503 case SIOCSIFFLAGS:
504 LE_LOCK(sc);
505 if (if_getflags(ifp) & IFF_PROMISC) {
506 if (!(sc->sc_flags & LE_PROMISC)) {
507 sc->sc_flags |= LE_PROMISC;
508 lance_init_locked(sc);
509 }
510 } else if (sc->sc_flags & LE_PROMISC) {
511 sc->sc_flags &= ~LE_PROMISC;
512 lance_init_locked(sc);
513 }
514
515 if ((if_getflags(ifp) & IFF_ALLMULTI) &&
516 !(sc->sc_flags & LE_ALLMULTI)) {
517 sc->sc_flags |= LE_ALLMULTI;
518 lance_init_locked(sc);
519 } else if (!(if_getflags(ifp) & IFF_ALLMULTI) &&
520 (sc->sc_flags & LE_ALLMULTI)) {
521 sc->sc_flags &= ~LE_ALLMULTI;
522 lance_init_locked(sc);
523 }
524
525 if (!(if_getflags(ifp) & IFF_UP) &&
526 if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
527 /*
528 * If interface is marked down and it is running, then
529 * stop it.
530 */
531 lance_stop(sc);
532 } else if (if_getflags(ifp) & IFF_UP &&
533 !(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
534 /*
535 * If interface is marked up and it is stopped, then
536 * start it.
537 */
538 lance_init_locked(sc);
539 }
540 #ifdef LEDEBUG
541 if (if_getflags(ifp) & IFF_DEBUG)
542 sc->sc_flags |= LE_DEBUG;
543 else
544 sc->sc_flags &= ~LE_DEBUG;
545 #endif
546 LE_UNLOCK(sc);
547 break;
548
549 case SIOCADDMULTI:
550 case SIOCDELMULTI:
551 /*
552 * Multicast list has changed; set the hardware filter
553 * accordingly.
554 */
555 LE_LOCK(sc);
556 if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
557 lance_init_locked(sc);
558 LE_UNLOCK(sc);
559 break;
560
561 case SIOCGIFMEDIA:
562 case SIOCSIFMEDIA:
563 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
564 break;
565
566 default:
567 error = ether_ioctl(ifp, cmd, data);
568 break;
569 }
570
571 return (error);
572 }
573
574 struct lance_hash_maddr_ctx {
575 struct lance_softc *sc;
576 uint16_t *af;
577 };
578
579 static u_int
lance_hash_maddr(void * arg,struct sockaddr_dl * sdl,u_int cnt)580 lance_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
581 {
582 struct lance_hash_maddr_ctx *ctx = arg;
583 struct lance_softc *sc = ctx->sc;
584 uint32_t crc;
585
586 crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN);
587 /* Just want the 6 most significant bits. */
588 crc >>= 26;
589 /* Set the corresponding bit in the filter. */
590 ctx->af[crc >> 4] |= LE_HTOLE16(1 << (crc & 0xf));
591
592 return (1);
593 }
594
595 /*
596 * Set up the logical address filter.
597 */
598 void
lance_setladrf(struct lance_softc * sc,uint16_t * af)599 lance_setladrf(struct lance_softc *sc, uint16_t *af)
600 {
601 if_t ifp = sc->sc_ifp;
602 struct lance_hash_maddr_ctx ctx = { sc, af };
603
604 /*
605 * Set up multicast address filter by passing all multicast addresses
606 * through a crc generator, and then using the high order 6 bits as an
607 * index into the 64 bit logical address filter. The high order bit
608 * selects the word, while the rest of the bits select the bit within
609 * the word.
610 */
611
612 if (if_getflags(ifp) & IFF_PROMISC || sc->sc_flags & LE_ALLMULTI) {
613 af[0] = af[1] = af[2] = af[3] = 0xffff;
614 return;
615 }
616
617 af[0] = af[1] = af[2] = af[3] = 0x0000;
618 if_foreach_llmaddr(ifp, lance_hash_maddr, &ctx);
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
lance_copytobuf_contig(struct lance_softc * sc,void * from,int boff,int len)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
lance_copyfrombuf_contig(struct lance_softc * sc,void * to,int boff,int len)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
lance_zerobuf_contig(struct lance_softc * sc,int boff,int len)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 */
820