The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/smc91cxx.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 /*      $OpenBSD: smc91cxx.c,v 1.52 2022/08/15 01:59:00 jsg Exp $       */
    2 /*      $NetBSD: smc91cxx.c,v 1.11 1998/08/08 23:51:41 mycroft Exp $    */
    3 
    4 /*-
    5  * Copyright (c) 1997 The NetBSD Foundation, Inc.
    6  * All rights reserved.
    7  *
    8  * This code is derived from software contributed to The NetBSD Foundation
    9  * by Jason R. Thorpe of the Numerical Aerospace Simulation Facility,
   10  * NASA Ames Research Center.
   11  *
   12  * Redistribution and use in source and binary forms, with or without
   13  * modification, are permitted provided that the following conditions
   14  * are met:
   15  * 1. Redistributions of source code must retain the above copyright
   16  *    notice, this list of conditions and the following disclaimer.
   17  * 2. Redistributions in binary form must reproduce the above copyright
   18  *    notice, this list of conditions and the following disclaimer in the
   19  *    documentation and/or other materials provided with the distribution.
   20  *
   21  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
   22  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
   23  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
   24  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
   25  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
   26  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
   27  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
   28  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
   29  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
   30  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   31  * POSSIBILITY OF SUCH DAMAGE.
   32  */
   33 
   34 /*      
   35  * Copyright (c) 1996 Gardner Buchanan <gbuchanan@shl.com>
   36  * All rights reserved.
   37  *      
   38  * Redistribution and use in source and binary forms, with or without
   39  * modification, are permitted provided that the following conditions
   40  * are met:
   41  * 1. Redistributions of source code must retain the above copyright
   42  *    notice, this list of conditions and the following disclaimer.
   43  * 2. Redistributions in binary form must reproduce the above copyright
   44  *    notice, this list of conditions and the following disclaimer in the
   45  *    documentation and/or other materials provided with the distribution.
   46  * 3. All advertising materials mentioning features or use of this software
   47  *    must display the following acknowledgement:
   48  *      This product includes software developed by Gardner Buchanan.
   49  * 4. The name of Gardner Buchanan may not be used to endorse or promote
   50  *    products derived from this software without specific prior written
   51  *    permission.
   52  *       
   53  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   54  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   55  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   56  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   57  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   58  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   59  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   60  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   61  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   62  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   63  *      
   64  *   from FreeBSD Id: if_sn.c,v 1.4 1996/03/18 15:47:16 gardner Exp
   65  */      
   66 
   67 /*
   68  * Core driver for the SMC 91Cxx family of Ethernet chips.
   69  *
   70  * Memory allocation interrupt logic is derived from an SMC 91C90 driver
   71  * written for NetBSD/amiga by Michael Hitch.
   72  */
   73 
   74 #include "bpfilter.h"
   75 
   76 #include <sys/param.h> 
   77 #include <sys/systm.h>
   78 #include <sys/mbuf.h>
   79 #include <sys/syslog.h>
   80 #include <sys/socket.h>
   81 #include <sys/device.h>
   82 #include <sys/timeout.h>
   83 #include <sys/kernel.h>
   84 #include <sys/malloc.h>
   85 #include <sys/ioctl.h> 
   86 #include <sys/errno.h>
   87 
   88 #include <machine/bus.h>
   89 #include <machine/intr.h>
   90 
   91 #include <net/if.h>
   92 #include <net/if_media.h> 
   93 
   94 #include <netinet/in.h> 
   95 #include <netinet/if_ether.h>
   96 
   97 #if NBPFILTER > 0
   98 #include <net/bpf.h>
   99 #endif
  100 
  101 #include <dev/mii/mii.h>
  102 #include <dev/mii/miivar.h>
  103 #include <dev/mii/mii_bitbang.h>
  104 
  105 #include <dev/ic/smc91cxxreg.h>
  106 #include <dev/ic/smc91cxxvar.h>
  107 
  108 #ifndef __BUS_SPACE_HAS_STREAM_METHODS
  109 #define bus_space_write_multi_stream_2 bus_space_write_multi_2
  110 #define bus_space_write_multi_stream_4 bus_space_write_multi_4
  111 #define bus_space_read_multi_stream_2  bus_space_read_multi_2
  112 #define bus_space_read_multi_stream_4  bus_space_read_multi_4
  113 #endif /* __BUS_SPACE_HAS_STREAM_METHODS */
  114 
  115 /* XXX Hardware padding doesn't work yet(?) */
  116 #define SMC91CXX_SW_PAD
  117 
  118 const char *smc91cxx_idstrs[] = {
  119         NULL,                           /* 0 */
  120         NULL,                           /* 1 */
  121         NULL,                           /* 2 */
  122         "SMC91C90/91C92",               /* 3 */
  123         "SMC91C94/91C96",               /* 4 */
  124         "SMC91C95",                     /* 5 */
  125         NULL,                           /* 6 */
  126         "SMC91C100",                    /* 7 */
  127         "SMC91C100FD",                  /* 8 */
  128         NULL,                           /* 9 */
  129         NULL,                           /* 10 */
  130         NULL,                           /* 11 */
  131         NULL,                           /* 12 */
  132         NULL,                           /* 13 */
  133         NULL,                           /* 14 */
  134         NULL,                           /* 15 */
  135 };
  136 
  137 /* Supported media types. */
  138 const uint64_t smc91cxx_media[] = {
  139         IFM_ETHER|IFM_10_T,
  140         IFM_ETHER|IFM_10_5,
  141 };
  142 #define NSMC91CxxMEDIA  (sizeof(smc91cxx_media) / sizeof(smc91cxx_media[0]))
  143 
  144 /*
  145  * MII bit-bang glue.
  146  */
  147 u_int32_t smc91cxx_mii_bitbang_read(struct device *);
  148 void smc91cxx_mii_bitbang_write(struct device *, u_int32_t);
  149 
  150 const struct mii_bitbang_ops smc91cxx_mii_bitbang_ops = {
  151         smc91cxx_mii_bitbang_read,
  152         smc91cxx_mii_bitbang_write,
  153         {
  154                 MR_MDO,         /* MII_BIT_MDO */
  155                 MR_MDI,         /* MII_BIT_MDI */
  156                 MR_MCLK,        /* MII_BIT_MDC */
  157                 MR_MDOE,        /* MII_BIT_DIR_HOST_PHY */
  158                 0,              /* MII_BIT_DIR_PHY_HOST */
  159         }
  160 };
  161 
  162 struct cfdriver sm_cd = {
  163         NULL, "sm", DV_IFNET
  164 };
  165 
  166 /* MII callbacks */
  167 int     smc91cxx_mii_readreg(struct device *, int, int);
  168 void    smc91cxx_mii_writereg(struct device *, int, int, int);
  169 void    smc91cxx_statchg(struct device *);
  170 void    smc91cxx_tick(void *);
  171 
  172 int     smc91cxx_mediachange(struct ifnet *);
  173 void    smc91cxx_mediastatus(struct ifnet *, struct ifmediareq *);
  174 
  175 int     smc91cxx_set_media(struct smc91cxx_softc *, uint64_t);
  176 
  177 void    smc91cxx_read(struct smc91cxx_softc *);
  178 void    smc91cxx_reset(struct smc91cxx_softc *);
  179 void    smc91cxx_start(struct ifnet *);
  180 void    smc91cxx_resume(struct smc91cxx_softc *);
  181 void    smc91cxx_watchdog(struct ifnet *);
  182 int     smc91cxx_ioctl(struct ifnet *, u_long, caddr_t);
  183 
  184 void
  185 smc91cxx_attach(struct smc91cxx_softc *sc, u_int8_t *myea)
  186 {
  187         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  188         bus_space_tag_t bst = sc->sc_bst;
  189         bus_space_handle_t bsh = sc->sc_bsh;
  190         struct ifmedia *ifm = &sc->sc_mii.mii_media;
  191         u_int32_t miicapabilities;
  192         u_int16_t tmp;
  193         int i, aui;
  194         const char *idstr;
  195 
  196         /* Make sure the chip is stopped. */
  197         smc91cxx_stop(sc);
  198 
  199         SMC_SELECT_BANK(sc, 3);
  200         tmp = bus_space_read_2(bst, bsh, REVISION_REG_W);
  201         sc->sc_chipid = RR_ID(tmp);
  202         /* check magic number */
  203         if ((tmp & BSR_DETECT_MASK) != BSR_DETECT_VALUE) {
  204                 idstr = NULL;
  205                 printf("%s: invalid BSR 0x%04x\n", sc->sc_dev.dv_xname, tmp);
  206         } else
  207                 idstr = smc91cxx_idstrs[RR_ID(tmp)];
  208 #ifdef SMC_DEBUG
  209         printf("\n%s: ", sc->sc_dev.dv_xname);
  210         if (idstr != NULL)
  211                 printf("%s, ", idstr);
  212         else
  213                 printf("unknown chip id %d, ", sc->sc_chipid);
  214         printf("revision %d", RR_REV(tmp));
  215 #endif
  216 
  217         /* Read the station address from the chip. */
  218         SMC_SELECT_BANK(sc, 1);
  219         if (myea == NULL) {
  220                 for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
  221                         tmp = bus_space_read_2(bst, bsh, IAR_ADDR0_REG_W + i);
  222                         sc->sc_arpcom.ac_enaddr[i + 1] = (tmp >>8) & 0xff;
  223                         sc->sc_arpcom.ac_enaddr[i] = tmp & 0xff;
  224                 }
  225         } else {
  226                 bcopy(myea, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
  227         }
  228 
  229         printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
  230 
  231         /* Initialize the ifnet structure. */
  232         bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
  233         ifp->if_softc = sc;
  234         ifp->if_start = smc91cxx_start;
  235         ifp->if_ioctl = smc91cxx_ioctl;
  236         ifp->if_watchdog = smc91cxx_watchdog;
  237         ifp->if_flags =
  238             IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  239 
  240         /* Attach the interface. */
  241         if_attach(ifp);
  242         ether_ifattach(ifp);
  243 
  244         /*
  245          * Initialize our media structures and MII info.  We will
  246          * probe the MII if we are on the SMC91Cxx
  247          */
  248         sc->sc_mii.mii_ifp = ifp;
  249         sc->sc_mii.mii_readreg = smc91cxx_mii_readreg;
  250         sc->sc_mii.mii_writereg = smc91cxx_mii_writereg;
  251         sc->sc_mii.mii_statchg = smc91cxx_statchg;
  252         ifmedia_init(ifm, 0, smc91cxx_mediachange, smc91cxx_mediastatus);
  253 
  254         SMC_SELECT_BANK(sc, 1);
  255         tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W);
  256 
  257         miicapabilities = BMSR_MEDIAMASK|BMSR_ANEG;
  258         switch (sc->sc_chipid) {
  259         case CHIP_91100:
  260                 /*
  261                  * The 91100 does not have full-duplex capabilities,
  262                  * even if the PHY does.
  263                  */
  264                 miicapabilities &= ~(BMSR_100TXFDX | BMSR_10TFDX);
  265                 /* FALLTHROUGH */
  266         case CHIP_91100FD:
  267                 if (tmp & CR_MII_SELECT) {
  268 #ifdef SMC_DEBUG
  269                         printf("%s: default media MII\n",
  270                             sc->sc_dev.dv_xname);
  271 #endif
  272                         mii_attach(&sc->sc_dev, &sc->sc_mii, miicapabilities,
  273                             MII_PHY_ANY, MII_OFFSET_ANY, 0);
  274                         if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
  275                                 ifmedia_add(&sc->sc_mii.mii_media,
  276                                     IFM_ETHER|IFM_NONE, 0, NULL);
  277                                 ifmedia_set(&sc->sc_mii.mii_media,
  278                                     IFM_ETHER|IFM_NONE);
  279                         } else {
  280                                 ifmedia_set(&sc->sc_mii.mii_media,
  281                                     IFM_ETHER|IFM_AUTO);
  282                         }
  283                         sc->sc_flags |= SMC_FLAGS_HAS_MII;
  284                         break;
  285                 }
  286                 /* FALLTHROUGH */
  287         default:
  288                 aui = tmp & CR_AUI_SELECT;
  289 #ifdef SMC_DEBUG
  290                 printf("%s: default media %s\n", sc->sc_dev.dv_xname,
  291                         aui ? "AUI" : "UTP");
  292 #endif
  293                 for (i = 0; i < NSMC91CxxMEDIA; i++)
  294                         ifmedia_add(ifm, smc91cxx_media[i], 0, NULL);
  295                 ifmedia_set(ifm, IFM_ETHER | (aui ? IFM_10_5 : IFM_10_T));
  296                 break;
  297         }
  298 
  299         /* The attach is successful. */
  300         sc->sc_flags |= SMC_FLAGS_ATTACHED;
  301 }
  302 
  303 /*
  304  * Change media according to request.
  305  */
  306 int
  307 smc91cxx_mediachange(struct ifnet *ifp)
  308 {
  309         struct smc91cxx_softc *sc = ifp->if_softc;
  310 
  311         return (smc91cxx_set_media(sc, sc->sc_mii.mii_media.ifm_media));
  312 }
  313 
  314 int
  315 smc91cxx_set_media(struct smc91cxx_softc *sc, uint64_t media)
  316 {
  317         bus_space_tag_t bst = sc->sc_bst;
  318         bus_space_handle_t bsh = sc->sc_bsh;
  319         u_int16_t tmp;
  320 
  321         /*
  322          * If the interface is not currently powered on, just return.
  323          * When it is enabled later, smc91cxx_init() will properly set
  324          * up the media for us.
  325          */
  326         if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0)
  327                 return (0);
  328 
  329         if (IFM_TYPE(media) != IFM_ETHER)
  330                 return (EINVAL);
  331 
  332         if (sc->sc_flags & SMC_FLAGS_HAS_MII)
  333                 return (mii_mediachg(&sc->sc_mii));
  334 
  335         switch (IFM_SUBTYPE(media)) {
  336         case IFM_10_T:
  337         case IFM_10_5:
  338                 SMC_SELECT_BANK(sc, 1);
  339                 tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W);
  340                 if (IFM_SUBTYPE(media) == IFM_10_5)
  341                         tmp |= CR_AUI_SELECT;
  342                 else
  343                         tmp &= ~CR_AUI_SELECT;
  344                 bus_space_write_2(bst, bsh, CONFIG_REG_W, tmp);
  345                 delay(20000);   /* XXX is this needed? */
  346                 break;
  347 
  348         default:
  349                 return (EINVAL);
  350         }
  351 
  352         return (0);
  353 }
  354 
  355 /*
  356  * Notify the world which media we're using.
  357  */
  358 void
  359 smc91cxx_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
  360 {
  361         struct smc91cxx_softc *sc = ifp->if_softc;
  362         bus_space_tag_t bst = sc->sc_bst;
  363         bus_space_handle_t bsh = sc->sc_bsh;
  364         u_int16_t tmp;
  365 
  366         if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0) {
  367                 ifmr->ifm_active = IFM_ETHER | IFM_NONE;
  368                 ifmr->ifm_status = 0;
  369                 return;
  370         }
  371 
  372         /*
  373          * If we have MII, go ask the PHY what's going on.
  374          */
  375         if (sc->sc_flags & SMC_FLAGS_HAS_MII) {
  376                 mii_pollstat(&sc->sc_mii);
  377                 ifmr->ifm_active = sc->sc_mii.mii_media_active;
  378                 ifmr->ifm_status = sc->sc_mii.mii_media_status;
  379                 return;
  380         }
  381 
  382         SMC_SELECT_BANK(sc, 1);
  383         tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W);
  384         ifmr->ifm_active =
  385             IFM_ETHER | ((tmp & CR_AUI_SELECT) ? IFM_10_5 : IFM_10_T);
  386 }
  387 
  388 /*
  389  * Reset and initialize the chip.
  390  */
  391 void
  392 smc91cxx_init(struct smc91cxx_softc *sc)
  393 {
  394         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  395         bus_space_tag_t bst = sc->sc_bst;
  396         bus_space_handle_t bsh = sc->sc_bsh;
  397         u_int16_t tmp;
  398         int s, i;
  399 
  400         s = splnet();
  401 
  402         /*
  403          * This resets the registers mostly to defaults, but doesn't
  404          * affect the EEPROM.  After the reset cycle, we pause briefly
  405          * for the chip to recover.
  406          *
  407          * XXX how long are we really supposed to delay?  --thorpej
  408          */
  409         SMC_SELECT_BANK(sc, 0);
  410         bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, RCR_SOFTRESET);
  411         delay(100);
  412         bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, 0);
  413         delay(200);
  414 
  415         bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, 0);
  416 
  417         /* Set the Ethernet address. */
  418         SMC_SELECT_BANK(sc, 1);
  419         for (i = 0; i < ETHER_ADDR_LEN; i++ )
  420                 bus_space_write_1(bst, bsh, IAR_ADDR0_REG_W + i,
  421                     sc->sc_arpcom.ac_enaddr[i]);
  422 
  423         /*
  424          * Set the control register to automatically release successfully
  425          * transmitted packets (making the best use of our limited memory)
  426          * and enable the EPH interrupt on certain TX errors.
  427          */
  428         bus_space_write_2(bst, bsh, CONTROL_REG_W, (CTR_AUTO_RELEASE |
  429             CTR_TE_ENABLE | CTR_CR_ENABLE | CTR_LE_ENABLE));
  430 
  431         /*
  432          * Reset the MMU and wait for it to be un-busy.
  433          */
  434         SMC_SELECT_BANK(sc, 2);
  435         bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_RESET);
  436         while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY)
  437                 /* XXX bound this loop! */ ;
  438 
  439         /*
  440          * Disable all interrupts.
  441          */
  442         bus_space_write_1(bst, bsh, INTR_MASK_REG_B, 0);
  443 
  444         /*
  445          * Set current media.
  446          */
  447         smc91cxx_set_media(sc, sc->sc_mii.mii_media.ifm_cur->ifm_media);
  448 
  449         /*
  450          * Set the receive filter.  We want receive enable and auto
  451          * strip of CRC from received packet.  If we are in promisc. mode,
  452          * then set that bit as well.
  453          *
  454          * XXX Initialize multicast filter.  For now, we just accept
  455          * XXX all multicast.
  456          */
  457         SMC_SELECT_BANK(sc, 0);
  458 
  459         tmp = RCR_ENABLE | RCR_STRIP_CRC | RCR_ALMUL;
  460         if (ifp->if_flags & IFF_PROMISC)
  461                 tmp |= RCR_PROMISC;
  462 
  463         bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, tmp);
  464 
  465         /*
  466          * Set transmitter control to "enabled".
  467          */
  468         tmp = TCR_ENABLE;
  469 
  470 #ifndef SMC91CXX_SW_PAD
  471         /*
  472          * Enable hardware padding of transmitted packets.
  473          * XXX doesn't work?
  474          */
  475         tmp |= TCR_PAD_ENABLE;
  476 #endif
  477 
  478         bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, tmp);
  479 
  480         /*
  481          * Now, enable interrupts.
  482          */
  483         SMC_SELECT_BANK(sc, 2);
  484 
  485         bus_space_write_1(bst, bsh, INTR_MASK_REG_B,
  486             IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT | IM_TX_INT);
  487 
  488         /* Interface is now running, with no output active. */
  489         ifp->if_flags |= IFF_RUNNING;
  490         ifq_clr_oactive(&ifp->if_snd);
  491 
  492         if (sc->sc_flags & SMC_FLAGS_HAS_MII) {
  493                 /* Start the one second clock. */
  494                 timeout_set(&sc->sc_mii_timeout, smc91cxx_tick, sc);
  495                 timeout_add_sec(&sc->sc_mii_timeout, 1);
  496         }
  497 
  498         /*
  499          * Attempt to start any pending transmission.
  500          */
  501         smc91cxx_start(ifp);
  502 
  503         splx(s);
  504 }
  505 
  506 /*
  507  * Start output on an interface.
  508  * Must be called at splnet or interrupt level.
  509  */
  510 void
  511 smc91cxx_start(struct ifnet *ifp)
  512 {
  513         struct smc91cxx_softc *sc = ifp->if_softc;
  514         bus_space_tag_t bst = sc->sc_bst;
  515         bus_space_handle_t bsh = sc->sc_bsh;
  516         u_int len;
  517         struct mbuf *m, *top;
  518         u_int16_t length, npages;
  519         u_int8_t packetno;
  520         int timo, pad;
  521 
  522         if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
  523                 return;
  524 
  525  again:
  526         /*
  527          * Peek at the next packet.
  528          */
  529         m = ifq_deq_begin(&ifp->if_snd);
  530         if (m == NULL)
  531                 return;
  532 
  533         /*
  534          * Compute the frame length and set pad to give an overall even
  535          * number of bytes.  Below, we assume that the packet length
  536          * is even.
  537          */
  538         for (len = 0, top = m; m != NULL; m = m->m_next)
  539                 len += m->m_len;
  540         pad = (len & 1);
  541 
  542         /*
  543          * We drop packets that are too large.  Perhaps we should
  544          * truncate them instead?
  545          */
  546         if ((len + pad) > (ETHER_MAX_LEN - ETHER_CRC_LEN)) {
  547                 printf("%s: large packet discarded\n", sc->sc_dev.dv_xname);
  548                 ifp->if_oerrors++;
  549                 ifq_deq_commit(&ifp->if_snd, m);
  550                 m_freem(m);
  551                 goto readcheck;
  552         }
  553 
  554 #ifdef SMC91CXX_SW_PAD
  555         /*
  556          * Not using hardware padding; pad to ETHER_MIN_LEN.
  557          */
  558         if (len < (ETHER_MIN_LEN - ETHER_CRC_LEN))
  559                 pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len;
  560 #endif
  561 
  562         length = pad + len;
  563 
  564         /*
  565          * The MMU has a 256 byte page size.  The MMU expects us to
  566          * ask for "npages - 1".  We include space for the status word,
  567          * byte count, and control bytes in the allocation request.
  568          */
  569         npages = (length + 6) >> 8;
  570 
  571         /*
  572          * Now allocate the memory.
  573          */
  574         SMC_SELECT_BANK(sc, 2);
  575         bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_ALLOC | npages);
  576 
  577         timo = MEMORY_WAIT_TIME;
  578         do {
  579                 if (bus_space_read_1(bst, bsh, INTR_STAT_REG_B) & IM_ALLOC_INT)
  580                         break;
  581                 delay(1);
  582         } while (--timo);
  583 
  584         packetno = bus_space_read_1(bst, bsh, ALLOC_RESULT_REG_B);
  585 
  586         if (packetno & ARR_FAILED || timo == 0) {
  587                 /*
  588                  * No transmit memory is available.  Record the number
  589                  * of requested pages and enable the allocation completion
  590                  * interrupt.  Set up the watchdog timer in case we miss
  591                  * the interrupt.  Mark the interface as active so that
  592                  * no one else attempts to transmit while we're allocating
  593                  * memory.
  594                  */
  595                 bus_space_write_1(bst, bsh, INTR_MASK_REG_B,
  596                     bus_space_read_1(bst, bsh, INTR_MASK_REG_B) | IM_ALLOC_INT);
  597 
  598                 ifp->if_timer = 5;
  599                 ifq_deq_rollback(&ifp->if_snd, m);
  600                 ifq_set_oactive(&ifp->if_snd);
  601                 return;
  602         }
  603 
  604         /*
  605          * We have a packet number - set the data window.
  606          */
  607         bus_space_write_1(bst, bsh, PACKET_NUM_REG_B, packetno);
  608 
  609         /*
  610          * Point to the beginning of the packet.
  611          */
  612         bus_space_write_2(bst, bsh, POINTER_REG_W, PTR_AUTOINC /* | 0x0000 */);
  613 
  614         /*
  615          * Send the packet length (+6 for stats, length, and control bytes)
  616          * and the status word (set to zeros).
  617          */
  618         bus_space_write_2(bst, bsh, DATA_REG_W, 0);
  619         bus_space_write_1(bst, bsh, DATA_REG_B, (length + 6) & 0xff);
  620         bus_space_write_1(bst, bsh, DATA_REG_B, ((length + 6) >> 8) & 0xff);
  621 
  622         /*
  623          * Get the packet from the kernel.  This will include the Ethernet
  624          * frame header, MAC address, etc.
  625          */
  626         ifq_deq_commit(&ifp->if_snd, m);
  627 
  628         /*
  629          * Push the packet out to the card.
  630          */
  631         for (top = m; m != NULL; m = m->m_next) {
  632                 /* Words... */
  633                 if (m->m_len > 1)
  634                         bus_space_write_multi_stream_2(bst, bsh, DATA_REG_W,
  635                             mtod(m, u_int16_t *), m->m_len >> 1);
  636 
  637                 /* ...and the remaining byte, if any. */
  638                 if (m->m_len & 1)
  639                         bus_space_write_1(bst, bsh, DATA_REG_B,
  640                           *(u_int8_t *)(mtod(m, u_int8_t *) + (m->m_len - 1)));
  641         }
  642 
  643 #ifdef SMC91CXX_SW_PAD
  644         /*
  645          * Push out padding.
  646          */
  647         while (pad > 1) {
  648                 bus_space_write_2(bst, bsh, DATA_REG_W, 0);
  649                 pad -= 2;
  650         }
  651         if (pad)
  652                 bus_space_write_1(bst, bsh, DATA_REG_B, 0);
  653 #endif
  654 
  655         /*
  656          * Push out control byte and unused packet byte.  The control byte
  657          * is 0, meaning the packet is even lengthed and no special
  658          * CRC handling is necessary.
  659          */
  660         bus_space_write_2(bst, bsh, DATA_REG_W, 0);
  661 
  662         /*
  663          * Enable transmit interrupts and let the chip go.  Set a watchdog
  664          * in case we miss the interrupt.
  665          */
  666         bus_space_write_1(bst, bsh, INTR_MASK_REG_B,
  667             bus_space_read_1(bst, bsh, INTR_MASK_REG_B) |
  668             IM_TX_INT | IM_TX_EMPTY_INT);
  669 
  670         bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_ENQUEUE);
  671 
  672         ifp->if_timer = 5;
  673 
  674 #if NBPFILTER > 0
  675         if (ifp->if_bpf)
  676                 bpf_mtap(ifp->if_bpf, top, BPF_DIRECTION_OUT);
  677 #endif
  678 
  679         m_freem(top);
  680 
  681  readcheck:
  682         /*
  683          * Check for incoming packets.  We don't want to overflow the small
  684          * RX FIFO.  If nothing has arrived, attempt to queue another
  685          * transmit packet.
  686          */
  687         if (bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W) & FIFO_REMPTY)
  688                 goto again;
  689 }
  690 
  691 /*
  692  * Interrupt service routine.
  693  */
  694 int
  695 smc91cxx_intr(void *arg)
  696 {
  697         struct smc91cxx_softc *sc = arg;
  698         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  699         bus_space_tag_t bst = sc->sc_bst;
  700         bus_space_handle_t bsh = sc->sc_bsh;
  701         u_int8_t mask, interrupts, status;
  702         u_int16_t packetno, tx_status, card_stats;
  703 
  704         if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0 ||
  705             (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
  706                 return (0);
  707 
  708         SMC_SELECT_BANK(sc, 2);
  709 
  710         /*
  711          * Obtain the current interrupt mask.
  712          */
  713         mask = bus_space_read_1(bst, bsh, INTR_MASK_REG_B);
  714 
  715         /*
  716          * Get the set of interrupt which occurred and eliminate any
  717          * which are not enabled.
  718          */
  719         interrupts = bus_space_read_1(bst, bsh, INTR_STAT_REG_B);
  720         status = interrupts & mask;
  721 
  722         /* Ours? */
  723         if (status == 0)
  724                 return (0);
  725 
  726         /*
  727          * It's ours; disable all interrupts while we process them.
  728          */
  729         bus_space_write_1(bst, bsh, INTR_MASK_REG_B, 0);
  730 
  731         /*
  732          * Receive overrun interrupts.
  733          */
  734         if (status & IM_RX_OVRN_INT) {
  735                 bus_space_write_1(bst, bsh, INTR_ACK_REG_B, IM_RX_OVRN_INT);
  736                 ifp->if_ierrors++;
  737         }
  738 
  739         /*
  740          * Receive interrupts.
  741          */
  742         if (status & IM_RCV_INT) {
  743 #if 1 /* DIAGNOSTIC */
  744                 packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W);
  745                 if (packetno & FIFO_REMPTY) {
  746                         printf("%s: receive interrupt on empty fifo\n",
  747                             sc->sc_dev.dv_xname);
  748                         goto out;
  749                 } else
  750 #endif
  751                 smc91cxx_read(sc);
  752         }
  753 
  754         /*
  755          * Memory allocation interrupts.
  756          */
  757         if (status & IM_ALLOC_INT) {
  758                 /* Disable this interrupt. */
  759                 mask &= ~IM_ALLOC_INT;
  760 
  761                 /*
  762                  * Release the just-allocated memory.  We will reallocate
  763                  * it through the normal start logic.
  764                  */
  765                 while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY)
  766                         /* XXX bound this loop! */ ;
  767                 bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_FREEPKT);
  768 
  769                 ifq_clr_oactive(&ifp->if_snd);
  770                 ifp->if_timer = 0;
  771         }
  772 
  773         /*
  774          * Transmit complete interrupt.  Handle transmission error messages.
  775          * This will only be called on error condition because of AUTO RELEASE
  776          * mode.
  777          */
  778         if (status & IM_TX_INT) {
  779                 bus_space_write_1(bst, bsh, INTR_ACK_REG_B, IM_TX_INT);
  780 
  781                 packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W) &
  782                     FIFO_TX_MASK;
  783 
  784                 /*
  785                  * Select this as the packet to read from.
  786                  */
  787                 bus_space_write_1(bst, bsh, PACKET_NUM_REG_B, packetno);
  788 
  789                 /*
  790                  * Position the pointer to the beginning of the packet.
  791                  */
  792                 bus_space_write_2(bst, bsh, POINTER_REG_W,
  793                     PTR_AUTOINC | PTR_READ /* | 0x0000 */);
  794 
  795                 /*
  796                  * Fetch the TX status word.  This will be a copy of
  797                  * the EPH_STATUS_REG_W at the time of the transmission
  798                  * failure.
  799                  */
  800                 tx_status = bus_space_read_2(bst, bsh, DATA_REG_W);
  801 
  802                 if (tx_status & EPHSR_TX_SUC)
  803                         printf("%s: successful packet caused TX interrupt?!\n",
  804                             sc->sc_dev.dv_xname);
  805                 else
  806                         ifp->if_oerrors++;
  807 
  808                 if (tx_status & EPHSR_LATCOL)
  809                         ifp->if_collisions++;
  810 
  811                 /*
  812                  * Some of these errors disable the transmitter; reenable it.
  813                  */
  814                 SMC_SELECT_BANK(sc, 0);
  815 #ifdef SMC91CXX_SW_PAD
  816                 bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, TCR_ENABLE);
  817 #else
  818                 bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W,
  819                     TCR_ENABLE | TCR_PAD_ENABLE);
  820 #endif
  821 
  822                 /*
  823                  * Kill the failed packet and wait for the MMU to unbusy.
  824                  */
  825                 SMC_SELECT_BANK(sc, 2);
  826                 while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY)
  827                         /* XXX bound this loop! */ ;
  828                 bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_FREEPKT);
  829 
  830                 ifp->if_timer = 0;
  831         }
  832 
  833         /*
  834          * Transmit underrun interrupts.  We use this opportunity to
  835          * update transmit statistics from the card.
  836          */
  837         if (status & IM_TX_EMPTY_INT) {
  838                 bus_space_write_1(bst, bsh, INTR_ACK_REG_B, IM_TX_EMPTY_INT);
  839 
  840                 /* Disable this interrupt. */
  841                 mask &= ~IM_TX_EMPTY_INT;
  842 
  843                 SMC_SELECT_BANK(sc, 0);
  844                 card_stats = bus_space_read_2(bst, bsh, COUNTER_REG_W);
  845 
  846                 /* Single collisions. */
  847                 ifp->if_collisions += card_stats & ECR_COLN_MASK;
  848 
  849                 /* Multiple collisions. */
  850                 ifp->if_collisions += (card_stats & ECR_MCOLN_MASK) >> 4;
  851 
  852                 SMC_SELECT_BANK(sc, 2);
  853 
  854                 ifp->if_timer = 0;
  855         }
  856 
  857         /*
  858          * Other errors.  Reset the interface.
  859          */
  860         if (status & IM_EPH_INT) {
  861                 smc91cxx_stop(sc);
  862                 smc91cxx_init(sc);
  863         }
  864 
  865         /*
  866          * Attempt to queue more packets for transmission.
  867          */
  868         smc91cxx_start(ifp);
  869 
  870 out:
  871         /*
  872          * Reenable the interrupts we wish to receive now that processing
  873          * is complete.
  874          */
  875         mask |= bus_space_read_1(bst, bsh, INTR_MASK_REG_B);
  876         bus_space_write_1(bst, bsh, INTR_MASK_REG_B, mask);
  877 
  878         return (1);
  879 }
  880 
  881 /*
  882  * Read a packet from the card and pass it up to the kernel.
  883  * NOTE!  WE EXPECT TO BE IN REGISTER WINDOW 2!
  884  */
  885 void
  886 smc91cxx_read(struct smc91cxx_softc *sc)
  887 {
  888         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  889         bus_space_tag_t bst = sc->sc_bst;
  890         bus_space_handle_t bsh = sc->sc_bsh;
  891         struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  892         struct mbuf *m;
  893         u_int16_t status, packetno, packetlen;
  894         u_int8_t *data;
  895 
  896  again:
  897         /*
  898          * Set data pointer to the beginning of the packet.  Since
  899          * PTR_RCV is set, the packet number will be found automatically
  900          * in FIFO_PORTS_REG_W, FIFO_RX_MASK.
  901          */
  902         bus_space_write_2(bst, bsh, POINTER_REG_W,
  903             PTR_READ | PTR_RCV | PTR_AUTOINC /* | 0x0000 */);
  904 
  905         /*
  906          * First two words are status and packet length.
  907          */
  908         status = bus_space_read_2(bst, bsh, DATA_REG_W);
  909         packetlen = bus_space_read_2(bst, bsh, DATA_REG_W);
  910 
  911         /*
  912          * The packet length includes 3 extra words: status, length,
  913          * and an extra word that includes the control byte.
  914          */
  915         packetlen -= 6;
  916 
  917         /*
  918          * Account for receive errors and discard.
  919          */
  920         if (status & RS_ERRORS) {
  921                 ifp->if_ierrors++;
  922                 goto out;
  923         }
  924 
  925         /*
  926          * Adjust for odd-length packet.
  927          */
  928         if (status & RS_ODDFRAME)
  929                 packetlen++;
  930 
  931         /*
  932          * Allocate a header mbuf.
  933          */
  934         MGETHDR(m, M_DONTWAIT, MT_DATA);
  935         if (m == NULL)
  936                 goto out;
  937         m->m_pkthdr.len = packetlen;
  938 
  939         /*
  940          * Always put the packet in a cluster.
  941          * XXX should chain small mbufs if less than threshold.
  942          */
  943         MCLGET(m, M_DONTWAIT);
  944         if ((m->m_flags & M_EXT) == 0) {
  945                 m_freem(m);
  946                 ifp->if_ierrors++;
  947                 printf("%s: can't allocate cluster for incoming packet\n",
  948                     sc->sc_dev.dv_xname);
  949                 goto out;
  950         }
  951 
  952         /*
  953          * Pull the packet off the interface.  Make sure the payload
  954          * is aligned.
  955          */
  956         m->m_data = (caddr_t) ALIGN(mtod(m, caddr_t) +
  957             sizeof(struct ether_header)) - sizeof(struct ether_header);
  958 
  959         data = mtod(m, u_int8_t *);
  960         if (packetlen > 1)
  961                 bus_space_read_multi_stream_2(bst, bsh, DATA_REG_W,
  962                     (u_int16_t *)data, packetlen >> 1);
  963         if (packetlen & 1) {
  964                 data += packetlen & ~1;
  965                 *data = bus_space_read_1(bst, bsh, DATA_REG_B);
  966         }
  967 
  968         m->m_pkthdr.len = m->m_len = packetlen;
  969         ml_enqueue(&ml, m);
  970 
  971  out:
  972         /*
  973          * Tell the card to free the memory occupied by this packet.
  974          */
  975         while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY)
  976                 /* XXX bound this loop! */ ;
  977         bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_RELEASE);
  978 
  979         /*
  980          * Check for another packet.
  981          */
  982         packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W);
  983         if (packetno & FIFO_REMPTY) {
  984                 if_input(ifp, &ml);
  985                 return;
  986         }
  987         goto again;
  988 }
  989 
  990 /*
  991  * Process an ioctl request.
  992  */
  993 int
  994 smc91cxx_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  995 {
  996         struct smc91cxx_softc *sc = ifp->if_softc;
  997         struct ifreq *ifr = (struct ifreq *)data;
  998         int s, error = 0;
  999 
 1000         s = splnet();
 1001 
 1002         switch (cmd) {
 1003         case SIOCSIFADDR:
 1004                 if ((error = smc91cxx_enable(sc)) != 0)
 1005                         break;
 1006                 ifp->if_flags |= IFF_UP;
 1007                 smc91cxx_init(sc);
 1008                 break;
 1009 
 1010         case SIOCSIFFLAGS:
 1011                 if ((ifp->if_flags & IFF_UP) == 0 &&
 1012                     (ifp->if_flags & IFF_RUNNING) != 0) {
 1013                         /*
 1014                          * If interface is marked down and it is running,
 1015                          * stop it.
 1016                          */
 1017                         smc91cxx_stop(sc);
 1018                         ifp->if_flags &= ~IFF_RUNNING;
 1019                         smc91cxx_disable(sc);
 1020                 } else if ((ifp->if_flags & IFF_UP) != 0 &&
 1021                            (ifp->if_flags & IFF_RUNNING) == 0) {
 1022                         /*
 1023                          * If interface is marked up and it is stopped,
 1024                          * start it.
 1025                          */
 1026                         if ((error = smc91cxx_enable(sc)) != 0)
 1027                                 break;
 1028                         smc91cxx_init(sc);
 1029                 } else if ((ifp->if_flags & IFF_UP) != 0) {
 1030                         /*
 1031                          * Reset the interface to pick up changes in any
 1032                          * other flags that affect hardware registers.
 1033                          */
 1034                         smc91cxx_reset(sc);
 1035                 }
 1036                 break;
 1037 
 1038         case SIOCGIFMEDIA:
 1039         case SIOCSIFMEDIA:
 1040                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
 1041                 break;
 1042 
 1043         default:
 1044                 error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data);
 1045         }
 1046 
 1047         if (error == ENETRESET) {
 1048                 if (ifp->if_flags & IFF_RUNNING)
 1049                         smc91cxx_reset(sc);
 1050                 error = 0;
 1051         }
 1052 
 1053         splx(s);
 1054         return (error);
 1055 }
 1056 
 1057 /*
 1058  * Reset the interface.
 1059  */
 1060 void
 1061 smc91cxx_reset(struct smc91cxx_softc *sc)
 1062 {
 1063         int s;
 1064 
 1065         s = splnet();
 1066         smc91cxx_stop(sc);
 1067         smc91cxx_init(sc);
 1068         splx(s);
 1069 }
 1070 
 1071 /*
 1072  * Watchdog timer.
 1073  */
 1074 void
 1075 smc91cxx_watchdog(struct ifnet *ifp)
 1076 {
 1077         struct smc91cxx_softc *sc = ifp->if_softc;
 1078 
 1079         log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
 1080         ++sc->sc_arpcom.ac_if.if_oerrors;
 1081 
 1082         smc91cxx_reset(sc);
 1083 }
 1084 
 1085 /*
 1086  * Stop output on the interface.
 1087  */
 1088 void
 1089 smc91cxx_stop(struct smc91cxx_softc *sc)
 1090 {
 1091         bus_space_tag_t bst = sc->sc_bst;
 1092         bus_space_handle_t bsh = sc->sc_bsh;
 1093 
 1094         /*
 1095          * Clear interrupt mask; disable all interrupts.
 1096          */
 1097         SMC_SELECT_BANK(sc, 2);
 1098         bus_space_write_1(bst, bsh, INTR_MASK_REG_B, 0);
 1099 
 1100         /*
 1101          * Disable transmitter and receiver.
 1102          */
 1103         SMC_SELECT_BANK(sc, 0);
 1104         bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, 0);
 1105         bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, 0);
 1106 
 1107         /*
 1108          * Cancel watchdog timer.
 1109          */
 1110         sc->sc_arpcom.ac_if.if_timer = 0;
 1111 }
 1112 
 1113 /*
 1114  * Enable power on the interface.
 1115  */
 1116 int
 1117 smc91cxx_enable(struct smc91cxx_softc *sc)
 1118 {
 1119         if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0 && sc->sc_enable != NULL) {
 1120                 if ((*sc->sc_enable)(sc) != 0) {
 1121                         printf("%s: device enable failed\n",
 1122                             sc->sc_dev.dv_xname);
 1123                         return (EIO);
 1124                 }
 1125         }
 1126 
 1127         sc->sc_flags |= SMC_FLAGS_ENABLED;
 1128         return (0);
 1129 }
 1130 
 1131 /*
 1132  * Disable power on the interface.
 1133  */
 1134 void
 1135 smc91cxx_disable(struct smc91cxx_softc *sc)
 1136 {
 1137         if ((sc->sc_flags & SMC_FLAGS_ENABLED) != 0 && sc->sc_disable != NULL) {
 1138                 (*sc->sc_disable)(sc);
 1139                 sc->sc_flags &= ~SMC_FLAGS_ENABLED;
 1140         }
 1141 }
 1142 
 1143 int
 1144 smc91cxx_detach(struct device *self, int flags)
 1145 {
 1146         struct smc91cxx_softc *sc = (struct smc91cxx_softc *)self;
 1147         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
 1148 
 1149         /* Succeed now if there's no work to do. */
 1150         if ((sc->sc_flags & SMC_FLAGS_ATTACHED) == 0)
 1151                 return(0);
 1152 
 1153         /* smc91cxx_disable() checks SMC_FLAGS_ENABLED */
 1154         smc91cxx_disable(sc);
 1155 
 1156         /* smc91cxx_attach() never fails */
 1157 
 1158         /* Delete all media. */
 1159         ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
 1160 
 1161         ether_ifdetach(ifp);
 1162         if_detach(ifp);
 1163 
 1164         return (0);
 1165 }
 1166 
 1167 u_int32_t
 1168 smc91cxx_mii_bitbang_read(struct device *self)
 1169 {
 1170         struct smc91cxx_softc *sc = (void *) self;
 1171 
 1172         /* We're already in bank 3. */
 1173         return (bus_space_read_2(sc->sc_bst, sc->sc_bsh, MGMT_REG_W));
 1174 }
 1175 
 1176 void
 1177 smc91cxx_mii_bitbang_write(struct device *self, u_int32_t val)
 1178 {
 1179         struct smc91cxx_softc *sc = (void *) self;
 1180 
 1181         /* We're already in bank 3. */
 1182         bus_space_write_2(sc->sc_bst, sc->sc_bsh, MGMT_REG_W, val);
 1183 }
 1184 
 1185 int
 1186 smc91cxx_mii_readreg(struct device *self, int phy, int reg)
 1187 {
 1188         struct smc91cxx_softc *sc = (void *) self;
 1189         int val;
 1190 
 1191         SMC_SELECT_BANK(sc, 3);
 1192 
 1193         val = mii_bitbang_readreg(self, &smc91cxx_mii_bitbang_ops, phy, reg);
 1194 
 1195         SMC_SELECT_BANK(sc, 2);
 1196 
 1197         return (val);
 1198 }
 1199 
 1200 void
 1201 smc91cxx_mii_writereg(struct device *self, int phy, int reg, int val)
 1202 {
 1203         struct smc91cxx_softc *sc = (void *) self;
 1204 
 1205         SMC_SELECT_BANK(sc, 3);
 1206 
 1207         mii_bitbang_writereg(self, &smc91cxx_mii_bitbang_ops, phy, reg, val);
 1208 
 1209         SMC_SELECT_BANK(sc, 2);
 1210 }
 1211 
 1212 void
 1213 smc91cxx_statchg(struct device *self)
 1214 {
 1215         struct smc91cxx_softc *sc = (struct smc91cxx_softc *)self;
 1216         bus_space_tag_t bst = sc->sc_bst;
 1217         bus_space_handle_t bsh = sc->sc_bsh;
 1218         int mctl;
 1219 
 1220         SMC_SELECT_BANK(sc, 0);
 1221         mctl = bus_space_read_2(bst, bsh, TXMIT_CONTROL_REG_W);
 1222         if (sc->sc_mii.mii_media_active & IFM_FDX)
 1223                 mctl |= TCR_SWFDUP;
 1224         else
 1225                 mctl &= ~TCR_SWFDUP;
 1226         bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, mctl);
 1227         SMC_SELECT_BANK(sc, 2); /* back to operating window */
 1228 }
 1229 
 1230 /*
 1231  * One second timer, used to tick the MII.
 1232  */
 1233 void
 1234 smc91cxx_tick(void *arg)
 1235 {
 1236         struct smc91cxx_softc *sc = arg;
 1237         int s;
 1238 
 1239 #ifdef DIAGNOSTIC
 1240         if ((sc->sc_flags & SMC_FLAGS_HAS_MII) == 0)
 1241                 panic("smc91cxx_tick");
 1242 #endif
 1243 
 1244         if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
 1245                 return;
 1246 
 1247         s = splnet();
 1248         mii_tick(&sc->sc_mii);
 1249         splx(s);
 1250 
 1251         timeout_add_sec(&sc->sc_mii_timeout, 1);
 1252 }

Cache object: aecdfffb054f6e32daf0bc20715b7473


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