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
111 callout_init_mtx(&sc->sc_wdog_ch, &sc->sc_mtx, 0);
112
113 /* Initialize ifnet structure. */
114 if_setsoftc(ifp, sc);
115 if_initname(ifp, name, unit);
116 if_setstartfn(ifp, lance_start);
117 if_setioctlfn(ifp, lance_ioctl);
118 if_setinitfn(ifp, lance_init);
119 if_setflags(ifp, IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST);
120 #ifdef LANCE_REVC_BUG
121 if_setflagsbit(ifp, 0, IFF_MULTICAST);
122 #endif
123 if_setbaudrate(ifp, IF_Mbps(10));
124 if_setsendqlen(ifp, ifqmaxlen);
125 if_setsendqready(ifp);
126
127 /* Initialize ifmedia structures. */
128 ifmedia_init(&sc->sc_media, 0, lance_mediachange, lance_mediastatus);
129 if (sc->sc_supmedia != NULL) {
130 for (i = 0; i < sc->sc_nsupmedia; i++)
131 ifmedia_add(&sc->sc_media, sc->sc_supmedia[i], 0, NULL);
132 ifmedia_set(&sc->sc_media, sc->sc_defaultmedia);
133 } else {
134 ifmedia_add(&sc->sc_media,
135 IFM_MAKEWORD(IFM_ETHER, IFM_MANUAL, 0, 0), 0, NULL);
136 ifmedia_set(&sc->sc_media,
137 IFM_MAKEWORD(IFM_ETHER, IFM_MANUAL, 0, 0));
138 }
139
140 switch (sc->sc_memsize) {
141 case 8192:
142 sc->sc_nrbuf = 4;
143 sc->sc_ntbuf = 1;
144 break;
145 case 16384:
146 sc->sc_nrbuf = 8;
147 sc->sc_ntbuf = 2;
148 break;
149 case 32768:
150 sc->sc_nrbuf = 16;
151 sc->sc_ntbuf = 4;
152 break;
153 case 65536:
154 sc->sc_nrbuf = 32;
155 sc->sc_ntbuf = 8;
156 break;
157 case 131072:
158 sc->sc_nrbuf = 64;
159 sc->sc_ntbuf = 16;
160 break;
161 case 262144:
162 sc->sc_nrbuf = 128;
163 sc->sc_ntbuf = 32;
164 break;
165 default:
166 /* weird memory size; cope with it */
167 nbuf = sc->sc_memsize / LEBLEN;
168 sc->sc_ntbuf = nbuf / 5;
169 sc->sc_nrbuf = nbuf - sc->sc_ntbuf;
170 }
171
172 if_printf(ifp, "%d receive buffers, %d transmit buffers\n",
173 sc->sc_nrbuf, sc->sc_ntbuf);
174
175 /* Make sure the chip is stopped. */
176 LE_LOCK(sc);
177 lance_stop(sc);
178 LE_UNLOCK(sc);
179
180 return (0);
181 }
182
183 void
lance_attach(struct lance_softc * sc)184 lance_attach(struct lance_softc *sc)
185 {
186 if_t ifp = sc->sc_ifp;
187
188 /* Attach the interface. */
189 ether_ifattach(ifp, sc->sc_enaddr);
190
191 /* Claim 802.1q capability. */
192 if_setifheaderlen(ifp, sizeof(struct ether_vlan_header));
193 if_setcapabilitiesbit(ifp, IFCAP_VLAN_MTU, 0);
194 if_setcapenablebit(ifp, IFCAP_VLAN_MTU, 0);
195
196 gone_in(15, "le: 10/100 NIC no longer needed for Qemu/MIPS");
197 }
198
199 void
lance_detach(struct lance_softc * sc)200 lance_detach(struct lance_softc *sc)
201 {
202 if_t ifp = sc->sc_ifp;
203
204 LE_LOCK(sc);
205 lance_stop(sc);
206 LE_UNLOCK(sc);
207 callout_drain(&sc->sc_wdog_ch);
208 ether_ifdetach(ifp);
209 if_free(ifp);
210 }
211
212 void
lance_suspend(struct lance_softc * sc)213 lance_suspend(struct lance_softc *sc)
214 {
215
216 LE_LOCK(sc);
217 lance_stop(sc);
218 LE_UNLOCK(sc);
219 }
220
221 void
lance_resume(struct lance_softc * sc)222 lance_resume(struct lance_softc *sc)
223 {
224
225 LE_LOCK(sc);
226 if (if_getflags(sc->sc_ifp) & IFF_UP)
227 lance_init_locked(sc);
228 LE_UNLOCK(sc);
229 }
230
231 static void
lance_start(if_t ifp)232 lance_start(if_t ifp)
233 {
234 struct lance_softc *sc = if_getsoftc(ifp);
235
236 LE_LOCK(sc);
237 (*sc->sc_start_locked)(sc);
238 LE_UNLOCK(sc);
239 }
240
241 static void
lance_stop(struct lance_softc * sc)242 lance_stop(struct lance_softc *sc)
243 {
244 if_t ifp = sc->sc_ifp;
245
246 LE_LOCK_ASSERT(sc, MA_OWNED);
247
248 /*
249 * Mark the interface down and cancel the watchdog timer.
250 */
251 if_setdrvflagbits(ifp, 0, (IFF_DRV_RUNNING | IFF_DRV_OACTIVE));
252 callout_stop(&sc->sc_wdog_ch);
253 sc->sc_wdog_timer = 0;
254
255 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
256 }
257
258 static void
lance_init(void * xsc)259 lance_init(void *xsc)
260 {
261 struct lance_softc *sc = (struct lance_softc *)xsc;
262
263 LE_LOCK(sc);
264 lance_init_locked(sc);
265 LE_UNLOCK(sc);
266 }
267
268 /*
269 * Initialization of interface; set up initialization block
270 * and transmit/receive descriptor rings.
271 */
272 void
lance_init_locked(struct lance_softc * sc)273 lance_init_locked(struct lance_softc *sc)
274 {
275 if_t ifp = sc->sc_ifp;
276 u_long a;
277 int timo;
278
279 LE_LOCK_ASSERT(sc, MA_OWNED);
280
281 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
282 DELAY(100);
283
284 /* Newer LANCE chips have a reset register. */
285 if (sc->sc_hwreset)
286 (*sc->sc_hwreset)(sc);
287
288 /* Set the correct byte swapping mode, etc. */
289 (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
290
291 /* Set the current media. This may require the chip to be stopped. */
292 if (sc->sc_mediachange)
293 (void)(*sc->sc_mediachange)(sc);
294
295 /*
296 * Update our private copy of the Ethernet address.
297 * We NEED the copy so we can ensure its alignment!
298 */
299 memcpy(sc->sc_enaddr, if_getlladdr(ifp), ETHER_ADDR_LEN);
300
301 /* Set up LANCE init block. */
302 (*sc->sc_meminit)(sc);
303
304 /* Give LANCE the physical address of its init block. */
305 a = sc->sc_addr + LE_INITADDR(sc);
306 (*sc->sc_wrcsr)(sc, LE_CSR1, a & 0xffff);
307 (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
308
309 /* Try to initialize the LANCE. */
310 DELAY(100);
311 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
312
313 /* Wait for initialization to finish. */
314 for (timo = 100000; timo; timo--)
315 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
316 break;
317
318 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
319 /* Start the LANCE. */
320 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT);
321 if_setdrvflagbits(ifp, IFF_DRV_RUNNING, 0);
322 if_setdrvflagbits(ifp, 0, IFF_DRV_OACTIVE);
323 sc->sc_wdog_timer = 0;
324 callout_reset(&sc->sc_wdog_ch, hz, lance_watchdog, sc);
325 (*sc->sc_start_locked)(sc);
326 } else
327 if_printf(ifp, "controller failed to initialize\n");
328
329 if (sc->sc_hwinit)
330 (*sc->sc_hwinit)(sc);
331 }
332
333 /*
334 * Routine to copy from mbuf chain to transmit buffer in
335 * network buffer memory.
336 */
337 int
lance_put(struct lance_softc * sc,int boff,struct mbuf * m)338 lance_put(struct lance_softc *sc, int boff, struct mbuf *m)
339 {
340 struct mbuf *n;
341 int len, tlen = 0;
342
343 LE_LOCK_ASSERT(sc, MA_OWNED);
344
345 for (; m; m = n) {
346 len = m->m_len;
347 if (len == 0) {
348 n = m_free(m);
349 m = NULL;
350 continue;
351 }
352 (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
353 boff += len;
354 tlen += len;
355 n = m_free(m);
356 m = NULL;
357 }
358 if (tlen < LEMINSIZE) {
359 (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
360 tlen = LEMINSIZE;
361 }
362 return (tlen);
363 }
364
365 /*
366 * Pull data off an interface.
367 * Len is length of data, with local net header stripped.
368 * We copy the data into mbufs. When full cluster sized units are present
369 * we copy into clusters.
370 */
371 struct mbuf *
lance_get(struct lance_softc * sc,int boff,int totlen)372 lance_get(struct lance_softc *sc, int boff, int totlen)
373 {
374 if_t ifp = sc->sc_ifp;
375 struct mbuf *m, *m0, *newm;
376 caddr_t newdata;
377 int len;
378
379 if (totlen <= ETHER_HDR_LEN || totlen > LEBLEN - ETHER_CRC_LEN) {
380 #ifdef LEDEBUG
381 if_printf(ifp, "invalid packet size %d; dropping\n", totlen);
382 #endif
383 return (NULL);
384 }
385
386 MGETHDR(m0, M_NOWAIT, MT_DATA);
387 if (m0 == NULL)
388 return (NULL);
389 m0->m_pkthdr.rcvif = ifp;
390 m0->m_pkthdr.len = totlen;
391 len = MHLEN;
392 m = m0;
393
394 while (totlen > 0) {
395 if (totlen >= MINCLSIZE) {
396 if (!(MCLGET(m, M_NOWAIT)))
397 goto bad;
398 len = MCLBYTES;
399 }
400
401 if (m == m0) {
402 newdata = (caddr_t)
403 ALIGN(m->m_data + ETHER_HDR_LEN) - ETHER_HDR_LEN;
404 len -= newdata - m->m_data;
405 m->m_data = newdata;
406 }
407
408 m->m_len = len = min(totlen, len);
409 (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
410 boff += len;
411
412 totlen -= len;
413 if (totlen > 0) {
414 MGET(newm, M_NOWAIT, MT_DATA);
415 if (newm == NULL)
416 goto bad;
417 len = MLEN;
418 m = m->m_next = newm;
419 }
420 }
421
422 return (m0);
423
424 bad:
425 m_freem(m0);
426 return (NULL);
427 }
428
429 static void
lance_watchdog(void * xsc)430 lance_watchdog(void *xsc)
431 {
432 struct lance_softc *sc = (struct lance_softc *)xsc;
433 if_t ifp = sc->sc_ifp;
434
435 LE_LOCK_ASSERT(sc, MA_OWNED);
436
437 if (sc->sc_wdog_timer == 0 || --sc->sc_wdog_timer != 0) {
438 callout_reset(&sc->sc_wdog_ch, hz, lance_watchdog, sc);
439 return;
440 }
441
442 if_printf(ifp, "device timeout\n");
443 if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
444 lance_init_locked(sc);
445 }
446
447 static int
lance_mediachange(if_t ifp)448 lance_mediachange(if_t ifp)
449 {
450 struct lance_softc *sc = if_getsoftc(ifp);
451
452 if (sc->sc_mediachange) {
453 /*
454 * For setting the port in LE_CSR15 the PCnet chips must
455 * be powered down or stopped and unlike documented may
456 * not take effect without an initialization. So don't
457 * invoke (*sc_mediachange) directly here but go through
458 * lance_init_locked().
459 */
460 LE_LOCK(sc);
461 lance_stop(sc);
462 lance_init_locked(sc);
463 if (!if_sendq_empty(ifp))
464 (*sc->sc_start_locked)(sc);
465 LE_UNLOCK(sc);
466 }
467 return (0);
468 }
469
470 static void
lance_mediastatus(if_t ifp,struct ifmediareq * ifmr)471 lance_mediastatus(if_t ifp, struct ifmediareq *ifmr)
472 {
473 struct lance_softc *sc = if_getsoftc(ifp);
474
475 LE_LOCK(sc);
476 if (!(if_getflags(ifp) & IFF_UP)) {
477 LE_UNLOCK(sc);
478 return;
479 }
480
481 ifmr->ifm_status = IFM_AVALID;
482 if (sc->sc_flags & LE_CARRIER)
483 ifmr->ifm_status |= IFM_ACTIVE;
484
485 if (sc->sc_mediastatus)
486 (*sc->sc_mediastatus)(sc, ifmr);
487 LE_UNLOCK(sc);
488 }
489
490 /*
491 * Process an ioctl request.
492 */
493 static int
lance_ioctl(if_t ifp,u_long cmd,caddr_t data)494 lance_ioctl(if_t ifp, u_long cmd, caddr_t data)
495 {
496 struct lance_softc *sc = if_getsoftc(ifp);
497 struct ifreq *ifr = (struct ifreq *)data;
498 int error = 0;
499
500 switch (cmd) {
501 case SIOCSIFFLAGS:
502 LE_LOCK(sc);
503 if (if_getflags(ifp) & IFF_PROMISC) {
504 if (!(sc->sc_flags & LE_PROMISC)) {
505 sc->sc_flags |= LE_PROMISC;
506 lance_init_locked(sc);
507 }
508 } else if (sc->sc_flags & LE_PROMISC) {
509 sc->sc_flags &= ~LE_PROMISC;
510 lance_init_locked(sc);
511 }
512
513 if ((if_getflags(ifp) & IFF_ALLMULTI) &&
514 !(sc->sc_flags & LE_ALLMULTI)) {
515 sc->sc_flags |= LE_ALLMULTI;
516 lance_init_locked(sc);
517 } else if (!(if_getflags(ifp) & IFF_ALLMULTI) &&
518 (sc->sc_flags & LE_ALLMULTI)) {
519 sc->sc_flags &= ~LE_ALLMULTI;
520 lance_init_locked(sc);
521 }
522
523 if (!(if_getflags(ifp) & IFF_UP) &&
524 if_getdrvflags(ifp) & IFF_DRV_RUNNING) {
525 /*
526 * If interface is marked down and it is running, then
527 * stop it.
528 */
529 lance_stop(sc);
530 } else if (if_getflags(ifp) & IFF_UP &&
531 !(if_getdrvflags(ifp) & IFF_DRV_RUNNING)) {
532 /*
533 * If interface is marked up and it is stopped, then
534 * start it.
535 */
536 lance_init_locked(sc);
537 }
538 #ifdef LEDEBUG
539 if (if_getflags(ifp) & IFF_DEBUG)
540 sc->sc_flags |= LE_DEBUG;
541 else
542 sc->sc_flags &= ~LE_DEBUG;
543 #endif
544 LE_UNLOCK(sc);
545 break;
546
547 case SIOCADDMULTI:
548 case SIOCDELMULTI:
549 /*
550 * Multicast list has changed; set the hardware filter
551 * accordingly.
552 */
553 LE_LOCK(sc);
554 if (if_getdrvflags(ifp) & IFF_DRV_RUNNING)
555 lance_init_locked(sc);
556 LE_UNLOCK(sc);
557 break;
558
559 case SIOCGIFMEDIA:
560 case SIOCSIFMEDIA:
561 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
562 break;
563
564 default:
565 error = ether_ioctl(ifp, cmd, data);
566 break;
567 }
568
569 return (error);
570 }
571
572 struct lance_hash_maddr_ctx {
573 struct lance_softc *sc;
574 uint16_t *af;
575 };
576
577 static u_int
lance_hash_maddr(void * arg,struct sockaddr_dl * sdl,u_int cnt)578 lance_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
579 {
580 struct lance_hash_maddr_ctx *ctx = arg;
581 struct lance_softc *sc = ctx->sc;
582 uint32_t crc;
583
584 crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN);
585 /* Just want the 6 most significant bits. */
586 crc >>= 26;
587 /* Set the corresponding bit in the filter. */
588 ctx->af[crc >> 4] |= LE_HTOLE16(1 << (crc & 0xf));
589
590 return (1);
591 }
592
593 /*
594 * Set up the logical address filter.
595 */
596 void
lance_setladrf(struct lance_softc * sc,uint16_t * af)597 lance_setladrf(struct lance_softc *sc, uint16_t *af)
598 {
599 if_t ifp = sc->sc_ifp;
600 struct lance_hash_maddr_ctx ctx = { sc, af };
601
602 /*
603 * Set up multicast address filter by passing all multicast addresses
604 * through a crc generator, and then using the high order 6 bits as an
605 * index into the 64 bit logical address filter. The high order bit
606 * selects the word, while the rest of the bits select the bit within
607 * the word.
608 */
609
610 if (if_getflags(ifp) & IFF_PROMISC || sc->sc_flags & LE_ALLMULTI) {
611 af[0] = af[1] = af[2] = af[3] = 0xffff;
612 return;
613 }
614
615 af[0] = af[1] = af[2] = af[3] = 0x0000;
616 if_foreach_llmaddr(ifp, lance_hash_maddr, &ctx);
617 }
618
619 /*
620 * Routines for accessing the transmit and receive buffers.
621 * The various CPU and adapter configurations supported by this
622 * driver require three different access methods for buffers
623 * and descriptors:
624 * (1) contig (contiguous data; no padding),
625 * (2) gap2 (two bytes of data followed by two bytes of padding),
626 * (3) gap16 (16 bytes of data followed by 16 bytes of padding).
627 */
628
629 /*
630 * contig: contiguous data with no padding.
631 *
632 * Buffers may have any alignment.
633 */
634
635 void
lance_copytobuf_contig(struct lance_softc * sc,void * from,int boff,int len)636 lance_copytobuf_contig(struct lance_softc *sc, void *from, int boff, int len)
637 {
638 volatile caddr_t buf = sc->sc_mem;
639
640 /*
641 * Just call memcpy() to do the work.
642 */
643 memcpy(buf + boff, from, len);
644 }
645
646 void
lance_copyfrombuf_contig(struct lance_softc * sc,void * to,int boff,int len)647 lance_copyfrombuf_contig(struct lance_softc *sc, void *to, int boff, int len)
648 {
649 volatile caddr_t buf = sc->sc_mem;
650
651 /*
652 * Just call memcpy() to do the work.
653 */
654 memcpy(to, buf + boff, len);
655 }
656
657 void
lance_zerobuf_contig(struct lance_softc * sc,int boff,int len)658 lance_zerobuf_contig(struct lance_softc *sc, int boff, int len)
659 {
660 volatile caddr_t buf = sc->sc_mem;
661
662 /*
663 * Just let memset() do the work
664 */
665 memset(buf + boff, 0, len);
666 }
667
668 #if 0
669 /*
670 * Examples only; duplicate these and tweak (if necessary) in
671 * machine-specific front-ends.
672 */
673
674 /*
675 * gap2: two bytes of data followed by two bytes of pad.
676 *
677 * Buffers must be 4-byte aligned. The code doesn't worry about
678 * doing an extra byte.
679 */
680
681 static void
682 lance_copytobuf_gap2(struct lance_softc *sc, void *fromv, int boff, int len)
683 {
684 volatile caddr_t buf = sc->sc_mem;
685 caddr_t from = fromv;
686 volatile uint16_t *bptr;
687
688 if (boff & 0x1) {
689 /* Handle unaligned first byte. */
690 bptr = ((volatile uint16_t *)buf) + (boff - 1);
691 *bptr = (*from++ << 8) | (*bptr & 0xff);
692 bptr += 2;
693 len--;
694 } else
695 bptr = ((volatile uint16_t *)buf) + boff;
696 while (len > 1) {
697 *bptr = (from[1] << 8) | (from[0] & 0xff);
698 bptr += 2;
699 from += 2;
700 len -= 2;
701 }
702 if (len == 1)
703 *bptr = (uint16_t)*from;
704 }
705
706 static void
707 lance_copyfrombuf_gap2(struct lance_softc *sc, void *tov, int boff, int len)
708 {
709 volatile caddr_t buf = sc->sc_mem;
710 caddr_t to = tov;
711 volatile uint16_t *bptr;
712 uint16_t tmp;
713
714 if (boff & 0x1) {
715 /* Handle unaligned first byte. */
716 bptr = ((volatile uint16_t *)buf) + (boff - 1);
717 *to++ = (*bptr >> 8) & 0xff;
718 bptr += 2;
719 len--;
720 } else
721 bptr = ((volatile uint16_t *)buf) + boff;
722 while (len > 1) {
723 tmp = *bptr;
724 *to++ = tmp & 0xff;
725 *to++ = (tmp >> 8) & 0xff;
726 bptr += 2;
727 len -= 2;
728 }
729 if (len == 1)
730 *to = *bptr & 0xff;
731 }
732
733 static void
734 lance_zerobuf_gap2(struct lance_softc *sc, int boff, int len)
735 {
736 volatile caddr_t buf = sc->sc_mem;
737 volatile uint16_t *bptr;
738
739 if ((unsigned)boff & 0x1) {
740 bptr = ((volatile uint16_t *)buf) + (boff - 1);
741 *bptr &= 0xff;
742 bptr += 2;
743 len--;
744 } else
745 bptr = ((volatile uint16_t *)buf) + boff;
746 while (len > 0) {
747 *bptr = 0;
748 bptr += 2;
749 len -= 2;
750 }
751 }
752
753 /*
754 * gap16: 16 bytes of data followed by 16 bytes of pad.
755 *
756 * Buffers must be 32-byte aligned.
757 */
758
759 static void
760 lance_copytobuf_gap16(struct lance_softc *sc, void *fromv, int boff, int len)
761 {
762 volatile caddr_t buf = sc->sc_mem;
763 caddr_t bptr, from = fromv;
764 int xfer;
765
766 bptr = buf + ((boff << 1) & ~0x1f);
767 boff &= 0xf;
768 xfer = min(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 = min(len, 16);
776 }
777 }
778
779 static void
780 lance_copyfrombuf_gap16(struct lance_softc *sc, void *tov, int boff, int len)
781 {
782 volatile caddr_t buf = sc->sc_mem;
783 caddr_t bptr, to = tov;
784 int xfer;
785
786 bptr = buf + ((boff << 1) & ~0x1f);
787 boff &= 0xf;
788 xfer = min(len, 16 - boff);
789 while (len > 0) {
790 memcpy(to, bptr + boff, xfer);
791 to += xfer;
792 bptr += 32;
793 boff = 0;
794 len -= xfer;
795 xfer = min(len, 16);
796 }
797 }
798
799 static void
800 lance_zerobuf_gap16(struct lance_softc *sc, int boff, int len)
801 {
802 volatile caddr_t buf = sc->sc_mem;
803 caddr_t bptr;
804 int xfer;
805
806 bptr = buf + ((boff << 1) & ~0x1f);
807 boff &= 0xf;
808 xfer = min(len, 16 - boff);
809 while (len > 0) {
810 memset(bptr + boff, 0, xfer);
811 bptr += 32;
812 boff = 0;
813 len -= xfer;
814 xfer = min(len, 16);
815 }
816 }
817 #endif /* Example only */
818