am7990.c revision 1.36 1 /* $NetBSD: am7990.c,v 1.36 1997/10/05 18:35:07 thorpej Exp $ */
2
3 /*-
4 * Copyright (c) 1997 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
9 * NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40 /*-
41 * Copyright (c) 1995 Charles M. Hannum. All rights reserved.
42 * Copyright (c) 1992, 1993
43 * The Regents of the University of California. All rights reserved.
44 *
45 * This code is derived from software contributed to Berkeley by
46 * Ralph Campbell and Rick Macklem.
47 *
48 * Redistribution and use in source and binary forms, with or without
49 * modification, are permitted provided that the following conditions
50 * are met:
51 * 1. Redistributions of source code must retain the above copyright
52 * notice, this list of conditions and the following disclaimer.
53 * 2. Redistributions in binary form must reproduce the above copyright
54 * notice, this list of conditions and the following disclaimer in the
55 * documentation and/or other materials provided with the distribution.
56 * 3. All advertising materials mentioning features or use of this software
57 * must display the following acknowledgement:
58 * This product includes software developed by the University of
59 * California, Berkeley and its contributors.
60 * 4. Neither the name of the University nor the names of its contributors
61 * may be used to endorse or promote products derived from this software
62 * without specific prior written permission.
63 *
64 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
65 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
66 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
67 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
68 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
69 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
70 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
71 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
72 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
73 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
74 * SUCH DAMAGE.
75 *
76 * @(#)if_le.c 8.2 (Berkeley) 11/16/93
77 */
78
79 #include "bpfilter.h"
80
81 #include <sys/param.h>
82 #include <sys/systm.h>
83 #include <sys/mbuf.h>
84 #include <sys/syslog.h>
85 #include <sys/socket.h>
86 #include <sys/device.h>
87 #include <sys/malloc.h>
88 #include <sys/ioctl.h>
89 #include <sys/errno.h>
90
91 #include <net/if.h>
92 #include <net/if_dl.h>
93 #include <net/if_ether.h>
94 #include <net/if_media.h>
95
96 #ifdef INET
97 #include <netinet/in.h>
98 #include <netinet/if_inarp.h>
99 #include <netinet/in_systm.h>
100 #include <netinet/in_var.h>
101 #include <netinet/ip.h>
102 #endif
103
104 #ifdef NS
105 #include <netns/ns.h>
106 #include <netns/ns_if.h>
107 #endif
108
109 #if defined(CCITT) && defined(LLC)
110 #include <sys/socketvar.h>
111 #include <netccitt/x25.h>
112 #include <netccitt/pk.h>
113 #include <netccitt/pk_var.h>
114 #include <netccitt/pk_extern.h>
115 #endif
116
117 #if NBPFILTER > 0
118 #include <net/bpf.h>
119 #include <net/bpfdesc.h>
120 #endif
121
122 #include <dev/ic/am7990reg.h>
123 #include <dev/ic/am7990var.h>
124
125 #ifdef LEDEBUG
126 void am7990_recv_print __P((struct am7990_softc *, int));
127 void am7990_xmit_print __P((struct am7990_softc *, int));
128 #endif
129
130 integrate void am7990_rint __P((struct am7990_softc *));
131 integrate void am7990_tint __P((struct am7990_softc *));
132
133 integrate int am7990_put __P((struct am7990_softc *, int, struct mbuf *));
134 integrate struct mbuf *am7990_get __P((struct am7990_softc *, int, int));
135 integrate void am7990_read __P((struct am7990_softc *, int, int));
136
137 hide void am7990_shutdown __P((void *));
138
139 int am7990_mediachange __P((struct ifnet *));
140 void am7990_mediastatus __P((struct ifnet *, struct ifmediareq *));
141
142 #define ifp (&sc->sc_ethercom.ec_if)
143
144 static inline int ether_cmp __P((char *, char *));
145
146 /*
147 * Compare two Ether/802 addresses for equality, inlined and
148 * unrolled for speed.
149 * Note: test last byte of ethernet address first, as it will
150 * likely have the most random distribution.
151 */
152 static inline int
153 ether_cmp(a, b)
154 char *a, *b;
155 {
156
157 return ((a[5] != b[5]) || (a[4] != b[4]) || (a[3] != b[3]) ||
158 (a[2] != b[2]) || (a[1] != b[1]) || (a[0] != b[0]));
159 }
160
161 #define ETHER_CMP ether_cmp
162
163 /*
164 * am7990 configuration driver. Attachments are provided by
165 * machine-dependent driver front-ends.
166 */
167 struct cfdriver le_cd = {
168 NULL, "le", DV_IFNET
169 };
170
171 void
172 am7990_config(sc)
173 struct am7990_softc *sc;
174 {
175 int mem, i;
176
177 /* Make sure the chip is stopped. */
178 am7990_stop(sc);
179
180 /* Initialize ifnet structure. */
181 bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
182 ifp->if_softc = sc;
183 ifp->if_start = am7990_start;
184 ifp->if_ioctl = am7990_ioctl;
185 ifp->if_watchdog = am7990_watchdog;
186 ifp->if_flags =
187 IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
188 #ifdef LANCE_REVC_BUG
189 ifp->if_flags &= ~IFF_MULTICAST;
190 #endif
191
192 /* Initialize ifmedia structures. */
193 ifmedia_init(&sc->sc_media, 0, am7990_mediachange, am7990_mediastatus);
194 if (sc->sc_supmedia != NULL) {
195 for (i = 0; i < sc->sc_nsupmedia; i++)
196 ifmedia_add(&sc->sc_media, sc->sc_supmedia[i],
197 0, NULL);
198 ifmedia_set(&sc->sc_media, sc->sc_defaultmedia);
199 } else {
200 ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
201 ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
202 }
203
204 /* Attach the interface. */
205 if_attach(ifp);
206 ether_ifattach(ifp, sc->sc_enaddr);
207
208 #if NBPFILTER > 0
209 bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
210 #endif
211
212 switch (sc->sc_memsize) {
213 case 8192:
214 sc->sc_nrbuf = 4;
215 sc->sc_ntbuf = 1;
216 break;
217 case 16384:
218 sc->sc_nrbuf = 8;
219 sc->sc_ntbuf = 2;
220 break;
221 case 32768:
222 sc->sc_nrbuf = 16;
223 sc->sc_ntbuf = 4;
224 break;
225 case 65536:
226 sc->sc_nrbuf = 32;
227 sc->sc_ntbuf = 8;
228 break;
229 case 131072:
230 sc->sc_nrbuf = 64;
231 sc->sc_ntbuf = 16;
232 break;
233 default:
234 panic("am7990_config: weird memory size");
235 }
236
237 printf(": address %s\n", ether_sprintf(sc->sc_enaddr));
238 printf("%s: %d receive buffers, %d transmit buffers\n",
239 sc->sc_dev.dv_xname, sc->sc_nrbuf, sc->sc_ntbuf);
240
241 sc->sc_sh = shutdownhook_establish(am7990_shutdown, sc);
242 if (sc->sc_sh == NULL)
243 panic("am7990_config: can't establish shutdownhook");
244 sc->sc_rbufaddr = malloc(sc->sc_nrbuf * sizeof(int), M_DEVBUF,
245 M_WAITOK);
246 sc->sc_tbufaddr = malloc(sc->sc_ntbuf * sizeof(int), M_DEVBUF,
247 M_WAITOK);
248
249 mem = 0;
250 sc->sc_initaddr = mem;
251 mem += sizeof(struct leinit);
252 sc->sc_rmdaddr = mem;
253 mem += sizeof(struct lermd) * sc->sc_nrbuf;
254 sc->sc_tmdaddr = mem;
255 mem += sizeof(struct letmd) * sc->sc_ntbuf;
256 for (i = 0; i < sc->sc_nrbuf; i++, mem += LEBLEN)
257 sc->sc_rbufaddr[i] = mem;
258 for (i = 0; i < sc->sc_ntbuf; i++, mem += LEBLEN)
259 sc->sc_tbufaddr[i] = mem;
260 #ifdef notyet
261 if (mem > ...)
262 panic(...);
263 #endif
264 }
265
266 void
267 am7990_reset(sc)
268 struct am7990_softc *sc;
269 {
270 int s;
271
272 s = splimp();
273 am7990_init(sc);
274 splx(s);
275 }
276
277 /*
278 * Set up the initialization block and the descriptor rings.
279 */
280 void
281 am7990_meminit(sc)
282 register struct am7990_softc *sc;
283 {
284 u_long a;
285 int bix;
286 struct leinit init;
287 struct lermd rmd;
288 struct letmd tmd;
289 u_int8_t *myaddr;
290
291 #if NBPFILTER > 0
292 if (ifp->if_flags & IFF_PROMISC)
293 init.init_mode = LE_MODE_NORMAL | LE_MODE_PROM;
294 else
295 #endif
296 init.init_mode = LE_MODE_NORMAL;
297 if (sc->sc_initmodemedia == 1)
298 init.init_mode |= LE_MODE_PSEL0;
299
300 myaddr = LLADDR(ifp->if_sadl);
301 init.init_padr[0] = (myaddr[1] << 8) | myaddr[0];
302 init.init_padr[1] = (myaddr[3] << 8) | myaddr[2];
303 init.init_padr[2] = (myaddr[5] << 8) | myaddr[4];
304 am7990_setladrf(&sc->sc_ethercom, init.init_ladrf);
305
306 sc->sc_last_rd = 0;
307 sc->sc_first_td = sc->sc_last_td = sc->sc_no_td = 0;
308
309 a = sc->sc_addr + LE_RMDADDR(sc, 0);
310 init.init_rdra = a;
311 init.init_rlen = (a >> 16) | ((ffs(sc->sc_nrbuf) - 1) << 13);
312
313 a = sc->sc_addr + LE_TMDADDR(sc, 0);
314 init.init_tdra = a;
315 init.init_tlen = (a >> 16) | ((ffs(sc->sc_ntbuf) - 1) << 13);
316
317 (*sc->sc_copytodesc)(sc, &init, LE_INITADDR(sc), sizeof(init));
318
319 /*
320 * Set up receive ring descriptors.
321 */
322 for (bix = 0; bix < sc->sc_nrbuf; bix++) {
323 a = sc->sc_addr + LE_RBUFADDR(sc, bix);
324 rmd.rmd0 = a;
325 rmd.rmd1_hadr = a >> 16;
326 rmd.rmd1_bits = LE_R1_OWN;
327 rmd.rmd2 = -LEBLEN | LE_XMD2_ONES;
328 rmd.rmd3 = 0;
329 (*sc->sc_copytodesc)(sc, &rmd, LE_RMDADDR(sc, bix),
330 sizeof(rmd));
331 }
332
333 /*
334 * Set up transmit ring descriptors.
335 */
336 for (bix = 0; bix < sc->sc_ntbuf; bix++) {
337 a = sc->sc_addr + LE_TBUFADDR(sc, bix);
338 tmd.tmd0 = a;
339 tmd.tmd1_hadr = a >> 16;
340 tmd.tmd1_bits = 0;
341 tmd.tmd2 = 0 | LE_XMD2_ONES;
342 tmd.tmd3 = 0;
343 (*sc->sc_copytodesc)(sc, &tmd, LE_TMDADDR(sc, bix),
344 sizeof(tmd));
345 }
346 }
347
348 void
349 am7990_stop(sc)
350 struct am7990_softc *sc;
351 {
352
353 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
354 }
355
356 /*
357 * Initialization of interface; set up initialization block
358 * and transmit/receive descriptor rings.
359 */
360 void
361 am7990_init(sc)
362 register struct am7990_softc *sc;
363 {
364 register int timo;
365 u_long a;
366
367 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
368 DELAY(100);
369
370 /* Newer LANCE chips have a reset register */
371 if (sc->sc_hwreset)
372 (*sc->sc_hwreset)(sc);
373
374 /* Set the correct byte swapping mode, etc. */
375 (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
376
377 /* Set up LANCE init block. */
378 am7990_meminit(sc);
379
380 /* Give LANCE the physical address of its init block. */
381 a = sc->sc_addr + LE_INITADDR(sc);
382 (*sc->sc_wrcsr)(sc, LE_CSR1, a);
383 (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
384
385 /* Try to initialize the LANCE. */
386 DELAY(100);
387 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
388
389 /* Wait for initialization to finish. */
390 for (timo = 100000; timo; timo--)
391 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
392 break;
393
394 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
395 /* Start the LANCE. */
396 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT |
397 LE_C0_IDON);
398 ifp->if_flags |= IFF_RUNNING;
399 ifp->if_flags &= ~IFF_OACTIVE;
400 ifp->if_timer = 0;
401 am7990_start(ifp);
402 } else
403 printf("%s: card failed to initialize\n", sc->sc_dev.dv_xname);
404 if (sc->sc_hwinit)
405 (*sc->sc_hwinit)(sc);
406 }
407
408 /*
409 * Routine to copy from mbuf chain to transmit buffer in
410 * network buffer memory.
411 */
412 integrate int
413 am7990_put(sc, boff, m)
414 struct am7990_softc *sc;
415 int boff;
416 register struct mbuf *m;
417 {
418 register struct mbuf *n;
419 register int len, tlen = 0;
420
421 for (; m; m = n) {
422 len = m->m_len;
423 if (len == 0) {
424 MFREE(m, n);
425 continue;
426 }
427 (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
428 boff += len;
429 tlen += len;
430 MFREE(m, n);
431 }
432 if (tlen < LEMINSIZE) {
433 (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
434 tlen = LEMINSIZE;
435 }
436 return (tlen);
437 }
438
439 /*
440 * Pull data off an interface.
441 * Len is length of data, with local net header stripped.
442 * We copy the data into mbufs. When full cluster sized units are present
443 * we copy into clusters.
444 */
445 integrate struct mbuf *
446 am7990_get(sc, boff, totlen)
447 struct am7990_softc *sc;
448 int boff, totlen;
449 {
450 register struct mbuf *m;
451 struct mbuf *top, **mp;
452 int len;
453
454 MGETHDR(m, M_DONTWAIT, MT_DATA);
455 if (m == 0)
456 return (0);
457 m->m_pkthdr.rcvif = ifp;
458 m->m_pkthdr.len = totlen;
459 len = MHLEN;
460 top = 0;
461 mp = ⊤
462
463 while (totlen > 0) {
464 if (top) {
465 MGET(m, M_DONTWAIT, MT_DATA);
466 if (m == 0) {
467 m_freem(top);
468 return 0;
469 }
470 len = MLEN;
471 }
472 if (totlen >= MINCLSIZE) {
473 MCLGET(m, M_DONTWAIT);
474 if ((m->m_flags & M_EXT) == 0) {
475 m_free(m);
476 m_freem(top);
477 return 0;
478 }
479 len = MCLBYTES;
480 }
481 if (!top) {
482 register int pad =
483 ALIGN(sizeof(struct ether_header)) -
484 sizeof(struct ether_header);
485 m->m_data += pad;
486 len -= pad;
487 }
488 m->m_len = len = min(totlen, len);
489 (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
490 boff += len;
491 totlen -= len;
492 *mp = m;
493 mp = &m->m_next;
494 }
495
496 return (top);
497 }
498
499 /*
500 * Pass a packet to the higher levels.
501 */
502 integrate void
503 am7990_read(sc, boff, len)
504 register struct am7990_softc *sc;
505 int boff, len;
506 {
507 struct mbuf *m;
508 struct ether_header *eh;
509
510 if (len <= sizeof(struct ether_header) ||
511 len > ETHERMTU + sizeof(struct ether_header)) {
512 #ifdef LEDEBUG
513 printf("%s: invalid packet size %d; dropping\n",
514 sc->sc_dev.dv_xname, len);
515 #endif
516 ifp->if_ierrors++;
517 return;
518 }
519
520 /* Pull packet off interface. */
521 m = am7990_get(sc, boff, len);
522 if (m == 0) {
523 ifp->if_ierrors++;
524 return;
525 }
526
527 ifp->if_ipackets++;
528
529 /* We assume that the header fit entirely in one mbuf. */
530 eh = mtod(m, struct ether_header *);
531
532 #if NBPFILTER > 0
533 /*
534 * Check if there's a BPF listener on this interface.
535 * If so, hand off the raw packet to BPF.
536 */
537 if (ifp->if_bpf) {
538 bpf_mtap(ifp->if_bpf, m);
539
540 #ifndef LANCE_REVC_BUG
541 /*
542 * Note that the interface cannot be in promiscuous mode if
543 * there are no BPF listeners. And if we are in promiscuous
544 * mode, we have to check if this packet is really ours.
545 */
546 if ((ifp->if_flags & IFF_PROMISC) != 0 &&
547 (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
548 ETHER_CMP(eh->ether_dhost, LLADDR(ifp->if_sadl))) {
549 m_freem(m);
550 return;
551 }
552 #endif
553 }
554 #endif
555
556 #ifdef LANCE_REVC_BUG
557 /*
558 * The old LANCE (Rev. C) chips have a bug which causes
559 * garbage to be inserted in front of the received packet.
560 * The work-around is to ignore packets with an invalid
561 * destination address (garbage will usually not match).
562 * Of course, this precludes multicast support...
563 */
564 if (ETHER_CMP(eh->ether_dhost, LLADDR(ifp->if_sadl)) &&
565 ETHER_CMP(eh->ether_dhost, etherbroadcastaddr)) {
566 m_freem(m);
567 return;
568 }
569 #endif
570
571 /* Pass the packet up, with the ether header sort-of removed. */
572 m_adj(m, sizeof(struct ether_header));
573 ether_input(ifp, eh, m);
574 }
575
576 integrate void
577 am7990_rint(sc)
578 struct am7990_softc *sc;
579 {
580 register int bix;
581 int rp;
582 struct lermd rmd;
583
584 bix = sc->sc_last_rd;
585
586 /* Process all buffers with valid data. */
587 for (;;) {
588 rp = LE_RMDADDR(sc, bix);
589 (*sc->sc_copyfromdesc)(sc, &rmd, rp, sizeof(rmd));
590
591 if (rmd.rmd1_bits & LE_R1_OWN)
592 break;
593
594 if (rmd.rmd1_bits & LE_R1_ERR) {
595 if (rmd.rmd1_bits & LE_R1_ENP) {
596 #ifdef LEDEBUG
597 if ((rmd.rmd1_bits & LE_R1_OFLO) == 0) {
598 if (rmd.rmd1_bits & LE_R1_FRAM)
599 printf("%s: framing error\n",
600 sc->sc_dev.dv_xname);
601 if (rmd.rmd1_bits & LE_R1_CRC)
602 printf("%s: crc mismatch\n",
603 sc->sc_dev.dv_xname);
604 }
605 #endif
606 } else {
607 if (rmd.rmd1_bits & LE_R1_OFLO)
608 printf("%s: overflow\n",
609 sc->sc_dev.dv_xname);
610 }
611 if (rmd.rmd1_bits & LE_R1_BUFF)
612 printf("%s: receive buffer error\n",
613 sc->sc_dev.dv_xname);
614 ifp->if_ierrors++;
615 } else if ((rmd.rmd1_bits & (LE_R1_STP | LE_R1_ENP)) !=
616 (LE_R1_STP | LE_R1_ENP)) {
617 printf("%s: dropping chained buffer\n",
618 sc->sc_dev.dv_xname);
619 ifp->if_ierrors++;
620 } else {
621 #ifdef LEDEBUG
622 if (sc->sc_debug)
623 am7990_recv_print(sc, sc->sc_last_rd);
624 #endif
625 am7990_read(sc, LE_RBUFADDR(sc, bix),
626 (int)rmd.rmd3 - 4);
627 }
628
629 rmd.rmd1_bits = LE_R1_OWN;
630 rmd.rmd2 = -LEBLEN | LE_XMD2_ONES;
631 rmd.rmd3 = 0;
632 (*sc->sc_copytodesc)(sc, &rmd, rp, sizeof(rmd));
633
634 #ifdef LEDEBUG
635 if (sc->sc_debug)
636 printf("sc->sc_last_rd = %x, rmd: "
637 "ladr %04x, hadr %02x, flags %02x, "
638 "bcnt %04x, mcnt %04x\n",
639 sc->sc_last_rd,
640 rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits,
641 rmd.rmd2, rmd.rmd3);
642 #endif
643
644 if (++bix == sc->sc_nrbuf)
645 bix = 0;
646 }
647
648 sc->sc_last_rd = bix;
649 }
650
651 integrate void
652 am7990_tint(sc)
653 register struct am7990_softc *sc;
654 {
655 register int bix;
656 struct letmd tmd;
657
658 bix = sc->sc_first_td;
659
660 for (;;) {
661 if (sc->sc_no_td <= 0)
662 break;
663
664 #ifdef LEDEBUG
665 if (sc->sc_debug)
666 printf("trans tmd: "
667 "ladr %04x, hadr %02x, flags %02x, "
668 "bcnt %04x, mcnt %04x\n",
669 tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits,
670 tmd.tmd2, tmd.tmd3);
671 #endif
672
673 (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, bix),
674 sizeof(tmd));
675
676 if (tmd.tmd1_bits & LE_T1_OWN)
677 break;
678
679 ifp->if_flags &= ~IFF_OACTIVE;
680
681 if (tmd.tmd1_bits & LE_T1_ERR) {
682 if (tmd.tmd3 & LE_T3_BUFF)
683 printf("%s: transmit buffer error\n",
684 sc->sc_dev.dv_xname);
685 else if (tmd.tmd3 & LE_T3_UFLO)
686 printf("%s: underflow\n", sc->sc_dev.dv_xname);
687 if (tmd.tmd3 & (LE_T3_BUFF | LE_T3_UFLO)) {
688 am7990_reset(sc);
689 return;
690 }
691 if (tmd.tmd3 & LE_T3_LCAR) {
692 sc->sc_havecarrier = 0;
693 if (sc->sc_nocarrier)
694 (*sc->sc_nocarrier)(sc);
695 else
696 printf("%s: lost carrier\n",
697 sc->sc_dev.dv_xname);
698 }
699 if (tmd.tmd3 & LE_T3_LCOL)
700 ifp->if_collisions++;
701 if (tmd.tmd3 & LE_T3_RTRY) {
702 printf("%s: excessive collisions, tdr %d\n",
703 sc->sc_dev.dv_xname,
704 tmd.tmd3 & LE_T3_TDR_MASK);
705 ifp->if_collisions += 16;
706 }
707 ifp->if_oerrors++;
708 } else {
709 if (tmd.tmd1_bits & LE_T1_ONE)
710 ifp->if_collisions++;
711 else if (tmd.tmd1_bits & LE_T1_MORE)
712 /* Real number is unknown. */
713 ifp->if_collisions += 2;
714 ifp->if_opackets++;
715 }
716
717 if (++bix == sc->sc_ntbuf)
718 bix = 0;
719
720 --sc->sc_no_td;
721 }
722
723 sc->sc_first_td = bix;
724
725 am7990_start(ifp);
726
727 if (sc->sc_no_td == 0)
728 ifp->if_timer = 0;
729 }
730
731 /*
732 * Controller interrupt.
733 */
734 int
735 am7990_intr(arg)
736 register void *arg;
737 {
738 register struct am7990_softc *sc = arg;
739 register u_int16_t isr;
740
741 isr = (*sc->sc_rdcsr)(sc, LE_CSR0) | sc->sc_saved_csr0;
742 sc->sc_saved_csr0 = 0;
743 #ifdef LEDEBUG
744 if (sc->sc_debug)
745 printf("%s: am7990_intr entering with isr=%04x\n",
746 sc->sc_dev.dv_xname, isr);
747 #endif
748 if ((isr & LE_C0_INTR) == 0)
749 return (0);
750
751 (*sc->sc_wrcsr)(sc, LE_CSR0,
752 isr & (LE_C0_INEA | LE_C0_BABL | LE_C0_MISS | LE_C0_MERR |
753 LE_C0_RINT | LE_C0_TINT | LE_C0_IDON));
754 if (isr & LE_C0_ERR) {
755 if (isr & LE_C0_BABL) {
756 #ifdef LEDEBUG
757 printf("%s: babble\n", sc->sc_dev.dv_xname);
758 #endif
759 ifp->if_oerrors++;
760 }
761 #if 0
762 if (isr & LE_C0_CERR) {
763 printf("%s: collision error\n", sc->sc_dev.dv_xname);
764 ifp->if_collisions++;
765 }
766 #endif
767 if (isr & LE_C0_MISS) {
768 #ifdef LEDEBUG
769 printf("%s: missed packet\n", sc->sc_dev.dv_xname);
770 #endif
771 ifp->if_ierrors++;
772 }
773 if (isr & LE_C0_MERR) {
774 printf("%s: memory error\n", sc->sc_dev.dv_xname);
775 am7990_reset(sc);
776 return (1);
777 }
778 }
779
780 if ((isr & LE_C0_RXON) == 0) {
781 printf("%s: receiver disabled\n", sc->sc_dev.dv_xname);
782 ifp->if_ierrors++;
783 am7990_reset(sc);
784 return (1);
785 }
786 if ((isr & LE_C0_TXON) == 0) {
787 printf("%s: transmitter disabled\n", sc->sc_dev.dv_xname);
788 ifp->if_oerrors++;
789 am7990_reset(sc);
790 return (1);
791 }
792
793 /*
794 * Pretend we have carrier; if we don't this will be cleared
795 * shortly.
796 */
797 sc->sc_havecarrier = 1;
798
799 if (isr & LE_C0_RINT)
800 am7990_rint(sc);
801 if (isr & LE_C0_TINT)
802 am7990_tint(sc);
803
804 return (1);
805 }
806
807 #undef ifp
808
809 void
810 am7990_watchdog(ifp)
811 struct ifnet *ifp;
812 {
813 struct am7990_softc *sc = ifp->if_softc;
814
815 log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
816 ++ifp->if_oerrors;
817
818 am7990_reset(sc);
819 }
820
821 int
822 am7990_mediachange(ifp)
823 struct ifnet *ifp;
824 {
825 struct am7990_softc *sc = ifp->if_softc;
826
827 if (sc->sc_mediachange)
828 return ((*sc->sc_mediachange)(sc));
829 return (EINVAL);
830 }
831
832 void
833 am7990_mediastatus(ifp, ifmr)
834 struct ifnet *ifp;
835 struct ifmediareq *ifmr;
836 {
837 struct am7990_softc *sc = ifp->if_softc;
838
839 if ((ifp->if_flags & IFF_UP) == 0)
840 return;
841
842 ifmr->ifm_status = IFM_AVALID;
843 if (sc->sc_havecarrier)
844 ifmr->ifm_status |= IFM_ACTIVE;
845
846 if (sc->sc_mediastatus)
847 (*sc->sc_mediastatus)(sc, ifmr);
848 }
849
850 /*
851 * Setup output on interface.
852 * Get another datagram to send off of the interface queue, and map it to the
853 * interface before starting the output.
854 * Called only at splimp or interrupt level.
855 */
856 void
857 am7990_start(ifp)
858 register struct ifnet *ifp;
859 {
860 register struct am7990_softc *sc = ifp->if_softc;
861 register int bix;
862 register struct mbuf *m;
863 struct letmd tmd;
864 int rp;
865 int len;
866
867 if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
868 return;
869
870 bix = sc->sc_last_td;
871
872 for (;;) {
873 rp = LE_TMDADDR(sc, bix);
874 (*sc->sc_copyfromdesc)(sc, &tmd, rp, sizeof(tmd));
875
876 if (tmd.tmd1_bits & LE_T1_OWN) {
877 ifp->if_flags |= IFF_OACTIVE;
878 printf("missing buffer, no_td = %d, last_td = %d\n",
879 sc->sc_no_td, sc->sc_last_td);
880 }
881
882 IF_DEQUEUE(&ifp->if_snd, m);
883 if (m == 0)
884 break;
885
886 #if NBPFILTER > 0
887 /*
888 * If BPF is listening on this interface, let it see the packet
889 * before we commit it to the wire.
890 */
891 if (ifp->if_bpf)
892 bpf_mtap(ifp->if_bpf, m);
893 #endif
894
895 /*
896 * Copy the mbuf chain into the transmit buffer.
897 */
898 len = am7990_put(sc, LE_TBUFADDR(sc, bix), m);
899
900 #ifdef LEDEBUG
901 if (len > ETHERMTU + sizeof(struct ether_header))
902 printf("packet length %d\n", len);
903 #endif
904
905 ifp->if_timer = 5;
906
907 /*
908 * Init transmit registers, and set transmit start flag.
909 */
910 tmd.tmd1_bits = LE_T1_OWN | LE_T1_STP | LE_T1_ENP;
911 tmd.tmd2 = -len | LE_XMD2_ONES;
912 tmd.tmd3 = 0;
913
914 (*sc->sc_copytodesc)(sc, &tmd, rp, sizeof(tmd));
915
916 #ifdef LEDEBUG
917 if (sc->sc_debug)
918 am7990_xmit_print(sc, sc->sc_last_td);
919 #endif
920
921 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_TDMD);
922
923 if (++bix == sc->sc_ntbuf)
924 bix = 0;
925
926 if (++sc->sc_no_td == sc->sc_ntbuf) {
927 ifp->if_flags |= IFF_OACTIVE;
928 break;
929 }
930
931 }
932
933 sc->sc_last_td = bix;
934 }
935
936 /*
937 * Process an ioctl request.
938 */
939 int
940 am7990_ioctl(ifp, cmd, data)
941 register struct ifnet *ifp;
942 u_long cmd;
943 caddr_t data;
944 {
945 register struct am7990_softc *sc = ifp->if_softc;
946 struct ifaddr *ifa = (struct ifaddr *)data;
947 struct ifreq *ifr = (struct ifreq *)data;
948 int s, error = 0;
949
950 s = splimp();
951
952 switch (cmd) {
953
954 case SIOCSIFADDR:
955 ifp->if_flags |= IFF_UP;
956
957 switch (ifa->ifa_addr->sa_family) {
958 #ifdef INET
959 case AF_INET:
960 am7990_init(sc);
961 arp_ifinit(ifp, ifa);
962 break;
963 #endif
964 #ifdef NS
965 case AF_NS:
966 {
967 register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
968
969 if (ns_nullhost(*ina))
970 ina->x_host =
971 *(union ns_host *)LLADDR(ifp->if_sadl);
972 else {
973 bcopy(ina->x_host.c_host,
974 LLADDR(ifp->if_sadl),
975 sizeof(sc->sc_enaddr));
976 }
977 /* Set new address. */
978 am7990_init(sc);
979 break;
980 }
981 #endif
982 default:
983 am7990_init(sc);
984 break;
985 }
986 break;
987
988 #if defined(CCITT) && defined(LLC)
989 case SIOCSIFCONF_X25:
990 ifp->if_flags |= IFF_UP;
991 ifa->ifa_rtrequest = cons_rtrequest; /* XXX */
992 error = x25_llcglue(PRC_IFUP, ifa->ifa_addr);
993 if (error == 0)
994 am7990_init(sc);
995 break;
996 #endif /* CCITT && LLC */
997
998 case SIOCSIFFLAGS:
999 if ((ifp->if_flags & IFF_UP) == 0 &&
1000 (ifp->if_flags & IFF_RUNNING) != 0) {
1001 /*
1002 * If interface is marked down and it is running, then
1003 * stop it.
1004 */
1005 am7990_stop(sc);
1006 ifp->if_flags &= ~IFF_RUNNING;
1007 } else if ((ifp->if_flags & IFF_UP) != 0 &&
1008 (ifp->if_flags & IFF_RUNNING) == 0) {
1009 /*
1010 * If interface is marked up and it is stopped, then
1011 * start it.
1012 */
1013 am7990_init(sc);
1014 } else {
1015 /*
1016 * Reset the interface to pick up changes in any other
1017 * flags that affect hardware registers.
1018 */
1019 /*am7990_stop(sc);*/
1020 am7990_init(sc);
1021 }
1022 #ifdef LEDEBUG
1023 if (ifp->if_flags & IFF_DEBUG)
1024 sc->sc_debug = 1;
1025 else
1026 sc->sc_debug = 0;
1027 #endif
1028 break;
1029
1030 case SIOCADDMULTI:
1031 case SIOCDELMULTI:
1032 error = (cmd == SIOCADDMULTI) ?
1033 ether_addmulti(ifr, &sc->sc_ethercom) :
1034 ether_delmulti(ifr, &sc->sc_ethercom);
1035
1036 if (error == ENETRESET) {
1037 /*
1038 * Multicast list has changed; set the hardware filter
1039 * accordingly.
1040 */
1041 am7990_reset(sc);
1042 error = 0;
1043 }
1044 break;
1045
1046 case SIOCGIFMEDIA:
1047 case SIOCSIFMEDIA:
1048 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
1049 break;
1050
1051 default:
1052 error = EINVAL;
1053 break;
1054 }
1055
1056 splx(s);
1057 return (error);
1058 }
1059
1060 hide void
1061 am7990_shutdown(arg)
1062 void *arg;
1063 {
1064
1065 am7990_stop((struct am7990_softc *)arg);
1066 }
1067
1068 #ifdef LEDEBUG
1069 void
1070 am7990_recv_print(sc, no)
1071 struct am7990_softc *sc;
1072 int no;
1073 {
1074 struct lermd rmd;
1075 u_int16_t len;
1076 struct ether_header eh;
1077
1078 (*sc->sc_copyfromdesc)(sc, &rmd, LE_RMDADDR(sc, no), sizeof(rmd));
1079 len = rmd.rmd3;
1080 printf("%s: receive buffer %d, len = %d\n", sc->sc_dev.dv_xname, no,
1081 len);
1082 printf("%s: status %04x\n", sc->sc_dev.dv_xname,
1083 (*sc->sc_rdcsr)(sc, LE_CSR0));
1084 printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n",
1085 sc->sc_dev.dv_xname,
1086 rmd.rmd0, rmd.rmd1_hadr, rmd.rmd1_bits, rmd.rmd2, rmd.rmd3);
1087 if (len >= sizeof(eh)) {
1088 (*sc->sc_copyfrombuf)(sc, &eh, LE_RBUFADDR(sc, no), sizeof(eh));
1089 printf("%s: dst %s", sc->sc_dev.dv_xname,
1090 ether_sprintf(eh.ether_dhost));
1091 printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
1092 ntohs(eh.ether_type));
1093 }
1094 }
1095
1096 void
1097 am7990_xmit_print(sc, no)
1098 struct am7990_softc *sc;
1099 int no;
1100 {
1101 struct letmd tmd;
1102 u_int16_t len;
1103 struct ether_header eh;
1104
1105 (*sc->sc_copyfromdesc)(sc, &tmd, LE_TMDADDR(sc, no), sizeof(tmd));
1106 len = -tmd.tmd2;
1107 printf("%s: transmit buffer %d, len = %d\n", sc->sc_dev.dv_xname, no,
1108 len);
1109 printf("%s: status %04x\n", sc->sc_dev.dv_xname,
1110 (*sc->sc_rdcsr)(sc, LE_CSR0));
1111 printf("%s: ladr %04x, hadr %02x, flags %02x, bcnt %04x, mcnt %04x\n",
1112 sc->sc_dev.dv_xname,
1113 tmd.tmd0, tmd.tmd1_hadr, tmd.tmd1_bits, tmd.tmd2, tmd.tmd3);
1114 if (len >= sizeof(eh)) {
1115 (*sc->sc_copyfrombuf)(sc, &eh, LE_TBUFADDR(sc, no), sizeof(eh));
1116 printf("%s: dst %s", sc->sc_dev.dv_xname,
1117 ether_sprintf(eh.ether_dhost));
1118 printf(" src %s type %04x\n", ether_sprintf(eh.ether_shost),
1119 ntohs(eh.ether_type));
1120 }
1121 }
1122 #endif /* LEDEBUG */
1123
1124 /*
1125 * Set up the logical address filter.
1126 */
1127 void
1128 am7990_setladrf(ac, af)
1129 struct ethercom *ac;
1130 u_int16_t *af;
1131 {
1132 struct ifnet *ifp = &ac->ec_if;
1133 struct ether_multi *enm;
1134 register u_char *cp, c;
1135 register u_int32_t crc;
1136 register int i, len;
1137 struct ether_multistep step;
1138
1139 /*
1140 * Set up multicast address filter by passing all multicast addresses
1141 * through a crc generator, and then using the high order 6 bits as an
1142 * index into the 64 bit logical address filter. The high order bit
1143 * selects the word, while the rest of the bits select the bit within
1144 * the word.
1145 */
1146
1147 if (ifp->if_flags & IFF_PROMISC)
1148 goto allmulti;
1149
1150 af[0] = af[1] = af[2] = af[3] = 0x0000;
1151 ETHER_FIRST_MULTI(step, ac, enm);
1152 while (enm != NULL) {
1153 if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
1154 /*
1155 * We must listen to a range of multicast addresses.
1156 * For now, just accept all multicasts, rather than
1157 * trying to set only those filter bits needed to match
1158 * the range. (At this time, the only use of address
1159 * ranges is for IP multicast routing, for which the
1160 * range is big enough to require all bits set.)
1161 */
1162 goto allmulti;
1163 }
1164
1165 cp = enm->enm_addrlo;
1166 crc = 0xffffffff;
1167 for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
1168 c = *cp++;
1169 for (i = 8; --i >= 0;) {
1170 if ((crc & 0x01) ^ (c & 0x01)) {
1171 crc >>= 1;
1172 crc ^= 0xedb88320;
1173 } else
1174 crc >>= 1;
1175 c >>= 1;
1176 }
1177 }
1178 /* Just want the 6 most significant bits. */
1179 crc >>= 26;
1180
1181 /* Set the corresponding bit in the filter. */
1182 af[crc >> 4] |= 1 << (crc & 0xf);
1183
1184 ETHER_NEXT_MULTI(step, enm);
1185 }
1186 ifp->if_flags &= ~IFF_ALLMULTI;
1187 return;
1188
1189 allmulti:
1190 ifp->if_flags |= IFF_ALLMULTI;
1191 af[0] = af[1] = af[2] = af[3] = 0xffff;
1192 }
1193
1194
1195 /*
1196 * Routines for accessing the transmit and receive buffers.
1197 * The various CPU and adapter configurations supported by this
1198 * driver require three different access methods for buffers
1199 * and descriptors:
1200 * (1) contig (contiguous data; no padding),
1201 * (2) gap2 (two bytes of data followed by two bytes of padding),
1202 * (3) gap16 (16 bytes of data followed by 16 bytes of padding).
1203 */
1204
1205 /*
1206 * contig: contiguous data with no padding.
1207 *
1208 * Buffers may have any alignment.
1209 */
1210
1211 void
1212 am7990_copytobuf_contig(sc, from, boff, len)
1213 struct am7990_softc *sc;
1214 void *from;
1215 int boff, len;
1216 {
1217 volatile caddr_t buf = sc->sc_mem;
1218
1219 /*
1220 * Just call bcopy() to do the work.
1221 */
1222 bcopy(from, buf + boff, len);
1223 }
1224
1225 void
1226 am7990_copyfrombuf_contig(sc, to, boff, len)
1227 struct am7990_softc *sc;
1228 void *to;
1229 int boff, len;
1230 {
1231 volatile caddr_t buf = sc->sc_mem;
1232
1233 /*
1234 * Just call bcopy() to do the work.
1235 */
1236 bcopy(buf + boff, to, len);
1237 }
1238
1239 void
1240 am7990_zerobuf_contig(sc, boff, len)
1241 struct am7990_softc *sc;
1242 int boff, len;
1243 {
1244 volatile caddr_t buf = sc->sc_mem;
1245
1246 /*
1247 * Just let bzero() do the work
1248 */
1249 bzero(buf + boff, len);
1250 }
1251
1252 #if 0
1253 /*
1254 * Examples only; duplicate these and tweak (if necessary) in
1255 * machine-specific front-ends.
1256 */
1257
1258 /*
1259 * gap2: two bytes of data followed by two bytes of pad.
1260 *
1261 * Buffers must be 4-byte aligned. The code doesn't worry about
1262 * doing an extra byte.
1263 */
1264
1265 void
1266 am7990_copytobuf_gap2(sc, fromv, boff, len)
1267 struct am7990_softc *sc;
1268 void *fromv;
1269 int boff;
1270 register int len;
1271 {
1272 volatile caddr_t buf = sc->sc_mem;
1273 register caddr_t from = fromv;
1274 register volatile u_int16_t *bptr;
1275
1276 if (boff & 0x1) {
1277 /* handle unaligned first byte */
1278 bptr = ((volatile u_int16_t *)buf) + (boff - 1);
1279 *bptr = (*from++ << 8) | (*bptr & 0xff);
1280 bptr += 2;
1281 len--;
1282 } else
1283 bptr = ((volatile u_int16_t *)buf) + boff;
1284 while (len > 1) {
1285 *bptr = (from[1] << 8) | (from[0] & 0xff);
1286 bptr += 2;
1287 from += 2;
1288 len -= 2;
1289 }
1290 if (len == 1)
1291 *bptr = (u_int16_t)*from;
1292 }
1293
1294 void
1295 am7990_copyfrombuf_gap2(sc, tov, boff, len)
1296 struct am7990_softc *sc;
1297 void *tov;
1298 int boff, len;
1299 {
1300 volatile caddr_t buf = sc->sc_mem;
1301 register caddr_t to = tov;
1302 register volatile u_int16_t *bptr;
1303 register u_int16_t tmp;
1304
1305 if (boff & 0x1) {
1306 /* handle unaligned first byte */
1307 bptr = ((volatile u_int16_t *)buf) + (boff - 1);
1308 *to++ = (*bptr >> 8) & 0xff;
1309 bptr += 2;
1310 len--;
1311 } else
1312 bptr = ((volatile u_int16_t *)buf) + boff;
1313 while (len > 1) {
1314 tmp = *bptr;
1315 *to++ = tmp & 0xff;
1316 *to++ = (tmp >> 8) & 0xff;
1317 bptr += 2;
1318 len -= 2;
1319 }
1320 if (len == 1)
1321 *to = *bptr & 0xff;
1322 }
1323
1324 void
1325 am7990_zerobuf_gap2(sc, boff, len)
1326 struct am7990_softc *sc;
1327 int boff, len;
1328 {
1329 volatile caddr_t buf = sc->sc_mem;
1330 register volatile u_int16_t *bptr;
1331
1332 if ((unsigned)boff & 0x1) {
1333 bptr = ((volatile u_int16_t *)buf) + (boff - 1);
1334 *bptr &= 0xff;
1335 bptr += 2;
1336 len--;
1337 } else
1338 bptr = ((volatile u_int16_t *)buf) + boff;
1339 while (len > 0) {
1340 *bptr = 0;
1341 bptr += 2;
1342 len -= 2;
1343 }
1344 }
1345
1346 /*
1347 * gap16: 16 bytes of data followed by 16 bytes of pad.
1348 *
1349 * Buffers must be 32-byte aligned.
1350 */
1351
1352 void
1353 am7990_copytobuf_gap16(sc, fromv, boff, len)
1354 struct am7990_softc *sc;
1355 void *fromv;
1356 int boff;
1357 register int len;
1358 {
1359 volatile caddr_t buf = sc->sc_mem;
1360 register caddr_t from = fromv;
1361 register caddr_t bptr;
1362 register int xfer;
1363
1364 bptr = buf + ((boff << 1) & ~0x1f);
1365 boff &= 0xf;
1366 xfer = min(len, 16 - boff);
1367 while (len > 0) {
1368 bcopy(from, bptr + boff, xfer);
1369 from += xfer;
1370 bptr += 32;
1371 boff = 0;
1372 len -= xfer;
1373 xfer = min(len, 16);
1374 }
1375 }
1376
1377 void
1378 am7990_copyfrombuf_gap16(sc, tov, boff, len)
1379 struct am7990_softc *sc;
1380 void *tov;
1381 int boff, len;
1382 {
1383 volatile caddr_t buf = sc->sc_mem;
1384 register caddr_t to = tov;
1385 register caddr_t bptr;
1386 register int xfer;
1387
1388 bptr = buf + ((boff << 1) & ~0x1f);
1389 boff &= 0xf;
1390 xfer = min(len, 16 - boff);
1391 while (len > 0) {
1392 bcopy(bptr + boff, to, xfer);
1393 to += xfer;
1394 bptr += 32;
1395 boff = 0;
1396 len -= xfer;
1397 xfer = min(len, 16);
1398 }
1399 }
1400
1401 void
1402 am7990_zerobuf_gap16(sc, boff, len)
1403 struct am7990_softc *sc;
1404 int boff, len;
1405 {
1406 volatile caddr_t buf = sc->sc_mem;
1407 register caddr_t bptr;
1408 register int xfer;
1409
1410 bptr = buf + ((boff << 1) & ~0x1f);
1411 boff &= 0xf;
1412 xfer = min(len, 16 - boff);
1413 while (len > 0) {
1414 bzero(bptr + boff, xfer);
1415 bptr += 32;
1416 boff = 0;
1417 len -= xfer;
1418 xfer = min(len, 16);
1419 }
1420 }
1421 #endif /* Example only */
1422