lance.c revision 1.11 1 1.11 augustss /* $NetBSD: lance.c,v 1.11 2000/03/30 12:45:31 augustss 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.11 augustss u_int16_t *a = (u_short *) one;
176 1.11 augustss u_int16_t *b = (u_short *) two;
177 1.11 augustss 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 switch (sc->sc_memsize) {
243 1.1 drochner case 8192:
244 1.1 drochner sc->sc_nrbuf = 4;
245 1.1 drochner sc->sc_ntbuf = 1;
246 1.1 drochner break;
247 1.1 drochner case 16384:
248 1.1 drochner sc->sc_nrbuf = 8;
249 1.1 drochner sc->sc_ntbuf = 2;
250 1.1 drochner break;
251 1.1 drochner case 32768:
252 1.1 drochner sc->sc_nrbuf = 16;
253 1.1 drochner sc->sc_ntbuf = 4;
254 1.1 drochner break;
255 1.1 drochner case 65536:
256 1.1 drochner sc->sc_nrbuf = 32;
257 1.1 drochner sc->sc_ntbuf = 8;
258 1.1 drochner break;
259 1.1 drochner case 131072:
260 1.1 drochner sc->sc_nrbuf = 64;
261 1.1 drochner sc->sc_ntbuf = 16;
262 1.4 leo break;
263 1.4 leo case 262144:
264 1.4 leo sc->sc_nrbuf = 128;
265 1.4 leo sc->sc_ntbuf = 32;
266 1.1 drochner break;
267 1.1 drochner default:
268 1.1 drochner panic("lance_config: weird memory size");
269 1.1 drochner }
270 1.1 drochner
271 1.1 drochner printf(": address %s\n", ether_sprintf(sc->sc_enaddr));
272 1.1 drochner printf("%s: %d receive buffers, %d transmit buffers\n",
273 1.1 drochner sc->sc_dev.dv_xname, sc->sc_nrbuf, sc->sc_ntbuf);
274 1.10 simonb
275 1.10 simonb /* Attach the interface. */
276 1.10 simonb if_attach(ifp);
277 1.10 simonb ether_ifattach(ifp, sc->sc_enaddr);
278 1.10 simonb
279 1.10 simonb #if NBPFILTER > 0
280 1.10 simonb bpfattach(&ifp->if_bpf, ifp, DLT_EN10MB, sizeof(struct ether_header));
281 1.10 simonb #endif
282 1.1 drochner
283 1.1 drochner sc->sc_sh = shutdownhook_establish(lance_shutdown, sc);
284 1.1 drochner if (sc->sc_sh == NULL)
285 1.1 drochner panic("lance_config: can't establish shutdownhook");
286 1.1 drochner sc->sc_rbufaddr = malloc(sc->sc_nrbuf * sizeof(int), M_DEVBUF,
287 1.1 drochner M_WAITOK);
288 1.1 drochner sc->sc_tbufaddr = malloc(sc->sc_ntbuf * sizeof(int), M_DEVBUF,
289 1.1 drochner M_WAITOK);
290 1.1 drochner
291 1.1 drochner #if NRND > 0
292 1.1 drochner rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
293 1.7 explorer RND_TYPE_NET, 0);
294 1.1 drochner #endif
295 1.1 drochner }
296 1.1 drochner
297 1.1 drochner void
298 1.1 drochner lance_reset(sc)
299 1.1 drochner struct lance_softc *sc;
300 1.1 drochner {
301 1.1 drochner int s;
302 1.1 drochner
303 1.2 mycroft s = splnet();
304 1.1 drochner lance_init(sc);
305 1.1 drochner splx(s);
306 1.1 drochner }
307 1.1 drochner
308 1.1 drochner void
309 1.1 drochner lance_stop(sc)
310 1.1 drochner struct lance_softc *sc;
311 1.1 drochner {
312 1.1 drochner
313 1.1 drochner (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
314 1.1 drochner }
315 1.1 drochner
316 1.1 drochner /*
317 1.1 drochner * Initialization of interface; set up initialization block
318 1.1 drochner * and transmit/receive descriptor rings.
319 1.1 drochner */
320 1.1 drochner void
321 1.1 drochner lance_init(sc)
322 1.11 augustss struct lance_softc *sc;
323 1.1 drochner {
324 1.11 augustss int timo;
325 1.1 drochner u_long a;
326 1.1 drochner
327 1.1 drochner (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
328 1.1 drochner DELAY(100);
329 1.1 drochner
330 1.1 drochner /* Newer LANCE chips have a reset register */
331 1.1 drochner if (sc->sc_hwreset)
332 1.1 drochner (*sc->sc_hwreset)(sc);
333 1.1 drochner
334 1.1 drochner /* Set the correct byte swapping mode, etc. */
335 1.1 drochner (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
336 1.1 drochner
337 1.1 drochner /* Set up LANCE init block. */
338 1.1 drochner (*sc->sc_meminit)(sc);
339 1.1 drochner
340 1.1 drochner /* Give LANCE the physical address of its init block. */
341 1.1 drochner a = sc->sc_addr + LE_INITADDR(sc);
342 1.1 drochner (*sc->sc_wrcsr)(sc, LE_CSR1, a);
343 1.1 drochner (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
344 1.1 drochner
345 1.1 drochner /* Try to initialize the LANCE. */
346 1.1 drochner DELAY(100);
347 1.1 drochner (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
348 1.1 drochner
349 1.1 drochner /* Wait for initialization to finish. */
350 1.1 drochner for (timo = 100000; timo; timo--)
351 1.1 drochner if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
352 1.1 drochner break;
353 1.1 drochner
354 1.1 drochner if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
355 1.1 drochner /* Start the LANCE. */
356 1.1 drochner (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT |
357 1.1 drochner LE_C0_IDON);
358 1.1 drochner ifp->if_flags |= IFF_RUNNING;
359 1.1 drochner ifp->if_flags &= ~IFF_OACTIVE;
360 1.1 drochner ifp->if_timer = 0;
361 1.1 drochner (*sc->sc_start)(ifp);
362 1.1 drochner } else
363 1.1 drochner printf("%s: controller failed to initialize\n",
364 1.1 drochner sc->sc_dev.dv_xname);
365 1.1 drochner if (sc->sc_hwinit)
366 1.1 drochner (*sc->sc_hwinit)(sc);
367 1.1 drochner }
368 1.1 drochner
369 1.1 drochner /*
370 1.1 drochner * Routine to copy from mbuf chain to transmit buffer in
371 1.1 drochner * network buffer memory.
372 1.1 drochner */
373 1.1 drochner int
374 1.1 drochner lance_put(sc, boff, m)
375 1.1 drochner struct lance_softc *sc;
376 1.1 drochner int boff;
377 1.11 augustss struct mbuf *m;
378 1.1 drochner {
379 1.11 augustss struct mbuf *n;
380 1.11 augustss int len, tlen = 0;
381 1.1 drochner
382 1.1 drochner for (; m; m = n) {
383 1.1 drochner len = m->m_len;
384 1.1 drochner if (len == 0) {
385 1.1 drochner MFREE(m, n);
386 1.1 drochner continue;
387 1.1 drochner }
388 1.1 drochner (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
389 1.1 drochner boff += len;
390 1.1 drochner tlen += len;
391 1.1 drochner MFREE(m, n);
392 1.1 drochner }
393 1.1 drochner if (tlen < LEMINSIZE) {
394 1.1 drochner (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
395 1.1 drochner tlen = LEMINSIZE;
396 1.1 drochner }
397 1.1 drochner return (tlen);
398 1.1 drochner }
399 1.1 drochner
400 1.1 drochner /*
401 1.1 drochner * Pull data off an interface.
402 1.1 drochner * Len is length of data, with local net header stripped.
403 1.1 drochner * We copy the data into mbufs. When full cluster sized units are present
404 1.1 drochner * we copy into clusters.
405 1.1 drochner */
406 1.1 drochner integrate struct mbuf *
407 1.1 drochner lance_get(sc, boff, totlen)
408 1.1 drochner struct lance_softc *sc;
409 1.1 drochner int boff, totlen;
410 1.1 drochner {
411 1.5 mycroft struct mbuf *m, *m0, *newm;
412 1.1 drochner int len;
413 1.1 drochner
414 1.5 mycroft MGETHDR(m0, M_DONTWAIT, MT_DATA);
415 1.5 mycroft if (m0 == 0)
416 1.1 drochner return (0);
417 1.5 mycroft m0->m_pkthdr.rcvif = ifp;
418 1.5 mycroft m0->m_pkthdr.len = totlen;
419 1.1 drochner len = MHLEN;
420 1.5 mycroft m = m0;
421 1.1 drochner
422 1.1 drochner while (totlen > 0) {
423 1.1 drochner if (totlen >= MINCLSIZE) {
424 1.1 drochner MCLGET(m, M_DONTWAIT);
425 1.5 mycroft if ((m->m_flags & M_EXT) == 0)
426 1.5 mycroft goto bad;
427 1.1 drochner len = MCLBYTES;
428 1.1 drochner }
429 1.5 mycroft
430 1.5 mycroft if (m == m0) {
431 1.5 mycroft caddr_t newdata = (caddr_t)
432 1.5 mycroft ALIGN(m->m_data + sizeof(struct ether_header)) -
433 1.5 mycroft sizeof(struct ether_header);
434 1.5 mycroft len -= newdata - m->m_data;
435 1.5 mycroft m->m_data = newdata;
436 1.1 drochner }
437 1.5 mycroft
438 1.1 drochner m->m_len = len = min(totlen, len);
439 1.1 drochner (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
440 1.1 drochner boff += len;
441 1.5 mycroft
442 1.1 drochner totlen -= len;
443 1.5 mycroft if (totlen > 0) {
444 1.5 mycroft MGET(newm, M_DONTWAIT, MT_DATA);
445 1.5 mycroft if (newm == 0)
446 1.5 mycroft goto bad;
447 1.5 mycroft len = MLEN;
448 1.5 mycroft m = m->m_next = newm;
449 1.5 mycroft }
450 1.1 drochner }
451 1.1 drochner
452 1.5 mycroft return (m0);
453 1.5 mycroft
454 1.5 mycroft bad:
455 1.5 mycroft m_freem(m0);
456 1.5 mycroft return (0);
457 1.1 drochner }
458 1.1 drochner
459 1.1 drochner /*
460 1.1 drochner * Pass a packet to the higher levels.
461 1.1 drochner */
462 1.1 drochner void
463 1.1 drochner lance_read(sc, boff, len)
464 1.11 augustss struct lance_softc *sc;
465 1.1 drochner int boff, len;
466 1.1 drochner {
467 1.1 drochner struct mbuf *m;
468 1.1 drochner struct ether_header *eh;
469 1.1 drochner
470 1.1 drochner if (len <= sizeof(struct ether_header) ||
471 1.1 drochner len > ETHERMTU + sizeof(struct ether_header)) {
472 1.1 drochner #ifdef LEDEBUG
473 1.1 drochner printf("%s: invalid packet size %d; dropping\n",
474 1.1 drochner sc->sc_dev.dv_xname, len);
475 1.1 drochner #endif
476 1.1 drochner ifp->if_ierrors++;
477 1.1 drochner return;
478 1.1 drochner }
479 1.1 drochner
480 1.1 drochner /* Pull packet off interface. */
481 1.1 drochner m = lance_get(sc, boff, len);
482 1.1 drochner if (m == 0) {
483 1.1 drochner ifp->if_ierrors++;
484 1.1 drochner return;
485 1.1 drochner }
486 1.1 drochner
487 1.1 drochner ifp->if_ipackets++;
488 1.1 drochner
489 1.1 drochner /* We assume that the header fit entirely in one mbuf. */
490 1.1 drochner eh = mtod(m, struct ether_header *);
491 1.1 drochner
492 1.1 drochner #if NBPFILTER > 0
493 1.1 drochner /*
494 1.1 drochner * Check if there's a BPF listener on this interface.
495 1.1 drochner * If so, hand off the raw packet to BPF.
496 1.1 drochner */
497 1.1 drochner if (ifp->if_bpf) {
498 1.1 drochner bpf_mtap(ifp->if_bpf, m);
499 1.1 drochner
500 1.1 drochner #ifndef LANCE_REVC_BUG
501 1.1 drochner /*
502 1.1 drochner * Note that the interface cannot be in promiscuous mode if
503 1.1 drochner * there are no BPF listeners. And if we are in promiscuous
504 1.1 drochner * mode, we have to check if this packet is really ours.
505 1.1 drochner */
506 1.1 drochner if ((ifp->if_flags & IFF_PROMISC) != 0 &&
507 1.1 drochner (eh->ether_dhost[0] & 1) == 0 && /* !mcast and !bcast */
508 1.1 drochner ETHER_CMP(eh->ether_dhost, sc->sc_enaddr)) {
509 1.1 drochner m_freem(m);
510 1.1 drochner return;
511 1.1 drochner }
512 1.1 drochner #endif
513 1.1 drochner }
514 1.1 drochner #endif
515 1.1 drochner
516 1.1 drochner #ifdef LANCE_REVC_BUG
517 1.1 drochner /*
518 1.1 drochner * The old LANCE (Rev. C) chips have a bug which causes
519 1.1 drochner * garbage to be inserted in front of the received packet.
520 1.1 drochner * The work-around is to ignore packets with an invalid
521 1.1 drochner * destination address (garbage will usually not match).
522 1.1 drochner * Of course, this precludes multicast support...
523 1.1 drochner */
524 1.1 drochner if (ETHER_CMP(eh->ether_dhost, sc->sc_enaddr) &&
525 1.1 drochner ETHER_CMP(eh->ether_dhost, bcast_enaddr)) {
526 1.1 drochner m_freem(m);
527 1.1 drochner return;
528 1.1 drochner }
529 1.1 drochner #endif
530 1.1 drochner
531 1.9 thorpej /* Pass the packet up. */
532 1.9 thorpej (*ifp->if_input)(ifp, m);
533 1.1 drochner }
534 1.1 drochner
535 1.1 drochner #undef ifp
536 1.1 drochner
537 1.1 drochner void
538 1.1 drochner lance_watchdog(ifp)
539 1.1 drochner struct ifnet *ifp;
540 1.1 drochner {
541 1.1 drochner struct lance_softc *sc = ifp->if_softc;
542 1.1 drochner
543 1.1 drochner log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
544 1.1 drochner ++ifp->if_oerrors;
545 1.1 drochner
546 1.1 drochner lance_reset(sc);
547 1.1 drochner }
548 1.1 drochner
549 1.1 drochner int
550 1.1 drochner lance_mediachange(ifp)
551 1.1 drochner struct ifnet *ifp;
552 1.1 drochner {
553 1.1 drochner struct lance_softc *sc = ifp->if_softc;
554 1.1 drochner
555 1.1 drochner if (sc->sc_mediachange)
556 1.1 drochner return ((*sc->sc_mediachange)(sc));
557 1.8 thorpej return (0);
558 1.1 drochner }
559 1.1 drochner
560 1.1 drochner void
561 1.1 drochner lance_mediastatus(ifp, ifmr)
562 1.1 drochner struct ifnet *ifp;
563 1.1 drochner struct ifmediareq *ifmr;
564 1.1 drochner {
565 1.1 drochner struct lance_softc *sc = ifp->if_softc;
566 1.1 drochner
567 1.1 drochner if ((ifp->if_flags & IFF_UP) == 0)
568 1.1 drochner return;
569 1.1 drochner
570 1.1 drochner ifmr->ifm_status = IFM_AVALID;
571 1.1 drochner if (sc->sc_havecarrier)
572 1.1 drochner ifmr->ifm_status |= IFM_ACTIVE;
573 1.1 drochner
574 1.1 drochner if (sc->sc_mediastatus)
575 1.1 drochner (*sc->sc_mediastatus)(sc, ifmr);
576 1.1 drochner }
577 1.1 drochner
578 1.1 drochner /*
579 1.1 drochner * Process an ioctl request.
580 1.1 drochner */
581 1.1 drochner int
582 1.1 drochner lance_ioctl(ifp, cmd, data)
583 1.11 augustss struct ifnet *ifp;
584 1.1 drochner u_long cmd;
585 1.1 drochner caddr_t data;
586 1.1 drochner {
587 1.11 augustss struct lance_softc *sc = ifp->if_softc;
588 1.1 drochner struct ifaddr *ifa = (struct ifaddr *)data;
589 1.1 drochner struct ifreq *ifr = (struct ifreq *)data;
590 1.1 drochner int s, error = 0;
591 1.1 drochner
592 1.2 mycroft s = splnet();
593 1.1 drochner
594 1.1 drochner switch (cmd) {
595 1.1 drochner
596 1.1 drochner case SIOCSIFADDR:
597 1.1 drochner ifp->if_flags |= IFF_UP;
598 1.1 drochner
599 1.1 drochner switch (ifa->ifa_addr->sa_family) {
600 1.1 drochner #ifdef INET
601 1.1 drochner case AF_INET:
602 1.1 drochner lance_init(sc);
603 1.1 drochner arp_ifinit(ifp, ifa);
604 1.1 drochner break;
605 1.1 drochner #endif
606 1.1 drochner #ifdef NS
607 1.1 drochner case AF_NS:
608 1.1 drochner {
609 1.11 augustss struct ns_addr *ina = &IA_SNS(ifa)->sns_addr;
610 1.1 drochner
611 1.1 drochner if (ns_nullhost(*ina))
612 1.1 drochner ina->x_host =
613 1.1 drochner *(union ns_host *)LLADDR(ifp->if_sadl);
614 1.1 drochner else {
615 1.1 drochner bcopy(ina->x_host.c_host,
616 1.1 drochner LLADDR(ifp->if_sadl),
617 1.1 drochner sizeof(sc->sc_enaddr));
618 1.1 drochner }
619 1.1 drochner /* Set new address. */
620 1.1 drochner lance_init(sc);
621 1.1 drochner break;
622 1.1 drochner }
623 1.1 drochner #endif
624 1.1 drochner default:
625 1.1 drochner lance_init(sc);
626 1.1 drochner break;
627 1.1 drochner }
628 1.1 drochner break;
629 1.1 drochner
630 1.1 drochner #if defined(CCITT) && defined(LLC)
631 1.1 drochner case SIOCSIFCONF_X25:
632 1.1 drochner ifp->if_flags |= IFF_UP;
633 1.1 drochner ifa->ifa_rtrequest = cons_rtrequest; /* XXX */
634 1.1 drochner error = x25_llcglue(PRC_IFUP, ifa->ifa_addr);
635 1.1 drochner if (error == 0)
636 1.1 drochner lance_init(sc);
637 1.1 drochner break;
638 1.1 drochner #endif /* CCITT && LLC */
639 1.1 drochner
640 1.1 drochner case SIOCSIFFLAGS:
641 1.1 drochner if ((ifp->if_flags & IFF_UP) == 0 &&
642 1.1 drochner (ifp->if_flags & IFF_RUNNING) != 0) {
643 1.1 drochner /*
644 1.1 drochner * If interface is marked down and it is running, then
645 1.1 drochner * stop it.
646 1.1 drochner */
647 1.1 drochner lance_stop(sc);
648 1.1 drochner ifp->if_flags &= ~IFF_RUNNING;
649 1.1 drochner } else if ((ifp->if_flags & IFF_UP) != 0 &&
650 1.1 drochner (ifp->if_flags & IFF_RUNNING) == 0) {
651 1.1 drochner /*
652 1.1 drochner * If interface is marked up and it is stopped, then
653 1.1 drochner * start it.
654 1.1 drochner */
655 1.1 drochner lance_init(sc);
656 1.6 thorpej } else if ((ifp->if_flags & IFF_UP) != 0) {
657 1.1 drochner /*
658 1.1 drochner * Reset the interface to pick up changes in any other
659 1.1 drochner * flags that affect hardware registers.
660 1.1 drochner */
661 1.1 drochner /*lance_stop(sc);*/
662 1.1 drochner lance_init(sc);
663 1.1 drochner }
664 1.1 drochner #ifdef LEDEBUG
665 1.1 drochner if (ifp->if_flags & IFF_DEBUG)
666 1.1 drochner sc->sc_debug = 1;
667 1.1 drochner else
668 1.1 drochner sc->sc_debug = 0;
669 1.1 drochner #endif
670 1.1 drochner break;
671 1.1 drochner
672 1.1 drochner case SIOCADDMULTI:
673 1.1 drochner case SIOCDELMULTI:
674 1.1 drochner error = (cmd == SIOCADDMULTI) ?
675 1.1 drochner ether_addmulti(ifr, &sc->sc_ethercom) :
676 1.1 drochner ether_delmulti(ifr, &sc->sc_ethercom);
677 1.1 drochner
678 1.1 drochner if (error == ENETRESET) {
679 1.1 drochner /*
680 1.1 drochner * Multicast list has changed; set the hardware filter
681 1.1 drochner * accordingly.
682 1.1 drochner */
683 1.1 drochner lance_reset(sc);
684 1.1 drochner error = 0;
685 1.1 drochner }
686 1.1 drochner break;
687 1.1 drochner
688 1.1 drochner case SIOCGIFMEDIA:
689 1.1 drochner case SIOCSIFMEDIA:
690 1.1 drochner error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
691 1.1 drochner break;
692 1.1 drochner
693 1.1 drochner default:
694 1.1 drochner error = EINVAL;
695 1.1 drochner break;
696 1.1 drochner }
697 1.1 drochner
698 1.1 drochner splx(s);
699 1.1 drochner return (error);
700 1.1 drochner }
701 1.1 drochner
702 1.1 drochner hide void
703 1.1 drochner lance_shutdown(arg)
704 1.1 drochner void *arg;
705 1.1 drochner {
706 1.1 drochner
707 1.1 drochner lance_stop((struct lance_softc *)arg);
708 1.1 drochner }
709 1.1 drochner
710 1.1 drochner /*
711 1.1 drochner * Set up the logical address filter.
712 1.1 drochner */
713 1.1 drochner void
714 1.1 drochner lance_setladrf(ac, af)
715 1.1 drochner struct ethercom *ac;
716 1.1 drochner u_int16_t *af;
717 1.1 drochner {
718 1.1 drochner struct ifnet *ifp = &ac->ec_if;
719 1.1 drochner struct ether_multi *enm;
720 1.11 augustss u_char *cp;
721 1.11 augustss u_int32_t crc;
722 1.1 drochner static const u_int32_t crctab[] = {
723 1.1 drochner 0x00000000, 0x1db71064, 0x3b6e20c8, 0x26d930ac,
724 1.1 drochner 0x76dc4190, 0x6b6b51f4, 0x4db26158, 0x5005713c,
725 1.1 drochner 0xedb88320, 0xf00f9344, 0xd6d6a3e8, 0xcb61b38c,
726 1.1 drochner 0x9b64c2b0, 0x86d3d2d4, 0xa00ae278, 0xbdbdf21c
727 1.1 drochner };
728 1.11 augustss int len;
729 1.1 drochner struct ether_multistep step;
730 1.1 drochner
731 1.1 drochner /*
732 1.1 drochner * Set up multicast address filter by passing all multicast addresses
733 1.1 drochner * through a crc generator, and then using the high order 6 bits as an
734 1.1 drochner * index into the 64 bit logical address filter. The high order bit
735 1.1 drochner * selects the word, while the rest of the bits select the bit within
736 1.1 drochner * the word.
737 1.1 drochner */
738 1.1 drochner
739 1.1 drochner if (ifp->if_flags & IFF_PROMISC)
740 1.1 drochner goto allmulti;
741 1.1 drochner
742 1.1 drochner af[0] = af[1] = af[2] = af[3] = 0x0000;
743 1.1 drochner ETHER_FIRST_MULTI(step, ac, enm);
744 1.1 drochner while (enm != NULL) {
745 1.1 drochner if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
746 1.1 drochner /*
747 1.1 drochner * We must listen to a range of multicast addresses.
748 1.1 drochner * For now, just accept all multicasts, rather than
749 1.1 drochner * trying to set only those filter bits needed to match
750 1.1 drochner * the range. (At this time, the only use of address
751 1.1 drochner * ranges is for IP multicast routing, for which the
752 1.1 drochner * range is big enough to require all bits set.)
753 1.1 drochner */
754 1.1 drochner goto allmulti;
755 1.1 drochner }
756 1.1 drochner
757 1.1 drochner cp = enm->enm_addrlo;
758 1.1 drochner crc = 0xffffffff;
759 1.1 drochner for (len = sizeof(enm->enm_addrlo); --len >= 0;) {
760 1.1 drochner crc ^= *cp++;
761 1.1 drochner crc = (crc >> 4) ^ crctab[crc & 0xf];
762 1.1 drochner crc = (crc >> 4) ^ crctab[crc & 0xf];
763 1.1 drochner }
764 1.1 drochner /* Just want the 6 most significant bits. */
765 1.1 drochner crc >>= 26;
766 1.1 drochner
767 1.1 drochner /* Set the corresponding bit in the filter. */
768 1.1 drochner af[crc >> 4] |= 1 << (crc & 0xf);
769 1.1 drochner
770 1.1 drochner ETHER_NEXT_MULTI(step, enm);
771 1.1 drochner }
772 1.1 drochner ifp->if_flags &= ~IFF_ALLMULTI;
773 1.1 drochner return;
774 1.1 drochner
775 1.1 drochner allmulti:
776 1.1 drochner ifp->if_flags |= IFF_ALLMULTI;
777 1.1 drochner af[0] = af[1] = af[2] = af[3] = 0xffff;
778 1.1 drochner }
779 1.1 drochner
780 1.1 drochner /*
781 1.1 drochner * Routines for accessing the transmit and receive buffers.
782 1.1 drochner * The various CPU and adapter configurations supported by this
783 1.1 drochner * driver require three different access methods for buffers
784 1.1 drochner * and descriptors:
785 1.1 drochner * (1) contig (contiguous data; no padding),
786 1.1 drochner * (2) gap2 (two bytes of data followed by two bytes of padding),
787 1.1 drochner * (3) gap16 (16 bytes of data followed by 16 bytes of padding).
788 1.1 drochner */
789 1.1 drochner
790 1.1 drochner /*
791 1.1 drochner * contig: contiguous data with no padding.
792 1.1 drochner *
793 1.1 drochner * Buffers may have any alignment.
794 1.1 drochner */
795 1.1 drochner
796 1.1 drochner void
797 1.1 drochner lance_copytobuf_contig(sc, from, boff, len)
798 1.1 drochner struct lance_softc *sc;
799 1.1 drochner void *from;
800 1.1 drochner int boff, len;
801 1.1 drochner {
802 1.1 drochner volatile caddr_t buf = sc->sc_mem;
803 1.1 drochner
804 1.1 drochner /*
805 1.1 drochner * Just call bcopy() to do the work.
806 1.1 drochner */
807 1.1 drochner bcopy(from, buf + boff, len);
808 1.1 drochner }
809 1.1 drochner
810 1.1 drochner void
811 1.1 drochner lance_copyfrombuf_contig(sc, to, boff, len)
812 1.1 drochner struct lance_softc *sc;
813 1.1 drochner void *to;
814 1.1 drochner int boff, len;
815 1.1 drochner {
816 1.1 drochner volatile caddr_t buf = sc->sc_mem;
817 1.1 drochner
818 1.1 drochner /*
819 1.1 drochner * Just call bcopy() to do the work.
820 1.1 drochner */
821 1.1 drochner bcopy(buf + boff, to, len);
822 1.1 drochner }
823 1.1 drochner
824 1.1 drochner void
825 1.1 drochner lance_zerobuf_contig(sc, boff, len)
826 1.1 drochner struct lance_softc *sc;
827 1.1 drochner int boff, len;
828 1.1 drochner {
829 1.1 drochner volatile caddr_t buf = sc->sc_mem;
830 1.1 drochner
831 1.1 drochner /*
832 1.1 drochner * Just let bzero() do the work
833 1.1 drochner */
834 1.1 drochner bzero(buf + boff, len);
835 1.1 drochner }
836 1.1 drochner
837 1.1 drochner #if 0
838 1.1 drochner /*
839 1.1 drochner * Examples only; duplicate these and tweak (if necessary) in
840 1.1 drochner * machine-specific front-ends.
841 1.1 drochner */
842 1.1 drochner
843 1.1 drochner /*
844 1.1 drochner * gap2: two bytes of data followed by two bytes of pad.
845 1.1 drochner *
846 1.1 drochner * Buffers must be 4-byte aligned. The code doesn't worry about
847 1.1 drochner * doing an extra byte.
848 1.1 drochner */
849 1.1 drochner
850 1.1 drochner void
851 1.1 drochner lance_copytobuf_gap2(sc, fromv, boff, len)
852 1.1 drochner struct lance_softc *sc;
853 1.1 drochner void *fromv;
854 1.1 drochner int boff;
855 1.11 augustss int len;
856 1.1 drochner {
857 1.1 drochner volatile caddr_t buf = sc->sc_mem;
858 1.11 augustss caddr_t from = fromv;
859 1.11 augustss volatile u_int16_t *bptr;
860 1.1 drochner
861 1.1 drochner if (boff & 0x1) {
862 1.1 drochner /* handle unaligned first byte */
863 1.1 drochner bptr = ((volatile u_int16_t *)buf) + (boff - 1);
864 1.1 drochner *bptr = (*from++ << 8) | (*bptr & 0xff);
865 1.1 drochner bptr += 2;
866 1.1 drochner len--;
867 1.1 drochner } else
868 1.1 drochner bptr = ((volatile u_int16_t *)buf) + boff;
869 1.1 drochner while (len > 1) {
870 1.1 drochner *bptr = (from[1] << 8) | (from[0] & 0xff);
871 1.1 drochner bptr += 2;
872 1.1 drochner from += 2;
873 1.1 drochner len -= 2;
874 1.1 drochner }
875 1.1 drochner if (len == 1)
876 1.1 drochner *bptr = (u_int16_t)*from;
877 1.1 drochner }
878 1.1 drochner
879 1.1 drochner void
880 1.1 drochner lance_copyfrombuf_gap2(sc, tov, boff, len)
881 1.1 drochner struct lance_softc *sc;
882 1.1 drochner void *tov;
883 1.1 drochner int boff, len;
884 1.1 drochner {
885 1.1 drochner volatile caddr_t buf = sc->sc_mem;
886 1.11 augustss caddr_t to = tov;
887 1.11 augustss volatile u_int16_t *bptr;
888 1.11 augustss u_int16_t tmp;
889 1.1 drochner
890 1.1 drochner if (boff & 0x1) {
891 1.1 drochner /* handle unaligned first byte */
892 1.1 drochner bptr = ((volatile u_int16_t *)buf) + (boff - 1);
893 1.1 drochner *to++ = (*bptr >> 8) & 0xff;
894 1.1 drochner bptr += 2;
895 1.1 drochner len--;
896 1.1 drochner } else
897 1.1 drochner bptr = ((volatile u_int16_t *)buf) + boff;
898 1.1 drochner while (len > 1) {
899 1.1 drochner tmp = *bptr;
900 1.1 drochner *to++ = tmp & 0xff;
901 1.1 drochner *to++ = (tmp >> 8) & 0xff;
902 1.1 drochner bptr += 2;
903 1.1 drochner len -= 2;
904 1.1 drochner }
905 1.1 drochner if (len == 1)
906 1.1 drochner *to = *bptr & 0xff;
907 1.1 drochner }
908 1.1 drochner
909 1.1 drochner void
910 1.1 drochner lance_zerobuf_gap2(sc, boff, len)
911 1.1 drochner struct lance_softc *sc;
912 1.1 drochner int boff, len;
913 1.1 drochner {
914 1.1 drochner volatile caddr_t buf = sc->sc_mem;
915 1.11 augustss volatile u_int16_t *bptr;
916 1.1 drochner
917 1.1 drochner if ((unsigned)boff & 0x1) {
918 1.1 drochner bptr = ((volatile u_int16_t *)buf) + (boff - 1);
919 1.1 drochner *bptr &= 0xff;
920 1.1 drochner bptr += 2;
921 1.1 drochner len--;
922 1.1 drochner } else
923 1.1 drochner bptr = ((volatile u_int16_t *)buf) + boff;
924 1.1 drochner while (len > 0) {
925 1.1 drochner *bptr = 0;
926 1.1 drochner bptr += 2;
927 1.1 drochner len -= 2;
928 1.1 drochner }
929 1.1 drochner }
930 1.1 drochner
931 1.1 drochner /*
932 1.1 drochner * gap16: 16 bytes of data followed by 16 bytes of pad.
933 1.1 drochner *
934 1.1 drochner * Buffers must be 32-byte aligned.
935 1.1 drochner */
936 1.1 drochner
937 1.1 drochner void
938 1.1 drochner lance_copytobuf_gap16(sc, fromv, boff, len)
939 1.1 drochner struct lance_softc *sc;
940 1.1 drochner void *fromv;
941 1.1 drochner int boff;
942 1.11 augustss int len;
943 1.1 drochner {
944 1.1 drochner volatile caddr_t buf = sc->sc_mem;
945 1.11 augustss caddr_t from = fromv;
946 1.11 augustss caddr_t bptr;
947 1.11 augustss int xfer;
948 1.1 drochner
949 1.1 drochner bptr = buf + ((boff << 1) & ~0x1f);
950 1.1 drochner boff &= 0xf;
951 1.1 drochner xfer = min(len, 16 - boff);
952 1.1 drochner while (len > 0) {
953 1.1 drochner bcopy(from, bptr + boff, xfer);
954 1.1 drochner from += xfer;
955 1.1 drochner bptr += 32;
956 1.1 drochner boff = 0;
957 1.1 drochner len -= xfer;
958 1.1 drochner xfer = min(len, 16);
959 1.1 drochner }
960 1.1 drochner }
961 1.1 drochner
962 1.1 drochner void
963 1.1 drochner lance_copyfrombuf_gap16(sc, tov, boff, len)
964 1.1 drochner struct lance_softc *sc;
965 1.1 drochner void *tov;
966 1.1 drochner int boff, len;
967 1.1 drochner {
968 1.1 drochner volatile caddr_t buf = sc->sc_mem;
969 1.11 augustss caddr_t to = tov;
970 1.11 augustss caddr_t bptr;
971 1.11 augustss int xfer;
972 1.1 drochner
973 1.1 drochner bptr = buf + ((boff << 1) & ~0x1f);
974 1.1 drochner boff &= 0xf;
975 1.1 drochner xfer = min(len, 16 - boff);
976 1.1 drochner while (len > 0) {
977 1.1 drochner bcopy(bptr + boff, to, xfer);
978 1.1 drochner to += xfer;
979 1.1 drochner bptr += 32;
980 1.1 drochner boff = 0;
981 1.1 drochner len -= xfer;
982 1.1 drochner xfer = min(len, 16);
983 1.1 drochner }
984 1.1 drochner }
985 1.1 drochner
986 1.1 drochner void
987 1.1 drochner lance_zerobuf_gap16(sc, boff, len)
988 1.1 drochner struct lance_softc *sc;
989 1.1 drochner int boff, len;
990 1.1 drochner {
991 1.1 drochner volatile caddr_t buf = sc->sc_mem;
992 1.11 augustss caddr_t bptr;
993 1.11 augustss int xfer;
994 1.1 drochner
995 1.1 drochner bptr = buf + ((boff << 1) & ~0x1f);
996 1.1 drochner boff &= 0xf;
997 1.1 drochner xfer = min(len, 16 - boff);
998 1.1 drochner while (len > 0) {
999 1.1 drochner bzero(bptr + boff, xfer);
1000 1.1 drochner bptr += 32;
1001 1.1 drochner boff = 0;
1002 1.1 drochner len -= xfer;
1003 1.1 drochner xfer = min(len, 16);
1004 1.1 drochner }
1005 1.1 drochner }
1006 1.1 drochner #endif /* Example only */
1007