Annotation of src/sys/dev/ic/lance.c, Revision 1.28.2.5
1.28.2.5! skrll 1: /* $NetBSD: lance.c,v 1.28.2.4 2004/11/02 07:51:31 skrll Exp $ */
1.1 drochner 2:
3: /*-
1.3 mycroft 4: * Copyright (c) 1997, 1998 The NetBSD Foundation, Inc.
1.1 drochner 5: * All rights reserved.
6: *
7: * This code is derived from software contributed to The NetBSD Foundation
1.3 mycroft 8: * by Charles M. Hannum and by Jason R. Thorpe of the Numerical Aerospace
9: * Simulation Facility, NASA Ames Research Center.
1.1 drochner 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.
1.28.2.1 skrll 55: * 3. Neither the name of the University nor the names of its contributors
1.1 drochner 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: */
1.26 lukem 73:
74: #include <sys/cdefs.h>
1.28.2.5! skrll 75: __KERNEL_RCSID(0, "$NetBSD: lance.c,v 1.28.2.4 2004/11/02 07:51:31 skrll Exp $");
1.1 drochner 76:
77: #include "opt_ccitt.h"
78: #include "opt_llc.h"
79: #include "bpfilter.h"
80: #include "rnd.h"
81:
82: #include <sys/param.h>
83: #include <sys/systm.h>
84: #include <sys/mbuf.h>
85: #include <sys/syslog.h>
86: #include <sys/socket.h>
87: #include <sys/device.h>
88: #include <sys/malloc.h>
89: #include <sys/ioctl.h>
90: #include <sys/errno.h>
91: #if NRND > 0
92: #include <sys/rnd.h>
93: #endif
94:
95: #include <net/if.h>
96: #include <net/if_dl.h>
97: #include <net/if_ether.h>
98: #include <net/if_media.h>
99:
100: #if defined(CCITT) && defined(LLC)
101: #include <sys/socketvar.h>
102: #include <netccitt/x25.h>
103: #include <netccitt/pk.h>
104: #include <netccitt/pk_var.h>
105: #include <netccitt/pk_extern.h>
106: #endif
107:
108: #if NBPFILTER > 0
109: #include <net/bpf.h>
110: #include <net/bpfdesc.h>
111: #endif
112:
113: #include <dev/ic/lancereg.h>
114: #include <dev/ic/lancevar.h>
115:
1.19 mrg 116: #if defined(_KERNEL_OPT)
1.1 drochner 117: #include "opt_ddb.h"
118: #endif
119:
120: #ifdef DDB
121: #define integrate
122: #define hide
123: #else
124: #define integrate static __inline
125: #define hide static
126: #endif
127:
1.28.2.5! skrll 128: integrate struct mbuf *lance_get(struct lance_softc *, int, int);
1.1 drochner 129:
1.28.2.5! skrll 130: hide void lance_shutdown(void *);
1.1 drochner 131:
1.28.2.5! skrll 132: int lance_mediachange(struct ifnet *);
! 133: void lance_mediastatus(struct ifnet *, struct ifmediareq *);
1.1 drochner 134:
1.28.2.5! skrll 135: static inline u_int16_t ether_cmp(void *, void *);
1.1 drochner 136:
1.28.2.5! skrll 137: void lance_stop(struct ifnet *, int);
! 138: int lance_ioctl(struct ifnet *, u_long, caddr_t);
! 139: void lance_watchdog(struct ifnet *);
1.1 drochner 140:
141: /*
142: * Compare two Ether/802 addresses for equality, inlined and
1.23 thorpej 143: * unrolled for speed. Use this like memcmp().
1.1 drochner 144: *
145: * XXX: Add <machine/inlines.h> for stuff like this?
146: * XXX: or maybe add it to libkern.h instead?
147: *
148: * "I'd love to have an inline assembler version of this."
149: * XXX: Who wanted that? mycroft? I wrote one, but this
150: * version in C is as good as hand-coded assembly. -gwr
151: *
152: * Please do NOT tweak this without looking at the actual
153: * assembly code generated before and after your tweaks!
154: */
155: static inline u_int16_t
156: ether_cmp(one, two)
157: void *one, *two;
158: {
1.11 augustss 159: u_int16_t *a = (u_short *) one;
160: u_int16_t *b = (u_short *) two;
161: u_int16_t diff;
1.1 drochner 162:
163: #ifdef m68k
164: /*
165: * The post-increment-pointer form produces the best
166: * machine code for m68k. This was carefully tuned
167: * so it compiles to just 8 short (2-byte) op-codes!
168: */
169: diff = *a++ - *b++;
170: diff |= *a++ - *b++;
171: diff |= *a++ - *b++;
172: #else
173: /*
174: * Most modern CPUs do better with a single expresion.
175: * Note that short-cut evaluation is NOT helpful here,
176: * because it just makes the code longer, not faster!
177: */
178: diff = (a[0] - b[0]) | (a[1] - b[1]) | (a[2] - b[2]);
179: #endif
180:
181: return (diff);
182: }
183:
184: #define ETHER_CMP ether_cmp
185:
186: #ifdef LANCE_REVC_BUG
187: /* Make sure this is short-aligned, for ether_cmp(). */
188: static u_int16_t bcast_enaddr[3] = { ~0, ~0, ~0 };
189: #endif
190:
191: void
192: lance_config(sc)
193: struct lance_softc *sc;
194: {
1.18 jdolecek 195: int i, nbuf;
1.20 jdolecek 196: struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1.1 drochner 197:
198: /* Initialize ifnet structure. */
1.24 thorpej 199: strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
1.1 drochner 200: ifp->if_softc = sc;
201: ifp->if_start = sc->sc_start;
202: ifp->if_ioctl = lance_ioctl;
203: ifp->if_watchdog = lance_watchdog;
1.20 jdolecek 204: ifp->if_init = lance_init;
205: ifp->if_stop = lance_stop;
1.1 drochner 206: ifp->if_flags =
207: IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS | IFF_MULTICAST;
208: #ifdef LANCE_REVC_BUG
209: ifp->if_flags &= ~IFF_MULTICAST;
210: #endif
1.17 thorpej 211: IFQ_SET_READY(&ifp->if_snd);
1.1 drochner 212:
213: /* Initialize ifmedia structures. */
214: ifmedia_init(&sc->sc_media, 0, lance_mediachange, lance_mediastatus);
215: if (sc->sc_supmedia != NULL) {
216: for (i = 0; i < sc->sc_nsupmedia; i++)
217: ifmedia_add(&sc->sc_media, sc->sc_supmedia[i],
218: 0, NULL);
219: ifmedia_set(&sc->sc_media, sc->sc_defaultmedia);
220: } else {
221: ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
222: ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
223: }
224:
225: switch (sc->sc_memsize) {
226: case 8192:
227: sc->sc_nrbuf = 4;
228: sc->sc_ntbuf = 1;
229: break;
230: case 16384:
231: sc->sc_nrbuf = 8;
232: sc->sc_ntbuf = 2;
233: break;
234: case 32768:
235: sc->sc_nrbuf = 16;
236: sc->sc_ntbuf = 4;
237: break;
238: case 65536:
239: sc->sc_nrbuf = 32;
240: sc->sc_ntbuf = 8;
241: break;
242: case 131072:
243: sc->sc_nrbuf = 64;
244: sc->sc_ntbuf = 16;
1.4 leo 245: break;
246: case 262144:
247: sc->sc_nrbuf = 128;
248: sc->sc_ntbuf = 32;
1.1 drochner 249: break;
250: default:
1.18 jdolecek 251: /* weird memory size; cope with it */
252: nbuf = sc->sc_memsize / LEBLEN;
253: sc->sc_ntbuf = nbuf / 5;
254: sc->sc_nrbuf = nbuf - sc->sc_ntbuf;
1.1 drochner 255: }
256:
257: printf(": address %s\n", ether_sprintf(sc->sc_enaddr));
258: printf("%s: %d receive buffers, %d transmit buffers\n",
259: sc->sc_dev.dv_xname, sc->sc_nrbuf, sc->sc_ntbuf);
1.10 simonb 260:
1.20 jdolecek 261: /* Make sure the chip is stopped. */
262: lance_stop(ifp, 0);
263:
1.14 bouyer 264: /* claim 802.1q capability */
265: sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
1.10 simonb 266: /* Attach the interface. */
267: if_attach(ifp);
268: ether_ifattach(ifp, sc->sc_enaddr);
1.1 drochner 269:
1.20 jdolecek 270: sc->sc_sh = shutdownhook_establish(lance_shutdown, ifp);
1.1 drochner 271: if (sc->sc_sh == NULL)
272: panic("lance_config: can't establish shutdownhook");
273: sc->sc_rbufaddr = malloc(sc->sc_nrbuf * sizeof(int), M_DEVBUF,
274: M_WAITOK);
275: sc->sc_tbufaddr = malloc(sc->sc_ntbuf * sizeof(int), M_DEVBUF,
276: M_WAITOK);
277:
278: #if NRND > 0
279: rnd_attach_source(&sc->rnd_source, sc->sc_dev.dv_xname,
1.7 explorer 280: RND_TYPE_NET, 0);
1.1 drochner 281: #endif
282: }
283:
284: void
285: lance_reset(sc)
286: struct lance_softc *sc;
287: {
288: int s;
289:
1.2 mycroft 290: s = splnet();
1.20 jdolecek 291: lance_init(&sc->sc_ethercom.ec_if);
1.1 drochner 292: splx(s);
293: }
294:
295: void
1.20 jdolecek 296: lance_stop(ifp, disable)
297: struct ifnet *ifp;
298: int disable;
1.1 drochner 299: {
1.20 jdolecek 300: struct lance_softc *sc = ifp->if_softc;
1.1 drochner 301:
302: (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
303: }
304:
305: /*
306: * Initialization of interface; set up initialization block
307: * and transmit/receive descriptor rings.
308: */
1.20 jdolecek 309: int
310: lance_init(ifp)
311: struct ifnet *ifp;
1.1 drochner 312: {
1.20 jdolecek 313: struct lance_softc *sc = ifp->if_softc;
1.11 augustss 314: int timo;
1.1 drochner 315: u_long a;
316:
317: (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
318: DELAY(100);
319:
320: /* Newer LANCE chips have a reset register */
321: if (sc->sc_hwreset)
322: (*sc->sc_hwreset)(sc);
323:
324: /* Set the correct byte swapping mode, etc. */
325: (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
326:
327: /* Set up LANCE init block. */
328: (*sc->sc_meminit)(sc);
329:
330: /* Give LANCE the physical address of its init block. */
331: a = sc->sc_addr + LE_INITADDR(sc);
332: (*sc->sc_wrcsr)(sc, LE_CSR1, a);
333: (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
334:
335: /* Try to initialize the LANCE. */
336: DELAY(100);
337: (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
338:
339: /* Wait for initialization to finish. */
340: for (timo = 100000; timo; timo--)
341: if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
342: break;
343:
344: if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
345: /* Start the LANCE. */
1.28 pk 346: (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT);
1.1 drochner 347: ifp->if_flags |= IFF_RUNNING;
348: ifp->if_flags &= ~IFF_OACTIVE;
349: ifp->if_timer = 0;
350: (*sc->sc_start)(ifp);
351: } else
352: printf("%s: controller failed to initialize\n",
353: sc->sc_dev.dv_xname);
354: if (sc->sc_hwinit)
355: (*sc->sc_hwinit)(sc);
1.20 jdolecek 356:
357: return (0);
1.1 drochner 358: }
359:
360: /*
361: * Routine to copy from mbuf chain to transmit buffer in
362: * network buffer memory.
363: */
364: int
365: lance_put(sc, boff, m)
366: struct lance_softc *sc;
367: int boff;
1.11 augustss 368: struct mbuf *m;
1.1 drochner 369: {
1.11 augustss 370: struct mbuf *n;
371: int len, tlen = 0;
1.1 drochner 372:
373: for (; m; m = n) {
374: len = m->m_len;
375: if (len == 0) {
376: MFREE(m, n);
377: continue;
378: }
379: (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
380: boff += len;
381: tlen += len;
382: MFREE(m, n);
383: }
384: if (tlen < LEMINSIZE) {
385: (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
386: tlen = LEMINSIZE;
387: }
388: return (tlen);
389: }
390:
391: /*
392: * Pull data off an interface.
393: * Len is length of data, with local net header stripped.
394: * We copy the data into mbufs. When full cluster sized units are present
395: * we copy into clusters.
396: */
397: integrate struct mbuf *
398: lance_get(sc, boff, totlen)
399: struct lance_softc *sc;
400: int boff, totlen;
401: {
1.5 mycroft 402: struct mbuf *m, *m0, *newm;
1.1 drochner 403: int len;
404:
1.5 mycroft 405: MGETHDR(m0, M_DONTWAIT, MT_DATA);
406: if (m0 == 0)
1.1 drochner 407: return (0);
1.20 jdolecek 408: m0->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if;
1.5 mycroft 409: m0->m_pkthdr.len = totlen;
1.1 drochner 410: len = MHLEN;
1.5 mycroft 411: m = m0;
1.1 drochner 412:
413: while (totlen > 0) {
414: if (totlen >= MINCLSIZE) {
415: MCLGET(m, M_DONTWAIT);
1.5 mycroft 416: if ((m->m_flags & M_EXT) == 0)
417: goto bad;
1.1 drochner 418: len = MCLBYTES;
419: }
1.5 mycroft 420:
421: if (m == m0) {
422: caddr_t newdata = (caddr_t)
423: ALIGN(m->m_data + sizeof(struct ether_header)) -
424: sizeof(struct ether_header);
425: len -= newdata - m->m_data;
426: m->m_data = newdata;
1.1 drochner 427: }
1.5 mycroft 428:
1.1 drochner 429: m->m_len = len = min(totlen, len);
430: (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
431: boff += len;
1.5 mycroft 432:
1.1 drochner 433: totlen -= len;
1.5 mycroft 434: if (totlen > 0) {
435: MGET(newm, M_DONTWAIT, MT_DATA);
436: if (newm == 0)
437: goto bad;
438: len = MLEN;
439: m = m->m_next = newm;
440: }
1.1 drochner 441: }
442:
1.5 mycroft 443: return (m0);
444:
445: bad:
446: m_freem(m0);
447: return (0);
1.1 drochner 448: }
449:
450: /*
451: * Pass a packet to the higher levels.
452: */
453: void
454: lance_read(sc, boff, len)
1.11 augustss 455: struct lance_softc *sc;
1.1 drochner 456: int boff, len;
457: {
458: struct mbuf *m;
1.20 jdolecek 459: struct ifnet *ifp = &sc->sc_ethercom.ec_if;
1.15 tsutsui 460: struct ether_header *eh;
1.1 drochner 461:
462: if (len <= sizeof(struct ether_header) ||
1.14 bouyer 463: len > ((sc->sc_ethercom.ec_capenable & ETHERCAP_VLAN_MTU) ?
464: ETHER_VLAN_ENCAP_LEN + ETHERMTU + sizeof(struct ether_header) :
465: ETHERMTU + sizeof(struct ether_header))) {
1.1 drochner 466: #ifdef LEDEBUG
467: printf("%s: invalid packet size %d; dropping\n",
468: sc->sc_dev.dv_xname, len);
469: #endif
470: ifp->if_ierrors++;
471: return;
472: }
473:
474: /* Pull packet off interface. */
475: m = lance_get(sc, boff, len);
476: if (m == 0) {
477: ifp->if_ierrors++;
478: return;
479: }
480:
481: ifp->if_ipackets++;
482:
1.27 itojun 483: eh = mtod(m, struct ether_header *);
1.1 drochner 484:
485: #ifdef LANCE_REVC_BUG
486: /*
487: * The old LANCE (Rev. C) chips have a bug which causes
488: * garbage to be inserted in front of the received packet.
489: * The work-around is to ignore packets with an invalid
490: * destination address (garbage will usually not match).
491: * Of course, this precludes multicast support...
492: */
493: if (ETHER_CMP(eh->ether_dhost, sc->sc_enaddr) &&
494: ETHER_CMP(eh->ether_dhost, bcast_enaddr)) {
495: m_freem(m);
496: return;
497: }
1.27 itojun 498: #endif
499:
500: /*
501: * Some lance device does not present IFF_SIMPLEX behavior on multicast
502: * packets. Make sure to drop it if it is from ourselves.
503: */
504: if (!ETHER_CMP(eh->ether_shost, sc->sc_enaddr)) {
505: m_freem(m);
506: return;
507: }
508:
509: #if NBPFILTER > 0
510: /*
511: * Check if there's a BPF listener on this interface.
512: * If so, hand off the raw packet to BPF.
513: */
514: if (ifp->if_bpf)
515: bpf_mtap(ifp->if_bpf, m);
1.1 drochner 516: #endif
517:
1.9 thorpej 518: /* Pass the packet up. */
519: (*ifp->if_input)(ifp, m);
1.1 drochner 520: }
521:
522: #undef ifp
523:
524: void
525: lance_watchdog(ifp)
526: struct ifnet *ifp;
527: {
528: struct lance_softc *sc = ifp->if_softc;
529:
530: log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
531: ++ifp->if_oerrors;
532:
533: lance_reset(sc);
534: }
535:
536: int
537: lance_mediachange(ifp)
538: struct ifnet *ifp;
539: {
540: struct lance_softc *sc = ifp->if_softc;
541:
542: if (sc->sc_mediachange)
543: return ((*sc->sc_mediachange)(sc));
1.8 thorpej 544: return (0);
1.1 drochner 545: }
546:
547: void
548: lance_mediastatus(ifp, ifmr)
549: struct ifnet *ifp;
550: struct ifmediareq *ifmr;
551: {
552: struct lance_softc *sc = ifp->if_softc;
553:
554: if ((ifp->if_flags & IFF_UP) == 0)
555: return;
556:
557: ifmr->ifm_status = IFM_AVALID;
558: if (sc->sc_havecarrier)
559: ifmr->ifm_status |= IFM_ACTIVE;
560:
561: if (sc->sc_mediastatus)
562: (*sc->sc_mediastatus)(sc, ifmr);
563: }
564:
565: /*
566: * Process an ioctl request.
567: */
568: int
569: lance_ioctl(ifp, cmd, data)
1.11 augustss 570: struct ifnet *ifp;
1.1 drochner 571: u_long cmd;
572: caddr_t data;
573: {
1.11 augustss 574: struct lance_softc *sc = ifp->if_softc;
1.1 drochner 575: struct ifreq *ifr = (struct ifreq *)data;
576: int s, error = 0;
577:
1.2 mycroft 578: s = splnet();
1.1 drochner 579:
580: switch (cmd) {
581:
582: case SIOCSIFADDR:
1.20 jdolecek 583: case SIOCSIFFLAGS:
584: error = ether_ioctl(ifp, cmd, data);
1.1 drochner 585: break;
586:
587: #if defined(CCITT) && defined(LLC)
588: case SIOCSIFCONF_X25:
1.22 jdolecek 589: {
590: struct ifaddr *ifa = (struct ifaddr *) data;
591:
1.1 drochner 592: ifp->if_flags |= IFF_UP;
593: ifa->ifa_rtrequest = cons_rtrequest; /* XXX */
594: error = x25_llcglue(PRC_IFUP, ifa->ifa_addr);
595: if (error == 0)
1.20 jdolecek 596: lance_init(&sc->sc_ethercom.ec_if);
1.1 drochner 597: break;
1.22 jdolecek 598: }
1.1 drochner 599: #endif /* CCITT && LLC */
600:
601: case SIOCADDMULTI:
602: case SIOCDELMULTI:
603: error = (cmd == SIOCADDMULTI) ?
604: ether_addmulti(ifr, &sc->sc_ethercom) :
605: ether_delmulti(ifr, &sc->sc_ethercom);
606:
607: if (error == ENETRESET) {
608: /*
609: * Multicast list has changed; set the hardware filter
610: * accordingly.
611: */
1.28.2.4 skrll 612: if (ifp->if_flags & IFF_RUNNING)
613: lance_reset(sc);
1.1 drochner 614: error = 0;
615: }
616: break;
617:
618: case SIOCGIFMEDIA:
619: case SIOCSIFMEDIA:
620: error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
621: break;
622:
623: default:
624: error = EINVAL;
625: break;
626: }
627:
628: splx(s);
629: return (error);
630: }
631:
632: hide void
633: lance_shutdown(arg)
634: void *arg;
635: {
636:
1.20 jdolecek 637: lance_stop((struct ifnet *)arg, 0);
1.1 drochner 638: }
639:
640: /*
641: * Set up the logical address filter.
642: */
643: void
644: lance_setladrf(ac, af)
645: struct ethercom *ac;
646: u_int16_t *af;
647: {
648: struct ifnet *ifp = &ac->ec_if;
649: struct ether_multi *enm;
1.11 augustss 650: u_int32_t crc;
1.1 drochner 651: struct ether_multistep step;
652:
653: /*
654: * Set up multicast address filter by passing all multicast addresses
655: * through a crc generator, and then using the high order 6 bits as an
656: * index into the 64 bit logical address filter. The high order bit
657: * selects the word, while the rest of the bits select the bit within
658: * the word.
659: */
660:
661: if (ifp->if_flags & IFF_PROMISC)
662: goto allmulti;
663:
664: af[0] = af[1] = af[2] = af[3] = 0x0000;
665: ETHER_FIRST_MULTI(step, ac, enm);
666: while (enm != NULL) {
667: if (ETHER_CMP(enm->enm_addrlo, enm->enm_addrhi)) {
668: /*
669: * We must listen to a range of multicast addresses.
670: * For now, just accept all multicasts, rather than
671: * trying to set only those filter bits needed to match
672: * the range. (At this time, the only use of address
673: * ranges is for IP multicast routing, for which the
674: * range is big enough to require all bits set.)
675: */
676: goto allmulti;
677: }
678:
1.12 thorpej 679: crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
680:
1.1 drochner 681: /* Just want the 6 most significant bits. */
682: crc >>= 26;
683:
684: /* Set the corresponding bit in the filter. */
685: af[crc >> 4] |= 1 << (crc & 0xf);
686:
687: ETHER_NEXT_MULTI(step, enm);
688: }
689: ifp->if_flags &= ~IFF_ALLMULTI;
690: return;
691:
692: allmulti:
693: ifp->if_flags |= IFF_ALLMULTI;
694: af[0] = af[1] = af[2] = af[3] = 0xffff;
695: }
696:
697: /*
698: * Routines for accessing the transmit and receive buffers.
699: * The various CPU and adapter configurations supported by this
700: * driver require three different access methods for buffers
701: * and descriptors:
702: * (1) contig (contiguous data; no padding),
703: * (2) gap2 (two bytes of data followed by two bytes of padding),
704: * (3) gap16 (16 bytes of data followed by 16 bytes of padding).
705: */
706:
707: /*
708: * contig: contiguous data with no padding.
709: *
710: * Buffers may have any alignment.
711: */
712:
713: void
714: lance_copytobuf_contig(sc, from, boff, len)
715: struct lance_softc *sc;
716: void *from;
717: int boff, len;
718: {
719: volatile caddr_t buf = sc->sc_mem;
720:
721: /*
1.24 thorpej 722: * Just call memcpy() to do the work.
1.1 drochner 723: */
1.24 thorpej 724: memcpy(buf + boff, from, len);
1.1 drochner 725: }
726:
727: void
728: lance_copyfrombuf_contig(sc, to, boff, len)
729: struct lance_softc *sc;
730: void *to;
731: int boff, len;
732: {
733: volatile caddr_t buf = sc->sc_mem;
734:
735: /*
1.24 thorpej 736: * Just call memcpy() to do the work.
1.1 drochner 737: */
1.24 thorpej 738: memcpy(to, buf + boff, len);
1.1 drochner 739: }
740:
741: void
742: lance_zerobuf_contig(sc, boff, len)
743: struct lance_softc *sc;
744: int boff, len;
745: {
746: volatile caddr_t buf = sc->sc_mem;
747:
748: /*
1.25 thorpej 749: * Just let memset() do the work
1.1 drochner 750: */
1.25 thorpej 751: memset(buf + boff, 0, len);
1.1 drochner 752: }
753:
754: #if 0
755: /*
756: * Examples only; duplicate these and tweak (if necessary) in
757: * machine-specific front-ends.
758: */
759:
760: /*
761: * gap2: two bytes of data followed by two bytes of pad.
762: *
763: * Buffers must be 4-byte aligned. The code doesn't worry about
764: * doing an extra byte.
765: */
766:
767: void
768: lance_copytobuf_gap2(sc, fromv, boff, len)
769: struct lance_softc *sc;
770: void *fromv;
771: int boff;
1.11 augustss 772: int len;
1.1 drochner 773: {
774: volatile caddr_t buf = sc->sc_mem;
1.11 augustss 775: caddr_t from = fromv;
776: volatile u_int16_t *bptr;
1.1 drochner 777:
778: if (boff & 0x1) {
779: /* handle unaligned first byte */
780: bptr = ((volatile u_int16_t *)buf) + (boff - 1);
781: *bptr = (*from++ << 8) | (*bptr & 0xff);
782: bptr += 2;
783: len--;
784: } else
785: bptr = ((volatile u_int16_t *)buf) + boff;
786: while (len > 1) {
787: *bptr = (from[1] << 8) | (from[0] & 0xff);
788: bptr += 2;
789: from += 2;
790: len -= 2;
791: }
792: if (len == 1)
793: *bptr = (u_int16_t)*from;
794: }
795:
796: void
797: lance_copyfrombuf_gap2(sc, tov, boff, len)
798: struct lance_softc *sc;
799: void *tov;
800: int boff, len;
801: {
802: volatile caddr_t buf = sc->sc_mem;
1.11 augustss 803: caddr_t to = tov;
804: volatile u_int16_t *bptr;
805: u_int16_t tmp;
1.1 drochner 806:
807: if (boff & 0x1) {
808: /* handle unaligned first byte */
809: bptr = ((volatile u_int16_t *)buf) + (boff - 1);
810: *to++ = (*bptr >> 8) & 0xff;
811: bptr += 2;
812: len--;
813: } else
814: bptr = ((volatile u_int16_t *)buf) + boff;
815: while (len > 1) {
816: tmp = *bptr;
817: *to++ = tmp & 0xff;
818: *to++ = (tmp >> 8) & 0xff;
819: bptr += 2;
820: len -= 2;
821: }
822: if (len == 1)
823: *to = *bptr & 0xff;
824: }
825:
826: void
827: lance_zerobuf_gap2(sc, boff, len)
828: struct lance_softc *sc;
829: int boff, len;
830: {
831: volatile caddr_t buf = sc->sc_mem;
1.11 augustss 832: volatile u_int16_t *bptr;
1.1 drochner 833:
834: if ((unsigned)boff & 0x1) {
835: bptr = ((volatile u_int16_t *)buf) + (boff - 1);
836: *bptr &= 0xff;
837: bptr += 2;
838: len--;
839: } else
840: bptr = ((volatile u_int16_t *)buf) + boff;
841: while (len > 0) {
842: *bptr = 0;
843: bptr += 2;
844: len -= 2;
845: }
846: }
847:
848: /*
849: * gap16: 16 bytes of data followed by 16 bytes of pad.
850: *
851: * Buffers must be 32-byte aligned.
852: */
853:
854: void
855: lance_copytobuf_gap16(sc, fromv, boff, len)
856: struct lance_softc *sc;
857: void *fromv;
858: int boff;
1.11 augustss 859: int len;
1.1 drochner 860: {
861: volatile caddr_t buf = sc->sc_mem;
1.11 augustss 862: caddr_t from = fromv;
863: caddr_t bptr;
864: int xfer;
1.1 drochner 865:
866: bptr = buf + ((boff << 1) & ~0x1f);
867: boff &= 0xf;
868: xfer = min(len, 16 - boff);
869: while (len > 0) {
1.24 thorpej 870: memcpy(bptr + boff, from, xfer);
1.1 drochner 871: from += xfer;
872: bptr += 32;
873: boff = 0;
874: len -= xfer;
875: xfer = min(len, 16);
876: }
877: }
878:
879: void
880: lance_copyfrombuf_gap16(sc, tov, boff, len)
881: struct lance_softc *sc;
882: void *tov;
883: int boff, len;
884: {
885: volatile caddr_t buf = sc->sc_mem;
1.11 augustss 886: caddr_t to = tov;
887: caddr_t bptr;
888: int xfer;
1.1 drochner 889:
890: bptr = buf + ((boff << 1) & ~0x1f);
891: boff &= 0xf;
892: xfer = min(len, 16 - boff);
893: while (len > 0) {
1.24 thorpej 894: memcpy(to, bptr + boff, xfer);
1.1 drochner 895: to += xfer;
896: bptr += 32;
897: boff = 0;
898: len -= xfer;
899: xfer = min(len, 16);
900: }
901: }
902:
903: void
904: lance_zerobuf_gap16(sc, boff, len)
905: struct lance_softc *sc;
906: int boff, len;
907: {
908: volatile caddr_t buf = sc->sc_mem;
1.11 augustss 909: caddr_t bptr;
910: int xfer;
1.1 drochner 911:
912: bptr = buf + ((boff << 1) & ~0x1f);
913: boff &= 0xf;
914: xfer = min(len, 16 - boff);
915: while (len > 0) {
1.25 thorpej 916: memset(bptr + boff, 0, xfer);
1.1 drochner 917: bptr += 32;
918: boff = 0;
919: len -= xfer;
920: xfer = min(len, 16);
921: }
922: }
923: #endif /* Example only */
CVSweb <webmaster@jp.NetBSD.org>