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