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