Deleted Added
full compact
lance.c (155093) lance.c (158663)
1/* $NetBSD: lance.c,v 1.34 2005/12/24 20:27:30 perry Exp $ */
2
3/*-
4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
9 * Simulation Facility, NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40/*-
41 * Copyright (c) 1992, 1993
42 * The Regents of the University of California. All rights reserved.
43 *
44 * This code is derived from software contributed to Berkeley by
45 * Ralph Campbell and Rick Macklem.
46 *
47 * Redistribution and use in source and binary forms, with or without
48 * modification, are permitted provided that the following conditions
49 * are met:
50 * 1. Redistributions of source code must retain the above copyright
51 * notice, this list of conditions and the following disclaimer.
52 * 2. Redistributions in binary form must reproduce the above copyright
53 * notice, this list of conditions and the following disclaimer in the
54 * documentation and/or other materials provided with the distribution.
55 * 3. Neither the name of the University nor the names of its contributors
56 * may be used to endorse or promote products derived from this software
57 * without specific prior written permission.
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 * SUCH DAMAGE.
70 *
71 * @(#)if_le.c 8.2 (Berkeley) 11/16/93
72 */
73
74#include <sys/cdefs.h>
1/* $NetBSD: lance.c,v 1.34 2005/12/24 20:27:30 perry Exp $ */
2
3/*-
4 * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
5 * All rights reserved.
6 *
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
9 * Simulation Facility, NASA Ames Research Center.
10 *
11 * Redistribution and use in source and binary forms, with or without
12 * modification, are permitted provided that the following conditions
13 * are met:
14 * 1. Redistributions of source code must retain the above copyright
15 * notice, this list of conditions and the following disclaimer.
16 * 2. Redistributions in binary form must reproduce the above copyright
17 * notice, this list of conditions and the following disclaimer in the
18 * documentation and/or other materials provided with the distribution.
19 * 3. All advertising materials mentioning features or use of this software
20 * must display the following acknowledgement:
21 * This product includes software developed by the NetBSD
22 * Foundation, Inc. and its contributors.
23 * 4. Neither the name of The NetBSD Foundation nor the names of its
24 * contributors may be used to endorse or promote products derived
25 * from this software without specific prior written permission.
26 *
27 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
28 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
29 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
30 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
31 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
32 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
33 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
34 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
35 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
36 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
37 * POSSIBILITY OF SUCH DAMAGE.
38 */
39
40/*-
41 * Copyright (c) 1992, 1993
42 * The Regents of the University of California. All rights reserved.
43 *
44 * This code is derived from software contributed to Berkeley by
45 * Ralph Campbell and Rick Macklem.
46 *
47 * Redistribution and use in source and binary forms, with or without
48 * modification, are permitted provided that the following conditions
49 * are met:
50 * 1. Redistributions of source code must retain the above copyright
51 * notice, this list of conditions and the following disclaimer.
52 * 2. Redistributions in binary form must reproduce the above copyright
53 * notice, this list of conditions and the following disclaimer in the
54 * documentation and/or other materials provided with the distribution.
55 * 3. Neither the name of the University nor the names of its contributors
56 * may be used to endorse or promote products derived from this software
57 * without specific prior written permission.
58 *
59 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
60 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
61 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
62 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
63 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
64 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
65 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
66 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
67 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
68 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 * SUCH DAMAGE.
70 *
71 * @(#)if_le.c 8.2 (Berkeley) 11/16/93
72 */
73
74#include <sys/cdefs.h>
75__FBSDID("$FreeBSD: head/sys/dev/le/lance.c 155093 2006-01-31 14:48:58Z marius $");
75__FBSDID("$FreeBSD: head/sys/dev/le/lance.c 158663 2006-05-16 21:04:01Z marius $");
76
77#include <sys/param.h>
78#include <sys/bus.h>
79#include <sys/endian.h>
80#include <sys/lock.h>
81#include <sys/mbuf.h>
82#include <sys/mutex.h>
83#include <sys/socket.h>
84#include <sys/sockio.h>
85
86#include <net/ethernet.h>
87#include <net/if.h>
88#include <net/if_arp.h>
89#include <net/if_dl.h>
90#include <net/if_media.h>
91#include <net/if_types.h>
92#include <net/if_vlan_var.h>
93
76
77#include <sys/param.h>
78#include <sys/bus.h>
79#include <sys/endian.h>
80#include <sys/lock.h>
81#include <sys/mbuf.h>
82#include <sys/mutex.h>
83#include <sys/socket.h>
84#include <sys/sockio.h>
85
86#include <net/ethernet.h>
87#include <net/if.h>
88#include <net/if_arp.h>
89#include <net/if_dl.h>
90#include <net/if_media.h>
91#include <net/if_types.h>
92#include <net/if_vlan_var.h>
93
94#include <machine/bus.h>
95
94#include <dev/le/lancereg.h>
95#include <dev/le/lancevar.h>
96
97devclass_t le_devclass;
98
96#include <dev/le/lancereg.h>
97#include <dev/le/lancevar.h>
98
99devclass_t le_devclass;
100
99static inline uint16_t ether_cmp(void *, void *);
100
101static void lance_start(struct ifnet *);
102static void lance_stop(struct lance_softc *);
103static void lance_init(void *);
101static void lance_start(struct ifnet *);
102static void lance_stop(struct lance_softc *);
103static void lance_init(void *);
104static struct mbuf *lance_get(struct lance_softc *, int, int);
105static void lance_watchdog(struct ifnet *);
106static int lance_mediachange(struct ifnet *);
107static void lance_mediastatus(struct ifnet *, struct ifmediareq *);
108static int lance_ioctl(struct ifnet *, u_long, caddr_t);
109
104static void lance_watchdog(struct ifnet *);
105static int lance_mediachange(struct ifnet *);
106static void lance_mediastatus(struct ifnet *, struct ifmediareq *);
107static int lance_ioctl(struct ifnet *, u_long, caddr_t);
108
110/*
111 * Compare two Ether/802 addresses for equality, inlined and
112 * unrolled for speed. Use this like memcmp().
113 *
114 * XXX: Add <machine/inlines.h> for stuff like this?
115 * XXX: or maybe add it to libkern.h instead?
116 *
117 * "I'd love to have an inline assembler version of this."
118 * XXX: Who wanted that? mycroft? I wrote one, but this
119 * version in C is as good as hand-coded assembly. -gwr
120 *
121 * Please do NOT tweak this without looking at the actual
122 * assembly code generated before and after your tweaks!
123 */
124static inline uint16_t
125ether_cmp(void *one, void *two)
126{
127 uint16_t *a = (u_short *)one;
128 uint16_t *b = (u_short *)two;
129 uint16_t diff;
130
131#ifdef m68k
132 /*
133 * The post-increment-pointer form produces the best
134 * machine code for m68k. This was carefully tuned
135 * so it compiles to just 8 short (2-byte) op-codes!
136 */
137 diff = *a++ - *b++;
138 diff |= *a++ - *b++;
139 diff |= *a++ - *b++;
140#else
141 /*
142 * Most modern CPUs do better with a single expresion.
143 * Note that short-cut evaluation is NOT helpful here,
144 * because it just makes the code longer, not faster!
145 */
146 diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
147#endif
148
149 return (diff);
150}
151
152#define ETHER_CMP ether_cmp
153
154#ifdef LANCE_REVC_BUG
155/* Make sure this is short-aligned, for ether_cmp(). */
156static uint16_t bcast_enaddr[3] = { ~0, ~0, ~0 };
157#endif
158
159int
160lance_config(struct lance_softc *sc, const char* name, int unit)
161{
162 struct ifnet *ifp;
163 int i, nbuf;
164
165 if (LE_LOCK_INITIALIZED(sc) == 0)
166 return (ENXIO);
167
168 ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
169 if (ifp == NULL)
170 return (ENOSPC);
171
172 /* Initialize ifnet structure. */
173 ifp->if_softc = sc;
174 if_initname(ifp, name, unit);
175 ifp->if_start = lance_start;
176 ifp->if_ioctl = lance_ioctl;
177 ifp->if_watchdog = lance_watchdog;
178 ifp->if_init = lance_init;
179 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
180#ifdef LANCE_REVC_BUG
181 ifp->if_flags &= ~IFF_MULTICAST;
182#endif
183 ifp->if_baudrate = IF_Mbps(10);
184 IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
185 ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
186 IFQ_SET_READY(&ifp->if_snd);
187
188 /* Initialize ifmedia structures. */
189 ifmedia_init(&sc->sc_media, 0, lance_mediachange, lance_mediastatus);
190 if (sc->sc_supmedia != NULL) {
191 for (i = 0; i < sc->sc_nsupmedia; i++)
192 ifmedia_add(&sc->sc_media, sc->sc_supmedia[i], 0, NULL);
193 ifmedia_set(&sc->sc_media, sc->sc_defaultmedia);
194 } else {
195 ifmedia_add(&sc->sc_media,
196 IFM_MAKEWORD(IFM_ETHER, IFM_MANUAL, 0, 0), 0, NULL);
197 ifmedia_set(&sc->sc_media,
198 IFM_MAKEWORD(IFM_ETHER, IFM_MANUAL, 0, 0));
199 }
200
201 switch (sc->sc_memsize) {
202 case 8192:
203 sc->sc_nrbuf = 4;
204 sc->sc_ntbuf = 1;
205 break;
206 case 16384:
207 sc->sc_nrbuf = 8;
208 sc->sc_ntbuf = 2;
209 break;
210 case 32768:
211 sc->sc_nrbuf = 16;
212 sc->sc_ntbuf = 4;
213 break;
214 case 65536:
215 sc->sc_nrbuf = 32;
216 sc->sc_ntbuf = 8;
217 break;
218 case 131072:
219 sc->sc_nrbuf = 64;
220 sc->sc_ntbuf = 16;
221 break;
222 case 262144:
223 sc->sc_nrbuf = 128;
224 sc->sc_ntbuf = 32;
225 break;
226 default:
227 /* weird memory size; cope with it */
228 nbuf = sc->sc_memsize / LEBLEN;
229 sc->sc_ntbuf = nbuf / 5;
230 sc->sc_nrbuf = nbuf - sc->sc_ntbuf;
231 }
232
233 if_printf(ifp, "%d receive buffers, %d transmit buffers\n",
234 sc->sc_nrbuf, sc->sc_ntbuf);
235
236 /* Make sure the chip is stopped. */
237 LE_LOCK(sc);
238 lance_stop(sc);
239 LE_UNLOCK(sc);
240
241 return (0);
242}
243
244void
245lance_attach(struct lance_softc *sc)
246{
247 struct ifnet *ifp = sc->sc_ifp;
248
249 /* Attach the interface. */
250 ether_ifattach(ifp, sc->sc_enaddr);
251
252 /* Claim 802.1q capability. */
253 ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
254 ifp->if_capabilities |= IFCAP_VLAN_MTU;
255 ifp->if_capenable |= IFCAP_VLAN_MTU;
256}
257
258void
259lance_detach(struct lance_softc *sc)
260{
261 struct ifnet *ifp = sc->sc_ifp;
262
263 LE_LOCK(sc);
264 lance_stop(sc);
265 LE_UNLOCK(sc);
266 ether_ifdetach(ifp);
267 if_free(ifp);
268}
269
270void
271lance_suspend(struct lance_softc *sc)
272{
273
274 LE_LOCK(sc);
275 lance_stop(sc);
276 LE_UNLOCK(sc);
277}
278
279void
280lance_resume(struct lance_softc *sc)
281{
282
283 LE_LOCK(sc);
284 if (sc->sc_ifp->if_flags & IFF_UP)
285 lance_init_locked(sc);
286 LE_UNLOCK(sc);
287}
288
289static void
290lance_start(struct ifnet *ifp)
291{
292 struct lance_softc *sc = ifp->if_softc;
293
294 LE_LOCK(sc);
295 (*sc->sc_start_locked)(sc);
296 LE_UNLOCK(sc);
297}
298
299static void
300lance_stop(struct lance_softc *sc)
301{
302 struct ifnet *ifp = sc->sc_ifp;
303
304 LE_LOCK_ASSERT(sc, MA_OWNED);
305
306 /*
307 * Mark the interface down and cancel the watchdog timer.
308 */
309 ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
310 ifp->if_timer = 0;
311
312 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
313}
314
315static void
316lance_init(void *xsc)
317{
318 struct lance_softc *sc = (struct lance_softc *)xsc;
319
320 LE_LOCK(sc);
321 lance_init_locked(sc);
322 LE_UNLOCK(sc);
323}
324
325/*
326 * Initialization of interface; set up initialization block
327 * and transmit/receive descriptor rings.
328 */
329void
330lance_init_locked(struct lance_softc *sc)
331{
332 struct ifnet *ifp = sc->sc_ifp;
333 u_long a;
334 int timo;
335
336 LE_LOCK_ASSERT(sc, MA_OWNED);
337
338 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
339 DELAY(100);
340
341 /* Newer LANCE chips have a reset register. */
342 if (sc->sc_hwreset)
343 (*sc->sc_hwreset)(sc);
344
345 /* Set the correct byte swapping mode, etc. */
346 (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
347
348 /*
349 * Update our private copy of the Ethernet address.
350 * We NEED the copy so we can ensure its alignment!
351 */
352 memcpy(sc->sc_enaddr, IF_LLADDR(ifp), ETHER_ADDR_LEN);
353
354 /* Set up LANCE init block. */
355 (*sc->sc_meminit)(sc);
356
357 /* Give LANCE the physical address of its init block. */
358 a = sc->sc_addr + LE_INITADDR(sc);
359 (*sc->sc_wrcsr)(sc, LE_CSR1, a & 0xffff);
360 (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
361
362 /* Try to initialize the LANCE. */
363 DELAY(100);
364 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
365
366 /* Wait for initialization to finish. */
367 for (timo = 100000; timo; timo--)
368 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
369 break;
370
371 /* Set the current media. */
372 if (sc->sc_mediachange)
373 (void)(*sc->sc_mediachange)(sc);
374
375 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
376 /* Start the LANCE. */
377 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT);
378 ifp->if_drv_flags |= IFF_DRV_RUNNING;
379 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
380 ifp->if_timer = 0;
381 (*sc->sc_start_locked)(sc);
382 } else
383 if_printf(ifp, "controller failed to initialize\n");
384
385 if (sc->sc_hwinit)
386 (*sc->sc_hwinit)(sc);
387}
388
389/*
390 * Routine to copy from mbuf chain to transmit buffer in
391 * network buffer memory.
392 */
393int
394lance_put(struct lance_softc *sc, int boff, struct mbuf *m)
395{
396 struct mbuf *n;
397 int len, tlen = 0;
398
399 LE_LOCK_ASSERT(sc, MA_OWNED);
400
401 for (; m; m = n) {
402 len = m->m_len;
403 if (len == 0) {
404 n = m_free(m);
405 m = NULL;
406 continue;
407 }
408 (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
409 boff += len;
410 tlen += len;
411 n = m_free(m);
412 m = NULL;
413 }
414 if (tlen < LEMINSIZE) {
415 (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
416 tlen = LEMINSIZE;
417 }
418 return (tlen);
419}
420
421/*
422 * Pull data off an interface.
423 * Len is length of data, with local net header stripped.
424 * We copy the data into mbufs. When full cluster sized units are present
425 * we copy into clusters.
426 */
109int
110lance_config(struct lance_softc *sc, const char* name, int unit)
111{
112 struct ifnet *ifp;
113 int i, nbuf;
114
115 if (LE_LOCK_INITIALIZED(sc) == 0)
116 return (ENXIO);
117
118 ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
119 if (ifp == NULL)
120 return (ENOSPC);
121
122 /* Initialize ifnet structure. */
123 ifp->if_softc = sc;
124 if_initname(ifp, name, unit);
125 ifp->if_start = lance_start;
126 ifp->if_ioctl = lance_ioctl;
127 ifp->if_watchdog = lance_watchdog;
128 ifp->if_init = lance_init;
129 ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
130#ifdef LANCE_REVC_BUG
131 ifp->if_flags &= ~IFF_MULTICAST;
132#endif
133 ifp->if_baudrate = IF_Mbps(10);
134 IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
135 ifp->if_snd.ifq_drv_maxlen = IFQ_MAXLEN;
136 IFQ_SET_READY(&ifp->if_snd);
137
138 /* Initialize ifmedia structures. */
139 ifmedia_init(&sc->sc_media, 0, lance_mediachange, lance_mediastatus);
140 if (sc->sc_supmedia != NULL) {
141 for (i = 0; i < sc->sc_nsupmedia; i++)
142 ifmedia_add(&sc->sc_media, sc->sc_supmedia[i], 0, NULL);
143 ifmedia_set(&sc->sc_media, sc->sc_defaultmedia);
144 } else {
145 ifmedia_add(&sc->sc_media,
146 IFM_MAKEWORD(IFM_ETHER, IFM_MANUAL, 0, 0), 0, NULL);
147 ifmedia_set(&sc->sc_media,
148 IFM_MAKEWORD(IFM_ETHER, IFM_MANUAL, 0, 0));
149 }
150
151 switch (sc->sc_memsize) {
152 case 8192:
153 sc->sc_nrbuf = 4;
154 sc->sc_ntbuf = 1;
155 break;
156 case 16384:
157 sc->sc_nrbuf = 8;
158 sc->sc_ntbuf = 2;
159 break;
160 case 32768:
161 sc->sc_nrbuf = 16;
162 sc->sc_ntbuf = 4;
163 break;
164 case 65536:
165 sc->sc_nrbuf = 32;
166 sc->sc_ntbuf = 8;
167 break;
168 case 131072:
169 sc->sc_nrbuf = 64;
170 sc->sc_ntbuf = 16;
171 break;
172 case 262144:
173 sc->sc_nrbuf = 128;
174 sc->sc_ntbuf = 32;
175 break;
176 default:
177 /* weird memory size; cope with it */
178 nbuf = sc->sc_memsize / LEBLEN;
179 sc->sc_ntbuf = nbuf / 5;
180 sc->sc_nrbuf = nbuf - sc->sc_ntbuf;
181 }
182
183 if_printf(ifp, "%d receive buffers, %d transmit buffers\n",
184 sc->sc_nrbuf, sc->sc_ntbuf);
185
186 /* Make sure the chip is stopped. */
187 LE_LOCK(sc);
188 lance_stop(sc);
189 LE_UNLOCK(sc);
190
191 return (0);
192}
193
194void
195lance_attach(struct lance_softc *sc)
196{
197 struct ifnet *ifp = sc->sc_ifp;
198
199 /* Attach the interface. */
200 ether_ifattach(ifp, sc->sc_enaddr);
201
202 /* Claim 802.1q capability. */
203 ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
204 ifp->if_capabilities |= IFCAP_VLAN_MTU;
205 ifp->if_capenable |= IFCAP_VLAN_MTU;
206}
207
208void
209lance_detach(struct lance_softc *sc)
210{
211 struct ifnet *ifp = sc->sc_ifp;
212
213 LE_LOCK(sc);
214 lance_stop(sc);
215 LE_UNLOCK(sc);
216 ether_ifdetach(ifp);
217 if_free(ifp);
218}
219
220void
221lance_suspend(struct lance_softc *sc)
222{
223
224 LE_LOCK(sc);
225 lance_stop(sc);
226 LE_UNLOCK(sc);
227}
228
229void
230lance_resume(struct lance_softc *sc)
231{
232
233 LE_LOCK(sc);
234 if (sc->sc_ifp->if_flags & IFF_UP)
235 lance_init_locked(sc);
236 LE_UNLOCK(sc);
237}
238
239static void
240lance_start(struct ifnet *ifp)
241{
242 struct lance_softc *sc = ifp->if_softc;
243
244 LE_LOCK(sc);
245 (*sc->sc_start_locked)(sc);
246 LE_UNLOCK(sc);
247}
248
249static void
250lance_stop(struct lance_softc *sc)
251{
252 struct ifnet *ifp = sc->sc_ifp;
253
254 LE_LOCK_ASSERT(sc, MA_OWNED);
255
256 /*
257 * Mark the interface down and cancel the watchdog timer.
258 */
259 ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
260 ifp->if_timer = 0;
261
262 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
263}
264
265static void
266lance_init(void *xsc)
267{
268 struct lance_softc *sc = (struct lance_softc *)xsc;
269
270 LE_LOCK(sc);
271 lance_init_locked(sc);
272 LE_UNLOCK(sc);
273}
274
275/*
276 * Initialization of interface; set up initialization block
277 * and transmit/receive descriptor rings.
278 */
279void
280lance_init_locked(struct lance_softc *sc)
281{
282 struct ifnet *ifp = sc->sc_ifp;
283 u_long a;
284 int timo;
285
286 LE_LOCK_ASSERT(sc, MA_OWNED);
287
288 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
289 DELAY(100);
290
291 /* Newer LANCE chips have a reset register. */
292 if (sc->sc_hwreset)
293 (*sc->sc_hwreset)(sc);
294
295 /* Set the correct byte swapping mode, etc. */
296 (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
297
298 /*
299 * Update our private copy of the Ethernet address.
300 * We NEED the copy so we can ensure its alignment!
301 */
302 memcpy(sc->sc_enaddr, IF_LLADDR(ifp), ETHER_ADDR_LEN);
303
304 /* Set up LANCE init block. */
305 (*sc->sc_meminit)(sc);
306
307 /* Give LANCE the physical address of its init block. */
308 a = sc->sc_addr + LE_INITADDR(sc);
309 (*sc->sc_wrcsr)(sc, LE_CSR1, a & 0xffff);
310 (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
311
312 /* Try to initialize the LANCE. */
313 DELAY(100);
314 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
315
316 /* Wait for initialization to finish. */
317 for (timo = 100000; timo; timo--)
318 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
319 break;
320
321 /* Set the current media. */
322 if (sc->sc_mediachange)
323 (void)(*sc->sc_mediachange)(sc);
324
325 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
326 /* Start the LANCE. */
327 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT);
328 ifp->if_drv_flags |= IFF_DRV_RUNNING;
329 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
330 ifp->if_timer = 0;
331 (*sc->sc_start_locked)(sc);
332 } else
333 if_printf(ifp, "controller failed to initialize\n");
334
335 if (sc->sc_hwinit)
336 (*sc->sc_hwinit)(sc);
337}
338
339/*
340 * Routine to copy from mbuf chain to transmit buffer in
341 * network buffer memory.
342 */
343int
344lance_put(struct lance_softc *sc, int boff, struct mbuf *m)
345{
346 struct mbuf *n;
347 int len, tlen = 0;
348
349 LE_LOCK_ASSERT(sc, MA_OWNED);
350
351 for (; m; m = n) {
352 len = m->m_len;
353 if (len == 0) {
354 n = m_free(m);
355 m = NULL;
356 continue;
357 }
358 (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
359 boff += len;
360 tlen += len;
361 n = m_free(m);
362 m = NULL;
363 }
364 if (tlen < LEMINSIZE) {
365 (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
366 tlen = LEMINSIZE;
367 }
368 return (tlen);
369}
370
371/*
372 * Pull data off an interface.
373 * Len is length of data, with local net header stripped.
374 * We copy the data into mbufs. When full cluster sized units are present
375 * we copy into clusters.
376 */
427static struct mbuf *
377struct mbuf *
428lance_get(struct lance_softc *sc, int boff, int totlen)
429{
430 struct ifnet *ifp = sc->sc_ifp;
431 struct mbuf *m, *m0, *newm;
432 caddr_t newdata;
433 int len;
434
378lance_get(struct lance_softc *sc, int boff, int totlen)
379{
380 struct ifnet *ifp = sc->sc_ifp;
381 struct mbuf *m, *m0, *newm;
382 caddr_t newdata;
383 int len;
384
385 if (totlen <= ETHER_HDR_LEN || totlen > LEBLEN - ETHER_CRC_LEN) {
386#ifdef LEDEBUG
387 if_printf(ifp, "invalid packet size %d; dropping\n", totlen);
388#endif
389 return (NULL);
390 }
391
435 MGETHDR(m0, M_DONTWAIT, MT_DATA);
392 MGETHDR(m0, M_DONTWAIT, MT_DATA);
436 if (m0 == 0)
437 return (0);
393 if (m0 == NULL)
394 return (NULL);
438 m0->m_pkthdr.rcvif = ifp;
439 m0->m_pkthdr.len = totlen;
440 len = MHLEN;
441 m = m0;
442
443 while (totlen > 0) {
444 if (totlen >= MINCLSIZE) {
445 MCLGET(m, M_DONTWAIT);
446 if ((m->m_flags & M_EXT) == 0)
447 goto bad;
448 len = MCLBYTES;
449 }
450
451 if (m == m0) {
452 newdata = (caddr_t)
453 ALIGN(m->m_data + ETHER_HDR_LEN) - ETHER_HDR_LEN;
454 len -= newdata - m->m_data;
455 m->m_data = newdata;
456 }
457
458 m->m_len = len = min(totlen, len);
459 (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
460 boff += len;
461
462 totlen -= len;
463 if (totlen > 0) {
464 MGET(newm, M_DONTWAIT, MT_DATA);
465 if (newm == 0)
466 goto bad;
467 len = MLEN;
468 m = m->m_next = newm;
469 }
470 }
471
472 return (m0);
473
474 bad:
475 m_freem(m0);
395 m0->m_pkthdr.rcvif = ifp;
396 m0->m_pkthdr.len = totlen;
397 len = MHLEN;
398 m = m0;
399
400 while (totlen > 0) {
401 if (totlen >= MINCLSIZE) {
402 MCLGET(m, M_DONTWAIT);
403 if ((m->m_flags & M_EXT) == 0)
404 goto bad;
405 len = MCLBYTES;
406 }
407
408 if (m == m0) {
409 newdata = (caddr_t)
410 ALIGN(m->m_data + ETHER_HDR_LEN) - ETHER_HDR_LEN;
411 len -= newdata - m->m_data;
412 m->m_data = newdata;
413 }
414
415 m->m_len = len = min(totlen, len);
416 (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
417 boff += len;
418
419 totlen -= len;
420 if (totlen > 0) {
421 MGET(newm, M_DONTWAIT, MT_DATA);
422 if (newm == 0)
423 goto bad;
424 len = MLEN;
425 m = m->m_next = newm;
426 }
427 }
428
429 return (m0);
430
431 bad:
432 m_freem(m0);
476 return (0);
433 return (NULL);
477}
478
434}
435
479/*
480 * Pass a packet to the higher levels.
481 */
482void
483lance_read(struct lance_softc *sc, int boff, int len)
484{
485 struct ifnet *ifp = sc->sc_ifp;
486 struct ether_header *eh;
487 struct mbuf *m;
488
489 LE_LOCK_ASSERT(sc, MA_OWNED);
490
491 if (len <= ETHER_HDR_LEN || len > LEBLEN - ETHER_CRC_LEN) {
492#ifdef LEDEBUG
493 if_printf(ifp, "invalid packet size %d; dropping\n", len);
494#endif
495 ifp->if_ierrors++;
496 return;
497 }
498
499 /* Pull packet off interface. */
500 m = lance_get(sc, boff, len);
501 if (m == 0) {
502 ifp->if_ierrors++;
503 return;
504 }
505
506 ifp->if_ipackets++;
507
508 eh = mtod(m, struct ether_header *);
509
510#ifdef LANCE_REVC_BUG
511 /*
512 * The old LANCE (Rev. C) chips have a bug which causes
513 * garbage to be inserted in front of the received packet.
514 * The work-around is to ignore packets with an invalid
515 * destination address (garbage will usually not match).
516 * Of course, this precludes multicast support...
517 */
518 if (ETHER_CMP(eh->ether_dhost, sc->sc_enaddr) &&
519 ETHER_CMP(eh->ether_dhost, bcast_enaddr)) {
520 m_freem(m);
521 return;
522 }
523#endif
524
525 /*
526 * Some lance device does not present IFF_SIMPLEX behavior on multicast
527 * packets. Make sure to drop it if it is from ourselves.
528 */
529 if (!ETHER_CMP(eh->ether_shost, sc->sc_enaddr)) {
530 m_freem(m);
531 return;
532 }
533
534 /* Pass the packet up. */
535 LE_UNLOCK(sc);
536 (*ifp->if_input)(ifp, m);
537 LE_LOCK(sc);
538}
539
540static void
541lance_watchdog(struct ifnet *ifp)
542{
543 struct lance_softc *sc = ifp->if_softc;
544
545 LE_LOCK(sc);
546 if_printf(ifp, "device timeout\n");
547 ++ifp->if_oerrors;
548 lance_init_locked(sc);
549 LE_UNLOCK(sc);
550}
551
552static int
553lance_mediachange(struct ifnet *ifp)
554{
555 struct lance_softc *sc = ifp->if_softc;
556 int error;
557
558 if (sc->sc_mediachange) {
559 LE_LOCK(sc);
560 error = (*sc->sc_mediachange)(sc);
561 LE_UNLOCK(sc);
562 return (error);
563 }
564 return (0);
565}
566
567static void
568lance_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
569{
570 struct lance_softc *sc = ifp->if_softc;
571
572 LE_LOCK(sc);
573 if (!(ifp->if_flags & IFF_UP)) {
574 LE_UNLOCK(sc);
575 return;
576 }
577
578 ifmr->ifm_status = IFM_AVALID;
579 if (sc->sc_flags & LE_CARRIER)
580 ifmr->ifm_status |= IFM_ACTIVE;
581
582 if (sc->sc_mediastatus)
583 (*sc->sc_mediastatus)(sc, ifmr);
584 LE_UNLOCK(sc);
585}
586
587/*
588 * Process an ioctl request.
589 */
590static int
591lance_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
592{
593 struct lance_softc *sc = ifp->if_softc;
594 struct ifreq *ifr = (struct ifreq *)data;
595 int error = 0;
596
597 switch (cmd) {
598 case SIOCSIFFLAGS:
599 LE_LOCK(sc);
600 if (ifp->if_flags & IFF_PROMISC) {
601 if (!(sc->sc_flags & LE_PROMISC)) {
602 sc->sc_flags |= LE_PROMISC;
603 lance_init_locked(sc);
604 }
605 } else if (sc->sc_flags & LE_PROMISC) {
606 sc->sc_flags &= ~LE_PROMISC;
607 lance_init_locked(sc);
608 }
609
610 if ((ifp->if_flags & IFF_ALLMULTI) &&
611 !(sc->sc_flags & LE_ALLMULTI)) {
612 sc->sc_flags |= LE_ALLMULTI;
613 lance_init_locked(sc);
614 } else if (!(ifp->if_flags & IFF_ALLMULTI) &&
615 (sc->sc_flags & LE_ALLMULTI)) {
616 sc->sc_flags &= ~LE_ALLMULTI;
617 lance_init_locked(sc);
618 }
619
620 if (!(ifp->if_flags & IFF_UP) &&
621 ifp->if_drv_flags & IFF_DRV_RUNNING) {
622 /*
623 * If interface is marked down and it is running, then
624 * stop it.
625 */
626 lance_stop(sc);
627 } else if (ifp->if_flags & IFF_UP &&
628 !(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
629 /*
630 * If interface is marked up and it is stopped, then
631 * start it.
632 */
633 lance_init_locked(sc);
634 }
635#ifdef LEDEBUG
636 if (ifp->if_flags & IFF_DEBUG)
637 sc->sc_flags |= LE_DEBUG;
638 else
639 sc->sc_flags &= ~LE_DEBUG;
640#endif
641 LE_UNLOCK(sc);
642 break;
643
644 case SIOCADDMULTI:
645 case SIOCDELMULTI:
646 /*
647 * Multicast list has changed; set the hardware filter
648 * accordingly.
649 */
650 LE_LOCK(sc);
651 if (ifp->if_drv_flags & IFF_DRV_RUNNING)
652 lance_init_locked(sc);
653 LE_UNLOCK(sc);
654 break;
655
656 case SIOCGIFMEDIA:
657 case SIOCSIFMEDIA:
658 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
659 break;
660
661 default:
662 error = ether_ioctl(ifp, cmd, data);
663 break;
664 }
665
666 return (error);
667}
668
669/*
670 * Set up the logical address filter.
671 */
672void
673lance_setladrf(struct lance_softc *sc, uint16_t *af)
674{
675 struct ifnet *ifp = sc->sc_ifp;
676 struct ifmultiaddr *ifma;
677 uint32_t crc;
678
679 /*
680 * Set up multicast address filter by passing all multicast addresses
681 * through a crc generator, and then using the high order 6 bits as an
682 * index into the 64 bit logical address filter. The high order bit
683 * selects the word, while the rest of the bits select the bit within
684 * the word.
685 */
686
687 if (ifp->if_flags & IFF_PROMISC || sc->sc_flags & LE_ALLMULTI) {
688 af[0] = af[1] = af[2] = af[3] = 0xffff;
689 return;
690 }
691
692 af[0] = af[1] = af[2] = af[3] = 0x0000;
693 IF_ADDR_LOCK(ifp);
694 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
695 if (ifma->ifma_addr->sa_family != AF_LINK)
696 continue;
697
698 crc = ether_crc32_le(LLADDR((struct sockaddr_dl *)
699 ifma->ifma_addr), ETHER_ADDR_LEN);
700
701 /* Just want the 6 most significant bits. */
702 crc >>= 26;
703
704 /* Set the corresponding bit in the filter. */
436static void
437lance_watchdog(struct ifnet *ifp)
438{
439 struct lance_softc *sc = ifp->if_softc;
440
441 LE_LOCK(sc);
442 if_printf(ifp, "device timeout\n");
443 ++ifp->if_oerrors;
444 lance_init_locked(sc);
445 LE_UNLOCK(sc);
446}
447
448static int
449lance_mediachange(struct ifnet *ifp)
450{
451 struct lance_softc *sc = ifp->if_softc;
452 int error;
453
454 if (sc->sc_mediachange) {
455 LE_LOCK(sc);
456 error = (*sc->sc_mediachange)(sc);
457 LE_UNLOCK(sc);
458 return (error);
459 }
460 return (0);
461}
462
463static void
464lance_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
465{
466 struct lance_softc *sc = ifp->if_softc;
467
468 LE_LOCK(sc);
469 if (!(ifp->if_flags & IFF_UP)) {
470 LE_UNLOCK(sc);
471 return;
472 }
473
474 ifmr->ifm_status = IFM_AVALID;
475 if (sc->sc_flags & LE_CARRIER)
476 ifmr->ifm_status |= IFM_ACTIVE;
477
478 if (sc->sc_mediastatus)
479 (*sc->sc_mediastatus)(sc, ifmr);
480 LE_UNLOCK(sc);
481}
482
483/*
484 * Process an ioctl request.
485 */
486static int
487lance_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
488{
489 struct lance_softc *sc = ifp->if_softc;
490 struct ifreq *ifr = (struct ifreq *)data;
491 int error = 0;
492
493 switch (cmd) {
494 case SIOCSIFFLAGS:
495 LE_LOCK(sc);
496 if (ifp->if_flags & IFF_PROMISC) {
497 if (!(sc->sc_flags & LE_PROMISC)) {
498 sc->sc_flags |= LE_PROMISC;
499 lance_init_locked(sc);
500 }
501 } else if (sc->sc_flags & LE_PROMISC) {
502 sc->sc_flags &= ~LE_PROMISC;
503 lance_init_locked(sc);
504 }
505
506 if ((ifp->if_flags & IFF_ALLMULTI) &&
507 !(sc->sc_flags & LE_ALLMULTI)) {
508 sc->sc_flags |= LE_ALLMULTI;
509 lance_init_locked(sc);
510 } else if (!(ifp->if_flags & IFF_ALLMULTI) &&
511 (sc->sc_flags & LE_ALLMULTI)) {
512 sc->sc_flags &= ~LE_ALLMULTI;
513 lance_init_locked(sc);
514 }
515
516 if (!(ifp->if_flags & IFF_UP) &&
517 ifp->if_drv_flags & IFF_DRV_RUNNING) {
518 /*
519 * If interface is marked down and it is running, then
520 * stop it.
521 */
522 lance_stop(sc);
523 } else if (ifp->if_flags & IFF_UP &&
524 !(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
525 /*
526 * If interface is marked up and it is stopped, then
527 * start it.
528 */
529 lance_init_locked(sc);
530 }
531#ifdef LEDEBUG
532 if (ifp->if_flags & IFF_DEBUG)
533 sc->sc_flags |= LE_DEBUG;
534 else
535 sc->sc_flags &= ~LE_DEBUG;
536#endif
537 LE_UNLOCK(sc);
538 break;
539
540 case SIOCADDMULTI:
541 case SIOCDELMULTI:
542 /*
543 * Multicast list has changed; set the hardware filter
544 * accordingly.
545 */
546 LE_LOCK(sc);
547 if (ifp->if_drv_flags & IFF_DRV_RUNNING)
548 lance_init_locked(sc);
549 LE_UNLOCK(sc);
550 break;
551
552 case SIOCGIFMEDIA:
553 case SIOCSIFMEDIA:
554 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
555 break;
556
557 default:
558 error = ether_ioctl(ifp, cmd, data);
559 break;
560 }
561
562 return (error);
563}
564
565/*
566 * Set up the logical address filter.
567 */
568void
569lance_setladrf(struct lance_softc *sc, uint16_t *af)
570{
571 struct ifnet *ifp = sc->sc_ifp;
572 struct ifmultiaddr *ifma;
573 uint32_t crc;
574
575 /*
576 * Set up multicast address filter by passing all multicast addresses
577 * through a crc generator, and then using the high order 6 bits as an
578 * index into the 64 bit logical address filter. The high order bit
579 * selects the word, while the rest of the bits select the bit within
580 * the word.
581 */
582
583 if (ifp->if_flags & IFF_PROMISC || sc->sc_flags & LE_ALLMULTI) {
584 af[0] = af[1] = af[2] = af[3] = 0xffff;
585 return;
586 }
587
588 af[0] = af[1] = af[2] = af[3] = 0x0000;
589 IF_ADDR_LOCK(ifp);
590 TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
591 if (ifma->ifma_addr->sa_family != AF_LINK)
592 continue;
593
594 crc = ether_crc32_le(LLADDR((struct sockaddr_dl *)
595 ifma->ifma_addr), ETHER_ADDR_LEN);
596
597 /* Just want the 6 most significant bits. */
598 crc >>= 26;
599
600 /* Set the corresponding bit in the filter. */
705 af[crc >> 4] |= LE_HTOLE16(1U << (crc & 0xf));
601 af[crc >> 4] |= LE_HTOLE16(1 << (crc & 0xf));
706 }
707 IF_ADDR_UNLOCK(ifp);
708}
709
710/*
711 * Routines for accessing the transmit and receive buffers.
712 * The various CPU and adapter configurations supported by this
713 * driver require three different access methods for buffers
714 * and descriptors:
715 * (1) contig (contiguous data; no padding),
716 * (2) gap2 (two bytes of data followed by two bytes of padding),
717 * (3) gap16 (16 bytes of data followed by 16 bytes of padding).
718 */
719
720/*
721 * contig: contiguous data with no padding.
722 *
723 * Buffers may have any alignment.
724 */
725
726void
727lance_copytobuf_contig(struct lance_softc *sc, void *from, int boff, int len)
728{
729 volatile caddr_t buf = sc->sc_mem;
730
731 /*
732 * Just call memcpy() to do the work.
733 */
734 memcpy(buf + boff, from, len);
735}
736
737void
738lance_copyfrombuf_contig(struct lance_softc *sc, void *to, int boff, int len)
739{
740 volatile caddr_t buf = sc->sc_mem;
741
742 /*
743 * Just call memcpy() to do the work.
744 */
745 memcpy(to, buf + boff, len);
746}
747
748void
749lance_zerobuf_contig(struct lance_softc *sc, int boff, int len)
750{
751 volatile caddr_t buf = sc->sc_mem;
752
753 /*
754 * Just let memset() do the work
755 */
756 memset(buf + boff, 0, len);
757}
758
759#if 0
760/*
761 * Examples only; duplicate these and tweak (if necessary) in
762 * machine-specific front-ends.
763 */
764
765/*
766 * gap2: two bytes of data followed by two bytes of pad.
767 *
768 * Buffers must be 4-byte aligned. The code doesn't worry about
769 * doing an extra byte.
770 */
771
772static void
773lance_copytobuf_gap2(struct lance_softc *sc, void *fromv, int boff, int len)
774{
775 volatile caddr_t buf = sc->sc_mem;
776 caddr_t from = fromv;
777 volatile uint16_t *bptr;
778
779 if (boff & 0x1) {
780 /* Handle unaligned first byte. */
781 bptr = ((volatile uint16_t *)buf) + (boff - 1);
782 *bptr = (*from++ << 8) | (*bptr & 0xff);
783 bptr += 2;
784 len--;
785 } else
786 bptr = ((volatile uint16_t *)buf) + boff;
787 while (len > 1) {
788 *bptr = (from[1] << 8) | (from[0] & 0xff);
789 bptr += 2;
790 from += 2;
791 len -= 2;
792 }
793 if (len == 1)
794 *bptr = (uint16_t)*from;
795}
796
797static void
798lance_copyfrombuf_gap2(struct lance_softc *sc, void *tov, int boff, int len)
799{
800 volatile caddr_t buf = sc->sc_mem;
801 caddr_t to = tov;
802 volatile uint16_t *bptr;
803 uint16_t tmp;
804
805 if (boff & 0x1) {
806 /* Handle unaligned first byte. */
807 bptr = ((volatile uint16_t *)buf) + (boff - 1);
808 *to++ = (*bptr >> 8) & 0xff;
809 bptr += 2;
810 len--;
811 } else
812 bptr = ((volatile uint16_t *)buf) + boff;
813 while (len > 1) {
814 tmp = *bptr;
815 *to++ = tmp & 0xff;
816 *to++ = (tmp >> 8) & 0xff;
817 bptr += 2;
818 len -= 2;
819 }
820 if (len == 1)
821 *to = *bptr & 0xff;
822}
823
824static void
825lance_zerobuf_gap2(struct lance_softc *sc, int boff, int len)
826{
827 volatile caddr_t buf = sc->sc_mem;
828 volatile uint16_t *bptr;
829
830 if ((unsigned)boff & 0x1) {
831 bptr = ((volatile uint16_t *)buf) + (boff - 1);
832 *bptr &= 0xff;
833 bptr += 2;
834 len--;
835 } else
836 bptr = ((volatile uint16_t *)buf) + boff;
837 while (len > 0) {
838 *bptr = 0;
839 bptr += 2;
840 len -= 2;
841 }
842}
843
844/*
845 * gap16: 16 bytes of data followed by 16 bytes of pad.
846 *
847 * Buffers must be 32-byte aligned.
848 */
849
850static void
851lance_copytobuf_gap16(struct lance_softc *sc, void *fromv, int boff, int len)
852{
853 volatile caddr_t buf = sc->sc_mem;
854 caddr_t bptr, from = fromv;
855 int xfer;
856
857 bptr = buf + ((boff << 1) & ~0x1f);
858 boff &= 0xf;
859 xfer = min(len, 16 - boff);
860 while (len > 0) {
861 memcpy(bptr + boff, from, xfer);
862 from += xfer;
863 bptr += 32;
864 boff = 0;
865 len -= xfer;
866 xfer = min(len, 16);
867 }
868}
869
870static void
871lance_copyfrombuf_gap16(struct lance_softc *sc, void *tov, int boff, int len)
872{
873 volatile caddr_t buf = sc->sc_mem;
874 caddr_t bptr, to = tov;
875 int xfer;
876
877 bptr = buf + ((boff << 1) & ~0x1f);
878 boff &= 0xf;
879 xfer = min(len, 16 - boff);
880 while (len > 0) {
881 memcpy(to, bptr + boff, xfer);
882 to += xfer;
883 bptr += 32;
884 boff = 0;
885 len -= xfer;
886 xfer = min(len, 16);
887 }
888}
889
890static void
891lance_zerobuf_gap16(struct lance_softc *sc, int boff, int len)
892{
893 volatile caddr_t buf = sc->sc_mem;
894 caddr_t bptr;
895 int xfer;
896
897 bptr = buf + ((boff << 1) & ~0x1f);
898 boff &= 0xf;
899 xfer = min(len, 16 - boff);
900 while (len > 0) {
901 memset(bptr + boff, 0, xfer);
902 bptr += 32;
903 boff = 0;
904 len -= xfer;
905 xfer = min(len, 16);
906 }
907}
908#endif /* Example only */
602 }
603 IF_ADDR_UNLOCK(ifp);
604}
605
606/*
607 * Routines for accessing the transmit and receive buffers.
608 * The various CPU and adapter configurations supported by this
609 * driver require three different access methods for buffers
610 * and descriptors:
611 * (1) contig (contiguous data; no padding),
612 * (2) gap2 (two bytes of data followed by two bytes of padding),
613 * (3) gap16 (16 bytes of data followed by 16 bytes of padding).
614 */
615
616/*
617 * contig: contiguous data with no padding.
618 *
619 * Buffers may have any alignment.
620 */
621
622void
623lance_copytobuf_contig(struct lance_softc *sc, void *from, int boff, int len)
624{
625 volatile caddr_t buf = sc->sc_mem;
626
627 /*
628 * Just call memcpy() to do the work.
629 */
630 memcpy(buf + boff, from, len);
631}
632
633void
634lance_copyfrombuf_contig(struct lance_softc *sc, void *to, int boff, int len)
635{
636 volatile caddr_t buf = sc->sc_mem;
637
638 /*
639 * Just call memcpy() to do the work.
640 */
641 memcpy(to, buf + boff, len);
642}
643
644void
645lance_zerobuf_contig(struct lance_softc *sc, int boff, int len)
646{
647 volatile caddr_t buf = sc->sc_mem;
648
649 /*
650 * Just let memset() do the work
651 */
652 memset(buf + boff, 0, len);
653}
654
655#if 0
656/*
657 * Examples only; duplicate these and tweak (if necessary) in
658 * machine-specific front-ends.
659 */
660
661/*
662 * gap2: two bytes of data followed by two bytes of pad.
663 *
664 * Buffers must be 4-byte aligned. The code doesn't worry about
665 * doing an extra byte.
666 */
667
668static void
669lance_copytobuf_gap2(struct lance_softc *sc, void *fromv, int boff, int len)
670{
671 volatile caddr_t buf = sc->sc_mem;
672 caddr_t from = fromv;
673 volatile uint16_t *bptr;
674
675 if (boff & 0x1) {
676 /* Handle unaligned first byte. */
677 bptr = ((volatile uint16_t *)buf) + (boff - 1);
678 *bptr = (*from++ << 8) | (*bptr & 0xff);
679 bptr += 2;
680 len--;
681 } else
682 bptr = ((volatile uint16_t *)buf) + boff;
683 while (len > 1) {
684 *bptr = (from[1] << 8) | (from[0] & 0xff);
685 bptr += 2;
686 from += 2;
687 len -= 2;
688 }
689 if (len == 1)
690 *bptr = (uint16_t)*from;
691}
692
693static void
694lance_copyfrombuf_gap2(struct lance_softc *sc, void *tov, int boff, int len)
695{
696 volatile caddr_t buf = sc->sc_mem;
697 caddr_t to = tov;
698 volatile uint16_t *bptr;
699 uint16_t tmp;
700
701 if (boff & 0x1) {
702 /* Handle unaligned first byte. */
703 bptr = ((volatile uint16_t *)buf) + (boff - 1);
704 *to++ = (*bptr >> 8) & 0xff;
705 bptr += 2;
706 len--;
707 } else
708 bptr = ((volatile uint16_t *)buf) + boff;
709 while (len > 1) {
710 tmp = *bptr;
711 *to++ = tmp & 0xff;
712 *to++ = (tmp >> 8) & 0xff;
713 bptr += 2;
714 len -= 2;
715 }
716 if (len == 1)
717 *to = *bptr & 0xff;
718}
719
720static void
721lance_zerobuf_gap2(struct lance_softc *sc, int boff, int len)
722{
723 volatile caddr_t buf = sc->sc_mem;
724 volatile uint16_t *bptr;
725
726 if ((unsigned)boff & 0x1) {
727 bptr = ((volatile uint16_t *)buf) + (boff - 1);
728 *bptr &= 0xff;
729 bptr += 2;
730 len--;
731 } else
732 bptr = ((volatile uint16_t *)buf) + boff;
733 while (len > 0) {
734 *bptr = 0;
735 bptr += 2;
736 len -= 2;
737 }
738}
739
740/*
741 * gap16: 16 bytes of data followed by 16 bytes of pad.
742 *
743 * Buffers must be 32-byte aligned.
744 */
745
746static void
747lance_copytobuf_gap16(struct lance_softc *sc, void *fromv, int boff, int len)
748{
749 volatile caddr_t buf = sc->sc_mem;
750 caddr_t bptr, from = fromv;
751 int xfer;
752
753 bptr = buf + ((boff << 1) & ~0x1f);
754 boff &= 0xf;
755 xfer = min(len, 16 - boff);
756 while (len > 0) {
757 memcpy(bptr + boff, from, xfer);
758 from += xfer;
759 bptr += 32;
760 boff = 0;
761 len -= xfer;
762 xfer = min(len, 16);
763 }
764}
765
766static void
767lance_copyfrombuf_gap16(struct lance_softc *sc, void *tov, int boff, int len)
768{
769 volatile caddr_t buf = sc->sc_mem;
770 caddr_t bptr, to = tov;
771 int xfer;
772
773 bptr = buf + ((boff << 1) & ~0x1f);
774 boff &= 0xf;
775 xfer = min(len, 16 - boff);
776 while (len > 0) {
777 memcpy(to, bptr + boff, xfer);
778 to += xfer;
779 bptr += 32;
780 boff = 0;
781 len -= xfer;
782 xfer = min(len, 16);
783 }
784}
785
786static void
787lance_zerobuf_gap16(struct lance_softc *sc, int boff, int len)
788{
789 volatile caddr_t buf = sc->sc_mem;
790 caddr_t bptr;
791 int xfer;
792
793 bptr = buf + ((boff << 1) & ~0x1f);
794 boff &= 0xf;
795 xfer = min(len, 16 - boff);
796 while (len > 0) {
797 memset(bptr + boff, 0, xfer);
798 bptr += 32;
799 boff = 0;
800 len -= xfer;
801 xfer = min(len, 16);
802 }
803}
804#endif /* Example only */