lance.c revision 1.3 1 1.3 mycroft /* $NetBSD: lance.c,v 1.3 1998/08/15 10:51:18 mycroft Exp $ */
2 1.1 drochner
3 1.1 drochner /*-
4 1.3 mycroft * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5 1.1 drochner * All rights reserved.
6 1.1 drochner *
7 1.1 drochner * This code is derived from software contributed to The NetBSD Foundation
8 1.3 mycroft * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
9 1.3 mycroft * Simulation Facility, NASA Ames Research Center.
10 1.1 drochner *
11 1.1 drochner * Redistribution and use in source and binary forms, with or without
12 1.1 drochner * modification, are permitted provided that the following conditions
13 1.1 drochner * are met:
14 1.1 drochner * 1. Redistributions of source code must retain the above copyright
15 1.1 drochner * notice, this list of conditions and the following disclaimer.
16 1.1 drochner * 2. Redistributions in binary form must reproduce the above copyright
17 1.1 drochner * notice, this list of conditions and the following disclaimer in the
18 1.1 drochner * documentation and/or other materials provided with the distribution.
19 1.1 drochner * 3. All advertising materials mentioning features or use of this software
20 1.1 drochner * must display the following acknowledgement:
21 1.1 drochner * This product includes software developed by the NetBSD
22 1.1 drochner * Foundation, Inc. and its contributors.
23 1.1 drochner * 4. Neither the name of The NetBSD Foundation nor the names of its
24 1.1 drochner * contributors may be used to endorse or promote products derived
25 1.1 drochner * from this software without specific prior written permission.
26 1.1 drochner *
27 1.1 drochner * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 1.1 drochner * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 1.1 drochner * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 1.1 drochner * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 1.1 drochner * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 1.1 drochner * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 1.1 drochner * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 1.1 drochner * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 1.1 drochner * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 1.1 drochner * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 1.1 drochner * POSSIBILITY OF SUCH DAMAGE.
38 1.1 drochner */
39 1.1 drochner
40 1.1 drochner /*-
41 1.1 drochner * Copyright (c) 1992, 1993
42 1.1 drochner * The Regents of the University of California. All rights reserved.
43 1.1 drochner *
44 1.1 drochner * This code is derived from software contributed to Berkeley by
45 1.1 drochner * Ralph Campbell and Rick Macklem.
46 1.1 drochner *
47 1.1 drochner * Redistribution and use in source and binary forms, with or without
48 1.1 drochner * modification, are permitted provided that the following conditions
49 1.1 drochner * are met:
50 1.1 drochner * 1. Redistributions of source code must retain the above copyright
51 1.1 drochner * notice, this list of conditions and the following disclaimer.
52 1.1 drochner * 2. Redistributions in binary form must reproduce the above copyright
53 1.1 drochner * notice, this list of conditions and the following disclaimer in the
54 1.1 drochner * documentation and/or other materials provided with the distribution.
55 1.1 drochner * 3. All advertising materials mentioning features or use of this software
56 1.1 drochner * must display the following acknowledgement:
57 1.1 drochner * This product includes software developed by the University of
58 1.1 drochner * California, Berkeley and its contributors.
59 1.1 drochner * 4. Neither the name of the University nor the names of its contributors
60 1.1 drochner * may be used to endorse or promote products derived from this software
61 1.1 drochner * without specific prior written permission.
62 1.1 drochner *
63 1.1 drochner * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
64 1.1 drochner * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
65 1.1 drochner * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
66 1.1 drochner * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
67 1.1 drochner * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
68 1.1 drochner * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
69 1.1 drochner * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
70 1.1 drochner * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
71 1.1 drochner * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
72 1.1 drochner * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
73 1.1 drochner * SUCH DAMAGE.
74 1.1 drochner *
75 1.1 drochner * @(#)if_le.c 8.2 (Berkeley) 11/16/93
76 1.1 drochner */
77 1.1 drochner
78 1.1 drochner #include "opt_inet.h"
79 1.1 drochner #include "opt_ccitt.h"
80 1.1 drochner #include "opt_llc.h"
81 1.1 drochner #include "opt_ns.h"
82 1.1 drochner #include "bpfilter.h"
83 1.1 drochner #include "rnd.h"
84 1.1 drochner
85 1.1 drochner #include <sys/param.h>
86 1.1 drochner #include <sys/systm.h>
87 1.1 drochner #include <sys/mbuf.h>
88 1.1 drochner #include <sys/syslog.h>
89 1.1 drochner #include <sys/socket.h>
90 1.1 drochner #include <sys/device.h>
91 1.1 drochner #include <sys/malloc.h>
92 1.1 drochner #include <sys/ioctl.h>
93 1.1 drochner #include <sys/errno.h>
94 1.1 drochner #if NRND > 0
95 1.1 drochner #include <sys/rnd.h>
96 1.1 drochner #endif
97 1.1 drochner
98 1.1 drochner #include <net/if.h>
99 1.1 drochner #include <net/if_dl.h>
100 1.1 drochner #include <net/if_ether.h>
101 1.1 drochner #include <net/if_media.h>
102 1.1 drochner
103 1.1 drochner #ifdef INET
104 1.1 drochner #include <netinet/in.h>
105 1.1 drochner #include <netinet/if_inarp.h>
106 1.1 drochner #include <netinet/in_systm.h>
107 1.1 drochner #include <netinet/in_var.h>
108 1.1 drochner #include <netinet/ip.h>
109 1.1 drochner #endif
110 1.1 drochner
111 1.1 drochner #ifdef NS
112 1.1 drochner #include <netns/ns.h>
113 1.1 drochner #include <netns/ns_if.h>
114 1.1 drochner #endif
115 1.1 drochner
116 1.1 drochner #if defined(CCITT) && defined(LLC)
117 1.1 drochner #include <sys/socketvar.h>
118 1.1 drochner #include <netccitt/x25.h>
119 1.1 drochner #include <netccitt/pk.h>
120 1.1 drochner #include <netccitt/pk_var.h>
121 1.1 drochner #include <netccitt/pk_extern.h>
122 1.1 drochner #endif
123 1.1 drochner
124 1.1 drochner #if NBPFILTER > 0
125 1.1 drochner #include <net/bpf.h>
126 1.1 drochner #include <net/bpfdesc.h>
127 1.1 drochner #endif
128 1.1 drochner
129 1.1 drochner #include <dev/ic/lancereg.h>
130 1.1 drochner #include <dev/ic/lancevar.h>
131 1.1 drochner
132 1.1 drochner #if defined(_KERNEL) && !defined(_LKM)
133 1.1 drochner #include "opt_ddb.h"
134 1.1 drochner #endif
135 1.1 drochner
136 1.1 drochner #ifdef DDB
137 1.1 drochner #define integrate
138 1.1 drochner #define hide
139 1.1 drochner #else
140 1.1 drochner #define integrate static __inline
141 1.1 drochner #define hide static
142 1.1 drochner #endif
143 1.1 drochner
144 1.1 drochner integrate struct mbuf *lance_get __P((struct lance_softc *, int, int));
145 1.1 drochner
146 1.1 drochner hide void lance_shutdown __P((void *));
147 1.1 drochner
148 1.1 drochner int lance_mediachange __P((struct ifnet *));
149 1.1 drochner void lance_mediastatus __P((struct ifnet *, struct ifmediareq *));
150 1.1 drochner
151 1.1 drochner static inline u_int16_t ether_cmp __P((void *, void *));
152 1.1 drochner
153 1.1 drochner void lance_stop __P((struct lance_softc *));
154 1.1 drochner int lance_ioctl __P((struct ifnet *, u_long, caddr_t));
155 1.1 drochner void lance_watchdog __P((struct ifnet *));
156 1.1 drochner
157 1.1 drochner /*
158 1.1 drochner * Compare two Ether/802 addresses for equality, inlined and
159 1.1 drochner * unrolled for speed. Use this like bcmp().
160 1.1 drochner *
161 1.1 drochner * XXX: Add <machine/inlines.h> for stuff like this?
162 1.1 drochner * XXX: or maybe add it to libkern.h instead?
163 1.1 drochner *
164 1.1 drochner * "I'd love to have an inline assembler version of this."
165 1.1 drochner * XXX: Who wanted that? mycroft? I wrote one, but this
166 1.1 drochner * version in C is as good as hand-coded assembly. -gwr
167 1.1 drochner *
168 1.1 drochner * Please do NOT tweak this without looking at the actual
169 1.1 drochner * assembly code generated before and after your tweaks!
170 1.1 drochner */
171 1.1 drochner static inline u_int16_t
172 1.1 drochner ether_cmp(one, two)
173 1.1 drochner void *one, *two;
174 1.1 drochner {
175 1.1 drochner register u_int16_t *a = (u_short *) one;
176 1.1 drochner register u_int16_t *b = (u_short *) two;
177 1.1 drochner register u_int16_t diff;
178 1.1 drochner
179 1.1 drochner #ifdef m68k
180 1.1 drochner /*
181 1.1 drochner * The post-increment-pointer form produces the best
182 1.1 drochner * machine code for m68k. This was carefully tuned
183 1.1 drochner * so it compiles to just 8 short (2-byte) op-codes!
184 1.1 drochner */
185 1.1 drochner diff = *a++ - *b++;
186 1.1 drochner diff |= *a++ - *b++;
187 1.1 drochner diff |= *a++ - *b++;
188 1.1 drochner #else
189 1.1 drochner /*
190 1.1 drochner * Most modern CPUs do better with a single expresion.
191 1.1 drochner * Note that short-cut evaluation is NOT helpful here,
192 1.1 drochner * because it just makes the code longer, not faster!
193 1.1 drochner */
194 1.1 drochner diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
195 1.1 drochner #endif
196 1.1 drochner
197 1.1 drochner return (diff);
198 1.1 drochner }
199 1.1 drochner
200 1.1 drochner #define ETHER_CMP ether_cmp
201 1.1 drochner
202 1.1 drochner #ifdef LANCE_REVC_BUG
203 1.1 drochner /* Make sure this is short-aligned, for ether_cmp(). */
204 1.1 drochner static u_int16_t bcast_enaddr[3] = { ~0, ~0, ~0 };
205 1.1 drochner #endif
206 1.1 drochner
207 1.1 drochner #define ifp (&sc->sc_ethercom.ec_if)
208 1.1 drochner
209 1.1 drochner void
210 1.1 drochner lance_config(sc)
211 1.1 drochner struct lance_softc *sc;
212 1.1 drochner {
213 1.1 drochner int i;
214 1.1 drochner
215 1.1 drochner /* Make sure the chip is stopped. */
216 1.1 drochner lance_stop(sc);
217 1.1 drochner
218 1.1 drochner /* Initialize ifnet structure. */
219 1.1 drochner bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
220 1.1 drochner ifp->if_softc = sc;
221 1.1 drochner ifp->if_start = sc->sc_start;
222 1.1 drochner ifp->if_ioctl = lance_ioctl;
223 1.1 drochner ifp->if_watchdog = lance_watchdog;
224 1.1 drochner ifp->if_flags =
225 1.1 drochner IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
226 1.1 drochner #ifdef LANCE_REVC_BUG
227 1.1 drochner ifp->if_flags &= ~IFF_MULTICAST;
228 1.1 drochner #endif
229 1.1 drochner
230 1.1 drochner /* Initialize ifmedia structures. */
231 1.1 drochner ifmedia_init(&sc->sc_media, 0, lance_mediachange, lance_mediastatus);
232 1.1 drochner if (sc->sc_supmedia != NULL) {
233 1.1 drochner for (i = 0; i < sc->sc_nsupmedia; i++)
234 1.1 drochner ifmedia_add(&sc->sc_media, sc->sc_supmedia[i],
235 1.1 drochner 0, NULL);
236 1.1 drochner ifmedia_set(&sc->sc_media, sc->sc_defaultmedia);
237 1.1 drochner } else {
238 1.1 drochner ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
239 1.1 drochner ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
240 1.1 drochner }
241 1.1 drochner
242 1.1 drochner /* Attach the interface. */
243 1.1 drochner if_attach(ifp);
244 1.1 drochner ether_ifattach(ifp, sc->sc_enaddr);
245 1.1 drochner
246 1.1 drochner #if NBPFILTER > 0
247 1.1 drochner bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
248 1.1 drochner #endif
249 1.1 drochner
250 1.1 drochner switch (sc->sc_memsize) {
251 1.1 drochner case 8192:
252 1.1 drochner sc->sc_nrbuf = 4;
253 1.1 drochner sc->sc_ntbuf = 1;
254 1.1 drochner break;
255 1.1 drochner case 16384:
256 1.1 drochner sc->sc_nrbuf = 8;
257 1.1 drochner sc->sc_ntbuf = 2;
258 1.1 drochner break;
259 1.1 drochner case 32768:
260 1.1 drochner sc->sc_nrbuf = 16;
261 1.1 drochner sc->sc_ntbuf = 4;
262 1.1 drochner break;
263 1.1 drochner case 65536:
264 1.1 drochner sc->sc_nrbuf = 32;
265 1.1 drochner sc->sc_ntbuf = 8;
266 1.1 drochner break;
267 1.1 drochner case 131072:
268 1.1 drochner sc->sc_nrbuf = 64;
269 1.1 drochner sc->sc_ntbuf = 16;
270 1.1 drochner break;
271 1.1 drochner default:
272 1.1 drochner panic("lance_config: weird memory size");
273 1.1 drochner }
274 1.1 drochner
275 1.1 drochner printf(": address %s\n", ether_sprintf(sc->sc_enaddr));
276 1.1 drochner printf("%s: %d receive buffers, %d transmit buffers\n",
277 1.1 drochner sc->sc_dev.dv_xname, sc->sc_nrbuf, sc->sc_ntbuf);
278 1.1 drochner
279 1.1 drochner sc->sc_sh = shutdownhook_establish(lance_shutdown, sc);
280 1.1 drochner if (sc->sc_sh == NULL)
281 1.1 drochner panic("lance_config: can't establish shutdownhook");
282 1.1 drochner sc->sc_rbufaddr = malloc(sc->sc_nrbuf * sizeof(int), M_DEVBUF,
283 1.1 drochner M_WAITOK);
284 1.1 drochner sc->sc_tbufaddr = malloc(sc->sc_ntbuf * sizeof(int), M_DEVBUF,
285 1.1 drochner M_WAITOK);
286 1.1 drochner
287 1.1 drochner #if NRND > 0
288 1.1 drochner rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
289 1.1 drochner RND_TYPE_NET);
290 1.1 drochner #endif
291 1.1 drochner }
292 1.1 drochner
293 1.1 drochner void
294 1.1 drochner lance_reset(sc)
295 1.1 drochner struct lance_softc *sc;
296 1.1 drochner {
297 1.1 drochner int s;
298 1.1 drochner
299 1.2 mycroft s = splnet();
300 1.1 drochner lance_init(sc);
301 1.1 drochner splx(s);
302 1.1 drochner }
303 1.1 drochner
304 1.1 drochner void
305 1.1 drochner lance_stop(sc)
306 1.1 drochner struct lance_softc *sc;
307 1.1 drochner {
308 1.1 drochner
309 1.1 drochner (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
310 1.1 drochner }
311 1.1 drochner
312 1.1 drochner /*
313 1.1 drochner * Initialization of interface; set up initialization block
314 1.1 drochner * and transmit/receive descriptor rings.
315 1.1 drochner */
316 1.1 drochner void
317 1.1 drochner lance_init(sc)
318 1.1 drochner register struct lance_softc *sc;
319 1.1 drochner {
320 1.1 drochner register int timo;
321 1.1 drochner u_long a;
322 1.1 drochner
323 1.1 drochner (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
324 1.1 drochner DELAY(100);
325 1.1 drochner
326 1.1 drochner /* Newer LANCE chips have a reset register */
327 1.1 drochner if (sc->sc_hwreset)
328 1.1 drochner (*sc->sc_hwreset)(sc);
329 1.1 drochner
330 1.1 drochner /* Set the correct byte swapping mode, etc. */
331 1.1 drochner (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
332 1.1 drochner
333 1.1 drochner /* Set up LANCE init block. */
334 1.1 drochner (*sc->sc_meminit)(sc);
335 1.1 drochner
336 1.1 drochner /* Give LANCE the physical address of its init block. */
337 1.1 drochner a = sc->sc_addr + LE_INITADDR(sc);
338 1.1 drochner (*sc->sc_wrcsr)(sc, LE_CSR1, a);
339 1.1 drochner (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
340 1.1 drochner
341 1.1 drochner /* Try to initialize the LANCE. */
342 1.1 drochner DELAY(100);
343 1.1 drochner (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
344 1.1 drochner
345 1.1 drochner /* Wait for initialization to finish. */
346 1.1 drochner for (timo = 100000; timo; timo--)
347 1.1 drochner if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
348 1.1 drochner break;
349 1.1 drochner
350 1.1 drochner if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
351 1.1 drochner /* Start the LANCE. */
352 1.1 drochner (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT |
353 1.1 drochner LE_C0_IDON);
354 1.1 drochner ifp->if_flags |= IFF_RUNNING;
355 1.1 drochner ifp->if_flags &= ~IFF_OACTIVE;
356 1.1 drochner ifp->if_timer = 0;
357 1.1 drochner (*sc->sc_start)(ifp);
358 1.1 drochner } else
359 1.1 drochner printf("%s: controller failed to initialize\n",
360 1.1 drochner sc->sc_dev.dv_xname);
361 1.1 drochner if (sc->sc_hwinit)
362 1.1 drochner (*sc->sc_hwinit)(sc);
363 1.1 drochner }
364 1.1 drochner
365 1.1 drochner /*
366 1.1 drochner * Routine to copy from mbuf chain to transmit buffer in
367 1.1 drochner * network buffer memory.
368 1.1 drochner */
369 1.1 drochner int
370 1.1 drochner lance_put(sc, boff, m)
371 1.1 drochner struct lance_softc *sc;
372 1.1 drochner int boff;
373 1.1 drochner register struct mbuf *m;
374 1.1 drochner {
375 1.1 drochner register struct mbuf *n;
376 1.1 drochner register int len, tlen = 0;
377 1.1 drochner
378 1.1 drochner for (; m; m = n) {
379 1.1 drochner len = m->m_len;
380 1.1 drochner if (len == 0) {
381 1.1 drochner MFREE(m, n);
382 1.1 drochner continue;
383 1.1 drochner }
384 1.1 drochner (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
385 1.1 drochner boff += len;
386 1.1 drochner tlen += len;
387 1.1 drochner MFREE(m, n);
388 1.1 drochner }
389 1.1 drochner if (tlen < LEMINSIZE) {
390 1.1 drochner (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
391 1.1 drochner tlen = LEMINSIZE;
392 1.1 drochner }
393 1.1 drochner return (tlen);
394 1.1 drochner }
395 1.1 drochner
396 1.1 drochner /*
397 1.1 drochner * Pull data off an interface.
398 1.1 drochner * Len is length of data, with local net header stripped.
399 1.1 drochner * We copy the data into mbufs. When full cluster sized units are present
400 1.1 drochner * we copy into clusters.
401 1.1 drochner */
402 1.1 drochner integrate struct mbuf *
403 1.1 drochner lance_get(sc, boff, totlen)
404 1.1 drochner struct lance_softc *sc;
405 1.1 drochner int boff, totlen;
406 1.1 drochner {
407 1.1 drochner register struct mbuf *m;
408 1.1 drochner struct mbuf *top, **mp;
409 1.1 drochner int len;
410 1.1 drochner
411 1.1 drochner MGETHDR(m, M_DONTWAIT, MT_DATA);
412 1.1 drochner if (m == 0)
413 1.1 drochner return (0);
414 1.1 drochner m->m_pkthdr.rcvif = ifp;
415 1.1 drochner m->m_pkthdr.len = totlen;
416 1.1 drochner len = MHLEN;
417 1.1 drochner top = 0;
418 1.1 drochner mp = ⊤
419 1.1 drochner
420 1.1 drochner while (totlen > 0) {
421 1.1 drochner if (top) {
422 1.1 drochner MGET(m, M_DONTWAIT, MT_DATA);
423 1.1 drochner if (m == 0) {
424 1.1 drochner m_freem(top);
425 1.1 drochner return 0;
426 1.1 drochner }
427 1.1 drochner len = MLEN;
428 1.1 drochner }
429 1.1 drochner if (totlen >= MINCLSIZE) {
430 1.1 drochner MCLGET(m, M_DONTWAIT);
431 1.1 drochner if ((m->m_flags & M_EXT) == 0) {
432 1.1 drochner m_free(m);
433 1.1 drochner m_freem(top);
434 1.1 drochner return 0;
435 1.1 drochner }
436 1.1 drochner len = MCLBYTES;
437 1.1 drochner }
438 1.1 drochner if (!top) {
439 1.1 drochner register int pad =
440 1.1 drochner ALIGN(sizeof(struct ether_header)) -
441 1.1 drochner sizeof(struct ether_header);
442 1.1 drochner m->m_data += pad;
443 1.1 drochner len -= pad;
444 1.1 drochner }
445 1.1 drochner m->m_len = len = min(totlen, len);
446 1.1 drochner (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
447 1.1 drochner boff += len;
448 1.1 drochner totlen -= len;
449 1.1 drochner *mp = m;
450 1.1 drochner mp = &m->m_next;
451 1.1 drochner }
452 1.1 drochner
453 1.1 drochner return (top);
454 1.1 drochner }
455 1.1 drochner
456 1.1 drochner /*
457 1.1 drochner * Pass a packet to the higher levels.
458 1.1 drochner */
459 1.1 drochner void
460 1.1 drochner lance_read(sc, boff, len)
461 1.1 drochner register struct lance_softc *sc;
462 1.1 drochner int boff, len;
463 1.1 drochner {
464 1.1 drochner struct mbuf *m;
465 1.1 drochner struct ether_header *eh;
466 1.1 drochner
467 1.1 drochner if (len <= sizeof(struct ether_header) ||
468 1.1 drochner len > ETHERMTU + sizeof(struct ether_header)) {
469 1.1 drochner #ifdef LEDEBUG
470 1.1 drochner printf("%s: invalid packet size %d; dropping\n",
471 1.1 drochner sc->sc_dev.dv_xname, len);
472 1.1 drochner #endif
473 1.1 drochner ifp->if_ierrors++;
474 1.1 drochner return;
475 1.1 drochner }
476 1.1 drochner
477 1.1 drochner /* Pull packet off interface. */
478 1.1 drochner m = lance_get(sc, boff, len);
479 1.1 drochner if (m == 0) {
480 1.1 drochner ifp->if_ierrors++;
481 1.1 drochner return;
482 1.1 drochner }
483 1.1 drochner
484 1.1 drochner ifp->if_ipackets++;
485 1.1 drochner
486 1.1 drochner /* We assume that the header fit entirely in one mbuf. */
487 1.1 drochner eh = mtod(m, struct ether_header *);
488 1.1 drochner
489 1.1 drochner #if NBPFILTER > 0
490 1.1 drochner /*
491 1.1 drochner * Check if there's a BPF listener on this interface.
492 1.1 drochner * If so, hand off the raw packet to BPF.
493 1.1 drochner */
494 1.1 drochner if (ifp->if_bpf) {
495 1.1 drochner bpf_mtap(ifp->if_bpf, m);
496 1.1 drochner
497 1.1 drochner #ifndef LANCE_REVC_BUG
498 1.1 drochner /*
499 1.1 drochner * Note that the interface cannot be in promiscuous mode if
500 1.1 drochner * there are no BPF listeners. And if we are in promiscuous
501 1.1 drochner * mode, we have to check if this packet is really ours.
502 1.1 drochner */
503 1.1 drochner if ((ifp->if_flags & IFF_PROMISC) != 0 &&
504 1.1 drochner (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
505 1.1 drochner ETHER_CMP(eh->ether_dhost, sc->sc_enaddr)) {
506 1.1 drochner m_freem(m);
507 1.1 drochner return;
508 1.1 drochner }
509 1.1 drochner #endif
510 1.1 drochner }
511 1.1 drochner #endif
512 1.1 drochner
513 1.1 drochner #ifdef LANCE_REVC_BUG
514 1.1 drochner /*
515 1.1 drochner * The old LANCE (Rev. C) chips have a bug which causes
516 1.1 drochner * garbage to be inserted in front of the received packet.
517 1.1 drochner * The work-around is to ignore packets with an invalid
518 1.1 drochner * destination address (garbage will usually not match).
519 1.1 drochner * Of course, this precludes multicast support...
520 1.1 drochner */
521 1.1 drochner if (ETHER_CMP(eh->ether_dhost, sc->sc_enaddr) &&
522 1.1 drochner ETHER_CMP(eh->ether_dhost, bcast_enaddr)) {
523 1.1 drochner m_freem(m);
524 1.1 drochner return;
525 1.1 drochner }
526 1.1 drochner #endif
527 1.1 drochner
528 1.1 drochner /* Pass the packet up, with the ether header sort-of removed. */
529 1.1 drochner m_adj(m, sizeof(struct ether_header));
530 1.1 drochner ether_input(ifp, eh, m);
531 1.1 drochner }
532 1.1 drochner
533 1.1 drochner #undef ifp
534 1.1 drochner
535 1.1 drochner void
536 1.1 drochner lance_watchdog(ifp)
537 1.1 drochner struct ifnet *ifp;
538 1.1 drochner {
539 1.1 drochner struct lance_softc *sc = ifp->if_softc;
540 1.1 drochner
541 1.1 drochner log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
542 1.1 drochner ++ifp->if_oerrors;
543 1.1 drochner
544 1.1 drochner lance_reset(sc);
545 1.1 drochner }
546 1.1 drochner
547 1.1 drochner int
548 1.1 drochner lance_mediachange(ifp)
549 1.1 drochner struct ifnet *ifp;
550 1.1 drochner {
551 1.1 drochner struct lance_softc *sc = ifp->if_softc;
552 1.1 drochner
553 1.1 drochner if (sc->sc_mediachange)
554 1.1 drochner return ((*sc->sc_mediachange)(sc));
555 1.1 drochner return (EINVAL);
556 1.1 drochner }
557 1.1 drochner
558 1.1 drochner void
559 1.1 drochner lance_mediastatus(ifp, ifmr)
560 1.1 drochner struct ifnet *ifp;
561 1.1 drochner struct ifmediareq *ifmr;
562 1.1 drochner {
563 1.1 drochner struct lance_softc *sc = ifp->if_softc;
564 1.1 drochner
565 1.1 drochner if ((ifp->if_flags & IFF_UP) == 0)
566 1.1 drochner return;
567 1.1 drochner
568 1.1 drochner ifmr->ifm_status = IFM_AVALID;
569 1.1 drochner if (sc->sc_havecarrier)
570 1.1 drochner ifmr->ifm_status |= IFM_ACTIVE;
571 1.1 drochner
572 1.1 drochner if (sc->sc_mediastatus)
573 1.1 drochner (*sc->sc_mediastatus)(sc, ifmr);
574 1.1 drochner }
575 1.1 drochner
576 1.1 drochner /*
577 1.1 drochner * Process an ioctl request.
578 1.1 drochner */
579 1.1 drochner int
580 1.1 drochner lance_ioctl(ifp, cmd, data)
581 1.1 drochner register struct ifnet *ifp;
582 1.1 drochner u_long cmd;
583 1.1 drochner caddr_t data;
584 1.1 drochner {
585 1.1 drochner register struct lance_softc *sc = ifp->if_softc;
586 1.1 drochner struct ifaddr *ifa = (struct ifaddr *)data;
587 1.1 drochner struct ifreq *ifr = (struct ifreq *)data;
588 1.1 drochner int s, error = 0;
589 1.1 drochner
590 1.2 mycroft s = splnet();
591 1.1 drochner
592 1.1 drochner switch (cmd) {
593 1.1 drochner
594 1.1 drochner case SIOCSIFADDR:
595 1.1 drochner ifp->if_flags |= IFF_UP;
596 1.1 drochner
597 1.1 drochner switch (ifa->ifa_addr->sa_family) {
598 1.1 drochner #ifdef INET
599 1.1 drochner case AF_INET:
600 1.1 drochner lance_init(sc);
601 1.1 drochner arp_ifinit(ifp, ifa);
602 1.1 drochner break;
603 1.1 drochner #endif
604 1.1 drochner #ifdef NS
605 1.1 drochner case AF_NS:
606 1.1 drochner {
607 1.1 drochner register struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
608 1.1 drochner
609 1.1 drochner if (ns_nullhost(*ina))
610 1.1 drochner ina->x_host =
611 1.1 drochner *(union ns_host *)LLADDR(ifp->if_sadl);
612 1.1 drochner else {
613 1.1 drochner bcopy(ina->x_host.c_host,
614 1.1 drochner LLADDR(ifp->if_sadl),
615 1.1 drochner sizeof(sc->sc_enaddr));
616 1.1 drochner }
617 1.1 drochner /* Set new address. */
618 1.1 drochner lance_init(sc);
619 1.1 drochner break;
620 1.1 drochner }
621 1.1 drochner #endif
622 1.1 drochner default:
623 1.1 drochner lance_init(sc);
624 1.1 drochner break;
625 1.1 drochner }
626 1.1 drochner break;
627 1.1 drochner
628 1.1 drochner #if defined(CCITT) && defined(LLC)
629 1.1 drochner case SIOCSIFCONF_X25:
630 1.1 drochner ifp->if_flags |= IFF_UP;
631 1.1 drochner ifa->ifa_rtrequest = cons_rtrequest; /* XXX */
632 1.1 drochner error = x25_llcglue(PRC_IFUP, ifa->ifa_addr);
633 1.1 drochner if (error == 0)
634 1.1 drochner lance_init(sc);
635 1.1 drochner break;
636 1.1 drochner #endif /* CCITT && LLC */
637 1.1 drochner
638 1.1 drochner case SIOCSIFFLAGS:
639 1.1 drochner if ((ifp->if_flags & IFF_UP) == 0 &&
640 1.1 drochner (ifp->if_flags & IFF_RUNNING) != 0) {
641 1.1 drochner /*
642 1.1 drochner * If interface is marked down and it is running, then
643 1.1 drochner * stop it.
644 1.1 drochner */
645 1.1 drochner lance_stop(sc);
646 1.1 drochner ifp->if_flags &= ~IFF_RUNNING;
647 1.1 drochner } else if ((ifp->if_flags & IFF_UP) != 0 &&
648 1.1 drochner (ifp->if_flags & IFF_RUNNING) == 0) {
649 1.1 drochner /*
650 1.1 drochner * If interface is marked up and it is stopped, then
651 1.1 drochner * start it.
652 1.1 drochner */
653 1.1 drochner lance_init(sc);
654 1.1 drochner } else {
655 1.1 drochner /*
656 1.1 drochner * Reset the interface to pick up changes in any other
657 1.1 drochner * flags that affect hardware registers.
658 1.1 drochner */
659 1.1 drochner /*lance_stop(sc);*/
660 1.1 drochner lance_init(sc);
661 1.1 drochner }
662 1.1 drochner #ifdef LEDEBUG
663 1.1 drochner if (ifp->if_flags & IFF_DEBUG)
664 1.1 drochner sc->sc_debug = 1;
665 1.1 drochner else
666 1.1 drochner sc->sc_debug = 0;
667 1.1 drochner #endif
668 1.1 drochner break;
669 1.1 drochner
670 1.1 drochner case SIOCADDMULTI:
671 1.1 drochner case SIOCDELMULTI:
672 1.1 drochner error = (cmd == SIOCADDMULTI) ?
673 1.1 drochner ether_addmulti(ifr, &sc->sc_ethercom) :
674 1.1 drochner ether_delmulti(ifr, &sc->sc_ethercom);
675 1.1 drochner
676 1.1 drochner if (error == ENETRESET) {
677 1.1 drochner /*
678 1.1 drochner * Multicast list has changed; set the hardware filter
679 1.1 drochner * accordingly.
680 1.1 drochner */
681 1.1 drochner lance_reset(sc);
682 1.1 drochner error = 0;
683 1.1 drochner }
684 1.1 drochner break;
685 1.1 drochner
686 1.1 drochner case SIOCGIFMEDIA:
687 1.1 drochner case SIOCSIFMEDIA:
688 1.1 drochner error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
689 1.1 drochner break;
690 1.1 drochner
691 1.1 drochner default:
692 1.1 drochner error = EINVAL;
693 1.1 drochner break;
694 1.1 drochner }
695 1.1 drochner
696 1.1 drochner splx(s);
697 1.1 drochner return (error);
698 1.1 drochner }
699 1.1 drochner
700 1.1 drochner hide void
701 1.1 drochner lance_shutdown(arg)
702 1.1 drochner void *arg;
703 1.1 drochner {
704 1.1 drochner
705 1.1 drochner lance_stop((struct lance_softc *)arg);
706 1.1 drochner }
707 1.1 drochner
708 1.1 drochner /*
709 1.1 drochner * Set up the logical address filter.
710 1.1 drochner */
711 1.1 drochner void
712 1.1 drochner lance_setladrf(ac, af)
713 1.1 drochner struct ethercom *ac;
714 1.1 drochner u_int16_t *af;
715 1.1 drochner {
716 1.1 drochner struct ifnet *ifp = &ac->ec_if;
717 1.1 drochner struct ether_multi *enm;
718 1.1 drochner register u_char *cp;
719 1.1 drochner register u_int32_t crc;
720 1.1 drochner static const u_int32_t crctab[] = {
721 1.1 drochner 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
722 1.1 drochner 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
723 1.1 drochner 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
724 1.1 drochner 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
725 1.1 drochner };
726 1.1 drochner register int len;
727 1.1 drochner struct ether_multistep step;
728 1.1 drochner
729 1.1 drochner /*
730 1.1 drochner * Set up multicast address filter by passing all multicast addresses
731 1.1 drochner * through a crc generator, and then using the high order 6 bits as an
732 1.1 drochner * index into the 64 bit logical address filter. The high order bit
733 1.1 drochner * selects the word, while the rest of the bits select the bit within
734 1.1 drochner * the word.
735 1.1 drochner */
736 1.1 drochner
737 1.1 drochner if (ifp->if_flags & IFF_PROMISC)
738 1.1 drochner goto allmulti;
739 1.1 drochner
740 1.1 drochner af[0] = af[1] = af[2] = af[3] = 0x0000;
741 1.1 drochner ETHER_FIRST_MULTI(step, ac, enm);
742 1.1 drochner while (enm != NULL) {
743 1.1 drochner if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
744 1.1 drochner /*
745 1.1 drochner * We must listen to a range of multicast addresses.
746 1.1 drochner * For now, just accept all multicasts, rather than
747 1.1 drochner * trying to set only those filter bits needed to match
748 1.1 drochner * the range. (At this time, the only use of address
749 1.1 drochner * ranges is for IP multicast routing, for which the
750 1.1 drochner * range is big enough to require all bits set.)
751 1.1 drochner */
752 1.1 drochner goto allmulti;
753 1.1 drochner }
754 1.1 drochner
755 1.1 drochner cp = enm->enm_addrlo;
756 1.1 drochner crc = 0xffffffff;
757 1.1 drochner for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
758 1.1 drochner crc ^= *cp++;
759 1.1 drochner crc = (crc >> 4) ^ crctab[crc & 0xf];
760 1.1 drochner crc = (crc >> 4) ^ crctab[crc & 0xf];
761 1.1 drochner }
762 1.1 drochner /* Just want the 6 most significant bits. */
763 1.1 drochner crc >>= 26;
764 1.1 drochner
765 1.1 drochner /* Set the corresponding bit in the filter. */
766 1.1 drochner af[crc >> 4] |= 1 << (crc & 0xf);
767 1.1 drochner
768 1.1 drochner ETHER_NEXT_MULTI(step, enm);
769 1.1 drochner }
770 1.1 drochner ifp->if_flags &= ~IFF_ALLMULTI;
771 1.1 drochner return;
772 1.1 drochner
773 1.1 drochner allmulti:
774 1.1 drochner ifp->if_flags |= IFF_ALLMULTI;
775 1.1 drochner af[0] = af[1] = af[2] = af[3] = 0xffff;
776 1.1 drochner }
777 1.1 drochner
778 1.1 drochner /*
779 1.1 drochner * Routines for accessing the transmit and receive buffers.
780 1.1 drochner * The various CPU and adapter configurations supported by this
781 1.1 drochner * driver require three different access methods for buffers
782 1.1 drochner * and descriptors:
783 1.1 drochner * (1) contig (contiguous data; no padding),
784 1.1 drochner * (2) gap2 (two bytes of data followed by two bytes of padding),
785 1.1 drochner * (3) gap16 (16 bytes of data followed by 16 bytes of padding).
786 1.1 drochner */
787 1.1 drochner
788 1.1 drochner /*
789 1.1 drochner * contig: contiguous data with no padding.
790 1.1 drochner *
791 1.1 drochner * Buffers may have any alignment.
792 1.1 drochner */
793 1.1 drochner
794 1.1 drochner void
795 1.1 drochner lance_copytobuf_contig(sc, from, boff, len)
796 1.1 drochner struct lance_softc *sc;
797 1.1 drochner void *from;
798 1.1 drochner int boff, len;
799 1.1 drochner {
800 1.1 drochner volatile caddr_t buf = sc->sc_mem;
801 1.1 drochner
802 1.1 drochner /*
803 1.1 drochner * Just call bcopy() to do the work.
804 1.1 drochner */
805 1.1 drochner bcopy(from, buf + boff, len);
806 1.1 drochner }
807 1.1 drochner
808 1.1 drochner void
809 1.1 drochner lance_copyfrombuf_contig(sc, to, boff, len)
810 1.1 drochner struct lance_softc *sc;
811 1.1 drochner void *to;
812 1.1 drochner int boff, len;
813 1.1 drochner {
814 1.1 drochner volatile caddr_t buf = sc->sc_mem;
815 1.1 drochner
816 1.1 drochner /*
817 1.1 drochner * Just call bcopy() to do the work.
818 1.1 drochner */
819 1.1 drochner bcopy(buf + boff, to, len);
820 1.1 drochner }
821 1.1 drochner
822 1.1 drochner void
823 1.1 drochner lance_zerobuf_contig(sc, boff, len)
824 1.1 drochner struct lance_softc *sc;
825 1.1 drochner int boff, len;
826 1.1 drochner {
827 1.1 drochner volatile caddr_t buf = sc->sc_mem;
828 1.1 drochner
829 1.1 drochner /*
830 1.1 drochner * Just let bzero() do the work
831 1.1 drochner */
832 1.1 drochner bzero(buf + boff, len);
833 1.1 drochner }
834 1.1 drochner
835 1.1 drochner #if 0
836 1.1 drochner /*
837 1.1 drochner * Examples only; duplicate these and tweak (if necessary) in
838 1.1 drochner * machine-specific front-ends.
839 1.1 drochner */
840 1.1 drochner
841 1.1 drochner /*
842 1.1 drochner * gap2: two bytes of data followed by two bytes of pad.
843 1.1 drochner *
844 1.1 drochner * Buffers must be 4-byte aligned. The code doesn't worry about
845 1.1 drochner * doing an extra byte.
846 1.1 drochner */
847 1.1 drochner
848 1.1 drochner void
849 1.1 drochner lance_copytobuf_gap2(sc, fromv, boff, len)
850 1.1 drochner struct lance_softc *sc;
851 1.1 drochner void *fromv;
852 1.1 drochner int boff;
853 1.1 drochner register int len;
854 1.1 drochner {
855 1.1 drochner volatile caddr_t buf = sc->sc_mem;
856 1.1 drochner register caddr_t from = fromv;
857 1.1 drochner register volatile u_int16_t *bptr;
858 1.1 drochner
859 1.1 drochner if (boff & 0x1) {
860 1.1 drochner /* handle unaligned first byte */
861 1.1 drochner bptr = ((volatile u_int16_t *)buf) + (boff - 1);
862 1.1 drochner *bptr = (*from++ << 8) | (*bptr & 0xff);
863 1.1 drochner bptr += 2;
864 1.1 drochner len--;
865 1.1 drochner } else
866 1.1 drochner bptr = ((volatile u_int16_t *)buf) + boff;
867 1.1 drochner while (len > 1) {
868 1.1 drochner *bptr = (from[1] << 8) | (from[0] & 0xff);
869 1.1 drochner bptr += 2;
870 1.1 drochner from += 2;
871 1.1 drochner len -= 2;
872 1.1 drochner }
873 1.1 drochner if (len == 1)
874 1.1 drochner *bptr = (u_int16_t)*from;
875 1.1 drochner }
876 1.1 drochner
877 1.1 drochner void
878 1.1 drochner lance_copyfrombuf_gap2(sc, tov, boff, len)
879 1.1 drochner struct lance_softc *sc;
880 1.1 drochner void *tov;
881 1.1 drochner int boff, len;
882 1.1 drochner {
883 1.1 drochner volatile caddr_t buf = sc->sc_mem;
884 1.1 drochner register caddr_t to = tov;
885 1.1 drochner register volatile u_int16_t *bptr;
886 1.1 drochner register u_int16_t tmp;
887 1.1 drochner
888 1.1 drochner if (boff & 0x1) {
889 1.1 drochner /* handle unaligned first byte */
890 1.1 drochner bptr = ((volatile u_int16_t *)buf) + (boff - 1);
891 1.1 drochner *to++ = (*bptr >> 8) & 0xff;
892 1.1 drochner bptr += 2;
893 1.1 drochner len--;
894 1.1 drochner } else
895 1.1 drochner bptr = ((volatile u_int16_t *)buf) + boff;
896 1.1 drochner while (len > 1) {
897 1.1 drochner tmp = *bptr;
898 1.1 drochner *to++ = tmp & 0xff;
899 1.1 drochner *to++ = (tmp >> 8) & 0xff;
900 1.1 drochner bptr += 2;
901 1.1 drochner len -= 2;
902 1.1 drochner }
903 1.1 drochner if (len == 1)
904 1.1 drochner *to = *bptr & 0xff;
905 1.1 drochner }
906 1.1 drochner
907 1.1 drochner void
908 1.1 drochner lance_zerobuf_gap2(sc, boff, len)
909 1.1 drochner struct lance_softc *sc;
910 1.1 drochner int boff, len;
911 1.1 drochner {
912 1.1 drochner volatile caddr_t buf = sc->sc_mem;
913 1.1 drochner register volatile u_int16_t *bptr;
914 1.1 drochner
915 1.1 drochner if ((unsigned)boff & 0x1) {
916 1.1 drochner bptr = ((volatile u_int16_t *)buf) + (boff - 1);
917 1.1 drochner *bptr &= 0xff;
918 1.1 drochner bptr += 2;
919 1.1 drochner len--;
920 1.1 drochner } else
921 1.1 drochner bptr = ((volatile u_int16_t *)buf) + boff;
922 1.1 drochner while (len > 0) {
923 1.1 drochner *bptr = 0;
924 1.1 drochner bptr += 2;
925 1.1 drochner len -= 2;
926 1.1 drochner }
927 1.1 drochner }
928 1.1 drochner
929 1.1 drochner /*
930 1.1 drochner * gap16: 16 bytes of data followed by 16 bytes of pad.
931 1.1 drochner *
932 1.1 drochner * Buffers must be 32-byte aligned.
933 1.1 drochner */
934 1.1 drochner
935 1.1 drochner void
936 1.1 drochner lance_copytobuf_gap16(sc, fromv, boff, len)
937 1.1 drochner struct lance_softc *sc;
938 1.1 drochner void *fromv;
939 1.1 drochner int boff;
940 1.1 drochner register int len;
941 1.1 drochner {
942 1.1 drochner volatile caddr_t buf = sc->sc_mem;
943 1.1 drochner register caddr_t from = fromv;
944 1.1 drochner register caddr_t bptr;
945 1.1 drochner register int xfer;
946 1.1 drochner
947 1.1 drochner bptr = buf + ((boff << 1) & ~0x1f);
948 1.1 drochner boff &= 0xf;
949 1.1 drochner xfer = min(len, 16 - boff);
950 1.1 drochner while (len > 0) {
951 1.1 drochner bcopy(from, bptr + boff, xfer);
952 1.1 drochner from += xfer;
953 1.1 drochner bptr += 32;
954 1.1 drochner boff = 0;
955 1.1 drochner len -= xfer;
956 1.1 drochner xfer = min(len, 16);
957 1.1 drochner }
958 1.1 drochner }
959 1.1 drochner
960 1.1 drochner void
961 1.1 drochner lance_copyfrombuf_gap16(sc, tov, boff, len)
962 1.1 drochner struct lance_softc *sc;
963 1.1 drochner void *tov;
964 1.1 drochner int boff, len;
965 1.1 drochner {
966 1.1 drochner volatile caddr_t buf = sc->sc_mem;
967 1.1 drochner register caddr_t to = tov;
968 1.1 drochner register caddr_t bptr;
969 1.1 drochner register int xfer;
970 1.1 drochner
971 1.1 drochner bptr = buf + ((boff << 1) & ~0x1f);
972 1.1 drochner boff &= 0xf;
973 1.1 drochner xfer = min(len, 16 - boff);
974 1.1 drochner while (len > 0) {
975 1.1 drochner bcopy(bptr + boff, to, xfer);
976 1.1 drochner to += xfer;
977 1.1 drochner bptr += 32;
978 1.1 drochner boff = 0;
979 1.1 drochner len -= xfer;
980 1.1 drochner xfer = min(len, 16);
981 1.1 drochner }
982 1.1 drochner }
983 1.1 drochner
984 1.1 drochner void
985 1.1 drochner lance_zerobuf_gap16(sc, boff, len)
986 1.1 drochner struct lance_softc *sc;
987 1.1 drochner int boff, len;
988 1.1 drochner {
989 1.1 drochner volatile caddr_t buf = sc->sc_mem;
990 1.1 drochner register caddr_t bptr;
991 1.1 drochner register int xfer;
992 1.1 drochner
993 1.1 drochner bptr = buf + ((boff << 1) & ~0x1f);
994 1.1 drochner boff &= 0xf;
995 1.1 drochner xfer = min(len, 16 - boff);
996 1.1 drochner while (len > 0) {
997 1.1 drochner bzero(bptr + boff, xfer);
998 1.1 drochner bptr += 32;
999 1.1 drochner boff = 0;
1000 1.1 drochner len -= xfer;
1001 1.1 drochner xfer = min(len, 16);
1002 1.1 drochner }
1003 1.1 drochner }
1004 1.1 drochner #endif /* Example only */
1005