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

Cache object: 3b24a440ca94b35d80f7e5a15caed5b1


[ 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.