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