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