LCOV - code coverage report
Current view: top level - dev/ic - smc91cxx.c (source / functions) Hit Total Coverage
Test: 6.4 Lines: 0 431 0.0 %
Date: 2018-10-19 03:25:38 Functions: 0 22 0.0 %
Legend: Lines: hit not hit

          Line data    Source code
       1             : /*      $OpenBSD: smc91cxx.c,v 1.49 2017/01/22 10:17:38 dlg 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 drived 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           0 : smc91cxx_attach(sc, myea)
     186             :         struct smc91cxx_softc *sc;
     187             :         u_int8_t *myea;
     188             : {
     189           0 :         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
     190           0 :         bus_space_tag_t bst = sc->sc_bst;
     191           0 :         bus_space_handle_t bsh = sc->sc_bsh;
     192           0 :         struct ifmedia *ifm = &sc->sc_mii.mii_media;
     193             :         u_int32_t miicapabilities;
     194             :         u_int16_t tmp;
     195             :         int i, aui;
     196             :         const char *idstr;
     197             : 
     198             :         /* Make sure the chip is stopped. */
     199           0 :         smc91cxx_stop(sc);
     200             : 
     201           0 :         SMC_SELECT_BANK(sc, 3);
     202           0 :         tmp = bus_space_read_2(bst, bsh, REVISION_REG_W);
     203           0 :         sc->sc_chipid = RR_ID(tmp);
     204             :         /* check magic number */
     205           0 :         if ((tmp & BSR_DETECT_MASK) != BSR_DETECT_VALUE) {
     206             :                 idstr = NULL;
     207           0 :                 printf("%s: invalid BSR 0x%04x\n", sc->sc_dev.dv_xname, tmp);
     208           0 :         } else
     209           0 :                 idstr = smc91cxx_idstrs[RR_ID(tmp)];
     210             : #ifdef SMC_DEBUG
     211             :         printf("\n%s: ", sc->sc_dev.dv_xname);
     212             :         if (idstr != NULL)
     213             :                 printf("%s, ", idstr);
     214             :         else
     215             :                 printf("unknown chip id %d, ", sc->sc_chipid);
     216             :         printf("revision %d", RR_REV(tmp));
     217             : #endif
     218             : 
     219             :         /* Read the station address from the chip. */
     220           0 :         SMC_SELECT_BANK(sc, 1);
     221           0 :         if (myea == NULL) {
     222           0 :                 for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
     223           0 :                         tmp = bus_space_read_2(bst, bsh, IAR_ADDR0_REG_W + i);
     224           0 :                         sc->sc_arpcom.ac_enaddr[i + 1] = (tmp >>8) & 0xff;
     225           0 :                         sc->sc_arpcom.ac_enaddr[i] = tmp & 0xff;
     226             :                 }
     227             :         } else {
     228           0 :                 bcopy(myea, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
     229             :         }
     230             : 
     231           0 :         printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
     232             : 
     233             :         /* Initialize the ifnet structure. */
     234           0 :         bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
     235           0 :         ifp->if_softc = sc;
     236           0 :         ifp->if_start = smc91cxx_start;
     237           0 :         ifp->if_ioctl = smc91cxx_ioctl;
     238           0 :         ifp->if_watchdog = smc91cxx_watchdog;
     239           0 :         ifp->if_flags =
     240             :             IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
     241             : 
     242             :         /* Attach the interface. */
     243           0 :         if_attach(ifp);
     244           0 :         ether_ifattach(ifp);
     245             : 
     246             :         /*
     247             :          * Initialize our media structures and MII info.  We will
     248             :          * probe the MII if we are on the SMC91Cxx
     249             :          */
     250           0 :         sc->sc_mii.mii_ifp = ifp;
     251           0 :         sc->sc_mii.mii_readreg = smc91cxx_mii_readreg;
     252           0 :         sc->sc_mii.mii_writereg = smc91cxx_mii_writereg;
     253           0 :         sc->sc_mii.mii_statchg = smc91cxx_statchg;
     254           0 :         ifmedia_init(ifm, 0, smc91cxx_mediachange, smc91cxx_mediastatus);
     255             : 
     256           0 :         SMC_SELECT_BANK(sc, 1);
     257           0 :         tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W);
     258             : 
     259             :         miicapabilities = BMSR_MEDIAMASK|BMSR_ANEG;
     260           0 :         switch (sc->sc_chipid) {
     261             :         case CHIP_91100:
     262             :                 /*
     263             :                  * The 91100 does not have full-duplex capabilities,
     264             :                  * even if the PHY does.
     265             :                  */
     266           0 :                 miicapabilities &= ~(BMSR_100TXFDX | BMSR_10TFDX);
     267             :                 /* FALLTHROUGH */
     268             :         case CHIP_91100FD:
     269           0 :                 if (tmp & CR_MII_SELECT) {
     270             : #ifdef SMC_DEBUG
     271             :                         printf("%s: default media MII\n",
     272             :                             sc->sc_dev.dv_xname);
     273             : #endif
     274           0 :                         mii_attach(&sc->sc_dev, &sc->sc_mii, miicapabilities,
     275             :                             MII_PHY_ANY, MII_OFFSET_ANY, 0);
     276           0 :                         if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
     277           0 :                                 ifmedia_add(&sc->sc_mii.mii_media,
     278             :                                     IFM_ETHER|IFM_NONE, 0, NULL);
     279           0 :                                 ifmedia_set(&sc->sc_mii.mii_media,
     280             :                                     IFM_ETHER|IFM_NONE);
     281           0 :                         } else {
     282           0 :                                 ifmedia_set(&sc->sc_mii.mii_media,
     283             :                                     IFM_ETHER|IFM_AUTO);
     284             :                         }
     285           0 :                         sc->sc_flags |= SMC_FLAGS_HAS_MII;
     286           0 :                         break;
     287             :                 }
     288             :                 /* FALLTHROUGH */
     289             :         default:
     290           0 :                 aui = tmp & CR_AUI_SELECT;
     291             : #ifdef SMC_DEBUG
     292             :                 printf("%s: default media %s\n", sc->sc_dev.dv_xname,
     293             :                         aui ? "AUI" : "UTP");
     294             : #endif
     295           0 :                 for (i = 0; i < NSMC91CxxMEDIA; i++)
     296           0 :                         ifmedia_add(ifm, smc91cxx_media[i], 0, NULL);
     297           0 :                 ifmedia_set(ifm, IFM_ETHER | (aui ? IFM_10_5 : IFM_10_T));
     298           0 :                 break;
     299             :         }
     300             : 
     301             :         /* The attach is successful. */
     302           0 :         sc->sc_flags |= SMC_FLAGS_ATTACHED;
     303           0 : }
     304             : 
     305             : /*
     306             :  * Change media according to request.
     307             :  */
     308             : int
     309           0 : smc91cxx_mediachange(ifp)
     310             :         struct ifnet *ifp;
     311             : {
     312           0 :         struct smc91cxx_softc *sc = ifp->if_softc;
     313             : 
     314           0 :         return (smc91cxx_set_media(sc, sc->sc_mii.mii_media.ifm_media));
     315             : }
     316             : 
     317             : int
     318           0 : smc91cxx_set_media(sc, media)
     319             :         struct smc91cxx_softc *sc;
     320             :         uint64_t media;
     321             : {
     322           0 :         bus_space_tag_t bst = sc->sc_bst;
     323           0 :         bus_space_handle_t bsh = sc->sc_bsh;
     324             :         u_int16_t tmp;
     325             : 
     326             :         /*
     327             :          * If the interface is not currently powered on, just return.
     328             :          * When it is enabled later, smc91cxx_init() will properly set
     329             :          * up the media for us.
     330             :          */
     331           0 :         if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0)
     332           0 :                 return (0);
     333             : 
     334           0 :         if (IFM_TYPE(media) != IFM_ETHER)
     335           0 :                 return (EINVAL);
     336             : 
     337           0 :         if (sc->sc_flags & SMC_FLAGS_HAS_MII)
     338           0 :                 return (mii_mediachg(&sc->sc_mii));
     339             : 
     340           0 :         switch (IFM_SUBTYPE(media)) {
     341             :         case IFM_10_T:
     342             :         case IFM_10_5:
     343           0 :                 SMC_SELECT_BANK(sc, 1);
     344           0 :                 tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W);
     345           0 :                 if (IFM_SUBTYPE(media) == IFM_10_5)
     346           0 :                         tmp |= CR_AUI_SELECT;
     347             :                 else
     348           0 :                         tmp &= ~CR_AUI_SELECT;
     349           0 :                 bus_space_write_2(bst, bsh, CONFIG_REG_W, tmp);
     350           0 :                 delay(20000);   /* XXX is this needed? */
     351             :                 break;
     352             : 
     353             :         default:
     354           0 :                 return (EINVAL);
     355             :         }
     356             : 
     357           0 :         return (0);
     358           0 : }
     359             : 
     360             : /*
     361             :  * Notify the world which media we're using.
     362             :  */
     363             : void
     364           0 : smc91cxx_mediastatus(ifp, ifmr)
     365             :         struct ifnet *ifp;
     366             :         struct ifmediareq *ifmr;
     367             : {
     368           0 :         struct smc91cxx_softc *sc = ifp->if_softc;
     369           0 :         bus_space_tag_t bst = sc->sc_bst;
     370           0 :         bus_space_handle_t bsh = sc->sc_bsh;
     371             :         u_int16_t tmp;
     372             : 
     373           0 :         if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0) {
     374           0 :                 ifmr->ifm_active = IFM_ETHER | IFM_NONE;
     375           0 :                 ifmr->ifm_status = 0;
     376           0 :                 return;
     377             :         }
     378             : 
     379             :         /*
     380             :          * If we have MII, go ask the PHY what's going on.
     381             :          */
     382           0 :         if (sc->sc_flags & SMC_FLAGS_HAS_MII) {
     383           0 :                 mii_pollstat(&sc->sc_mii);
     384           0 :                 ifmr->ifm_active = sc->sc_mii.mii_media_active;
     385           0 :                 ifmr->ifm_status = sc->sc_mii.mii_media_status;
     386           0 :                 return;
     387             :         }
     388             : 
     389           0 :         SMC_SELECT_BANK(sc, 1);
     390           0 :         tmp = bus_space_read_2(bst, bsh, CONFIG_REG_W);
     391           0 :         ifmr->ifm_active =
     392           0 :             IFM_ETHER | ((tmp & CR_AUI_SELECT) ? IFM_10_5 : IFM_10_T);
     393           0 : }
     394             : 
     395             : /*
     396             :  * Reset and initialize the chip.
     397             :  */
     398             : void
     399           0 : smc91cxx_init(sc)
     400             :         struct smc91cxx_softc *sc;
     401             : {
     402           0 :         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
     403           0 :         bus_space_tag_t bst = sc->sc_bst;
     404           0 :         bus_space_handle_t bsh = sc->sc_bsh;
     405             :         u_int16_t tmp;
     406             :         int s, i;
     407             : 
     408           0 :         s = splnet();
     409             : 
     410             :         /*
     411             :          * This resets the registers mostly to defaults, but doesn't
     412             :          * affect the EEPROM.  After the reset cycle, we pause briefly
     413             :          * for the chip to recover.
     414             :          *
     415             :          * XXX how long are we really supposed to delay?  --thorpej
     416             :          */
     417           0 :         SMC_SELECT_BANK(sc, 0);
     418           0 :         bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, RCR_SOFTRESET);
     419           0 :         delay(100);
     420           0 :         bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, 0);
     421           0 :         delay(200);
     422             : 
     423           0 :         bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, 0);
     424             : 
     425             :         /* Set the Ethernet address. */
     426           0 :         SMC_SELECT_BANK(sc, 1);
     427           0 :         for (i = 0; i < ETHER_ADDR_LEN; i++ )
     428           0 :                 bus_space_write_1(bst, bsh, IAR_ADDR0_REG_W + i,
     429             :                     sc->sc_arpcom.ac_enaddr[i]);
     430             : 
     431             :         /*
     432             :          * Set the control register to automatically release successfully
     433             :          * transmitted packets (making the best use of our limited memory)
     434             :          * and enable the EPH interrupt on certain TX errors.
     435             :          */
     436           0 :         bus_space_write_2(bst, bsh, CONTROL_REG_W, (CTR_AUTO_RELEASE |
     437             :             CTR_TE_ENABLE | CTR_CR_ENABLE | CTR_LE_ENABLE));
     438             : 
     439             :         /*
     440             :          * Reset the MMU and wait for it to be un-busy.
     441             :          */
     442           0 :         SMC_SELECT_BANK(sc, 2);
     443           0 :         bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_RESET);
     444           0 :         while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY)
     445             :                 /* XXX bound this loop! */ ;
     446             : 
     447             :         /*
     448             :          * Disable all interrupts.
     449             :          */
     450           0 :         bus_space_write_1(bst, bsh, INTR_MASK_REG_B, 0);
     451             : 
     452             :         /*
     453             :          * Set current media.
     454             :          */
     455           0 :         smc91cxx_set_media(sc, sc->sc_mii.mii_media.ifm_cur->ifm_media);
     456             : 
     457             :         /*
     458             :          * Set the receive filter.  We want receive enable and auto
     459             :          * strip of CRC from received packet.  If we are in promisc. mode,
     460             :          * then set that bit as well.
     461             :          *
     462             :          * XXX Initialize multicast filter.  For now, we just accept
     463             :          * XXX all multicast.
     464             :          */
     465           0 :         SMC_SELECT_BANK(sc, 0);
     466             : 
     467             :         tmp = RCR_ENABLE | RCR_STRIP_CRC | RCR_ALMUL;
     468           0 :         if (ifp->if_flags & IFF_PROMISC)
     469           0 :                 tmp |= RCR_PROMISC;
     470             : 
     471           0 :         bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, tmp);
     472             : 
     473             :         /*
     474             :          * Set transmitter control to "enabled".
     475             :          */
     476             :         tmp = TCR_ENABLE;
     477             : 
     478             : #ifndef SMC91CXX_SW_PAD
     479             :         /*
     480             :          * Enable hardware padding of transmitted packets.
     481             :          * XXX doesn't work?
     482             :          */
     483             :         tmp |= TCR_PAD_ENABLE;
     484             : #endif
     485             : 
     486           0 :         bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, tmp);
     487             : 
     488             :         /*
     489             :          * Now, enable interrupts.
     490             :          */
     491           0 :         SMC_SELECT_BANK(sc, 2);
     492             : 
     493           0 :         bus_space_write_1(bst, bsh, INTR_MASK_REG_B,
     494             :             IM_EPH_INT | IM_RX_OVRN_INT | IM_RCV_INT | IM_TX_INT);
     495             : 
     496             :         /* Interface is now running, with no output active. */
     497           0 :         ifp->if_flags |= IFF_RUNNING;
     498           0 :         ifq_clr_oactive(&ifp->if_snd);
     499             : 
     500           0 :         if (sc->sc_flags & SMC_FLAGS_HAS_MII) {
     501             :                 /* Start the one second clock. */
     502           0 :                 timeout_set(&sc->sc_mii_timeout, smc91cxx_tick, sc);
     503           0 :                 timeout_add_sec(&sc->sc_mii_timeout, 1);
     504           0 :         }
     505             : 
     506             :         /*
     507             :          * Attempt to start any pending transmission.
     508             :          */
     509           0 :         smc91cxx_start(ifp);
     510             : 
     511           0 :         splx(s);
     512           0 : }
     513             : 
     514             : /*
     515             :  * Start output on an interface.
     516             :  * Must be called at splnet or interrupt level.
     517             :  */
     518             : void
     519           0 : smc91cxx_start(ifp)
     520             :         struct ifnet *ifp;
     521             : {
     522           0 :         struct smc91cxx_softc *sc = ifp->if_softc;
     523           0 :         bus_space_tag_t bst = sc->sc_bst;
     524           0 :         bus_space_handle_t bsh = sc->sc_bsh;
     525             :         u_int len;
     526             :         struct mbuf *m, *top;
     527             :         u_int16_t length, npages;
     528             :         u_int8_t packetno;
     529             :         int timo, pad;
     530             : 
     531           0 :         if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
     532           0 :                 return;
     533             : 
     534             :  again:
     535             :         /*
     536             :          * Peek at the next packet.
     537             :          */
     538           0 :         m = ifq_deq_begin(&ifp->if_snd);
     539           0 :         if (m == NULL)
     540           0 :                 return;
     541             : 
     542             :         /*
     543             :          * Compute the frame length and set pad to give an overall even
     544             :          * number of bytes.  Below, we assume that the packet length
     545             :          * is even.
     546             :          */
     547           0 :         for (len = 0, top = m; m != NULL; m = m->m_next)
     548           0 :                 len += m->m_len;
     549           0 :         pad = (len & 1);
     550             : 
     551             :         /*
     552             :          * We drop packets that are too large.  Perhaps we should
     553             :          * truncate them instead?
     554             :          */
     555           0 :         if ((len + pad) > (ETHER_MAX_LEN - ETHER_CRC_LEN)) {
     556           0 :                 printf("%s: large packet discarded\n", sc->sc_dev.dv_xname);
     557           0 :                 ifp->if_oerrors++;
     558           0 :                 ifq_deq_commit(&ifp->if_snd, m);
     559           0 :                 m_freem(m);
     560           0 :                 goto readcheck;
     561             :         }
     562             : 
     563             : #ifdef SMC91CXX_SW_PAD
     564             :         /*
     565             :          * Not using hardware padding; pad to ETHER_MIN_LEN.
     566             :          */
     567           0 :         if (len < (ETHER_MIN_LEN - ETHER_CRC_LEN))
     568           0 :                 pad = ETHER_MIN_LEN - ETHER_CRC_LEN - len;
     569             : #endif
     570             : 
     571           0 :         length = pad + len;
     572             : 
     573             :         /*
     574             :          * The MMU has a 256 byte page size.  The MMU expects us to
     575             :          * ask for "npages - 1".  We include space for the status word,
     576             :          * byte count, and control bytes in the allocation request.
     577             :          */
     578           0 :         npages = (length + 6) >> 8;
     579             : 
     580             :         /*
     581             :          * Now allocate the memory.
     582             :          */
     583           0 :         SMC_SELECT_BANK(sc, 2);
     584           0 :         bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_ALLOC | npages);
     585             : 
     586             :         timo = MEMORY_WAIT_TIME;
     587           0 :         do {
     588           0 :                 if (bus_space_read_1(bst, bsh, INTR_STAT_REG_B) & IM_ALLOC_INT)
     589             :                         break;
     590           0 :                 delay(1);
     591           0 :         } while (--timo);
     592             : 
     593           0 :         packetno = bus_space_read_1(bst, bsh, ALLOC_RESULT_REG_B);
     594             : 
     595           0 :         if (packetno & ARR_FAILED || timo == 0) {
     596             :                 /*
     597             :                  * No transmit memory is available.  Record the number
     598             :                  * of requestd pages and enable the allocation completion
     599             :                  * interrupt.  Set up the watchdog timer in case we miss
     600             :                  * the interrupt.  Mark the interface as active so that
     601             :                  * no one else attempts to transmit while we're allocating
     602             :                  * memory.
     603             :                  */
     604           0 :                 bus_space_write_1(bst, bsh, INTR_MASK_REG_B,
     605             :                     bus_space_read_1(bst, bsh, INTR_MASK_REG_B) | IM_ALLOC_INT);
     606             : 
     607           0 :                 ifp->if_timer = 5;
     608           0 :                 ifq_deq_rollback(&ifp->if_snd, m);
     609           0 :                 ifq_set_oactive(&ifp->if_snd);
     610           0 :                 return;
     611             :         }
     612             : 
     613             :         /*
     614             :          * We have a packet number - set the data window.
     615             :          */
     616           0 :         bus_space_write_1(bst, bsh, PACKET_NUM_REG_B, packetno);
     617             : 
     618             :         /*
     619             :          * Point to the beginning of the packet.
     620             :          */
     621           0 :         bus_space_write_2(bst, bsh, POINTER_REG_W, PTR_AUTOINC /* | 0x0000 */);
     622             : 
     623             :         /*
     624             :          * Send the packet length (+6 for stats, length, and control bytes)
     625             :          * and the status word (set to zeros).
     626             :          */
     627           0 :         bus_space_write_2(bst, bsh, DATA_REG_W, 0);
     628           0 :         bus_space_write_1(bst, bsh, DATA_REG_B, (length + 6) & 0xff);
     629           0 :         bus_space_write_1(bst, bsh, DATA_REG_B, ((length + 6) >> 8) & 0xff);
     630             : 
     631             :         /*
     632             :          * Get the packet from the kernel.  This will include the Ethernet
     633             :          * frame header, MAC address, etc.
     634             :          */
     635           0 :         ifq_deq_commit(&ifp->if_snd, m);
     636             : 
     637             :         /*
     638             :          * Push the packet out to the card.
     639             :          */
     640           0 :         for (top = m; m != NULL; m = m->m_next) {
     641             :                 /* Words... */
     642           0 :                 if (m->m_len > 1)
     643           0 :                         bus_space_write_multi_stream_2(bst, bsh, DATA_REG_W,
     644             :                             mtod(m, u_int16_t *), m->m_len >> 1);
     645             : 
     646             :                 /* ...and the remaining byte, if any. */
     647           0 :                 if (m->m_len & 1)
     648           0 :                         bus_space_write_1(bst, bsh, DATA_REG_B,
     649             :                           *(u_int8_t *)(mtod(m, u_int8_t *) + (m->m_len - 1)));
     650             :         }
     651             : 
     652             : #ifdef SMC91CXX_SW_PAD
     653             :         /*
     654             :          * Push out padding.
     655             :          */
     656           0 :         while (pad > 1) {
     657           0 :                 bus_space_write_2(bst, bsh, DATA_REG_W, 0);
     658           0 :                 pad -= 2;
     659             :         }
     660           0 :         if (pad)
     661           0 :                 bus_space_write_1(bst, bsh, DATA_REG_B, 0);
     662             : #endif
     663             : 
     664             :         /*
     665             :          * Push out control byte and unused packet byte.  The control byte
     666             :          * is 0, meaning the packet is even lengthed and no special
     667             :          * CRC handling is necessary.
     668             :          */
     669           0 :         bus_space_write_2(bst, bsh, DATA_REG_W, 0);
     670             : 
     671             :         /*
     672             :          * Enable transmit interrupts and let the chip go.  Set a watchdog
     673             :          * in case we miss the interrupt.
     674             :          */
     675           0 :         bus_space_write_1(bst, bsh, INTR_MASK_REG_B,
     676             :             bus_space_read_1(bst, bsh, INTR_MASK_REG_B) |
     677             :             IM_TX_INT | IM_TX_EMPTY_INT);
     678             : 
     679           0 :         bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_ENQUEUE);
     680             : 
     681           0 :         ifp->if_timer = 5;
     682             : 
     683             : #if NBPFILTER > 0
     684           0 :         if (ifp->if_bpf)
     685           0 :                 bpf_mtap(ifp->if_bpf, top, BPF_DIRECTION_OUT);
     686             : #endif
     687             : 
     688           0 :         m_freem(top);
     689             : 
     690             :  readcheck:
     691             :         /*
     692             :          * Check for incoming packets.  We don't want to overflow the small
     693             :          * RX FIFO.  If nothing has arrived, attempt to queue another
     694             :          * transmit packet.
     695             :          */
     696           0 :         if (bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W) & FIFO_REMPTY)
     697           0 :                 goto again;
     698           0 : }
     699             : 
     700             : /*
     701             :  * Interrupt service routine.
     702             :  */
     703             : int
     704           0 : smc91cxx_intr(arg)
     705             :         void *arg;
     706             : {
     707           0 :         struct smc91cxx_softc *sc = arg;
     708           0 :         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
     709           0 :         bus_space_tag_t bst = sc->sc_bst;
     710           0 :         bus_space_handle_t bsh = sc->sc_bsh;
     711             :         u_int8_t mask, interrupts, status;
     712             :         u_int16_t packetno, tx_status, card_stats;
     713             : 
     714           0 :         if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0 ||
     715           0 :             (sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
     716           0 :                 return (0);
     717             : 
     718           0 :         SMC_SELECT_BANK(sc, 2);
     719             : 
     720             :         /*
     721             :          * Obtain the current interrupt mask.
     722             :          */
     723           0 :         mask = bus_space_read_1(bst, bsh, INTR_MASK_REG_B);
     724             : 
     725             :         /*
     726             :          * Get the set of interrupt which occurred and eliminate any
     727             :          * which are not enabled.
     728             :          */
     729           0 :         interrupts = bus_space_read_1(bst, bsh, INTR_STAT_REG_B);
     730           0 :         status = interrupts & mask;
     731             : 
     732             :         /* Ours? */
     733           0 :         if (status == 0)
     734           0 :                 return (0);
     735             : 
     736             :         /*
     737             :          * It's ours; disable all interrupts while we process them.
     738             :          */
     739           0 :         bus_space_write_1(bst, bsh, INTR_MASK_REG_B, 0);
     740             : 
     741             :         /*
     742             :          * Receive overrun interrupts.
     743             :          */
     744           0 :         if (status & IM_RX_OVRN_INT) {
     745           0 :                 bus_space_write_1(bst, bsh, INTR_ACK_REG_B, IM_RX_OVRN_INT);
     746           0 :                 ifp->if_ierrors++;
     747           0 :         }
     748             : 
     749             :         /*
     750             :          * Receive interrupts.
     751             :          */
     752           0 :         if (status & IM_RCV_INT) {
     753             : #if 1 /* DIAGNOSTIC */
     754           0 :                 packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W);
     755           0 :                 if (packetno & FIFO_REMPTY) {
     756           0 :                         printf("%s: receive interrupt on empty fifo\n",
     757           0 :                             sc->sc_dev.dv_xname);
     758           0 :                         goto out;
     759             :                 } else
     760             : #endif
     761           0 :                 smc91cxx_read(sc);
     762           0 :         }
     763             : 
     764             :         /*
     765             :          * Memory allocation interrupts.
     766             :          */
     767           0 :         if (status & IM_ALLOC_INT) {
     768             :                 /* Disable this interrupt. */
     769           0 :                 mask &= ~IM_ALLOC_INT;
     770             : 
     771             :                 /*
     772             :                  * Release the just-allocated memory.  We will reallocate
     773             :                  * it through the normal start logic.
     774             :                  */
     775           0 :                 while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY)
     776             :                         /* XXX bound this loop! */ ;
     777           0 :                 bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_FREEPKT);
     778             : 
     779           0 :                 ifq_clr_oactive(&ifp->if_snd);
     780           0 :                 ifp->if_timer = 0;
     781           0 :         }
     782             : 
     783             :         /*
     784             :          * Transmit complete interrupt.  Handle transmission error messages.
     785             :          * This will only be called on error condition because of AUTO RELEASE
     786             :          * mode.
     787             :          */
     788           0 :         if (status & IM_TX_INT) {
     789           0 :                 bus_space_write_1(bst, bsh, INTR_ACK_REG_B, IM_TX_INT);
     790             : 
     791           0 :                 packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W) &
     792             :                     FIFO_TX_MASK;
     793             : 
     794             :                 /*
     795             :                  * Select this as the packet to read from.
     796             :                  */
     797           0 :                 bus_space_write_1(bst, bsh, PACKET_NUM_REG_B, packetno);
     798             : 
     799             :                 /*
     800             :                  * Position the pointer to the beginning of the packet.
     801             :                  */
     802           0 :                 bus_space_write_2(bst, bsh, POINTER_REG_W,
     803             :                     PTR_AUTOINC | PTR_READ /* | 0x0000 */);
     804             : 
     805             :                 /*
     806             :                  * Fetch the TX status word.  This will be a copy of
     807             :                  * the EPH_STATUS_REG_W at the time of the transmission
     808             :                  * failure.
     809             :                  */
     810           0 :                 tx_status = bus_space_read_2(bst, bsh, DATA_REG_W);
     811             : 
     812           0 :                 if (tx_status & EPHSR_TX_SUC)
     813           0 :                         printf("%s: successful packet caused TX interrupt?!\n",
     814           0 :                             sc->sc_dev.dv_xname);
     815             :                 else
     816           0 :                         ifp->if_oerrors++;
     817             : 
     818           0 :                 if (tx_status & EPHSR_LATCOL)
     819           0 :                         ifp->if_collisions++;
     820             : 
     821             :                 /*
     822             :                  * Some of these errors disable the transmitter; reenable it.
     823             :                  */
     824           0 :                 SMC_SELECT_BANK(sc, 0);
     825             : #ifdef SMC91CXX_SW_PAD
     826           0 :                 bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, TCR_ENABLE);
     827             : #else
     828             :                 bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W,
     829             :                     TCR_ENABLE | TCR_PAD_ENABLE);
     830             : #endif
     831             : 
     832             :                 /*
     833             :                  * Kill the failed packet and wait for the MMU to unbusy.
     834             :                  */
     835           0 :                 SMC_SELECT_BANK(sc, 2);
     836           0 :                 while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY)
     837             :                         /* XXX bound this loop! */ ;
     838           0 :                 bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_FREEPKT);
     839             : 
     840           0 :                 ifp->if_timer = 0;
     841           0 :         }
     842             : 
     843             :         /*
     844             :          * Transmit underrun interrupts.  We use this opportunity to
     845             :          * update transmit statistics from the card.
     846             :          */
     847           0 :         if (status & IM_TX_EMPTY_INT) {
     848           0 :                 bus_space_write_1(bst, bsh, INTR_ACK_REG_B, IM_TX_EMPTY_INT);
     849             : 
     850             :                 /* Disable this interrupt. */
     851           0 :                 mask &= ~IM_TX_EMPTY_INT;
     852             : 
     853           0 :                 SMC_SELECT_BANK(sc, 0);
     854           0 :                 card_stats = bus_space_read_2(bst, bsh, COUNTER_REG_W);
     855             : 
     856             :                 /* Single collisions. */
     857           0 :                 ifp->if_collisions += card_stats & ECR_COLN_MASK;
     858             : 
     859             :                 /* Multiple collisions. */
     860           0 :                 ifp->if_collisions += (card_stats & ECR_MCOLN_MASK) >> 4;
     861             : 
     862           0 :                 SMC_SELECT_BANK(sc, 2);
     863             : 
     864           0 :                 ifp->if_timer = 0;
     865           0 :         }
     866             : 
     867             :         /*
     868             :          * Other errors.  Reset the interface.
     869             :          */
     870           0 :         if (status & IM_EPH_INT) {
     871           0 :                 smc91cxx_stop(sc);
     872           0 :                 smc91cxx_init(sc);
     873           0 :         }
     874             : 
     875             :         /*
     876             :          * Attempt to queue more packets for transmission.
     877             :          */
     878           0 :         smc91cxx_start(ifp);
     879             : 
     880             : out:
     881             :         /*
     882             :          * Reenable the interrupts we wish to receive now that processing
     883             :          * is complete.
     884             :          */
     885           0 :         mask |= bus_space_read_1(bst, bsh, INTR_MASK_REG_B);
     886           0 :         bus_space_write_1(bst, bsh, INTR_MASK_REG_B, mask);
     887             : 
     888           0 :         return (1);
     889           0 : }
     890             : 
     891             : /*
     892             :  * Read a packet from the card and pass it up to the kernel.
     893             :  * NOTE!  WE EXPECT TO BE IN REGISTER WINDOW 2!
     894             :  */
     895             : void
     896           0 : smc91cxx_read(sc)
     897             :         struct smc91cxx_softc *sc;
     898             : {
     899           0 :         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
     900           0 :         bus_space_tag_t bst = sc->sc_bst;
     901           0 :         bus_space_handle_t bsh = sc->sc_bsh;
     902           0 :         struct mbuf_list ml = MBUF_LIST_INITIALIZER();
     903             :         struct mbuf *m;
     904             :         u_int16_t status, packetno, packetlen;
     905           0 :         u_int8_t *data;
     906             : 
     907             :  again:
     908             :         /*
     909             :          * Set data pointer to the beginning of the packet.  Since
     910             :          * PTR_RCV is set, the packet number will be found automatically
     911             :          * in FIFO_PORTS_REG_W, FIFO_RX_MASK.
     912             :          */
     913           0 :         bus_space_write_2(bst, bsh, POINTER_REG_W,
     914             :             PTR_READ | PTR_RCV | PTR_AUTOINC /* | 0x0000 */);
     915             : 
     916             :         /*
     917             :          * First two words are status and packet length.
     918             :          */
     919           0 :         status = bus_space_read_2(bst, bsh, DATA_REG_W);
     920           0 :         packetlen = bus_space_read_2(bst, bsh, DATA_REG_W);
     921             : 
     922             :         /*
     923             :          * The packet length includes 3 extra words: status, length,
     924             :          * and an extra word that includes the control byte.
     925             :          */
     926           0 :         packetlen -= 6;
     927             : 
     928             :         /*
     929             :          * Account for receive errors and discard.
     930             :          */
     931           0 :         if (status & RS_ERRORS) {
     932           0 :                 ifp->if_ierrors++;
     933           0 :                 goto out;
     934             :         }
     935             : 
     936             :         /*
     937             :          * Adjust for odd-length packet.
     938             :          */
     939           0 :         if (status & RS_ODDFRAME)
     940           0 :                 packetlen++;
     941             : 
     942             :         /*
     943             :          * Allocate a header mbuf.
     944             :          */
     945           0 :         MGETHDR(m, M_DONTWAIT, MT_DATA);
     946           0 :         if (m == NULL)
     947             :                 goto out;
     948           0 :         m->m_pkthdr.len = packetlen;
     949             : 
     950             :         /*
     951             :          * Always put the packet in a cluster.
     952             :          * XXX should chain small mbufs if less than threshold.
     953             :          */
     954           0 :         MCLGET(m, M_DONTWAIT);
     955           0 :         if ((m->m_flags & M_EXT) == 0) {
     956           0 :                 m_freem(m);
     957           0 :                 ifp->if_ierrors++;
     958           0 :                 printf("%s: can't allocate cluster for incoming packet\n",
     959           0 :                     sc->sc_dev.dv_xname);
     960           0 :                 goto out;
     961             :         }
     962             : 
     963             :         /*
     964             :          * Pull the packet off the interface.  Make sure the payload
     965             :          * is aligned.
     966             :          */
     967           0 :         m->m_data = (caddr_t) ALIGN(mtod(m, caddr_t) +
     968           0 :             sizeof(struct ether_header)) - sizeof(struct ether_header);
     969             : 
     970             :         data = mtod(m, u_int8_t *);
     971           0 :         if (packetlen > 1)
     972           0 :                 bus_space_read_multi_stream_2(bst, bsh, DATA_REG_W,
     973             :                     (u_int16_t *)data, packetlen >> 1);
     974           0 :         if (packetlen & 1) {
     975           0 :                 data += packetlen & ~1;
     976           0 :                 *data = bus_space_read_1(bst, bsh, DATA_REG_B);
     977           0 :         }
     978             : 
     979           0 :         m->m_pkthdr.len = m->m_len = packetlen;
     980           0 :         ml_enqueue(&ml, m);
     981             : 
     982             :  out:
     983             :         /*
     984             :          * Tell the card to free the memory occupied by this packet.
     985             :          */
     986           0 :         while (bus_space_read_2(bst, bsh, MMU_CMD_REG_W) & MMUCR_BUSY)
     987             :                 /* XXX bound this loop! */ ;
     988           0 :         bus_space_write_2(bst, bsh, MMU_CMD_REG_W, MMUCR_RELEASE);
     989             : 
     990             :         /*
     991             :          * Check for another packet.
     992             :          */
     993           0 :         packetno = bus_space_read_2(bst, bsh, FIFO_PORTS_REG_W);
     994           0 :         if (packetno & FIFO_REMPTY) {
     995           0 :                 if_input(ifp, &ml);
     996             :                 return;
     997             :         }
     998           0 :         goto again;
     999           0 : }
    1000             : 
    1001             : /*
    1002             :  * Process an ioctl request.
    1003             :  */
    1004             : int
    1005           0 : smc91cxx_ioctl(ifp, cmd, data)
    1006             :         struct ifnet *ifp;
    1007             :         u_long cmd;
    1008             :         caddr_t data;
    1009             : {
    1010           0 :         struct smc91cxx_softc *sc = ifp->if_softc;
    1011           0 :         struct ifreq *ifr = (struct ifreq *)data;
    1012             :         int s, error = 0;
    1013             : 
    1014           0 :         s = splnet();
    1015             : 
    1016           0 :         switch (cmd) {
    1017             :         case SIOCSIFADDR:
    1018           0 :                 if ((error = smc91cxx_enable(sc)) != 0)
    1019             :                         break;
    1020           0 :                 ifp->if_flags |= IFF_UP;
    1021           0 :                 smc91cxx_init(sc);
    1022           0 :                 break;
    1023             : 
    1024             :         case SIOCSIFFLAGS:
    1025           0 :                 if ((ifp->if_flags & IFF_UP) == 0 &&
    1026           0 :                     (ifp->if_flags & IFF_RUNNING) != 0) {
    1027             :                         /*
    1028             :                          * If interface is marked down and it is running,
    1029             :                          * stop it.
    1030             :                          */
    1031           0 :                         smc91cxx_stop(sc);
    1032           0 :                         ifp->if_flags &= ~IFF_RUNNING;
    1033           0 :                         smc91cxx_disable(sc);
    1034           0 :                 } else if ((ifp->if_flags & IFF_UP) != 0 &&
    1035           0 :                            (ifp->if_flags & IFF_RUNNING) == 0) {
    1036             :                         /*
    1037             :                          * If interface is marked up and it is stopped,
    1038             :                          * start it.
    1039             :                          */
    1040           0 :                         if ((error = smc91cxx_enable(sc)) != 0)
    1041             :                                 break;
    1042           0 :                         smc91cxx_init(sc);
    1043           0 :                 } else if ((ifp->if_flags & IFF_UP) != 0) {
    1044             :                         /*
    1045             :                          * Reset the interface to pick up changes in any
    1046             :                          * other flags that affect hardware registers.
    1047             :                          */
    1048           0 :                         smc91cxx_reset(sc);
    1049           0 :                 }
    1050             :                 break;
    1051             : 
    1052             :         case SIOCGIFMEDIA:
    1053             :         case SIOCSIFMEDIA:
    1054           0 :                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
    1055           0 :                 break;
    1056             : 
    1057             :         default:
    1058           0 :                 error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data);
    1059           0 :         }
    1060             : 
    1061           0 :         if (error == ENETRESET) {
    1062           0 :                 if (ifp->if_flags & IFF_RUNNING)
    1063           0 :                         smc91cxx_reset(sc);
    1064             :                 error = 0;
    1065           0 :         }
    1066             : 
    1067           0 :         splx(s);
    1068           0 :         return (error);
    1069             : }
    1070             : 
    1071             : /*
    1072             :  * Reset the interface.
    1073             :  */
    1074             : void
    1075           0 : smc91cxx_reset(sc)
    1076             :         struct smc91cxx_softc *sc;
    1077             : {
    1078             :         int s;
    1079             : 
    1080           0 :         s = splnet();
    1081           0 :         smc91cxx_stop(sc);
    1082           0 :         smc91cxx_init(sc);
    1083           0 :         splx(s);
    1084           0 : }
    1085             : 
    1086             : /*
    1087             :  * Watchdog timer.
    1088             :  */
    1089             : void
    1090           0 : smc91cxx_watchdog(ifp)
    1091             :         struct ifnet *ifp;
    1092             : {
    1093           0 :         struct smc91cxx_softc *sc = ifp->if_softc;
    1094             : 
    1095           0 :         log(LOG_ERR, "%s: device timeout\n", sc->sc_dev.dv_xname);
    1096           0 :         ++sc->sc_arpcom.ac_if.if_oerrors;
    1097             : 
    1098           0 :         smc91cxx_reset(sc);
    1099           0 : }
    1100             : 
    1101             : /*
    1102             :  * Stop output on the interface.
    1103             :  */
    1104             : void
    1105           0 : smc91cxx_stop(sc)
    1106             :         struct smc91cxx_softc *sc;
    1107             : {
    1108           0 :         bus_space_tag_t bst = sc->sc_bst;
    1109           0 :         bus_space_handle_t bsh = sc->sc_bsh;
    1110             : 
    1111             :         /*
    1112             :          * Clear interrupt mask; disable all interrupts.
    1113             :          */
    1114           0 :         SMC_SELECT_BANK(sc, 2);
    1115           0 :         bus_space_write_1(bst, bsh, INTR_MASK_REG_B, 0);
    1116             : 
    1117             :         /*
    1118             :          * Disable transmitter and receiver.
    1119             :          */
    1120           0 :         SMC_SELECT_BANK(sc, 0);
    1121           0 :         bus_space_write_2(bst, bsh, RECV_CONTROL_REG_W, 0);
    1122           0 :         bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, 0);
    1123             : 
    1124             :         /*
    1125             :          * Cancel watchdog timer.
    1126             :          */
    1127           0 :         sc->sc_arpcom.ac_if.if_timer = 0;
    1128           0 : }
    1129             : 
    1130             : /*
    1131             :  * Enable power on the interface.
    1132             :  */
    1133             : int
    1134           0 : smc91cxx_enable(sc)
    1135             :         struct smc91cxx_softc *sc;
    1136             : {
    1137           0 :         if ((sc->sc_flags & SMC_FLAGS_ENABLED) == 0 && sc->sc_enable != NULL) {
    1138           0 :                 if ((*sc->sc_enable)(sc) != 0) {
    1139           0 :                         printf("%s: device enable failed\n",
    1140           0 :                             sc->sc_dev.dv_xname);
    1141           0 :                         return (EIO);
    1142             :                 }
    1143             :         }
    1144             : 
    1145           0 :         sc->sc_flags |= SMC_FLAGS_ENABLED;
    1146           0 :         return (0);
    1147           0 : }
    1148             : 
    1149             : /*
    1150             :  * Disable power on the interface.
    1151             :  */
    1152             : void
    1153           0 : smc91cxx_disable(sc)
    1154             :         struct smc91cxx_softc *sc;
    1155             : {
    1156           0 :         if ((sc->sc_flags & SMC_FLAGS_ENABLED) != 0 && sc->sc_disable != NULL) {
    1157           0 :                 (*sc->sc_disable)(sc);
    1158           0 :                 sc->sc_flags &= ~SMC_FLAGS_ENABLED;
    1159           0 :         }
    1160           0 : }
    1161             : 
    1162             : int
    1163           0 : smc91cxx_activate(self, act)
    1164             :         struct device *self;
    1165             :         int act;
    1166             : {
    1167             : #if 0
    1168             :         struct smc91cxx_softc *sc = (struct smc91cxx_softc *)self;
    1169             : #endif
    1170             :         int rv = 0, s;
    1171             : 
    1172           0 :         s = splnet();
    1173             :         switch (act) {
    1174             :         case DVACT_DEACTIVATE:
    1175             : #if 0
    1176             :                 if_deactivate(&sc->sc_ic.ic_if);
    1177             : #endif
    1178             :                 break;
    1179             :         }
    1180           0 :         splx(s);
    1181           0 :         return(rv);
    1182             : }
    1183             : 
    1184             : int
    1185           0 : smc91cxx_detach(self, flags)
    1186             :         struct device *self;
    1187             :         int flags;
    1188             : {
    1189           0 :         struct smc91cxx_softc *sc = (struct smc91cxx_softc *)self;
    1190           0 :         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
    1191             : 
    1192             :         /* Succeed now if there's no work to do. */
    1193           0 :         if ((sc->sc_flags & SMC_FLAGS_ATTACHED) == 0)
    1194           0 :                 return(0);
    1195             : 
    1196             :         /* smc91cxx_disable() checks SMC_FLAGS_ENABLED */
    1197           0 :         smc91cxx_disable(sc);
    1198             : 
    1199             :         /* smc91cxx_attach() never fails */
    1200             : 
    1201             :         /* Delete all media. */
    1202           0 :         ifmedia_delete_instance(&sc->sc_mii.mii_media, IFM_INST_ANY);
    1203             : 
    1204           0 :         ether_ifdetach(ifp);
    1205           0 :         if_detach(ifp);
    1206             : 
    1207           0 :         return (0);
    1208           0 : }
    1209             : 
    1210             : u_int32_t
    1211           0 : smc91cxx_mii_bitbang_read(self)
    1212             :         struct device *self;
    1213             : {
    1214           0 :         struct smc91cxx_softc *sc = (void *) self;
    1215             : 
    1216             :         /* We're already in bank 3. */
    1217           0 :         return (bus_space_read_2(sc->sc_bst, sc->sc_bsh, MGMT_REG_W));
    1218             : }
    1219             : 
    1220             : void
    1221           0 : smc91cxx_mii_bitbang_write(self, val)
    1222             :         struct device *self;
    1223             :         u_int32_t val;
    1224             : {
    1225           0 :         struct smc91cxx_softc *sc = (void *) self;
    1226             : 
    1227             :         /* We're already in bank 3. */
    1228           0 :         bus_space_write_2(sc->sc_bst, sc->sc_bsh, MGMT_REG_W, val);
    1229           0 : }
    1230             : 
    1231             : int
    1232           0 : smc91cxx_mii_readreg(self, phy, reg)
    1233             :         struct device *self;
    1234             :         int phy, reg;
    1235             : {
    1236           0 :         struct smc91cxx_softc *sc = (void *) self;
    1237             :         int val;
    1238             : 
    1239           0 :         SMC_SELECT_BANK(sc, 3);
    1240             : 
    1241           0 :         val = mii_bitbang_readreg(self, &smc91cxx_mii_bitbang_ops, phy, reg);
    1242             : 
    1243           0 :         SMC_SELECT_BANK(sc, 2);
    1244             : 
    1245           0 :         return (val);
    1246             : }
    1247             : 
    1248             : void
    1249           0 : smc91cxx_mii_writereg(self, phy, reg, val)
    1250             :         struct device *self;
    1251             :         int phy, reg, val;
    1252             : {
    1253           0 :         struct smc91cxx_softc *sc = (void *) self;
    1254             : 
    1255           0 :         SMC_SELECT_BANK(sc, 3);
    1256             : 
    1257           0 :         mii_bitbang_writereg(self, &smc91cxx_mii_bitbang_ops, phy, reg, val);
    1258             : 
    1259           0 :         SMC_SELECT_BANK(sc, 2);
    1260           0 : }
    1261             : 
    1262             : void
    1263           0 : smc91cxx_statchg(self)
    1264             :         struct device *self;
    1265             : {
    1266           0 :         struct smc91cxx_softc *sc = (struct smc91cxx_softc *)self;
    1267           0 :         bus_space_tag_t bst = sc->sc_bst;
    1268           0 :         bus_space_handle_t bsh = sc->sc_bsh;
    1269             :         int mctl;
    1270             : 
    1271           0 :         SMC_SELECT_BANK(sc, 0);
    1272           0 :         mctl = bus_space_read_2(bst, bsh, TXMIT_CONTROL_REG_W);
    1273           0 :         if (sc->sc_mii.mii_media_active & IFM_FDX)
    1274           0 :                 mctl |= TCR_SWFDUP;
    1275             :         else
    1276           0 :                 mctl &= ~TCR_SWFDUP;
    1277           0 :         bus_space_write_2(bst, bsh, TXMIT_CONTROL_REG_W, mctl);
    1278           0 :         SMC_SELECT_BANK(sc, 2); /* back to operating window */
    1279           0 : }
    1280             : 
    1281             : /*
    1282             :  * One second timer, used to tick the MII.
    1283             :  */
    1284             : void
    1285           0 : smc91cxx_tick(arg)
    1286             :         void *arg;
    1287             : {
    1288           0 :         struct smc91cxx_softc *sc = arg;
    1289             :         int s;
    1290             : 
    1291             : #ifdef DIAGNOSTIC
    1292           0 :         if ((sc->sc_flags & SMC_FLAGS_HAS_MII) == 0)
    1293           0 :                 panic("smc91cxx_tick");
    1294             : #endif
    1295             : 
    1296           0 :         if ((sc->sc_dev.dv_flags & DVF_ACTIVE) == 0)
    1297           0 :                 return;
    1298             : 
    1299           0 :         s = splnet();
    1300           0 :         mii_tick(&sc->sc_mii);
    1301           0 :         splx(s);
    1302             : 
    1303           0 :         timeout_add_sec(&sc->sc_mii_timeout, 1);
    1304           0 : }

Generated by: LCOV version 1.13