The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/lance.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: lance.c,v 1.32 2005/02/27 00:27:01 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 __KERNEL_RCSID(0, "$NetBSD: lance.c,v 1.32 2005/02/27 00:27:01 perry Exp $");
   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 
  116 #if defined(_KERNEL_OPT)
  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 
  128 integrate struct mbuf *lance_get(struct lance_softc *, int, int);
  129 
  130 hide void lance_shutdown(void *);
  131 
  132 int lance_mediachange(struct ifnet *);
  133 void lance_mediastatus(struct ifnet *, struct ifmediareq *);
  134 
  135 static inline u_int16_t ether_cmp(void *, void *);
  136 
  137 void lance_stop(struct ifnet *, int);
  138 int lance_ioctl(struct ifnet *, u_long, caddr_t);
  139 void lance_watchdog(struct ifnet *);
  140 
  141 /*
  142  * Compare two Ether/802 addresses for equality, inlined and
  143  * unrolled for speed.  Use this like memcmp().
  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 {
  159         u_int16_t *a = (u_short *) one;
  160         u_int16_t *b = (u_short *) two;
  161         u_int16_t diff;
  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 {
  195         int i, nbuf;
  196         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  197 
  198         /* Initialize ifnet structure. */
  199         strcpy(ifp->if_xname, sc->sc_dev.dv_xname);
  200         ifp->if_softc = sc;
  201         ifp->if_start = sc->sc_start;
  202         ifp->if_ioctl = lance_ioctl;
  203         ifp->if_watchdog = lance_watchdog;
  204         ifp->if_init = lance_init;
  205         ifp->if_stop = lance_stop;
  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
  211         IFQ_SET_READY(&ifp->if_snd);
  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;
  245                 break;
  246         case 262144:
  247                 sc->sc_nrbuf = 128;
  248                 sc->sc_ntbuf = 32;
  249                 break;
  250         default:
  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;
  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);
  260 
  261         /* Make sure the chip is stopped. */
  262         lance_stop(ifp, 0);
  263 
  264         /* claim 802.1q capability */
  265         sc->sc_ethercom.ec_capabilities |= ETHERCAP_VLAN_MTU;
  266         /* Attach the interface. */
  267         if_attach(ifp);
  268         ether_ifattach(ifp, sc->sc_enaddr);
  269 
  270         sc->sc_sh = shutdownhook_establish(lance_shutdown, ifp);
  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,
  280                           RND_TYPE_NET, 0);
  281 #endif
  282 }
  283 
  284 void
  285 lance_reset(sc)
  286         struct lance_softc *sc;
  287 {
  288         int s;
  289 
  290         s = splnet();
  291         lance_init(&sc->sc_ethercom.ec_if);
  292         splx(s);
  293 }
  294 
  295 void
  296 lance_stop(ifp, disable)
  297         struct ifnet *ifp;
  298         int disable;
  299 {
  300         struct lance_softc *sc = ifp->if_softc;
  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  */
  309 int
  310 lance_init(ifp)
  311         struct ifnet *ifp;
  312 {
  313         struct lance_softc *sc = ifp->if_softc;
  314         int timo;
  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. */
  346                 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT);
  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);
  356 
  357         return (0);
  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;
  368         struct mbuf *m;
  369 {
  370         struct mbuf *n;
  371         int len, tlen = 0;
  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 {
  402         struct mbuf *m, *m0, *newm;
  403         int len;
  404 
  405         MGETHDR(m0, M_DONTWAIT, MT_DATA);
  406         if (m0 == 0)
  407                 return (0);
  408         m0->m_pkthdr.rcvif = &sc->sc_ethercom.ec_if;
  409         m0->m_pkthdr.len = totlen;
  410         len = MHLEN;
  411         m = m0;
  412 
  413         while (totlen > 0) {
  414                 if (totlen >= MINCLSIZE) {
  415                         MCLGET(m, M_DONTWAIT);
  416                         if ((m->m_flags & M_EXT) == 0)
  417                                 goto bad;
  418                         len = MCLBYTES;
  419                 }
  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;
  427                 }
  428 
  429                 m->m_len = len = min(totlen, len);
  430                 (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
  431                 boff += len;
  432 
  433                 totlen -= len;
  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                 }
  441         }
  442 
  443         return (m0);
  444 
  445 bad:
  446         m_freem(m0);
  447         return (0);
  448 }
  449 
  450 /*
  451  * Pass a packet to the higher levels.
  452  */
  453 void
  454 lance_read(sc, boff, len)
  455         struct lance_softc *sc;
  456         int boff, len;
  457 {
  458         struct mbuf *m;
  459         struct ifnet *ifp = &sc->sc_ethercom.ec_if;
  460         struct ether_header *eh;
  461 
  462         if (len <= sizeof(struct ether_header) ||
  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))) {
  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 
  483         eh = mtod(m, struct ether_header *);
  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         }
  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);
  516 #endif
  517 
  518         /* Pass the packet up. */
  519         (*ifp->if_input)(ifp, m);
  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));
  544         return (0);
  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)
  570         struct ifnet *ifp;
  571         u_long cmd;
  572         caddr_t data;
  573 {
  574         struct lance_softc *sc = ifp->if_softc;
  575         struct ifreq *ifr = (struct ifreq *)data;
  576         int s, error = 0;
  577 
  578         s = splnet();
  579 
  580         switch (cmd) {
  581 
  582         case SIOCSIFADDR:
  583         case SIOCSIFFLAGS:
  584                 error = ether_ioctl(ifp, cmd, data);
  585                 break;
  586 
  587 #if defined(CCITT) && defined(LLC)
  588         case SIOCSIFCONF_X25:
  589             {
  590                 struct ifaddr *ifa = (struct ifaddr *) data;
  591 
  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)
  596                         lance_init(&sc->sc_ethercom.ec_if);
  597                 break;
  598             }
  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                          */
  612                         if (ifp->if_flags & IFF_RUNNING)
  613                                 lance_reset(sc);
  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 
  637         lance_stop((struct ifnet *)arg, 0);
  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;
  650         u_int32_t crc;
  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 
  679                 crc = ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN);
  680 
  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         /*
  722          * Just call memcpy() to do the work.
  723          */
  724         memcpy(buf + boff, from, len);
  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         /*
  736          * Just call memcpy() to do the work.
  737          */
  738         memcpy(to, buf + boff, len);
  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         /*
  749          * Just let memset() do the work
  750          */
  751         memset(buf + boff, 0, len);
  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;
  772         int len;
  773 {
  774         volatile caddr_t buf = sc->sc_mem;
  775         caddr_t from = fromv;
  776         volatile u_int16_t *bptr;
  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;
  803         caddr_t to = tov;
  804         volatile u_int16_t *bptr;
  805         u_int16_t tmp;
  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;
  832         volatile u_int16_t *bptr;
  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;
  859         int len;
  860 {
  861         volatile caddr_t buf = sc->sc_mem;
  862         caddr_t from = fromv;
  863         caddr_t bptr;
  864         int xfer;
  865 
  866         bptr = buf + ((boff << 1) & ~0x1f);
  867         boff &= 0xf;
  868         xfer = min(len, 16 - boff);
  869         while (len > 0) {
  870                 memcpy(bptr + boff, from, xfer);
  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;
  886         caddr_t to = tov;
  887         caddr_t bptr;
  888         int xfer;
  889 
  890         bptr = buf + ((boff << 1) & ~0x1f);
  891         boff &= 0xf;
  892         xfer = min(len, 16 - boff);
  893         while (len > 0) {
  894                 memcpy(to, bptr + boff, xfer);
  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;
  909         caddr_t bptr;
  910         int xfer;
  911 
  912         bptr = buf + ((boff << 1) & ~0x1f);
  913         boff &= 0xf;
  914         xfer = min(len, 16 - boff);
  915         while (len > 0) {
  916                 memset(bptr + boff, 0, xfer);
  917                 bptr += 32;
  918                 boff = 0;
  919                 len -= xfer;
  920                 xfer = min(len, 16);
  921         }
  922 }
  923 #endif /* Example only */

Cache object: 9ec7f81259fd4903383c5122183bc356


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]


This page is part of the FreeBSD/Linux Linux Kernel Cross-Reference, and was automatically generated using a modified version of the LXR engine.