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