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