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