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/le/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.34 2005/12/24 20:27:30 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 __FBSDID("$FreeBSD$");
   76 
   77 #include <sys/param.h>
   78 #include <sys/bus.h>
   79 #include <sys/endian.h>
   80 #include <sys/lock.h>
   81 #include <sys/kernel.h>
   82 #include <sys/mbuf.h>
   83 #include <sys/mutex.h>
   84 #include <sys/socket.h>
   85 #include <sys/sockio.h>
   86 
   87 #include <net/ethernet.h>
   88 #include <net/if.h>
   89 #include <net/if_arp.h>
   90 #include <net/if_dl.h>
   91 #include <net/if_media.h>
   92 #include <net/if_types.h>
   93 #include <net/if_vlan_var.h>
   94 
   95 #include <machine/bus.h>
   96 
   97 #include <dev/le/lancereg.h>
   98 #include <dev/le/lancevar.h>
   99 
  100 devclass_t le_devclass;
  101 
  102 static void lance_start(struct ifnet *);
  103 static void lance_stop(struct lance_softc *);
  104 static void lance_init(void *);
  105 static void lance_watchdog(void *s);
  106 static int lance_mediachange(struct ifnet *);
  107 static void lance_mediastatus(struct ifnet *, struct ifmediareq *);
  108 static int lance_ioctl(struct ifnet *, u_long, caddr_t);
  109 
  110 int
  111 lance_config(struct lance_softc *sc, const char* name, int unit)
  112 {
  113         struct ifnet *ifp;
  114         int i, nbuf;
  115 
  116         if (LE_LOCK_INITIALIZED(sc) == 0)
  117                 return (ENXIO);
  118 
  119         ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
  120         if (ifp == NULL)
  121                 return (ENOSPC);
  122 
  123         callout_init_mtx(&sc->sc_wdog_ch, &sc->sc_mtx, 0);
  124 
  125         /* Initialize ifnet structure. */
  126         ifp->if_softc = sc;
  127         if_initname(ifp, name, unit);
  128         ifp->if_start = lance_start;
  129         ifp->if_ioctl = lance_ioctl;
  130         ifp->if_init = lance_init;
  131         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  132 #ifdef LANCE_REVC_BUG
  133         ifp->if_flags &= ~IFF_MULTICAST;
  134 #endif
  135         ifp->if_baudrate = IF_Mbps(10);
  136         IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
  137         ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
  138         IFQ_SET_READY(&ifp->if_snd);
  139 
  140         /* Initialize ifmedia structures. */
  141         ifmedia_init(&sc->sc_media, 0, lance_mediachange, lance_mediastatus);
  142         if (sc->sc_supmedia != NULL) {
  143                 for (i = 0; i < sc->sc_nsupmedia; i++)
  144                         ifmedia_add(&sc->sc_media, sc->sc_supmedia[i], 0, NULL);
  145                 ifmedia_set(&sc->sc_media, sc->sc_defaultmedia);
  146         } else {
  147                 ifmedia_add(&sc->sc_media,
  148                     IFM_MAKEWORD(IFM_ETHER, IFM_MANUAL, 0, 0), 0, NULL);
  149                 ifmedia_set(&sc->sc_media,
  150                     IFM_MAKEWORD(IFM_ETHER, IFM_MANUAL, 0, 0));
  151         }
  152 
  153         switch (sc->sc_memsize) {
  154         case 8192:
  155                 sc->sc_nrbuf = 4;
  156                 sc->sc_ntbuf = 1;
  157                 break;
  158         case 16384:
  159                 sc->sc_nrbuf = 8;
  160                 sc->sc_ntbuf = 2;
  161                 break;
  162         case 32768:
  163                 sc->sc_nrbuf = 16;
  164                 sc->sc_ntbuf = 4;
  165                 break;
  166         case 65536:
  167                 sc->sc_nrbuf = 32;
  168                 sc->sc_ntbuf = 8;
  169                 break;
  170         case 131072:
  171                 sc->sc_nrbuf = 64;
  172                 sc->sc_ntbuf = 16;
  173                 break;
  174         case 262144:
  175                 sc->sc_nrbuf = 128;
  176                 sc->sc_ntbuf = 32;
  177                 break;
  178         default:
  179                 /* weird memory size; cope with it */
  180                 nbuf = sc->sc_memsize / LEBLEN;
  181                 sc->sc_ntbuf = nbuf / 5;
  182                 sc->sc_nrbuf = nbuf - sc->sc_ntbuf;
  183         }
  184 
  185         if_printf(ifp, "%d receive buffers, %d transmit buffers\n",
  186             sc->sc_nrbuf, sc->sc_ntbuf);
  187 
  188         /* Make sure the chip is stopped. */
  189         LE_LOCK(sc);
  190         lance_stop(sc);
  191         LE_UNLOCK(sc);
  192 
  193         return (0);
  194 }
  195 
  196 void
  197 lance_attach(struct lance_softc *sc)
  198 {
  199         struct ifnet *ifp = sc->sc_ifp;
  200 
  201         /* Attach the interface. */
  202         ether_ifattach(ifp, sc->sc_enaddr);
  203 
  204         /* Claim 802.1q capability. */
  205         ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
  206         ifp->if_capabilities |= IFCAP_VLAN_MTU;
  207         ifp->if_capenable |= IFCAP_VLAN_MTU;
  208 }
  209 
  210 void
  211 lance_detach(struct lance_softc *sc)
  212 {
  213         struct ifnet *ifp = sc->sc_ifp;
  214 
  215         LE_LOCK(sc);
  216         lance_stop(sc);
  217         LE_UNLOCK(sc);
  218         callout_drain(&sc->sc_wdog_ch);
  219         ether_ifdetach(ifp);
  220         if_free(ifp);
  221 }
  222 
  223 void
  224 lance_suspend(struct lance_softc *sc)
  225 {
  226 
  227         LE_LOCK(sc);
  228         lance_stop(sc);
  229         LE_UNLOCK(sc);
  230 }
  231 
  232 void
  233 lance_resume(struct lance_softc *sc)
  234 {
  235 
  236         LE_LOCK(sc);
  237         if (sc->sc_ifp->if_flags & IFF_UP)
  238                 lance_init_locked(sc);
  239         LE_UNLOCK(sc);
  240 }
  241 
  242 static void
  243 lance_start(struct ifnet *ifp)
  244 {
  245         struct lance_softc *sc = ifp->if_softc;
  246 
  247         LE_LOCK(sc);
  248         (*sc->sc_start_locked)(sc);
  249         LE_UNLOCK(sc);
  250 }
  251 
  252 static void
  253 lance_stop(struct lance_softc *sc)
  254 {
  255         struct ifnet *ifp = sc->sc_ifp;
  256 
  257         LE_LOCK_ASSERT(sc, MA_OWNED);
  258 
  259         /*
  260          * Mark the interface down and cancel the watchdog timer.
  261          */
  262         ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
  263         callout_stop(&sc->sc_wdog_ch);
  264         sc->sc_wdog_timer = 0;
  265 
  266         (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
  267 }
  268 
  269 static void
  270 lance_init(void *xsc)
  271 {
  272         struct lance_softc *sc = (struct lance_softc *)xsc;
  273 
  274         LE_LOCK(sc);
  275         lance_init_locked(sc);
  276         LE_UNLOCK(sc);
  277 }
  278 
  279 /*
  280  * Initialization of interface; set up initialization block
  281  * and transmit/receive descriptor rings.
  282  */
  283 void
  284 lance_init_locked(struct lance_softc *sc)
  285 {
  286         struct ifnet *ifp = sc->sc_ifp;
  287         u_long a;
  288         int timo;
  289 
  290         LE_LOCK_ASSERT(sc, MA_OWNED);
  291 
  292         (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
  293         DELAY(100);
  294 
  295         /* Newer LANCE chips have a reset register. */
  296         if (sc->sc_hwreset)
  297                 (*sc->sc_hwreset)(sc);
  298 
  299         /* Set the correct byte swapping mode, etc. */
  300         (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
  301 
  302         /* Set the current media. This may require the chip to be stopped. */
  303         if (sc->sc_mediachange)
  304                 (void)(*sc->sc_mediachange)(sc);
  305 
  306         /*
  307          * Update our private copy of the Ethernet address.
  308          * We NEED the copy so we can ensure its alignment!
  309          */
  310         memcpy(sc->sc_enaddr, IF_LLADDR(ifp), ETHER_ADDR_LEN);
  311 
  312         /* Set up LANCE init block. */
  313         (*sc->sc_meminit)(sc);
  314 
  315         /* Give LANCE the physical address of its init block. */
  316         a = sc->sc_addr + LE_INITADDR(sc);
  317         (*sc->sc_wrcsr)(sc, LE_CSR1, a & 0xffff);
  318         (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
  319 
  320         /* Try to initialize the LANCE. */
  321         DELAY(100);
  322         (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
  323 
  324         /* Wait for initialization to finish. */
  325         for (timo = 100000; timo; timo--)
  326                 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
  327                         break;
  328 
  329         if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
  330                 /* Start the LANCE. */
  331                 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT);
  332                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
  333                 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  334                 sc->sc_wdog_timer = 0;
  335                 callout_reset(&sc->sc_wdog_ch, hz, lance_watchdog, sc);
  336                 (*sc->sc_start_locked)(sc);
  337         } else
  338                 if_printf(ifp, "controller failed to initialize\n");
  339 
  340         if (sc->sc_hwinit)
  341                 (*sc->sc_hwinit)(sc);
  342 }
  343 
  344 /*
  345  * Routine to copy from mbuf chain to transmit buffer in
  346  * network buffer memory.
  347  */
  348 int
  349 lance_put(struct lance_softc *sc, int boff, struct mbuf *m)
  350 {
  351         struct mbuf *n;
  352         int len, tlen = 0;
  353 
  354         LE_LOCK_ASSERT(sc, MA_OWNED);
  355 
  356         for (; m; m = n) {
  357                 len = m->m_len;
  358                 if (len == 0) {
  359                         n = m_free(m);
  360                         m = NULL;
  361                         continue;
  362                 }
  363                 (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
  364                 boff += len;
  365                 tlen += len;
  366                 n = m_free(m);
  367                 m = NULL;
  368         }
  369         if (tlen < LEMINSIZE) {
  370                 (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
  371                 tlen = LEMINSIZE;
  372         }
  373         return (tlen);
  374 }
  375 
  376 /*
  377  * Pull data off an interface.
  378  * Len is length of data, with local net header stripped.
  379  * We copy the data into mbufs.  When full cluster sized units are present
  380  * we copy into clusters.
  381  */
  382 struct mbuf *
  383 lance_get(struct lance_softc *sc, int boff, int totlen)
  384 {
  385         struct ifnet *ifp = sc->sc_ifp;
  386         struct mbuf *m, *m0, *newm;
  387         caddr_t newdata;
  388         int len;
  389 
  390         if (totlen <= ETHER_HDR_LEN || totlen > LEBLEN - ETHER_CRC_LEN) {
  391 #ifdef LEDEBUG
  392                 if_printf(ifp, "invalid packet size %d; dropping\n", totlen);
  393 #endif
  394                 return (NULL);
  395         }
  396 
  397         MGETHDR(m0, M_DONTWAIT, MT_DATA);
  398         if (m0 == NULL)
  399                 return (NULL);
  400         m0->m_pkthdr.rcvif = ifp;
  401         m0->m_pkthdr.len = totlen;
  402         len = MHLEN;
  403         m = m0;
  404 
  405         while (totlen > 0) {
  406                 if (totlen >= MINCLSIZE) {
  407                         MCLGET(m, M_DONTWAIT);
  408                         if ((m->m_flags & M_EXT) == 0)
  409                                 goto bad;
  410                         len = MCLBYTES;
  411                 }
  412 
  413                 if (m == m0) {
  414                         newdata = (caddr_t)
  415                             ALIGN(m->m_data + ETHER_HDR_LEN) - ETHER_HDR_LEN;
  416                         len -= newdata - m->m_data;
  417                         m->m_data = newdata;
  418                 }
  419 
  420                 m->m_len = len = min(totlen, len);
  421                 (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
  422                 boff += len;
  423 
  424                 totlen -= len;
  425                 if (totlen > 0) {
  426                         MGET(newm, M_DONTWAIT, MT_DATA);
  427                         if (newm == 0)
  428                                 goto bad;
  429                         len = MLEN;
  430                         m = m->m_next = newm;
  431                 }
  432         }
  433 
  434         return (m0);
  435 
  436  bad:
  437         m_freem(m0);
  438         return (NULL);
  439 }
  440 
  441 static void
  442 lance_watchdog(void *xsc)
  443 {
  444         struct lance_softc *sc = (struct lance_softc *)xsc;
  445         struct ifnet *ifp = sc->sc_ifp;
  446 
  447         LE_LOCK_ASSERT(sc, MA_OWNED);
  448 
  449         if (sc->sc_wdog_timer == 0 || --sc->sc_wdog_timer != 0) {
  450                 callout_reset(&sc->sc_wdog_ch, hz, lance_watchdog, sc);
  451                 return;
  452         }
  453 
  454         if_printf(ifp, "device timeout\n");
  455         ++ifp->if_oerrors;
  456         lance_init_locked(sc);
  457 }
  458 
  459 static int
  460 lance_mediachange(struct ifnet *ifp)
  461 {
  462         struct lance_softc *sc = ifp->if_softc;
  463 
  464         if (sc->sc_mediachange) {
  465                 /*
  466                  * For setting the port in LE_CSR15 the PCnet chips must
  467                  * be powered down or stopped and unlike documented may
  468                  * not take effect without an initialization. So don't
  469                  * invoke (*sc_mediachange) directly here but go through
  470                  * lance_init_locked().
  471                  */
  472                 LE_LOCK(sc);
  473                 lance_stop(sc);
  474                 lance_init_locked(sc);
  475                 if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
  476                         (*sc->sc_start_locked)(sc);
  477                 LE_UNLOCK(sc);
  478         }
  479         return (0);
  480 }
  481 
  482 static void
  483 lance_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
  484 {
  485         struct lance_softc *sc = ifp->if_softc;
  486 
  487         LE_LOCK(sc);
  488         if (!(ifp->if_flags & IFF_UP)) {
  489                 LE_UNLOCK(sc);
  490                 return;
  491         }
  492 
  493         ifmr->ifm_status = IFM_AVALID;
  494         if (sc->sc_flags & LE_CARRIER)
  495                 ifmr->ifm_status |= IFM_ACTIVE;
  496 
  497         if (sc->sc_mediastatus)
  498                 (*sc->sc_mediastatus)(sc, ifmr);
  499         LE_UNLOCK(sc);
  500 }
  501 
  502 /*
  503  * Process an ioctl request.
  504  */
  505 static int
  506 lance_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  507 {
  508         struct lance_softc *sc = ifp->if_softc;
  509         struct ifreq *ifr = (struct ifreq *)data;
  510         int error = 0;
  511 
  512         switch (cmd) {
  513         case SIOCSIFFLAGS:
  514                 LE_LOCK(sc);
  515                 if (ifp->if_flags & IFF_PROMISC) {
  516                         if (!(sc->sc_flags & LE_PROMISC)) {
  517                                 sc->sc_flags |= LE_PROMISC;
  518                                 lance_init_locked(sc);
  519                         }
  520                 } else if (sc->sc_flags & LE_PROMISC) {
  521                         sc->sc_flags &= ~LE_PROMISC;
  522                         lance_init_locked(sc);
  523                 }
  524 
  525                 if ((ifp->if_flags & IFF_ALLMULTI) &&
  526                     !(sc->sc_flags & LE_ALLMULTI)) {
  527                         sc->sc_flags |= LE_ALLMULTI;
  528                         lance_init_locked(sc);
  529                 } else if (!(ifp->if_flags & IFF_ALLMULTI) &&
  530                     (sc->sc_flags & LE_ALLMULTI)) {
  531                         sc->sc_flags &= ~LE_ALLMULTI;
  532                         lance_init_locked(sc);
  533                 }
  534 
  535                 if (!(ifp->if_flags & IFF_UP) &&
  536                     ifp->if_drv_flags & IFF_DRV_RUNNING) {
  537                         /*
  538                          * If interface is marked down and it is running, then
  539                          * stop it.
  540                          */
  541                         lance_stop(sc);
  542                 } else if (ifp->if_flags & IFF_UP &&
  543                     !(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
  544                         /*
  545                          * If interface is marked up and it is stopped, then
  546                          * start it.
  547                          */
  548                         lance_init_locked(sc);
  549                 }
  550 #ifdef LEDEBUG
  551                 if (ifp->if_flags & IFF_DEBUG)
  552                         sc->sc_flags |= LE_DEBUG;
  553                 else
  554                         sc->sc_flags &= ~LE_DEBUG;
  555 #endif
  556                 LE_UNLOCK(sc);
  557                 break;
  558 
  559         case SIOCADDMULTI:
  560         case SIOCDELMULTI:
  561                 /*
  562                  * Multicast list has changed; set the hardware filter
  563                  * accordingly.
  564                  */
  565                 LE_LOCK(sc);
  566                 if (ifp->if_drv_flags & IFF_DRV_RUNNING)
  567                         lance_init_locked(sc);
  568                 LE_UNLOCK(sc);
  569                 break;
  570 
  571         case SIOCGIFMEDIA:
  572         case SIOCSIFMEDIA:
  573                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
  574                 break;
  575 
  576         default:
  577                 error = ether_ioctl(ifp, cmd, data);
  578                 break;
  579         }
  580 
  581         return (error);
  582 }
  583 
  584 /*
  585  * Set up the logical address filter.
  586  */
  587 void
  588 lance_setladrf(struct lance_softc *sc, uint16_t *af)
  589 {
  590         struct ifnet *ifp = sc->sc_ifp;
  591         struct ifmultiaddr *ifma;
  592         uint32_t crc;
  593 
  594         /*
  595          * Set up multicast address filter by passing all multicast addresses
  596          * through a crc generator, and then using the high order 6 bits as an
  597          * index into the 64 bit logical address filter.  The high order bit
  598          * selects the word, while the rest of the bits select the bit within
  599          * the word.
  600          */
  601 
  602         if (ifp->if_flags & IFF_PROMISC || sc->sc_flags & LE_ALLMULTI) {
  603                 af[0] = af[1] = af[2] = af[3] = 0xffff;
  604                 return;
  605         }
  606 
  607         af[0] = af[1] = af[2] = af[3] = 0x0000;
  608         IF_ADDR_LOCK(ifp);
  609         TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  610                 if (ifma->ifma_addr->sa_family != AF_LINK)
  611                         continue;
  612 
  613                 crc = ether_crc32_le(LLADDR((struct sockaddr_dl *)
  614                     ifma->ifma_addr), ETHER_ADDR_LEN);
  615 
  616                 /* Just want the 6 most significant bits. */
  617                 crc >>= 26;
  618 
  619                 /* Set the corresponding bit in the filter. */
  620                 af[crc >> 4] |= LE_HTOLE16(1 << (crc & 0xf));
  621         }
  622         IF_ADDR_UNLOCK(ifp);
  623 }
  624 
  625 /*
  626  * Routines for accessing the transmit and receive buffers.
  627  * The various CPU and adapter configurations supported by this
  628  * driver require three different access methods for buffers
  629  * and descriptors:
  630  *      (1) contig (contiguous data; no padding),
  631  *      (2) gap2 (two bytes of data followed by two bytes of padding),
  632  *      (3) gap16 (16 bytes of data followed by 16 bytes of padding).
  633  */
  634 
  635 /*
  636  * contig: contiguous data with no padding.
  637  *
  638  * Buffers may have any alignment.
  639  */
  640 
  641 void
  642 lance_copytobuf_contig(struct lance_softc *sc, void *from, int boff, int len)
  643 {
  644         volatile caddr_t buf = sc->sc_mem;
  645 
  646         /*
  647          * Just call memcpy() to do the work.
  648          */
  649         memcpy(buf + boff, from, len);
  650 }
  651 
  652 void
  653 lance_copyfrombuf_contig(struct lance_softc *sc, void *to, int boff, int len)
  654 {
  655         volatile caddr_t buf = sc->sc_mem;
  656 
  657         /*
  658          * Just call memcpy() to do the work.
  659          */
  660         memcpy(to, buf + boff, len);
  661 }
  662 
  663 void
  664 lance_zerobuf_contig(struct lance_softc *sc, int boff, int len)
  665 {
  666         volatile caddr_t buf = sc->sc_mem;
  667 
  668         /*
  669          * Just let memset() do the work
  670          */
  671         memset(buf + boff, 0, len);
  672 }
  673 
  674 #if 0
  675 /*
  676  * Examples only; duplicate these and tweak (if necessary) in
  677  * machine-specific front-ends.
  678  */
  679 
  680 /*
  681  * gap2: two bytes of data followed by two bytes of pad.
  682  *
  683  * Buffers must be 4-byte aligned.  The code doesn't worry about
  684  * doing an extra byte.
  685  */
  686 
  687 static void
  688 lance_copytobuf_gap2(struct lance_softc *sc, void *fromv, int boff, int len)
  689 {
  690         volatile caddr_t buf = sc->sc_mem;
  691         caddr_t from = fromv;
  692         volatile uint16_t *bptr;
  693 
  694         if (boff & 0x1) {
  695                 /* Handle unaligned first byte. */
  696                 bptr = ((volatile uint16_t *)buf) + (boff - 1);
  697                 *bptr = (*from++ << 8) | (*bptr & 0xff);
  698                 bptr += 2;
  699                 len--;
  700         } else
  701                 bptr = ((volatile uint16_t *)buf) + boff;
  702         while (len > 1) {
  703                 *bptr = (from[1] << 8) | (from[0] & 0xff);
  704                 bptr += 2;
  705                 from += 2;
  706                 len -= 2;
  707         }
  708         if (len == 1)
  709                 *bptr = (uint16_t)*from;
  710 }
  711 
  712 static void
  713 lance_copyfrombuf_gap2(struct lance_softc *sc, void *tov, int boff, int len)
  714 {
  715         volatile caddr_t buf = sc->sc_mem;
  716         caddr_t to = tov;
  717         volatile uint16_t *bptr;
  718         uint16_t tmp;
  719 
  720         if (boff & 0x1) {
  721                 /* Handle unaligned first byte. */
  722                 bptr = ((volatile uint16_t *)buf) + (boff - 1);
  723                 *to++ = (*bptr >> 8) & 0xff;
  724                 bptr += 2;
  725                 len--;
  726         } else
  727                 bptr = ((volatile uint16_t *)buf) + boff;
  728         while (len > 1) {
  729                 tmp = *bptr;
  730                 *to++ = tmp & 0xff;
  731                 *to++ = (tmp >> 8) & 0xff;
  732                 bptr += 2;
  733                 len -= 2;
  734         }
  735         if (len == 1)
  736                 *to = *bptr & 0xff;
  737 }
  738 
  739 static void
  740 lance_zerobuf_gap2(struct lance_softc *sc, int boff, int len)
  741 {
  742         volatile caddr_t buf = sc->sc_mem;
  743         volatile uint16_t *bptr;
  744 
  745         if ((unsigned)boff & 0x1) {
  746                 bptr = ((volatile uint16_t *)buf) + (boff - 1);
  747                 *bptr &= 0xff;
  748                 bptr += 2;
  749                 len--;
  750         } else
  751                 bptr = ((volatile uint16_t *)buf) + boff;
  752         while (len > 0) {
  753                 *bptr = 0;
  754                 bptr += 2;
  755                 len -= 2;
  756         }
  757 }
  758 
  759 /*
  760  * gap16: 16 bytes of data followed by 16 bytes of pad.
  761  *
  762  * Buffers must be 32-byte aligned.
  763  */
  764 
  765 static void
  766 lance_copytobuf_gap16(struct lance_softc *sc, void *fromv, int boff, int len)
  767 {
  768         volatile caddr_t buf = sc->sc_mem;
  769         caddr_t bptr, from = fromv;
  770         int xfer;
  771 
  772         bptr = buf + ((boff << 1) & ~0x1f);
  773         boff &= 0xf;
  774         xfer = min(len, 16 - boff);
  775         while (len > 0) {
  776                 memcpy(bptr + boff, from, xfer);
  777                 from += xfer;
  778                 bptr += 32;
  779                 boff = 0;
  780                 len -= xfer;
  781                 xfer = min(len, 16);
  782         }
  783 }
  784 
  785 static void
  786 lance_copyfrombuf_gap16(struct lance_softc *sc, void *tov, int boff, int len)
  787 {
  788         volatile caddr_t buf = sc->sc_mem;
  789         caddr_t bptr, to = tov;
  790         int xfer;
  791 
  792         bptr = buf + ((boff << 1) & ~0x1f);
  793         boff &= 0xf;
  794         xfer = min(len, 16 - boff);
  795         while (len > 0) {
  796                 memcpy(to, bptr + boff, xfer);
  797                 to += xfer;
  798                 bptr += 32;
  799                 boff = 0;
  800                 len -= xfer;
  801                 xfer = min(len, 16);
  802         }
  803 }
  804 
  805 static void
  806 lance_zerobuf_gap16(struct lance_softc *sc, int boff, int len)
  807 {
  808         volatile caddr_t buf = sc->sc_mem;
  809         caddr_t bptr;
  810         int xfer;
  811 
  812         bptr = buf + ((boff << 1) & ~0x1f);
  813         boff &= 0xf;
  814         xfer = min(len, 16 - boff);
  815         while (len > 0) {
  816                 memset(bptr + boff, 0, xfer);
  817                 bptr += 32;
  818                 boff = 0;
  819                 len -= xfer;
  820                 xfer = min(len, 16);
  821         }
  822 }
  823 #endif /* Example only */

Cache object: d98e6be0f96a291838b7dc3a0361223a


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