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