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

Cache object: fd3bd423e3f91a7b6d46037491875451


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