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 static void lance_start(struct ifnet *);
   98 static void lance_stop(struct lance_softc *);
   99 static void lance_init(void *);
  100 static void lance_watchdog(void *s);
  101 static int lance_mediachange(struct ifnet *);
  102 static void lance_mediastatus(struct ifnet *, struct ifmediareq *);
  103 static int lance_ioctl(struct ifnet *, u_long, caddr_t);
  104 
  105 int
  106 lance_config(struct lance_softc *sc, const char* name, int unit)
  107 {
  108         struct ifnet *ifp;
  109         int i, nbuf;
  110 
  111         if (LE_LOCK_INITIALIZED(sc) == 0)
  112                 return (ENXIO);
  113 
  114         ifp = sc->sc_ifp = if_alloc(IFT_ETHER);
  115         if (ifp == NULL)
  116                 return (ENOSPC);
  117 
  118         callout_init_mtx(&sc->sc_wdog_ch, &sc->sc_mtx, 0);
  119 
  120         /* Initialize ifnet structure. */
  121         ifp->if_softc = sc;
  122         if_initname(ifp, name, unit);
  123         ifp->if_start = lance_start;
  124         ifp->if_ioctl = lance_ioctl;
  125         ifp->if_init = lance_init;
  126         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  127 #ifdef LANCE_REVC_BUG
  128         ifp->if_flags &= ~IFF_MULTICAST;
  129 #endif
  130         ifp->if_baudrate = IF_Mbps(10);
  131         IFQ_SET_MAXLEN(&ifp->if_snd, ifqmaxlen);
  132         ifp->if_snd.ifq_drv_maxlen = ifqmaxlen;
  133         IFQ_SET_READY(&ifp->if_snd);
  134 
  135         /* Initialize ifmedia structures. */
  136         ifmedia_init(&sc->sc_media, 0, lance_mediachange, lance_mediastatus);
  137         if (sc->sc_supmedia != NULL) {
  138                 for (i = 0; i < sc->sc_nsupmedia; i++)
  139                         ifmedia_add(&sc->sc_media, sc->sc_supmedia[i], 0, NULL);
  140                 ifmedia_set(&sc->sc_media, sc->sc_defaultmedia);
  141         } else {
  142                 ifmedia_add(&sc->sc_media,
  143                     IFM_MAKEWORD(IFM_ETHER, IFM_MANUAL, 0, 0), 0, NULL);
  144                 ifmedia_set(&sc->sc_media,
  145                     IFM_MAKEWORD(IFM_ETHER, IFM_MANUAL, 0, 0));
  146         }
  147 
  148         switch (sc->sc_memsize) {
  149         case 8192:
  150                 sc->sc_nrbuf = 4;
  151                 sc->sc_ntbuf = 1;
  152                 break;
  153         case 16384:
  154                 sc->sc_nrbuf = 8;
  155                 sc->sc_ntbuf = 2;
  156                 break;
  157         case 32768:
  158                 sc->sc_nrbuf = 16;
  159                 sc->sc_ntbuf = 4;
  160                 break;
  161         case 65536:
  162                 sc->sc_nrbuf = 32;
  163                 sc->sc_ntbuf = 8;
  164                 break;
  165         case 131072:
  166                 sc->sc_nrbuf = 64;
  167                 sc->sc_ntbuf = 16;
  168                 break;
  169         case 262144:
  170                 sc->sc_nrbuf = 128;
  171                 sc->sc_ntbuf = 32;
  172                 break;
  173         default:
  174                 /* weird memory size; cope with it */
  175                 nbuf = sc->sc_memsize / LEBLEN;
  176                 sc->sc_ntbuf = nbuf / 5;
  177                 sc->sc_nrbuf = nbuf - sc->sc_ntbuf;
  178         }
  179 
  180         if_printf(ifp, "%d receive buffers, %d transmit buffers\n",
  181             sc->sc_nrbuf, sc->sc_ntbuf);
  182 
  183         /* Make sure the chip is stopped. */
  184         LE_LOCK(sc);
  185         lance_stop(sc);
  186         LE_UNLOCK(sc);
  187 
  188         return (0);
  189 }
  190 
  191 void
  192 lance_attach(struct lance_softc *sc)
  193 {
  194         struct ifnet *ifp = sc->sc_ifp;
  195 
  196         /* Attach the interface. */
  197         ether_ifattach(ifp, sc->sc_enaddr);
  198 
  199         /* Claim 802.1q capability. */
  200         ifp->if_hdrlen = sizeof(struct ether_vlan_header);
  201         ifp->if_capabilities |= IFCAP_VLAN_MTU;
  202         ifp->if_capenable |= IFCAP_VLAN_MTU;
  203 }
  204 
  205 void
  206 lance_detach(struct lance_softc *sc)
  207 {
  208         struct ifnet *ifp = sc->sc_ifp;
  209 
  210         LE_LOCK(sc);
  211         lance_stop(sc);
  212         LE_UNLOCK(sc);
  213         callout_drain(&sc->sc_wdog_ch);
  214         ether_ifdetach(ifp);
  215         if_free(ifp);
  216 }
  217 
  218 void
  219 lance_suspend(struct lance_softc *sc)
  220 {
  221 
  222         LE_LOCK(sc);
  223         lance_stop(sc);
  224         LE_UNLOCK(sc);
  225 }
  226 
  227 void
  228 lance_resume(struct lance_softc *sc)
  229 {
  230 
  231         LE_LOCK(sc);
  232         if (sc->sc_ifp->if_flags & IFF_UP)
  233                 lance_init_locked(sc);
  234         LE_UNLOCK(sc);
  235 }
  236 
  237 static void
  238 lance_start(struct ifnet *ifp)
  239 {
  240         struct lance_softc *sc = ifp->if_softc;
  241 
  242         LE_LOCK(sc);
  243         (*sc->sc_start_locked)(sc);
  244         LE_UNLOCK(sc);
  245 }
  246 
  247 static void
  248 lance_stop(struct lance_softc *sc)
  249 {
  250         struct ifnet *ifp = sc->sc_ifp;
  251 
  252         LE_LOCK_ASSERT(sc, MA_OWNED);
  253 
  254         /*
  255          * Mark the interface down and cancel the watchdog timer.
  256          */
  257         ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
  258         callout_stop(&sc->sc_wdog_ch);
  259         sc->sc_wdog_timer = 0;
  260 
  261         (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
  262 }
  263 
  264 static void
  265 lance_init(void *xsc)
  266 {
  267         struct lance_softc *sc = (struct lance_softc *)xsc;
  268 
  269         LE_LOCK(sc);
  270         lance_init_locked(sc);
  271         LE_UNLOCK(sc);
  272 }
  273 
  274 /*
  275  * Initialization of interface; set up initialization block
  276  * and transmit/receive descriptor rings.
  277  */
  278 void
  279 lance_init_locked(struct lance_softc *sc)
  280 {
  281         struct ifnet *ifp = sc->sc_ifp;
  282         u_long a;
  283         int timo;
  284 
  285         LE_LOCK_ASSERT(sc, MA_OWNED);
  286 
  287         (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_STOP);
  288         DELAY(100);
  289 
  290         /* Newer LANCE chips have a reset register. */
  291         if (sc->sc_hwreset)
  292                 (*sc->sc_hwreset)(sc);
  293 
  294         /* Set the correct byte swapping mode, etc. */
  295         (*sc->sc_wrcsr)(sc, LE_CSR3, sc->sc_conf3);
  296 
  297         /* Set the current media. This may require the chip to be stopped. */
  298         if (sc->sc_mediachange)
  299                 (void)(*sc->sc_mediachange)(sc);
  300 
  301         /*
  302          * Update our private copy of the Ethernet address.
  303          * We NEED the copy so we can ensure its alignment!
  304          */
  305         memcpy(sc->sc_enaddr, IF_LLADDR(ifp), ETHER_ADDR_LEN);
  306 
  307         /* Set up LANCE init block. */
  308         (*sc->sc_meminit)(sc);
  309 
  310         /* Give LANCE the physical address of its init block. */
  311         a = sc->sc_addr + LE_INITADDR(sc);
  312         (*sc->sc_wrcsr)(sc, LE_CSR1, a & 0xffff);
  313         (*sc->sc_wrcsr)(sc, LE_CSR2, a >> 16);
  314 
  315         /* Try to initialize the LANCE. */
  316         DELAY(100);
  317         (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INIT);
  318 
  319         /* Wait for initialization to finish. */
  320         for (timo = 100000; timo; timo--)
  321                 if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON)
  322                         break;
  323 
  324         if ((*sc->sc_rdcsr)(sc, LE_CSR0) & LE_C0_IDON) {
  325                 /* Start the LANCE. */
  326                 (*sc->sc_wrcsr)(sc, LE_CSR0, LE_C0_INEA | LE_C0_STRT);
  327                 ifp->if_drv_flags |= IFF_DRV_RUNNING;
  328                 ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
  329                 sc->sc_wdog_timer = 0;
  330                 callout_reset(&sc->sc_wdog_ch, hz, lance_watchdog, sc);
  331                 (*sc->sc_start_locked)(sc);
  332         } else
  333                 if_printf(ifp, "controller failed to initialize\n");
  334 
  335         if (sc->sc_hwinit)
  336                 (*sc->sc_hwinit)(sc);
  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         LE_LOCK_ASSERT(sc, MA_OWNED);
  350 
  351         for (; m; m = n) {
  352                 len = m->m_len;
  353                 if (len == 0) {
  354                         n = m_free(m);
  355                         m = NULL;
  356                         continue;
  357                 }
  358                 (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), boff, len);
  359                 boff += len;
  360                 tlen += len;
  361                 n = m_free(m);
  362                 m = NULL;
  363         }
  364         if (tlen < LEMINSIZE) {
  365                 (*sc->sc_zerobuf)(sc, boff, LEMINSIZE - tlen);
  366                 tlen = LEMINSIZE;
  367         }
  368         return (tlen);
  369 }
  370 
  371 /*
  372  * Pull data off an interface.
  373  * Len is length of data, with local net header stripped.
  374  * We copy the data into mbufs.  When full cluster sized units are present
  375  * we copy into clusters.
  376  */
  377 struct mbuf *
  378 lance_get(struct lance_softc *sc, int boff, int totlen)
  379 {
  380         struct ifnet *ifp = sc->sc_ifp;
  381         struct mbuf *m, *m0, *newm;
  382         caddr_t newdata;
  383         int len;
  384 
  385         if (totlen <= ETHER_HDR_LEN || totlen > LEBLEN - ETHER_CRC_LEN) {
  386 #ifdef LEDEBUG
  387                 if_printf(ifp, "invalid packet size %d; dropping\n", totlen);
  388 #endif
  389                 return (NULL);
  390         }
  391 
  392         MGETHDR(m0, M_NOWAIT, MT_DATA);
  393         if (m0 == NULL)
  394                 return (NULL);
  395         m0->m_pkthdr.rcvif = ifp;
  396         m0->m_pkthdr.len = totlen;
  397         len = MHLEN;
  398         m = m0;
  399 
  400         while (totlen > 0) {
  401                 if (totlen >= MINCLSIZE) {
  402                         if (!(MCLGET(m, M_NOWAIT)))
  403                                 goto bad;
  404                         len = MCLBYTES;
  405                 }
  406 
  407                 if (m == m0) {
  408                         newdata = (caddr_t)
  409                             ALIGN(m->m_data + ETHER_HDR_LEN) - ETHER_HDR_LEN;
  410                         len -= newdata - m->m_data;
  411                         m->m_data = newdata;
  412                 }
  413 
  414                 m->m_len = len = min(totlen, len);
  415                 (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), boff, len);
  416                 boff += len;
  417 
  418                 totlen -= len;
  419                 if (totlen > 0) {
  420                         MGET(newm, M_NOWAIT, MT_DATA);
  421                         if (newm == NULL)
  422                                 goto bad;
  423                         len = MLEN;
  424                         m = m->m_next = newm;
  425                 }
  426         }
  427 
  428         return (m0);
  429 
  430  bad:
  431         m_freem(m0);
  432         return (NULL);
  433 }
  434 
  435 static void
  436 lance_watchdog(void *xsc)
  437 {
  438         struct lance_softc *sc = (struct lance_softc *)xsc;
  439         struct ifnet *ifp = sc->sc_ifp;
  440 
  441         LE_LOCK_ASSERT(sc, MA_OWNED);
  442 
  443         if (sc->sc_wdog_timer == 0 || --sc->sc_wdog_timer != 0) {
  444                 callout_reset(&sc->sc_wdog_ch, hz, lance_watchdog, sc);
  445                 return;
  446         }
  447 
  448         if_printf(ifp, "device timeout\n");
  449         if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
  450         lance_init_locked(sc);
  451 }
  452 
  453 static int
  454 lance_mediachange(struct ifnet *ifp)
  455 {
  456         struct lance_softc *sc = ifp->if_softc;
  457 
  458         if (sc->sc_mediachange) {
  459                 /*
  460                  * For setting the port in LE_CSR15 the PCnet chips must
  461                  * be powered down or stopped and unlike documented may
  462                  * not take effect without an initialization. So don't
  463                  * invoke (*sc_mediachange) directly here but go through
  464                  * lance_init_locked().
  465                  */
  466                 LE_LOCK(sc);
  467                 lance_stop(sc);
  468                 lance_init_locked(sc);
  469                 if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
  470                         (*sc->sc_start_locked)(sc);
  471                 LE_UNLOCK(sc);
  472         }
  473         return (0);
  474 }
  475 
  476 static void
  477 lance_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
  478 {
  479         struct lance_softc *sc = ifp->if_softc;
  480 
  481         LE_LOCK(sc);
  482         if (!(ifp->if_flags & IFF_UP)) {
  483                 LE_UNLOCK(sc);
  484                 return;
  485         }
  486 
  487         ifmr->ifm_status = IFM_AVALID;
  488         if (sc->sc_flags & LE_CARRIER)
  489                 ifmr->ifm_status |= IFM_ACTIVE;
  490 
  491         if (sc->sc_mediastatus)
  492                 (*sc->sc_mediastatus)(sc, ifmr);
  493         LE_UNLOCK(sc);
  494 }
  495 
  496 /*
  497  * Process an ioctl request.
  498  */
  499 static int
  500 lance_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  501 {
  502         struct lance_softc *sc = ifp->if_softc;
  503         struct ifreq *ifr = (struct ifreq *)data;
  504         int error = 0;
  505 
  506         switch (cmd) {
  507         case SIOCSIFFLAGS:
  508                 LE_LOCK(sc);
  509                 if (ifp->if_flags & IFF_PROMISC) {
  510                         if (!(sc->sc_flags & LE_PROMISC)) {
  511                                 sc->sc_flags |= LE_PROMISC;
  512                                 lance_init_locked(sc);
  513                         }
  514                 } else if (sc->sc_flags & LE_PROMISC) {
  515                         sc->sc_flags &= ~LE_PROMISC;
  516                         lance_init_locked(sc);
  517                 }
  518 
  519                 if ((ifp->if_flags & IFF_ALLMULTI) &&
  520                     !(sc->sc_flags & LE_ALLMULTI)) {
  521                         sc->sc_flags |= LE_ALLMULTI;
  522                         lance_init_locked(sc);
  523                 } else if (!(ifp->if_flags & IFF_ALLMULTI) &&
  524                     (sc->sc_flags & LE_ALLMULTI)) {
  525                         sc->sc_flags &= ~LE_ALLMULTI;
  526                         lance_init_locked(sc);
  527                 }
  528 
  529                 if (!(ifp->if_flags & IFF_UP) &&
  530                     ifp->if_drv_flags & IFF_DRV_RUNNING) {
  531                         /*
  532                          * If interface is marked down and it is running, then
  533                          * stop it.
  534                          */
  535                         lance_stop(sc);
  536                 } else if (ifp->if_flags & IFF_UP &&
  537                     !(ifp->if_drv_flags & IFF_DRV_RUNNING)) {
  538                         /*
  539                          * If interface is marked up and it is stopped, then
  540                          * start it.
  541                          */
  542                         lance_init_locked(sc);
  543                 }
  544 #ifdef LEDEBUG
  545                 if (ifp->if_flags & IFF_DEBUG)
  546                         sc->sc_flags |= LE_DEBUG;
  547                 else
  548                         sc->sc_flags &= ~LE_DEBUG;
  549 #endif
  550                 LE_UNLOCK(sc);
  551                 break;
  552 
  553         case SIOCADDMULTI:
  554         case SIOCDELMULTI:
  555                 /*
  556                  * Multicast list has changed; set the hardware filter
  557                  * accordingly.
  558                  */
  559                 LE_LOCK(sc);
  560                 if (ifp->if_drv_flags & IFF_DRV_RUNNING)
  561                         lance_init_locked(sc);
  562                 LE_UNLOCK(sc);
  563                 break;
  564 
  565         case SIOCGIFMEDIA:
  566         case SIOCSIFMEDIA:
  567                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
  568                 break;
  569 
  570         default:
  571                 error = ether_ioctl(ifp, cmd, data);
  572                 break;
  573         }
  574 
  575         return (error);
  576 }
  577 
  578 struct lance_hash_maddr_ctx {
  579         struct lance_softc *sc;
  580         uint16_t *af;
  581 };
  582 
  583 static u_int
  584 lance_hash_maddr(void *arg, struct sockaddr_dl *sdl, u_int cnt)
  585 {
  586         struct lance_hash_maddr_ctx *ctx = arg;
  587         struct lance_softc *sc = ctx->sc;
  588         uint32_t crc;
  589 
  590         crc = ether_crc32_le(LLADDR(sdl), ETHER_ADDR_LEN);
  591         /* Just want the 6 most significant bits. */
  592         crc >>= 26;
  593         /* Set the corresponding bit in the filter. */
  594         ctx->af[crc >> 4] |= LE_HTOLE16(1 << (crc & 0xf));
  595 
  596         return (1);
  597 }
  598 
  599 /*
  600  * Set up the logical address filter.
  601  */
  602 void
  603 lance_setladrf(struct lance_softc *sc, uint16_t *af)
  604 {
  605         struct ifnet *ifp = sc->sc_ifp;
  606         struct lance_hash_maddr_ctx ctx = { sc, af };
  607 
  608         /*
  609          * Set up multicast address filter by passing all multicast addresses
  610          * through a crc generator, and then using the high order 6 bits as an
  611          * index into the 64 bit logical address filter.  The high order bit
  612          * selects the word, while the rest of the bits select the bit within
  613          * the word.
  614          */
  615 
  616         if (ifp->if_flags & IFF_PROMISC || sc->sc_flags & LE_ALLMULTI) {
  617                 af[0] = af[1] = af[2] = af[3] = 0xffff;
  618                 return;
  619         }
  620 
  621         af[0] = af[1] = af[2] = af[3] = 0x0000;
  622         if_foreach_llmaddr(ifp, lance_hash_maddr, &ctx);
  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: a2f21616d8400bccf62c57a0b2b817f4


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