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