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/snc/dp83932.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 /*      $FreeBSD: releng/5.3/sys/dev/snc/dp83932.c 133698 2004-08-13 23:47:01Z rwatson $        */
    2 /*      $NecBSD: dp83932.c,v 1.5 1999/07/29 05:08:44 kmatsuda Exp $     */
    3 /*      $NetBSD: if_snc.c,v 1.18 1998/04/25 21:27:40 scottr Exp $       */
    4 
    5 /*
    6  * Copyright (c) 1997, 1998, 1999
    7  *      Kouichi Matsuda.  All rights reserved.
    8  *
    9  * Redistribution and use in source and binary forms, with or without
   10  * modification, are permitted provided that the following conditions
   11  * are met:
   12  * 1. Redistributions of source code must retain the above copyright
   13  *    notice, this list of conditions and the following disclaimer.
   14  * 2. Redistributions in binary form must reproduce the above copyright
   15  *    notice, this list of conditions and the following disclaimer in the
   16  *    documentation and/or other materials provided with the distribution.
   17  * 3. All advertising materials mentioning features or use of this software
   18  *    must display the following acknowledgement:
   19  *      This product includes software developed by Kouichi Matsuda for
   20  *      NetBSD/pc98.
   21  * 4. The name of the author may not be used to endorse or promote products
   22  *    derived from this software without specific prior written permission
   23  *
   24  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   25  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   26  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   27  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   28  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   29  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   30  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   31  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   32  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   33  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   34  */
   35 
   36 /*
   37  * Modified for FreeBSD(98) 4.0 from NetBSD/pc98 1.4.2 by Motomichi Matsuzaki.
   38  */
   39 
   40 /*
   41  * Modified for NetBSD/pc98 1.2G from NetBSD/mac68k 1.2G by Kouichi Matsuda.
   42  * Make adapted for NEC PC-9801-83, 84, PC-9801-103, 104, PC-9801N-25 and
   43  * PC-9801N-J02, J02R, which uses National Semiconductor DP83934AVQB as
   44  * Ethernet Controller and National Semiconductor NS46C46 as
   45  * (64 * 16 bits) Microwire Serial EEPROM.
   46  */
   47 
   48 /*
   49  * National Semiconductor  DP8393X SONIC Driver
   50  * Copyright (c) 1991   Algorithmics Ltd (http://www.algor.co.uk)
   51  * You may use, copy, and modify this program so long as you retain the
   52  * copyright line.
   53  *
   54  * This driver has been substantially modified since Algorithmics donated
   55  * it.
   56  *
   57  *   Denton Gentry <denny1@home.com>
   58  * and also
   59  *   Yanagisawa Takeshi <yanagisw@aa.ap.titech.ac.jp>
   60  * did the work to get this running on the Macintosh.
   61  */
   62 
   63 #include "opt_inet.h"
   64 
   65 #include <sys/param.h>
   66 #include <sys/systm.h>
   67 #include <sys/sockio.h>
   68 #include <sys/mbuf.h>
   69 #include <sys/protosw.h>
   70 #include <sys/socket.h>
   71 #include <sys/syslog.h>
   72 #include <sys/errno.h>
   73 #if NRND > 0
   74 #include <sys/rnd.h>
   75 #endif
   76 
   77 #include <net/ethernet.h>
   78 #include <net/if.h>
   79 #include <net/if_arp.h>
   80 #include <net/if_dl.h>
   81 #include <net/if_media.h>
   82 
   83 #include <net/bpf.h>
   84 
   85 #include <sys/bus.h>
   86 #include <machine/bus.h>
   87 #include <dev/snc/dp83932reg.h>
   88 #include <dev/snc/dp83932var.h>
   89 
   90 hide void       sncwatchdog(struct ifnet *);
   91 hide void       sncinit(void *);
   92 hide int        sncstop(struct snc_softc *sc);
   93 hide int        sncioctl(struct ifnet *ifp, u_long cmd, caddr_t data);
   94 hide void       sncstart(struct ifnet *ifp);
   95 hide void       sncreset(struct snc_softc *sc);
   96 
   97 hide void       caminitialise(struct snc_softc *);
   98 hide void       camentry(struct snc_softc *, int, u_char *ea);
   99 hide void       camprogram(struct snc_softc *);
  100 hide void       initialise_tda(struct snc_softc *);
  101 hide void       initialise_rda(struct snc_softc *);
  102 hide void       initialise_rra(struct snc_softc *);
  103 #ifdef SNCDEBUG
  104 hide void       camdump(struct snc_softc *sc);
  105 #endif
  106 
  107 hide void       sonictxint(struct snc_softc *);
  108 hide void       sonicrxint(struct snc_softc *);
  109 
  110 hide u_int      sonicput(struct snc_softc *sc, struct mbuf *m0, int mtd_next);
  111 hide int        sonic_read(struct snc_softc *, u_int32_t, int);
  112 hide struct mbuf *sonic_get(struct snc_softc *, u_int32_t, int);
  113 
  114 int     snc_enable(struct snc_softc *);
  115 void    snc_disable(struct snc_softc *);
  116 
  117 int     snc_mediachange(struct ifnet *);
  118 void    snc_mediastatus(struct ifnet *, struct ifmediareq *);
  119 
  120 #ifdef NetBSD
  121 #if NetBSD <= 199714
  122 struct cfdriver snc_cd = {
  123         NULL, "snc", DV_IFNET
  124 };
  125 #endif
  126 #endif
  127 
  128 #undef assert
  129 #undef _assert
  130 
  131 #ifdef NDEBUG
  132 #define assert(e)       ((void)0)
  133 #define _assert(e)      ((void)0)
  134 #else
  135 #define _assert(e)      assert(e)
  136 #ifdef __STDC__
  137 #define assert(e)       ((e) ? (void)0 : __assert("snc ", __FILE__, __LINE__, #e))
  138 #else   /* PCC */
  139 #define assert(e)       ((e) ? (void)0 : __assert("snc "__FILE__, __LINE__, "e"))
  140 #endif
  141 #endif
  142 
  143 #ifdef  SNCDEBUG
  144 #define SNC_SHOWTXHDR   0x01    /* show tx ether_header */
  145 #define SNC_SHOWRXHDR   0x02    /* show rx ether_header */
  146 #define SNC_SHOWCAMENT  0x04    /* show CAM entry */
  147 #endif  /* SNCDEBUG */
  148 int sncdebug = 0;
  149 
  150 
  151 void
  152 sncconfig(sc, media, nmedia, defmedia, myea)
  153         struct snc_softc *sc;
  154         int *media, nmedia, defmedia;
  155         u_int8_t *myea;
  156 {
  157         struct ifnet *ifp = &sc->sc_if;
  158         int i;
  159 
  160 #ifdef SNCDEBUG
  161         if ((sncdebug & SNC_SHOWCAMENT) != 0) {
  162                 camdump(sc);
  163         }
  164 #endif
  165 
  166 #ifdef SNCDEBUG
  167         device_printf(sc->sc_dev,
  168                       "buffers: rra=0x%x cda=0x%x rda=0x%x tda=0x%x\n",
  169                       sc->v_rra[0], sc->v_cda,
  170                       sc->v_rda, sc->mtda[0].mtd_vtxp);
  171 #endif
  172 
  173         ifp->if_softc = sc;
  174         if_initname(ifp, device_get_name(sc->sc_dev),
  175             device_get_unit(sc->sc_dev));
  176         ifp->if_ioctl = sncioctl;
  177         ifp->if_start = sncstart;
  178         ifp->if_flags =
  179             IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST | IFF_NEEDSGIANT;
  180         ifp->if_watchdog = sncwatchdog;
  181         ifp->if_init = sncinit;
  182         ifp->if_mtu = ETHERMTU;
  183         ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
  184         bcopy(myea, sc->sc_ethercom.ac_enaddr, ETHER_ADDR_LEN);
  185 
  186         /* Initialize media goo. */
  187         ifmedia_init(&sc->sc_media, 0, snc_mediachange,
  188             snc_mediastatus);
  189         if (media != NULL) {
  190                 for (i = 0; i < nmedia; i++)
  191                         ifmedia_add(&sc->sc_media, media[i], 0, NULL);
  192                 ifmedia_set(&sc->sc_media, defmedia);
  193         } else {
  194                 ifmedia_add(&sc->sc_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
  195                 ifmedia_set(&sc->sc_media, IFM_ETHER|IFM_MANUAL);
  196         }
  197 
  198         ether_ifattach(ifp, myea);
  199 
  200 #if NRND > 0
  201         rnd_attach_source(&sc->rnd_source, device_get_nameunit(sc->sc_dev),
  202             RND_TYPE_NET, 0);
  203 #endif
  204 }
  205 
  206 void
  207 sncshutdown(arg)
  208         void *arg;
  209 {
  210 
  211         sncstop((struct snc_softc *)arg);
  212 }
  213 
  214 /*
  215  * Media change callback.
  216  */
  217 int
  218 snc_mediachange(ifp)
  219         struct ifnet *ifp;
  220 {
  221         struct snc_softc *sc = ifp->if_softc;
  222 
  223         if (sc->sc_mediachange)
  224                 return ((*sc->sc_mediachange)(sc));
  225         return (EINVAL);
  226 }
  227 
  228 /*
  229  * Media status callback.
  230  */
  231 void
  232 snc_mediastatus(ifp, ifmr)
  233         struct ifnet *ifp;
  234         struct ifmediareq *ifmr;
  235 {
  236         struct snc_softc *sc = ifp->if_softc;
  237 
  238         if (sc->sc_enabled == 0) {
  239                 ifmr->ifm_active = IFM_ETHER | IFM_NONE;
  240                 ifmr->ifm_status = 0;
  241                 return;
  242         }
  243 
  244         if (sc->sc_mediastatus)
  245                 (*sc->sc_mediastatus)(sc, ifmr);
  246 }
  247 
  248 
  249 hide int
  250 sncioctl(ifp, cmd, data)
  251         struct ifnet *ifp;
  252         u_long cmd;
  253         caddr_t data;
  254 {
  255         struct ifreq *ifr;
  256         struct snc_softc *sc = ifp->if_softc;
  257         int     s = splhardnet(), err = 0;
  258         int     temp;
  259 
  260         switch (cmd) {
  261 
  262         case SIOCSIFFLAGS:
  263                 if ((ifp->if_flags & IFF_UP) == 0 &&
  264                     (ifp->if_flags & IFF_RUNNING) != 0) {
  265                         /*
  266                          * If interface is marked down and it is running,
  267                          * then stop it.
  268                          */
  269                         sncstop(sc);
  270                         ifp->if_flags &= ~IFF_RUNNING;
  271                         snc_disable(sc);
  272                 } else if ((ifp->if_flags & IFF_UP) != 0 &&
  273                     (ifp->if_flags & IFF_RUNNING) == 0) {
  274                         /*
  275                          * If interface is marked up and it is stopped,
  276                          * then start it.
  277                          */
  278                         if ((err = snc_enable(sc)) != 0)
  279                                 break;
  280                         sncinit(sc);
  281                 } else if (sc->sc_enabled) {
  282                         /*
  283                          * reset the interface to pick up any other changes
  284                          * in flags
  285                          */
  286                         temp = ifp->if_flags & IFF_UP;
  287                         sncreset(sc);
  288                         ifp->if_flags |= temp;
  289                         sncstart(ifp);
  290                 }
  291                 break;
  292 
  293         case SIOCADDMULTI:
  294         case SIOCDELMULTI:
  295                 if (sc->sc_enabled == 0) {
  296                         err = EIO;
  297                         break;
  298                 }
  299                 temp = ifp->if_flags & IFF_UP;
  300                 sncreset(sc);
  301                 ifp->if_flags |= temp;
  302                 err = 0;
  303                 break;
  304         case SIOCGIFMEDIA:
  305         case SIOCSIFMEDIA:
  306                 ifr = (struct ifreq *) data;
  307                 err = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
  308                 break;
  309         default:
  310                 err = ether_ioctl(ifp, cmd, data);
  311                 break;
  312         }
  313         splx(s);
  314         return (err);
  315 }
  316 
  317 /*
  318  * Encapsulate a packet of type family for the local net.
  319  */
  320 hide void
  321 sncstart(ifp)
  322         struct ifnet *ifp;
  323 {
  324         struct snc_softc        *sc = ifp->if_softc;
  325         struct mbuf     *m;
  326         int             mtd_next;
  327 
  328         if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
  329                 return;
  330 
  331 outloop:
  332         /* Check for room in the xmit buffer. */
  333         if ((mtd_next = (sc->mtd_free + 1)) == NTDA)
  334                 mtd_next = 0;
  335 
  336         if (mtd_next == sc->mtd_hw) {
  337                 ifp->if_flags |= IFF_OACTIVE;
  338                 return;
  339         }
  340 
  341         IF_DEQUEUE(&ifp->if_snd, m);
  342         if (m == 0)
  343                 return;
  344 
  345         /* We need the header for m_pkthdr.len. */
  346         M_ASSERTPKTHDR(m);
  347 
  348         /*
  349          * If bpf is listening on this interface, let it
  350          * see the packet before we commit it to the wire.
  351          */
  352         BPF_MTAP(ifp, m);
  353 
  354         /*
  355          * If there is nothing in the o/p queue, and there is room in
  356          * the Tx ring, then send the packet directly.  Otherwise append
  357          * it to the o/p queue.
  358          */
  359         if ((sonicput(sc, m, mtd_next)) == 0) {
  360                 IF_PREPEND(&ifp->if_snd, m);
  361                 return;
  362         }
  363 
  364         sc->mtd_prev = sc->mtd_free;
  365         sc->mtd_free = mtd_next;
  366 
  367         ifp->if_opackets++;             /* # of pkts */
  368 
  369         /* Jump back for possibly more punishment. */
  370         goto outloop;
  371 }
  372 
  373 /*
  374  * reset and restart the SONIC.  Called in case of fatal
  375  * hardware/software errors.
  376  */
  377 hide void
  378 sncreset(sc)
  379         struct snc_softc *sc;
  380 {
  381         sncstop(sc);
  382         sncinit(sc);
  383 }
  384 
  385 hide void
  386 sncinit(xsc)
  387         void *xsc;
  388 {
  389         struct snc_softc *sc = xsc;
  390         u_long  s_rcr;
  391         int     s;
  392 
  393         if (sc->sc_if.if_flags & IFF_RUNNING)
  394                 /* already running */
  395                 return;
  396 
  397         s = splhardnet();
  398 
  399         NIC_PUT(sc, SNCR_CR, CR_RST);   /* DCR only accessable in reset mode! */
  400 
  401         /* config it */
  402         NIC_PUT(sc, SNCR_DCR, (sc->sncr_dcr |
  403                 (sc->bitmode ? DCR_DW32 : DCR_DW16)));
  404         NIC_PUT(sc, SNCR_DCR2, sc->sncr_dcr2);
  405 
  406         s_rcr = RCR_BRD | RCR_LBNONE;
  407         if (sc->sc_if.if_flags & IFF_PROMISC)
  408                 s_rcr |= RCR_PRO;
  409         if (sc->sc_if.if_flags & IFF_ALLMULTI)
  410                 s_rcr |= RCR_AMC;
  411         NIC_PUT(sc, SNCR_RCR, s_rcr);
  412 
  413         NIC_PUT(sc, SNCR_IMR, (IMR_PRXEN | IMR_PTXEN | IMR_TXEREN | IMR_LCDEN));
  414 
  415         /* clear pending interrupts */
  416         NIC_PUT(sc, SNCR_ISR, ISR_ALL);
  417 
  418         /* clear tally counters */
  419         NIC_PUT(sc, SNCR_CRCT, -1);
  420         NIC_PUT(sc, SNCR_FAET, -1);
  421         NIC_PUT(sc, SNCR_MPT, -1);
  422 
  423         initialise_tda(sc);
  424         initialise_rda(sc);
  425         initialise_rra(sc);
  426 
  427         /* enable the chip */
  428         NIC_PUT(sc, SNCR_CR, 0);
  429         wbflush();
  430 
  431         /* program the CAM */
  432         camprogram(sc);
  433 
  434         /* get it to read resource descriptors */
  435         NIC_PUT(sc, SNCR_CR, CR_RRRA);
  436         wbflush();
  437         while ((NIC_GET(sc, SNCR_CR)) & CR_RRRA)
  438                 continue;
  439 
  440         /* enable rx */
  441         NIC_PUT(sc, SNCR_CR, CR_RXEN);
  442         wbflush();
  443 
  444         /* flag interface as "running" */
  445         sc->sc_if.if_flags |= IFF_RUNNING;
  446         sc->sc_if.if_flags &= ~IFF_OACTIVE;
  447 
  448         splx(s);
  449         return;
  450 }
  451 
  452 /*
  453  * close down an interface and free its buffers
  454  * Called on final close of device, or if sncinit() fails
  455  * part way through.
  456  */
  457 hide int
  458 sncstop(sc)
  459         struct snc_softc *sc;
  460 {
  461         struct mtd *mtd;
  462         int     s = splhardnet();
  463 
  464         /* stick chip in reset */
  465         NIC_PUT(sc, SNCR_CR, CR_RST);
  466         wbflush();
  467 
  468         /* free all receive buffers (currently static so nothing to do) */
  469 
  470         /* free all pending transmit mbufs */
  471         while (sc->mtd_hw != sc->mtd_free) {
  472                 mtd = &sc->mtda[sc->mtd_hw];
  473                 if (mtd->mtd_mbuf)
  474                         m_freem(mtd->mtd_mbuf);
  475                 if (++sc->mtd_hw == NTDA) sc->mtd_hw = 0;
  476         }
  477 
  478         sc->sc_if.if_timer = 0;
  479         sc->sc_if.if_flags &= ~(IFF_RUNNING | IFF_UP);
  480 
  481         splx(s);
  482         return (0);
  483 }
  484 
  485 /*
  486  * Called if any Tx packets remain unsent after 5 seconds,
  487  * In all cases we just reset the chip, and any retransmission
  488  * will be handled by higher level protocol timeouts.
  489  */
  490 hide void
  491 sncwatchdog(ifp)
  492         struct ifnet *ifp;
  493 {
  494         struct snc_softc *sc = ifp->if_softc;
  495         struct mtd *mtd;
  496         int     temp;
  497 
  498         if (sc->mtd_hw != sc->mtd_free) {
  499                 /* something still pending for transmit */
  500                 mtd = &sc->mtda[sc->mtd_hw];
  501                 if (SRO(sc, mtd->mtd_vtxp, TXP_STATUS) == 0)
  502                         log(LOG_ERR, "%s: Tx - timeout\n",
  503                             device_get_nameunit(sc->sc_dev));
  504                 else
  505                         log(LOG_ERR, "%s: Tx - lost interrupt\n",
  506                             device_get_nameunit(sc->sc_dev));
  507                 temp = ifp->if_flags & IFF_UP;
  508                 sncreset(sc);
  509                 ifp->if_flags |= temp;
  510         }
  511 }
  512 
  513 /*
  514  * stuff packet into sonic (at splnet)
  515  */
  516 hide u_int
  517 sonicput(sc, m0, mtd_next)
  518         struct snc_softc *sc;
  519         struct mbuf *m0;
  520         int mtd_next;
  521 {
  522         struct mtd *mtdp;
  523         struct mbuf *m;
  524         u_int32_t buff;
  525         u_int32_t txp;
  526         u_int   len = 0;
  527         u_int   totlen = 0;
  528 
  529 #ifdef whyonearthwouldyoudothis
  530         if (NIC_GET(sc, SNCR_CR) & CR_TXP)
  531                 return (0);
  532 #endif
  533 
  534         /* grab the replacement mtd */
  535         mtdp = &sc->mtda[sc->mtd_free];
  536 
  537         buff = mtdp->mtd_vbuf;
  538         
  539         /* this packet goes to mtdnext fill in the TDA */
  540         mtdp->mtd_mbuf = m0;
  541         txp = mtdp->mtd_vtxp;
  542 
  543         /* Write to the config word. Every (NTDA/2)+1 packets we set an intr */
  544         if (sc->mtd_pint == 0) {
  545                 sc->mtd_pint = NTDA/2;
  546                 SWO(sc, txp, TXP_CONFIG, TCR_PINT);
  547         } else {
  548                 sc->mtd_pint--;
  549                 SWO(sc, txp, TXP_CONFIG, 0);
  550         }
  551 
  552         for (m = m0; m; m = m->m_next) {
  553                 len = m->m_len;
  554                 totlen += len;
  555                 (*sc->sc_copytobuf)(sc, mtod(m, caddr_t), buff, len);
  556                 buff += len;
  557         }
  558         if (totlen >= TXBSIZE) {
  559                 panic("%s: sonicput: packet overflow",
  560                       device_get_nameunit(sc->sc_dev));
  561         }
  562 
  563         SWO(sc, txp, TXP_FRAGOFF + (0 * TXP_FRAGSIZE) + TXP_FPTRLO,
  564             LOWER(mtdp->mtd_vbuf));
  565         SWO(sc, txp, TXP_FRAGOFF + (0 * TXP_FRAGSIZE) + TXP_FPTRHI,
  566             UPPER(mtdp->mtd_vbuf));
  567 
  568         if (totlen < ETHERMIN + sizeof(struct ether_header)) {
  569                 int pad = ETHERMIN + sizeof(struct ether_header) - totlen;
  570                 (*sc->sc_zerobuf)(sc, mtdp->mtd_vbuf + totlen, pad);
  571                 totlen = ETHERMIN + sizeof(struct ether_header);
  572         }
  573 
  574         SWO(sc, txp, TXP_FRAGOFF + (0 * TXP_FRAGSIZE) + TXP_FSIZE,
  575             totlen);
  576         SWO(sc, txp, TXP_FRAGCNT, 1);
  577         SWO(sc, txp, TXP_PKTSIZE, totlen);
  578 
  579         /* link onto the next mtd that will be used */
  580         SWO(sc, txp, TXP_FRAGOFF + (1 * TXP_FRAGSIZE) + TXP_FPTRLO,
  581             LOWER(sc->mtda[mtd_next].mtd_vtxp) | EOL);
  582 
  583         /*
  584          * The previous txp.tlink currently contains a pointer to
  585          * our txp | EOL. Want to clear the EOL, so write our
  586          * pointer to the previous txp.
  587          */
  588         SWO(sc, sc->mtda[sc->mtd_prev].mtd_vtxp, sc->mtd_tlinko,
  589             LOWER(mtdp->mtd_vtxp));
  590 
  591         /* make sure chip is running */
  592         wbflush();
  593         NIC_PUT(sc, SNCR_CR, CR_TXP);
  594         wbflush();
  595         sc->sc_if.if_timer = 5; /* 5 seconds to watch for failing to transmit */
  596 
  597         return (totlen);
  598 }
  599 
  600 /*
  601  * These are called from sonicioctl() when /etc/ifconfig is run to set
  602  * the address or switch the i/f on.
  603  */
  604 /*
  605  * CAM support
  606  */
  607 hide void
  608 caminitialise(sc)
  609         struct snc_softc *sc;
  610 {
  611         u_int32_t v_cda = sc->v_cda;
  612         int     i;
  613         int     camoffset;
  614 
  615         for (i = 0; i < MAXCAM; i++) {
  616                 camoffset = i * CDA_CAMDESC;
  617                 SWO(sc, v_cda, (camoffset + CDA_CAMEP), i);
  618                 SWO(sc, v_cda, (camoffset + CDA_CAMAP2), 0);
  619                 SWO(sc, v_cda, (camoffset + CDA_CAMAP1), 0);
  620                 SWO(sc, v_cda, (camoffset + CDA_CAMAP0), 0);
  621         }
  622         SWO(sc, v_cda, CDA_ENABLE, 0);
  623 
  624 #ifdef SNCDEBUG
  625         if ((sncdebug & SNC_SHOWCAMENT) != 0) {
  626                 camdump(sc);
  627         }
  628 #endif
  629 }
  630 
  631 hide void
  632 camentry(sc, entry, ea)
  633         int entry;
  634         u_char *ea;
  635         struct snc_softc *sc;
  636 {
  637         u_int32_t v_cda = sc->v_cda;
  638         int     camoffset = entry * CDA_CAMDESC;
  639 
  640         SWO(sc, v_cda, camoffset + CDA_CAMEP, entry);
  641         SWO(sc, v_cda, camoffset + CDA_CAMAP2, (ea[5] << 8) | ea[4]);
  642         SWO(sc, v_cda, camoffset + CDA_CAMAP1, (ea[3] << 8) | ea[2]);
  643         SWO(sc, v_cda, camoffset + CDA_CAMAP0, (ea[1] << 8) | ea[0]);
  644         SWO(sc, v_cda, CDA_ENABLE, 
  645             (SRO(sc, v_cda, CDA_ENABLE) | (1 << entry)));
  646 }
  647 
  648 hide void
  649 camprogram(sc)
  650         struct snc_softc *sc;
  651 {
  652         struct ifmultiaddr      *ifma;
  653         struct ifnet *ifp;
  654         int     timeout;
  655         int     mcount = 0;
  656 
  657         caminitialise(sc);
  658 
  659         ifp = &sc->sc_if;
  660 
  661         /* Always load our own address first. */
  662         camentry (sc, mcount, sc->sc_ethercom.ac_enaddr);
  663         mcount++;
  664 
  665         /* Assume we won't need allmulti bit. */
  666         ifp->if_flags &= ~IFF_ALLMULTI;
  667 
  668         /* Loop through multicast addresses */
  669         TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  670                 if (ifma->ifma_addr->sa_family != AF_LINK)
  671                         continue;
  672                 if (mcount == MAXCAM) {
  673                          ifp->if_flags |= IFF_ALLMULTI;
  674                          break;
  675                 }
  676 
  677                 /* program the CAM with the specified entry */
  678                 camentry(sc, mcount,
  679                          LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
  680                 mcount++;
  681         }
  682 
  683         NIC_PUT(sc, SNCR_CDP, LOWER(sc->v_cda));
  684         NIC_PUT(sc, SNCR_CDC, MAXCAM);
  685         NIC_PUT(sc, SNCR_CR, CR_LCAM);
  686         wbflush();
  687 
  688         timeout = 10000;
  689         while ((NIC_GET(sc, SNCR_CR) & CR_LCAM) && timeout--)
  690                 continue;
  691         if (timeout == 0) {
  692                 /* XXX */
  693                 panic("%s: CAM initialisation failed\n",
  694                       device_get_nameunit(sc->sc_dev));
  695         }
  696         timeout = 10000;
  697         while (((NIC_GET(sc, SNCR_ISR) & ISR_LCD) == 0) && timeout--)
  698                 continue;
  699 
  700         if (NIC_GET(sc, SNCR_ISR) & ISR_LCD)
  701                 NIC_PUT(sc, SNCR_ISR, ISR_LCD);
  702         else
  703                 device_printf(sc->sc_dev,
  704                               "CAM initialisation without interrupt\n");
  705 }
  706 
  707 #ifdef SNCDEBUG
  708 hide void
  709 camdump(sc)
  710         struct snc_softc *sc;
  711 {
  712         int     i;
  713 
  714         printf("CAM entries:\n");
  715         NIC_PUT(sc, SNCR_CR, CR_RST);
  716         wbflush();
  717 
  718         for (i = 0; i < 16; i++) {
  719                 u_short  ap2, ap1, ap0;
  720                 NIC_PUT(sc, SNCR_CEP, i);
  721                 wbflush();
  722                 ap2 = NIC_GET(sc, SNCR_CAP2);
  723                 ap1 = NIC_GET(sc, SNCR_CAP1);
  724                 ap0 = NIC_GET(sc, SNCR_CAP0);
  725                 printf("%d: ap2=0x%x ap1=0x%x ap0=0x%x\n", i, ap2, ap1, ap0);
  726         }
  727         printf("CAM enable 0x%x\n", NIC_GET(sc, SNCR_CEP));
  728 
  729         NIC_PUT(sc, SNCR_CR, 0);
  730         wbflush();
  731 }
  732 #endif
  733 
  734 hide void
  735 initialise_tda(sc)
  736         struct snc_softc *sc;
  737 {
  738         struct mtd *mtd;
  739         int     i;
  740 
  741         for (i = 0; i < NTDA; i++) {
  742                 mtd = &sc->mtda[i];
  743                 mtd->mtd_mbuf = 0;
  744         }
  745 
  746         sc->mtd_hw = 0;
  747         sc->mtd_prev = NTDA - 1;
  748         sc->mtd_free = 0;
  749         sc->mtd_tlinko = TXP_FRAGOFF + 1*TXP_FRAGSIZE + TXP_FPTRLO;
  750         sc->mtd_pint = NTDA/2;
  751 
  752         NIC_PUT(sc, SNCR_UTDA, UPPER(sc->mtda[0].mtd_vtxp));
  753         NIC_PUT(sc, SNCR_CTDA, LOWER(sc->mtda[0].mtd_vtxp));
  754 }
  755 
  756 hide void
  757 initialise_rda(sc)
  758         struct snc_softc *sc;
  759 {
  760         int             i;
  761         u_int32_t       vv_rda = 0;
  762         u_int32_t       v_rda = 0;
  763 
  764         /* link the RDA's together into a circular list */
  765         for (i = 0; i < (sc->sc_nrda - 1); i++) {
  766                 v_rda = sc->v_rda + (i * RXPKT_SIZE(sc));
  767                 vv_rda = sc->v_rda + ((i+1) * RXPKT_SIZE(sc));
  768                 SWO(sc, v_rda, RXPKT_RLINK, LOWER(vv_rda));
  769                 SWO(sc, v_rda, RXPKT_INUSE, 1);
  770         }
  771         v_rda = sc->v_rda + ((sc->sc_nrda - 1) * RXPKT_SIZE(sc));
  772         SWO(sc, v_rda, RXPKT_RLINK, LOWER(sc->v_rda) | EOL);
  773         SWO(sc, v_rda, RXPKT_INUSE, 1);
  774 
  775         /* mark end of receive descriptor list */
  776         sc->sc_rdamark = sc->sc_nrda - 1;
  777 
  778         sc->sc_rxmark = 0;
  779 
  780         NIC_PUT(sc, SNCR_URDA, UPPER(sc->v_rda));
  781         NIC_PUT(sc, SNCR_CRDA, LOWER(sc->v_rda));
  782         wbflush();
  783 }
  784 
  785 hide void
  786 initialise_rra(sc)
  787         struct snc_softc *sc;
  788 {
  789         int     i;
  790         u_int   v;
  791         int     bitmode = sc->bitmode;
  792 
  793         if (bitmode)
  794                 NIC_PUT(sc, SNCR_EOBC, RBASIZE(sc) / 2 - 2);
  795         else
  796                 NIC_PUT(sc, SNCR_EOBC, RBASIZE(sc) / 2 - 1);
  797 
  798         NIC_PUT(sc, SNCR_URRA, UPPER(sc->v_rra[0]));
  799         NIC_PUT(sc, SNCR_RSA, LOWER(sc->v_rra[0]));
  800         /* rea must point just past the end of the rra space */
  801         NIC_PUT(sc, SNCR_REA, LOWER(sc->v_rea));
  802         NIC_PUT(sc, SNCR_RRP, LOWER(sc->v_rra[0]));
  803         NIC_PUT(sc, SNCR_RSC, 0);
  804 
  805         /* fill up SOME of the rra with buffers */
  806         for (i = 0; i < NRBA; i++) {
  807                 v = SONIC_GETDMA(sc->rbuf[i]);
  808                 SWO(sc, sc->v_rra[i], RXRSRC_PTRHI, UPPER(v));
  809                 SWO(sc, sc->v_rra[i], RXRSRC_PTRLO, LOWER(v));
  810                 SWO(sc, sc->v_rra[i], RXRSRC_WCHI, UPPER(NBPG/2));
  811                 SWO(sc, sc->v_rra[i], RXRSRC_WCLO, LOWER(NBPG/2));
  812         }
  813         sc->sc_rramark = NRBA;
  814         NIC_PUT(sc, SNCR_RWP, LOWER(sc->v_rra[sc->sc_rramark]));
  815         wbflush();
  816 }
  817 
  818 void
  819 sncintr(arg)
  820         void    *arg;
  821 {
  822         struct snc_softc *sc = (struct snc_softc *)arg;
  823         int     isr;
  824 
  825         if (sc->sc_enabled == 0)
  826                 return;
  827 
  828         while ((isr = (NIC_GET(sc, SNCR_ISR) & ISR_ALL)) != 0) {
  829                 /* scrub the interrupts that we are going to service */
  830                 NIC_PUT(sc, SNCR_ISR, isr);
  831                 wbflush();
  832 
  833                 if (isr & (ISR_BR | ISR_LCD | ISR_TC))
  834                         device_printf(sc->sc_dev,
  835                                       "unexpected interrupt status 0x%x\n",
  836                                       isr);
  837 
  838                 if (isr & (ISR_TXDN | ISR_TXER | ISR_PINT))
  839                         sonictxint(sc);
  840 
  841                 if (isr & ISR_PKTRX)
  842                         sonicrxint(sc);
  843 
  844                 if (isr & (ISR_HBL | ISR_RDE | ISR_RBE | ISR_RBAE | ISR_RFO)) {
  845                         if (isr & ISR_HBL)
  846                                 /*
  847                                  * The repeater is not providing a heartbeat.
  848                                  * In itself this isn't harmful, lots of the
  849                                  * cheap repeater hubs don't supply a heartbeat.
  850                                  * So ignore the lack of heartbeat. Its only
  851                                  * if we can't detect a carrier that we have a
  852                                  * problem.
  853                                  */
  854                                 ;
  855                         if (isr & ISR_RDE)
  856                                 device_printf(sc->sc_dev, 
  857                                         "receive descriptors exhausted\n");
  858                         if (isr & ISR_RBE)
  859                                 device_printf(sc->sc_dev, 
  860                                         "receive buffers exhausted\n");
  861                         if (isr & ISR_RBAE)
  862                                 device_printf(sc->sc_dev, 
  863                                         "receive buffer area exhausted\n");
  864                         if (isr & ISR_RFO)
  865                                 device_printf(sc->sc_dev, 
  866                                         "receive FIFO overrun\n");
  867                 }
  868                 if (isr & (ISR_CRC | ISR_FAE | ISR_MP)) {
  869 #ifdef notdef
  870                         if (isr & ISR_CRC)
  871                                 sc->sc_crctally++;
  872                         if (isr & ISR_FAE)
  873                                 sc->sc_faetally++;
  874                         if (isr & ISR_MP)
  875                                 sc->sc_mptally++;
  876 #endif
  877                 }
  878                 sncstart(&sc->sc_if);
  879 
  880 #if NRND > 0
  881                 if (isr)
  882                         rnd_add_uint32(&sc->rnd_source, isr);
  883 #endif
  884         }
  885         return;
  886 }
  887 
  888 /*
  889  * Transmit interrupt routine
  890  */
  891 hide void
  892 sonictxint(sc)
  893         struct snc_softc *sc;
  894 {
  895         struct mtd      *mtd;
  896         u_int32_t       txp;
  897         unsigned short  txp_status;
  898         int             mtd_hw;
  899         struct ifnet    *ifp = &sc->sc_if;
  900 
  901         mtd_hw = sc->mtd_hw;
  902 
  903         if (mtd_hw == sc->mtd_free)
  904                 return;
  905 
  906         while (mtd_hw != sc->mtd_free) {
  907                 mtd = &sc->mtda[mtd_hw];
  908 
  909                 txp = mtd->mtd_vtxp;
  910 
  911                 if (SRO(sc, txp, TXP_STATUS) == 0) {
  912                         break; /* it hasn't really gone yet */
  913                 }
  914 
  915 #ifdef SNCDEBUG
  916                 if ((sncdebug & SNC_SHOWTXHDR) != 0)
  917                 {
  918                         struct ether_header eh;
  919 
  920                         (*sc->sc_copyfrombuf)(sc, &eh, mtd->mtd_vbuf, sizeof(eh));
  921                         device_printf(sc->sc_dev,
  922                             "xmit status=0x%x len=%d type=0x%x from %6D",
  923                             SRO(sc, txp, TXP_STATUS),
  924                             SRO(sc, txp, TXP_PKTSIZE),
  925                             htons(eh.ether_type),
  926                             eh.ether_shost, ":");
  927                         printf(" (to %6D)\n", eh.ether_dhost, ":");
  928                 }
  929 #endif /* SNCDEBUG */
  930 
  931                 ifp->if_flags &= ~IFF_OACTIVE;
  932 
  933                 if (mtd->mtd_mbuf != 0) {
  934                         m_freem(mtd->mtd_mbuf);
  935                         mtd->mtd_mbuf = 0;
  936                 }
  937                 if (++mtd_hw == NTDA) mtd_hw = 0;
  938 
  939                 txp_status = SRO(sc, txp, TXP_STATUS);
  940 
  941                 ifp->if_collisions += (txp_status & TCR_EXC) ? 16 :
  942                         ((txp_status & TCR_NC) >> 12);
  943 
  944                 if ((txp_status & TCR_PTX) == 0) {
  945                         ifp->if_oerrors++;
  946                         device_printf(sc->sc_dev, "Tx packet status=0x%x\n",
  947                                       txp_status);
  948                         
  949                         /* XXX - DG This looks bogus */
  950                         if (mtd_hw != sc->mtd_free) {
  951                                 printf("resubmitting remaining packets\n");
  952                                 mtd = &sc->mtda[mtd_hw];
  953                                 NIC_PUT(sc, SNCR_CTDA, LOWER(mtd->mtd_vtxp));
  954                                 NIC_PUT(sc, SNCR_CR, CR_TXP);
  955                                 wbflush();
  956                                 break;
  957                         }
  958                 }
  959         }
  960 
  961         sc->mtd_hw = mtd_hw;
  962         return;
  963 }
  964 
  965 /*
  966  * Receive interrupt routine
  967  */
  968 hide void
  969 sonicrxint(sc)
  970         struct snc_softc *sc;
  971 {
  972         u_int32_t rda;
  973         int     orra;
  974         int     len;
  975         int     rramark;
  976         int     rdamark;
  977         u_int16_t rxpkt_ptr;
  978 
  979         rda = sc->v_rda + (sc->sc_rxmark * RXPKT_SIZE(sc));
  980 
  981         while (SRO(sc, rda, RXPKT_INUSE) == 0) {
  982                 u_int status = SRO(sc, rda, RXPKT_STATUS);
  983 
  984                 orra = RBASEQ(SRO(sc, rda, RXPKT_SEQNO)) & RRAMASK;
  985                 rxpkt_ptr = SRO(sc, rda, RXPKT_PTRLO);
  986                 /*
  987                  * Do not trunc ether_header length.
  988                  * Our sonic_read() and sonic_get() require it.
  989                  */
  990                 len = SRO(sc, rda, RXPKT_BYTEC) - FCSSIZE;
  991                 if (status & RCR_PRX) {
  992                         /* XXX: Does PGOFSET require? */
  993                         u_int32_t pkt =
  994                             sc->rbuf[orra & RBAMASK] + (rxpkt_ptr & PGOFSET);
  995                         if (sonic_read(sc, pkt, len))
  996                                 sc->sc_if.if_ipackets++;
  997                         else
  998                                 sc->sc_if.if_ierrors++;
  999                 } else
 1000                         sc->sc_if.if_ierrors++;
 1001 
 1002                 /*
 1003                  * give receive buffer area back to chip.
 1004                  *
 1005                  * If this was the last packet in the RRA, give the RRA to
 1006                  * the chip again.
 1007                  * If sonic read didnt copy it out then we would have to
 1008                  * wait !!
 1009                  * (dont bother add it back in again straight away)
 1010                  *
 1011                  * Really, we're doing v_rra[rramark] = v_rra[orra] but
 1012                  * we have to use the macros because SONIC might be in
 1013                  * 16 or 32 bit mode.
 1014                  */
 1015                 if (status & RCR_LPKT) {
 1016                         u_int32_t tmp1, tmp2;
 1017 
 1018                         rramark = sc->sc_rramark;
 1019                         tmp1 = sc->v_rra[rramark];
 1020                         tmp2 = sc->v_rra[orra];
 1021                         SWO(sc, tmp1, RXRSRC_PTRLO,
 1022                                 SRO(sc, tmp2, RXRSRC_PTRLO));
 1023                         SWO(sc, tmp1, RXRSRC_PTRHI,
 1024                                 SRO(sc, tmp2, RXRSRC_PTRHI));
 1025                         SWO(sc, tmp1, RXRSRC_WCLO,
 1026                                 SRO(sc, tmp2, RXRSRC_WCLO));
 1027                         SWO(sc, tmp1, RXRSRC_WCHI,
 1028                                 SRO(sc, tmp2, RXRSRC_WCHI));
 1029 
 1030                         /* zap old rra for fun */
 1031                         SWO(sc, tmp2, RXRSRC_WCHI, 0);
 1032                         SWO(sc, tmp2, RXRSRC_WCLO, 0);
 1033 
 1034                         sc->sc_rramark = (++rramark) & RRAMASK;
 1035                         NIC_PUT(sc, SNCR_RWP, LOWER(sc->v_rra[rramark]));
 1036                         wbflush();
 1037                 }
 1038 
 1039                 /*
 1040                  * give receive descriptor back to chip simple
 1041                  * list is circular
 1042                  */
 1043                 rdamark = sc->sc_rdamark;
 1044                 SWO(sc, rda, RXPKT_INUSE, 1);
 1045                 SWO(sc, rda, RXPKT_RLINK,
 1046                         SRO(sc, rda, RXPKT_RLINK) | EOL);
 1047                 SWO(sc, (sc->v_rda + (rdamark * RXPKT_SIZE(sc))), RXPKT_RLINK,
 1048                         SRO(sc, (sc->v_rda + (rdamark * RXPKT_SIZE(sc))),
 1049                         RXPKT_RLINK) & ~EOL);
 1050                 sc->sc_rdamark = sc->sc_rxmark;
 1051 
 1052                 if (++sc->sc_rxmark >= sc->sc_nrda)
 1053                         sc->sc_rxmark = 0;
 1054                 rda = sc->v_rda + (sc->sc_rxmark * RXPKT_SIZE(sc));
 1055         }
 1056 }
 1057 
 1058 /*
 1059  * sonic_read -- pull packet off interface and forward to
 1060  * appropriate protocol handler
 1061  */
 1062 hide int
 1063 sonic_read(sc, pkt, len)
 1064         struct snc_softc *sc;
 1065         u_int32_t pkt;
 1066         int len;
 1067 {
 1068         struct ifnet *ifp = &sc->sc_if;
 1069         struct ether_header *et;
 1070         struct mbuf *m;
 1071 
 1072         if (len <= sizeof(struct ether_header) ||
 1073             len > ETHERMTU + sizeof(struct ether_header)) {
 1074                 device_printf(sc->sc_dev,
 1075                               "invalid packet length %d bytes\n", len);
 1076                 return (0);
 1077         }
 1078 
 1079         /* Pull packet off interface. */
 1080         m = sonic_get(sc, pkt, len);
 1081         if (m == 0) {
 1082                 return (0);
 1083         }
 1084 
 1085         /* We assume that the header fit entirely in one mbuf. */
 1086         et = mtod(m, struct ether_header *);
 1087 
 1088 #ifdef SNCDEBUG
 1089         if ((sncdebug & SNC_SHOWRXHDR) != 0)
 1090         {
 1091                 device_printf(sc->sc_dev, "rcvd 0x%x len=%d type=0x%x from %6D",
 1092                     pkt, len, htons(et->ether_type),
 1093                     et->ether_shost, ":");
 1094                 printf(" (to %6D)\n", et->ether_dhost, ":");
 1095         }
 1096 #endif /* SNCDEBUG */
 1097 
 1098         /* Pass the packet up. */
 1099         (*ifp->if_input)(ifp, m);
 1100         return (1);
 1101 }
 1102 
 1103 
 1104 /*
 1105  * munge the received packet into an mbuf chain
 1106  */
 1107 hide struct mbuf *
 1108 sonic_get(sc, pkt, datalen)
 1109         struct snc_softc *sc;
 1110         u_int32_t pkt;
 1111         int datalen;
 1112 {
 1113         struct  mbuf *m, *top, **mp;
 1114         int     len;
 1115         /*
 1116          * Do not trunc ether_header length.
 1117          * Our sonic_read() and sonic_get() require it.
 1118          */
 1119 
 1120         MGETHDR(m, M_DONTWAIT, MT_DATA);
 1121         if (m == 0)
 1122                 return (0);
 1123         m->m_pkthdr.rcvif = &sc->sc_if;
 1124         m->m_pkthdr.len = datalen;
 1125         len = MHLEN;
 1126         top = 0;
 1127         mp = &top;
 1128 
 1129         while (datalen > 0) {
 1130                 if (top) {
 1131                         MGET(m, M_DONTWAIT, MT_DATA);
 1132                         if (m == 0) {
 1133                                 m_freem(top);
 1134                                 return (0);
 1135                         }
 1136                         len = MLEN;
 1137                 }
 1138                 if (datalen >= MINCLSIZE) {
 1139                         MCLGET(m, M_DONTWAIT);
 1140                         if ((m->m_flags & M_EXT) == 0) {
 1141                                 if (top) m_freem(top);
 1142                                 return (0);
 1143                         }
 1144                         len = MCLBYTES;
 1145                 }
 1146 #if 0
 1147                 /* XXX: Require? */
 1148                 if (!top) {
 1149                         register int pad =
 1150                             ALIGN(sizeof(struct ether_header)) -
 1151                                 sizeof(struct ether_header);
 1152                         m->m_data += pad;
 1153                         len -= pad;
 1154                 }
 1155 #endif
 1156                 m->m_len = len = min(datalen, len);
 1157 
 1158                 (*sc->sc_copyfrombuf)(sc, mtod(m, caddr_t), pkt, len);
 1159                 pkt += len;
 1160                 datalen -= len;
 1161                 *mp = m;
 1162                 mp = &m->m_next;
 1163         }
 1164 
 1165         return (top);
 1166 }
 1167 /*
 1168  * Enable power on the interface.
 1169  */
 1170 int
 1171 snc_enable(sc)
 1172         struct snc_softc *sc;
 1173 {
 1174 
 1175 #ifdef  SNCDEBUG
 1176         device_printf(sc->sc_dev, "snc_enable()\n");
 1177 #endif  /* SNCDEBUG */
 1178 
 1179         if (sc->sc_enabled == 0 && sc->sc_enable != NULL) {
 1180                 if ((*sc->sc_enable)(sc) != 0) {
 1181                         device_printf(sc->sc_dev, "device enable failed\n");
 1182                         return (EIO);
 1183                 }
 1184         }
 1185 
 1186         sc->sc_enabled = 1;
 1187         return (0);
 1188 }
 1189 
 1190 /*
 1191  * Disable power on the interface.
 1192  */
 1193 void
 1194 snc_disable(sc)
 1195         struct snc_softc *sc;
 1196 {
 1197 
 1198 #ifdef  SNCDEBUG
 1199         device_printf(sc->sc_dev, "snc_disable()\n");
 1200 #endif  /* SNCDEBUG */
 1201 
 1202         if (sc->sc_enabled != 0 && sc->sc_disable != NULL) {
 1203                 (*sc->sc_disable)(sc);
 1204                 sc->sc_enabled = 0;
 1205         }
 1206 }
 1207 
 1208 

Cache object: 98e6499a5a8529d6424ba64986baf88d


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