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/isa/if_ef_isapnp.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: if_ef_isapnp.c,v 1.41 2022/04/06 18:59:28 naddy Exp $ */
    2 
    3 /*
    4  * Copyright (c) 1999 Jason L. Wright (jason@thought.net)
    5  * All rights reserved.
    6  *
    7  * Redistribution and use in source and binary forms, with or without
    8  * modification, are permitted provided that the following conditions
    9  * are met:
   10  * 1. Redistributions of source code must retain the above copyright
   11  *    notice, this list of conditions and the following disclaimer.
   12  * 2. Redistributions in binary form must reproduce the above copyright
   13  *    notice, this list of conditions and the following disclaimer in the
   14  *    documentation and/or other materials provided with the distribution.
   15  *
   16  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   17  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
   18  * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
   19  * DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT,
   20  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
   21  * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
   22  * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   23  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
   24  * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
   25  * ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
   26  * POSSIBILITY OF SUCH DAMAGE.
   27  */
   28 
   29 #include "bpfilter.h"
   30 
   31 #include <sys/param.h>
   32 #include <sys/systm.h>
   33 #include <sys/mbuf.h>
   34 #include <sys/socket.h>
   35 #include <sys/ioctl.h>
   36 #include <sys/errno.h>
   37 #include <sys/syslog.h>
   38 #include <sys/selinfo.h>
   39 #include <sys/device.h>
   40 #include <sys/queue.h>
   41 #include <sys/kernel.h>
   42 #include <sys/timeout.h>
   43 
   44 #include <net/if.h>
   45 #include <net/if_media.h>
   46 
   47 #include <netinet/in.h>
   48 #include <netinet/if_ether.h>
   49 
   50 #if NBPFILTER > 0
   51 #include <net/bpf.h>
   52 #endif
   53 
   54 #include <machine/cpu.h>
   55 #include <machine/bus.h>
   56 #include <machine/intr.h>
   57 
   58 #include <dev/mii/mii.h>
   59 #include <dev/mii/miivar.h>
   60 #include <dev/isa/isavar.h>
   61 #include <dev/isa/isadmavar.h>
   62 #include <dev/ic/elink3reg.h>
   63 
   64 #undef EF_DEBUG
   65 
   66 struct ef_softc {
   67         struct device           sc_dv;
   68         bus_space_tag_t         sc_iot;
   69         bus_space_handle_t      sc_ioh;
   70         struct arpcom           sc_arpcom;
   71         struct mii_data         sc_mii;
   72         struct timeout          sc_tick_tmo;
   73         void *                  sc_ih;
   74         int                     sc_tx_start_thresh;
   75         int                     sc_tx_succ_ok;
   76         int                     sc_busmaster;
   77 };
   78 
   79 #define EF_W0_EEPROM_COMMAND    0x200a
   80 #define    EF_EEPROM_BUSY       (1 << 9)
   81 #define    EF_EEPROM_READ       (1 << 7)
   82 #define EF_W0_EEPROM_DATA       0x200c
   83 
   84 #define EF_W1_TX_PIO_WR_1       0x10
   85 #define EF_W1_RX_PIO_RR_1       0x10
   86 #define EF_W1_RX_ERRORS         0x14
   87 #define EF_W1_RX_STATUS         0x18
   88 #define EF_W1_TX_STATUS         0x1b
   89 #define EF_W1_FREE_TX           0x1c
   90 
   91 #define EF_W4_MEDIA             0x0a
   92 #define    EF_MEDIA_SQE         0x0008          /* sqe error for aui */
   93 #define    EF_MEDIA_TP          0x00c0          /* link/jabber, 10baseT */
   94 #define    EF_MEDIA_LNK         0x0080          /* linkbeat, 100baseTX/FX */
   95 #define    EF_MEDIA_LNKBEAT     0x0800
   96 
   97 /* Window 4: EP_W4_CTRLR_STATUS: mii manipulation */
   98 #define EF_MII_CLK              0x01            /* clock bit */
   99 #define EF_MII_DATA             0x02            /* data bit */
  100 #define EF_MII_DIR              0x04            /* direction */
  101 
  102 int ef_isapnp_match(struct device *, void *, void *);
  103 void ef_isapnp_attach(struct device *, struct device *, void *);
  104 
  105 void efstart(struct ifnet *);
  106 int efioctl(struct ifnet *, u_long, caddr_t);
  107 void efwatchdog(struct ifnet *);
  108 void efreset(struct ef_softc *);
  109 void efstop(struct ef_softc *);
  110 void efsetmulti(struct ef_softc *);
  111 int efbusyeeprom(struct ef_softc *);
  112 int efintr(void *);
  113 void efinit(struct ef_softc *);
  114 void efcompletecmd(struct ef_softc *, u_int, u_int);
  115 void eftxstat(struct ef_softc *);
  116 void efread(struct ef_softc *);
  117 struct mbuf *efget(struct ef_softc *, int totlen);
  118 
  119 void ef_miibus_writereg(struct device *, int, int, int);
  120 void ef_miibus_statchg(struct device *);
  121 int ef_miibus_readreg(struct device *, int, int);
  122 void ef_mii_writeb(struct ef_softc *, int);
  123 void ef_mii_sync(struct ef_softc *);
  124 int ef_ifmedia_upd(struct ifnet *);
  125 void ef_ifmedia_sts(struct ifnet *, struct ifmediareq *);
  126 void ef_tick(void *);
  127 
  128 struct cfdriver ef_cd = {
  129         NULL, "ef", DV_IFNET
  130 };
  131 
  132 const struct cfattach ef_isapnp_ca = {
  133         sizeof(struct ef_softc), ef_isapnp_match, ef_isapnp_attach
  134 };
  135 
  136 int
  137 ef_isapnp_match(struct device *parent, void *match, void *aux)
  138 {
  139         return (1);
  140 }
  141 
  142 void
  143 ef_isapnp_attach(struct device *parent, struct device *self, void *aux)
  144 {
  145         struct ef_softc *sc = (void *)self;
  146         struct isa_attach_args *ia = aux;
  147         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  148         bus_space_tag_t iot;
  149         bus_space_handle_t ioh;
  150         int i;
  151         u_int16_t x;
  152         u_int32_t cfg;
  153 
  154         sc->sc_iot = iot = ia->ia_iot;
  155         sc->sc_ioh = ioh = ia->ipa_io[0].h;
  156 
  157         efcompletecmd(sc, EP_COMMAND, GLOBAL_RESET);
  158         DELAY(1500);
  159 
  160         for (i = 0; i < 3; i++) {
  161                 if (efbusyeeprom(sc))
  162                         return;
  163 
  164                 bus_space_write_2(iot, ioh, EF_W0_EEPROM_COMMAND,
  165                     EF_EEPROM_READ | i);
  166 
  167                 if (efbusyeeprom(sc))
  168                         return;
  169 
  170                 x = bus_space_read_2(iot, ioh, EF_W0_EEPROM_DATA);
  171 
  172                 sc->sc_arpcom.ac_enaddr[(i << 1)] = x >> 8;
  173                 sc->sc_arpcom.ac_enaddr[(i << 1) + 1] = x;
  174         }
  175 
  176         printf(": address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
  177 
  178         GO_WINDOW(3);
  179         cfg = bus_space_read_4(iot, ioh, EP_W3_INTERNAL_CONFIG);
  180         cfg &= ~(0x00f00000);
  181         cfg |= (0x06 << 20);
  182         bus_space_write_4(iot, ioh, EP_W3_INTERNAL_CONFIG, cfg);
  183 
  184         sc->sc_ih = isa_intr_establish(ia->ia_ic, ia->ia_irq, IST_EDGE,
  185             IPL_NET, efintr, sc, sc->sc_dv.dv_xname);
  186 
  187         if (ia->ia_drq != DRQUNK)
  188                 isadma_cascade(ia->ia_drq);
  189 
  190         timeout_set(&sc->sc_tick_tmo, ef_tick, sc);
  191 
  192         bcopy(sc->sc_dv.dv_xname, ifp->if_xname, IFNAMSIZ);
  193         ifp->if_softc = sc;
  194         ifp->if_start = efstart;
  195         ifp->if_ioctl = efioctl;
  196         ifp->if_watchdog = efwatchdog;
  197         ifp->if_flags =
  198             IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  199 
  200         sc->sc_mii.mii_ifp = ifp;
  201         sc->sc_mii.mii_readreg = ef_miibus_readreg;
  202         sc->sc_mii.mii_writereg = ef_miibus_writereg;
  203         sc->sc_mii.mii_statchg = ef_miibus_statchg;
  204         ifmedia_init(&sc->sc_mii.mii_media, 0, ef_ifmedia_upd, ef_ifmedia_sts);
  205         mii_attach(self, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY,
  206             0);
  207         if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
  208                 ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE, 0, NULL);
  209                 ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_NONE);
  210         } else
  211                 ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO);
  212 
  213         if_attach(ifp);
  214         ether_ifattach(ifp);
  215 
  216         sc->sc_tx_start_thresh = 20;
  217 
  218         efcompletecmd(sc, EP_COMMAND, RX_RESET);
  219         efcompletecmd(sc, EP_COMMAND, TX_RESET);
  220 }
  221 
  222 void
  223 efstart(struct ifnet *ifp)
  224 {
  225         struct ef_softc *sc = ifp->if_softc;
  226         bus_space_tag_t iot = sc->sc_iot;
  227         bus_space_handle_t ioh = sc->sc_ioh;
  228         struct mbuf *m, *m0;
  229         int s, len, pad, i;
  230         int fillcnt = 0;
  231         u_int32_t filler = 0;
  232 
  233         if (!(ifp->if_flags & IFF_RUNNING) || ifq_is_oactive(&ifp->if_snd))
  234                 return;
  235 
  236 startagain:
  237         m0 = ifq_deq_begin(&ifp->if_snd);
  238         if (m0 == NULL)
  239                 return;
  240 
  241         if ((m0->m_flags & M_PKTHDR) == 0)
  242                 panic("efstart: no header mbuf");
  243         len = m0->m_pkthdr.len;
  244         pad = (4 - len) & 3;
  245 
  246         if (len + pad > ETHER_MAX_LEN) {
  247                 ifp->if_oerrors++;
  248                 ifq_deq_commit(&ifp->if_snd, m0);
  249                 m_freem(m0);
  250                 goto startagain;
  251         }
  252 
  253         if (bus_space_read_2(iot, ioh, EF_W1_FREE_TX) < len + pad + 4) {
  254                 bus_space_write_2(iot, ioh, EP_COMMAND,
  255                     SET_TX_AVAIL_THRESH | ((len + pad) >> 2));
  256                 ifq_deq_rollback(&ifp->if_snd, m0);
  257                 ifq_set_oactive(&ifp->if_snd);
  258                 return;
  259         } else {
  260                 bus_space_write_2(iot, ioh, EP_COMMAND,
  261                     SET_TX_AVAIL_THRESH | EP_THRESH_DISABLE);
  262         }
  263 
  264         bus_space_write_2(iot, ioh, EP_COMMAND, SET_TX_START_THRESH |
  265             ((len / 4 + sc->sc_tx_start_thresh)));
  266 
  267 #if NBPFILTER
  268         if (ifp->if_bpf)
  269                 bpf_mtap(ifp->if_bpf, m0, BPF_DIRECTION_OUT);
  270 #endif
  271 
  272         ifq_deq_commit(&ifp->if_snd, m0);
  273         if (m0 == NULL) /* XXX not needed */
  274                 return;
  275 
  276         s = splhigh();
  277 
  278         bus_space_write_4(iot, ioh, EF_W1_TX_PIO_WR_1, len);
  279         for (m = m0; m; ) {
  280                 if (fillcnt) {
  281                         while (m->m_len && fillcnt < 4) {
  282                                 fillcnt++;
  283                                 filler >>= 8;
  284                                 filler |= m->m_data[0] << 24;
  285                                 m->m_data++;
  286                                 m->m_len--;
  287                         }
  288                         if (fillcnt == 4) {
  289                                 bus_space_write_4(iot, ioh,
  290                                     EF_W1_TX_PIO_WR_1, filler);
  291                                 filler = 0;
  292                                 fillcnt = 0;
  293                         }
  294                 }
  295 
  296                 if (m->m_len & ~3)
  297                         bus_space_write_multi_4(iot, ioh,
  298                             EF_W1_TX_PIO_WR_1, (u_int32_t *)m->m_data,
  299                             m->m_len >> 2);
  300                 for (i = 0; i < (m->m_len & 3); i++) {
  301                         fillcnt++;
  302                         filler >>= 8;
  303                         filler |= m->m_data[(m->m_len & ~3) + i] << 24;
  304                 }
  305                 m0 = m_free(m);
  306                 m = m0;
  307         }
  308 
  309         if (fillcnt) {
  310                 bus_space_write_4(iot, ioh, EF_W1_TX_PIO_WR_1,
  311                     filler >> (32 - (8 * fillcnt)));
  312                 fillcnt = 0;
  313                 filler = 0;
  314         }
  315 
  316         splx(s);
  317 
  318         goto startagain;
  319 }
  320 
  321 int
  322 efioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
  323 {
  324         struct ef_softc *sc = ifp->if_softc;
  325         struct ifreq *ifr = (struct ifreq *)data;
  326         int s, error = 0;
  327 
  328         s = splnet();
  329 
  330         switch (cmd) {
  331         case SIOCSIFADDR:
  332                 ifp->if_flags |= IFF_UP;
  333                 efinit(sc);
  334                 break;
  335         case SIOCSIFMEDIA:
  336         case SIOCGIFMEDIA:
  337                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd);
  338                 break;
  339         case SIOCSIFFLAGS:
  340                 if ((ifp->if_flags & IFF_UP) == 0 &&
  341                     (ifp->if_flags & IFF_RUNNING) != 0) {
  342                         efstop(sc);
  343                         ifp->if_flags &= ~IFF_RUNNING;
  344                 } else if ((ifp->if_flags & IFF_UP) != 0 &&
  345                            (ifp->if_flags & IFF_RUNNING) == 0) {
  346                         efinit(sc);
  347                 }
  348                 efsetmulti(sc);
  349                 break;
  350 
  351         default:
  352                 error = ether_ioctl(ifp, &sc->sc_arpcom, cmd, data);
  353         }
  354 
  355         if (error == ENETRESET) {
  356                 if (ifp->if_flags & IFF_RUNNING) {
  357                         efreset(sc);
  358                         efsetmulti(sc);
  359                 }
  360                 error = 0;
  361         }
  362 
  363         splx(s);
  364         return (error);
  365 }
  366 
  367 void
  368 efinit(struct ef_softc *sc)
  369 {
  370         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  371         bus_space_tag_t iot = sc->sc_iot;
  372         bus_space_handle_t ioh = sc->sc_ioh;
  373         int i, s;
  374 
  375         s = splnet();
  376 
  377         efstop(sc);
  378 
  379         while (bus_space_read_2(iot, ioh, EP_STATUS) & S_COMMAND_IN_PROGRESS)
  380                 ;
  381 
  382         GO_WINDOW(2);
  383         for (i = 0; i < 6; i++)
  384                 bus_space_write_1(iot, ioh, EP_W2_ADDR_0 + i,
  385                     sc->sc_arpcom.ac_enaddr[i]);
  386         for (i = 0; i < 3; i += 2)
  387                 bus_space_write_2(iot, ioh, EP_W2_RECVMASK_0 + (i * 2), 0);
  388 
  389         efcompletecmd(sc, EP_COMMAND, RX_RESET);
  390         efcompletecmd(sc, EP_COMMAND, TX_RESET);
  391 
  392         bus_space_write_2(iot, ioh, EP_COMMAND,
  393             SET_TX_AVAIL_THRESH | (ETHER_MAX_DIX_LEN >> 2));
  394 
  395         efsetmulti(sc);
  396 
  397         bus_space_write_2(iot, ioh, EP_COMMAND, STATUS_ENABLE | 0);
  398 
  399         GO_WINDOW(6);
  400         for (i = 0; i < 10; i++)
  401                 (void)bus_space_read_1(iot, ioh, i);
  402         (void)bus_space_read_2(iot, ioh, 10);
  403         (void)bus_space_read_2(iot, ioh, 12);
  404         GO_WINDOW(4);
  405         (void)bus_space_read_1(iot, ioh, 12);
  406         bus_space_write_2(iot, ioh, EP_W4_NET_DIAG, 0x0040);
  407 
  408         GO_WINDOW(7);
  409 
  410         efsetmulti(sc);
  411 
  412         bus_space_write_2(iot, ioh, EP_COMMAND, RX_ENABLE);
  413         bus_space_write_2(iot, ioh, EP_COMMAND, TX_ENABLE);
  414 
  415         bus_space_write_2(iot, ioh, EP_COMMAND, STATUS_ENABLE |
  416             S_CARD_FAILURE | S_INT_RQD | S_UPD_STATS | S_TX_COMPLETE |
  417             S_TX_AVAIL | S_RX_COMPLETE |
  418             (sc->sc_busmaster ? S_DMA_DONE : 0));
  419         bus_space_write_2(iot, ioh, EP_COMMAND, ACK_INTR |
  420             S_INTR_LATCH | S_TX_AVAIL | S_RX_EARLY | S_INT_RQD);
  421         bus_space_write_2(iot, ioh, EP_COMMAND, SET_INTR_MASK |
  422             S_INTR_LATCH | S_TX_AVAIL | S_RX_COMPLETE | S_UPD_STATS |
  423             (sc->sc_busmaster ? S_DMA_DONE : 0) | S_UP_COMPLETE |
  424             S_DOWN_COMPLETE | S_CARD_FAILURE | S_TX_COMPLETE);
  425 
  426         mii_mediachg(&sc->sc_mii);
  427 
  428         ifp->if_flags |= IFF_RUNNING;
  429         ifq_clr_oactive(&ifp->if_snd);
  430 
  431         splx(s);
  432 
  433         timeout_add_sec(&sc->sc_tick_tmo, 1);
  434 
  435         efstart(ifp);
  436 }
  437 
  438 void
  439 efreset(struct ef_softc *sc)
  440 {
  441         int s;
  442 
  443         s = splnet();
  444         efstop(sc);
  445         efinit(sc);
  446         splx(s);
  447 }
  448 
  449 void
  450 efstop(struct ef_softc *sc)
  451 {
  452         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  453         bus_space_tag_t iot = sc->sc_iot;
  454         bus_space_handle_t ioh = sc->sc_ioh;
  455 
  456         ifp->if_timer = 0;
  457         ifp->if_flags &= ~IFF_RUNNING;
  458         ifq_clr_oactive(&ifp->if_snd);
  459 
  460         timeout_del(&sc->sc_tick_tmo);
  461 
  462         bus_space_write_2(iot, ioh, EP_COMMAND, RX_DISABLE);
  463         efcompletecmd(sc, EP_COMMAND, RX_DISCARD_TOP_PACK);
  464 
  465         bus_space_write_2(iot, ioh, EP_COMMAND, TX_DISABLE);
  466         bus_space_write_2(iot, ioh, EP_COMMAND, STOP_TRANSCEIVER);
  467 
  468         efcompletecmd(sc, EP_COMMAND, RX_RESET);
  469         efcompletecmd(sc, EP_COMMAND, TX_RESET);
  470 
  471         bus_space_write_2(iot, ioh, EP_COMMAND, C_INTR_LATCH);
  472         bus_space_write_2(iot, ioh, EP_COMMAND, SET_RD_0_MASK);
  473         bus_space_write_2(iot, ioh, EP_COMMAND, SET_INTR_MASK);
  474         bus_space_write_2(iot, ioh, EP_COMMAND, SET_RX_FILTER);
  475 }
  476 
  477 void
  478 efcompletecmd(struct ef_softc *sc, u_int cmd, u_int arg)
  479 {
  480         bus_space_tag_t iot = sc->sc_iot;
  481         bus_space_handle_t ioh = sc->sc_ioh;
  482 
  483         bus_space_write_2(iot, ioh, cmd, arg);
  484         while (bus_space_read_2(iot, ioh, EP_STATUS) & S_COMMAND_IN_PROGRESS)
  485                 ;
  486 }
  487 
  488 int
  489 efintr(void *vsc)
  490 {
  491         struct ef_softc *sc = vsc;
  492         bus_space_tag_t iot = sc->sc_iot;
  493         bus_space_handle_t ioh = sc->sc_ioh;
  494         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  495         u_int16_t status;
  496         int r = 0;
  497 
  498         status = bus_space_read_2(iot, ioh, EP_STATUS);
  499 
  500         do {
  501                 if (status & S_RX_COMPLETE) {
  502                         r = 1;
  503                         bus_space_write_2(iot, ioh, EP_STATUS, C_RX_COMPLETE);
  504                         efread(sc);
  505                 }
  506                 if (status & S_TX_AVAIL) {
  507                         bus_space_write_2(iot, ioh, EP_STATUS, C_TX_AVAIL);
  508                         r = 1;
  509                         ifq_clr_oactive(&sc->sc_arpcom.ac_if.if_snd);
  510                         efstart(&sc->sc_arpcom.ac_if);
  511                 }
  512                 if (status & S_CARD_FAILURE) {
  513                         r = 1;
  514                         efreset(sc);
  515                         printf("%s: adapter failure (%x)\n",
  516                            sc->sc_dv.dv_xname, status);
  517                         bus_space_write_2(iot, ioh, EP_COMMAND,
  518                                           C_CARD_FAILURE);
  519                         return (1);
  520                 }
  521                 if (status & S_TX_COMPLETE) {
  522                         r = 1;
  523                         eftxstat(sc);
  524                         efstart(ifp);
  525                 }
  526                 bus_space_write_2(iot, ioh, EP_COMMAND,
  527                     C_INTR_LATCH | C_INT_RQD);
  528         } while ((status = bus_space_read_2(iot, ioh, EP_STATUS)) &
  529             (S_INT_RQD | S_RX_COMPLETE));
  530 
  531         return (r);
  532 }
  533 
  534 void
  535 eftxstat(struct ef_softc *sc)
  536 {
  537         bus_space_tag_t iot = sc->sc_iot;
  538         bus_space_handle_t ioh = sc->sc_ioh;
  539         int i;
  540 
  541         while ((i = bus_space_read_1(iot, ioh, EF_W1_TX_STATUS)) &
  542            TXS_COMPLETE) {
  543                 bus_space_write_1(iot, ioh, EF_W1_TX_STATUS, 0);
  544 
  545                 if (i & TXS_JABBER) {
  546                         sc->sc_arpcom.ac_if.if_oerrors++;
  547 #ifdef EF_DEBUG
  548                         if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
  549                                 printf("%s: jabber (%x)\n",
  550                                     sc->sc_dv.dv_xname, i);
  551 #endif
  552                         efreset(sc);
  553                 }
  554                 else if (i & TXS_UNDERRUN) {
  555                         sc->sc_arpcom.ac_if.if_oerrors++;
  556 #ifdef EF_DEBUG
  557                         if (sc->sc_arpcom.ac_if.if_flags & IFF_DEBUG)
  558                                 printf("%s: fifo underrun (%x) @%d\n",
  559                                     sc->sc_dv.dv_xname, i,
  560                                     sc->sc_tx_start_thresh);
  561 #endif
  562                         if (sc->sc_tx_succ_ok < 100)
  563                                 sc->sc_tx_start_thresh = min(ETHER_MAX_LEN,
  564                                     sc->sc_tx_start_thresh + 20);
  565                         sc->sc_tx_succ_ok = 0;
  566                         efreset(sc);
  567                 }
  568                 else if (i & TXS_MAX_COLLISION) {
  569                         sc->sc_arpcom.ac_if.if_collisions++;
  570                         bus_space_write_2(iot, ioh, EP_COMMAND, TX_ENABLE);
  571                         ifq_clr_oactive(&sc->sc_arpcom.ac_if.if_snd);
  572                 }
  573                 else
  574                         sc->sc_tx_succ_ok = (sc->sc_tx_succ_ok + 1) & 127;
  575         }
  576 }
  577 
  578 int
  579 efbusyeeprom(struct ef_softc *sc)
  580 {
  581         int i = 100, j;
  582 
  583         while (i--) {
  584                 j = bus_space_read_2(sc->sc_iot, sc->sc_ioh,
  585                                      EF_W0_EEPROM_COMMAND);
  586                 if (j & EF_EEPROM_BUSY)
  587                         delay(100);
  588                 else
  589                         break;
  590         }
  591         if (i == 0) {
  592                 printf("%s: eeprom failed to come ready\n",
  593                    sc->sc_dv.dv_xname);
  594                 return (1);
  595         }
  596 
  597         return (0);
  598 }
  599 
  600 void
  601 efwatchdog(struct ifnet *ifp)
  602 {
  603         struct ef_softc *sc = ifp->if_softc;
  604 
  605         printf("%s: device timeout\n", sc->sc_dv.dv_xname);
  606         sc->sc_arpcom.ac_if.if_oerrors++;
  607         efreset(sc);
  608 }
  609 
  610 void
  611 efsetmulti(struct ef_softc *sc)
  612 {
  613         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  614         struct arpcom *ac = &sc->sc_arpcom;
  615         bus_space_tag_t iot = sc->sc_iot;
  616         bus_space_handle_t ioh = sc->sc_ioh;
  617         struct ether_multi *enm;
  618         struct ether_multistep step;
  619         u_int16_t cmd = SET_RX_FILTER | FIL_INDIVIDUAL | FIL_BRDCST;
  620         int mcnt = 0;
  621 
  622         ETHER_FIRST_MULTI(step, ac, enm);
  623         while (enm != NULL) {
  624                 mcnt++;
  625                 ETHER_NEXT_MULTI(step, enm);
  626         }
  627         if (mcnt || ifp->if_flags & IFF_ALLMULTI)
  628                 cmd |= FIL_MULTICAST;
  629 
  630         if (ifp->if_flags & IFF_PROMISC)
  631                 cmd |= FIL_PROMISC;
  632 
  633         bus_space_write_2(iot, ioh, EP_COMMAND, cmd);
  634 }
  635 
  636 void
  637 efread(struct ef_softc *sc)
  638 {
  639         bus_space_tag_t iot = sc->sc_iot;
  640         bus_space_handle_t ioh = sc->sc_ioh;
  641         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  642         struct mbuf_list ml = MBUF_LIST_INITIALIZER();
  643         struct mbuf *m;
  644         int len;
  645 
  646         len = bus_space_read_2(iot, ioh, EF_W1_RX_STATUS);
  647 
  648 #ifdef EF_DEBUG
  649         if (ifp->if_flags & IFF_DEBUG) {
  650                 int err = len & ERR_MASK;
  651                 char *s = NULL;
  652 
  653                 if (len & ERR_INCOMPLETE)
  654                         s = "incomplete packet";
  655                 else if (err == ERR_OVERRUN)
  656                         s = "packet overrun";
  657                 else if (err == ERR_RUNT)
  658                         s = "runt packet";
  659                 else if (err == ERR_ALIGNMENT)
  660                         s = "bad alignment";
  661                 else if (err == ERR_CRC)
  662                         s = "bad crc";
  663                 else if (err == ERR_OVERSIZE)
  664                         s = "oversized packet";
  665                 else if (err == ERR_DRIBBLE)
  666                         s = "dribble bits";
  667 
  668                 if (s)
  669                         printf("%s: %s\n", sc->sc_dv.dv_xname, s);
  670         }
  671 #endif
  672 
  673         if (len & ERR_INCOMPLETE)
  674                 return;
  675 
  676         if (len & ERR_RX) {
  677                 ifp->if_ierrors++;
  678                 efcompletecmd(sc, EP_COMMAND, RX_DISCARD_TOP_PACK);
  679                 return;
  680         }
  681 
  682         len &= RX_BYTES_MASK;
  683         m = efget(sc, len);
  684         if (m == NULL) {
  685                 ifp->if_ierrors++;
  686                 efcompletecmd(sc, EP_COMMAND, RX_DISCARD_TOP_PACK);
  687                 return;
  688         }
  689 
  690         ml_enqueue(&ml, m);
  691         if_input(ifp, &ml);
  692 }
  693 
  694 struct mbuf *
  695 efget(struct ef_softc *sc, int totlen)
  696 {
  697         bus_space_tag_t iot = sc->sc_iot;
  698         bus_space_handle_t ioh = sc->sc_ioh;
  699         struct mbuf *top, **mp, *m;
  700         int len, pad, s;
  701 
  702         MGETHDR(m, M_DONTWAIT, MT_DATA);
  703         if (m == NULL)
  704                 return (NULL);
  705         m->m_pkthdr.len = totlen;
  706         pad = ALIGN(sizeof(struct ether_header)) - sizeof(struct ether_header);
  707         m->m_data += pad;
  708         len = MHLEN -pad;
  709         top = 0;
  710         mp = &top;
  711 
  712         s = splhigh();
  713 
  714         while (totlen > 0) {
  715                 if (top) {
  716                         MGET(m, M_DONTWAIT, MT_DATA);
  717                         if (m == NULL) {
  718                                 m_freem(top);
  719                                 splx(s);
  720                                 return (NULL);
  721                         }
  722                         len = MLEN;
  723                 }
  724                 if (top && totlen >= MINCLSIZE) {
  725                         MCLGET(m, M_DONTWAIT);
  726                         if (m->m_flags & M_EXT)
  727                                 len = MCLBYTES;
  728                 }
  729                 len = min(totlen, len);
  730                 if (len > 1) {
  731                         len &= ~1;
  732                         bus_space_read_raw_multi_2(iot, ioh,
  733                             EF_W1_RX_PIO_RR_1, mtod(m, u_int8_t *),
  734                             len);
  735                 } else
  736                         *(mtod(m, u_int8_t *)) =
  737                             bus_space_read_1(iot, ioh, EF_W1_RX_PIO_RR_1);
  738 
  739                 m->m_len = len;
  740                 totlen -= len;
  741                 *mp = m;
  742                 mp = &m->m_next;
  743         }
  744 
  745         efcompletecmd(sc, EP_COMMAND, RX_DISCARD_TOP_PACK);
  746 
  747         splx(s);
  748 
  749         return (top);
  750 }
  751 
  752 #define MII_SET(sc, x) \
  753         bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, EP_W4_CTRLR_STATUS, \
  754             bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, EP_W4_CTRLR_STATUS) \
  755             | (x))
  756 
  757 #define MII_CLR(sc, x) \
  758         bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, EP_W4_CTRLR_STATUS, \
  759             bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, EP_W4_CTRLR_STATUS) \
  760             & (~(x)))
  761 
  762 void
  763 ef_mii_writeb(struct ef_softc *sc, int b)
  764 {
  765         MII_CLR(sc, EF_MII_CLK);
  766 
  767         if (b)
  768                 MII_SET(sc, EF_MII_DATA);
  769         else
  770                 MII_CLR(sc, EF_MII_DATA);
  771 
  772         MII_CLR(sc, EF_MII_CLK);
  773         DELAY(1);
  774         MII_SET(sc, EF_MII_CLK);
  775         DELAY(1);
  776 }
  777 
  778 void
  779 ef_mii_sync(struct ef_softc *sc)
  780 {
  781         int i;
  782 
  783         for (i = 0; i < 32; i++)
  784                 ef_mii_writeb(sc, 1);
  785 }
  786 
  787 int
  788 ef_miibus_readreg(struct device *dev, int phy, int reg)
  789 {
  790         struct ef_softc *sc = (struct ef_softc *)dev;
  791         int i, ack, s, val = 0;
  792 
  793         s = splnet();
  794 
  795         GO_WINDOW(4);
  796         bus_space_write_2(sc->sc_iot, sc->sc_ioh, EP_W4_CTRLR_STATUS, 0);
  797 
  798         /* Turn on xmit */
  799         MII_SET(sc, EF_MII_DIR);
  800         MII_CLR(sc, EF_MII_CLK);
  801 
  802         ef_mii_sync(sc);
  803 
  804         /* Transmit start sequence */
  805         ef_mii_writeb(sc, 0);
  806         ef_mii_writeb(sc, 1);
  807 
  808         /* Transmit read sequence */
  809         ef_mii_writeb(sc, 1);
  810         ef_mii_writeb(sc, 0);
  811 
  812         /* Transmit phy addr */
  813         for (i = 0x10; i; i >>= 1)
  814                 ef_mii_writeb(sc, (phy & i) ? 1 : 0);
  815 
  816         /* Transmit reg addr */
  817         for (i = 0x10; i; i >>= 1)
  818                 ef_mii_writeb(sc, (reg & i) ? 1 : 0);
  819 
  820         /* First cycle of turnaround */
  821         MII_CLR(sc, EF_MII_CLK | EF_MII_DATA);
  822         DELAY(1);
  823         MII_SET(sc, EF_MII_CLK);
  824         DELAY(1);
  825 
  826         /* Turn off xmit */
  827         MII_CLR(sc, EF_MII_DIR);
  828 
  829         /* Second cycle of turnaround */
  830         MII_CLR(sc, EF_MII_CLK);
  831         DELAY(1);
  832         MII_SET(sc, EF_MII_CLK);
  833         DELAY(1);
  834         ack = bus_space_read_2(sc->sc_iot, sc->sc_ioh, EP_W4_CTRLR_STATUS) &
  835             EF_MII_DATA;
  836 
  837         /* Read 16bit data */
  838         for (i = 0x8000; i; i >>= 1) {
  839                 MII_CLR(sc, EF_MII_CLK);
  840                 DELAY(1);
  841                 if (bus_space_read_2(sc->sc_iot, sc->sc_ioh,
  842                                      EP_W4_CTRLR_STATUS) & EF_MII_DATA)
  843                         val |= i;
  844                 MII_SET(sc, EF_MII_CLK);
  845                 DELAY(1);
  846         }
  847 
  848         MII_CLR(sc, EF_MII_CLK);
  849         DELAY(1);
  850         MII_SET(sc, EF_MII_CLK);
  851         DELAY(1);
  852 
  853         splx(s);
  854 
  855         return (val);
  856 }
  857 
  858 void
  859 ef_miibus_writereg(struct device *dev, int phy, int reg, int val)
  860 {
  861         struct ef_softc *sc = (struct ef_softc *)dev;
  862         int s, i;
  863 
  864         s = splnet();
  865 
  866         GO_WINDOW(4);
  867         bus_space_write_2(sc->sc_iot, sc->sc_ioh, EP_W4_CTRLR_STATUS, 0);
  868 
  869         /* Turn on xmit */
  870         MII_SET(sc, EF_MII_DIR);
  871 
  872         ef_mii_sync(sc);
  873 
  874         ef_mii_writeb(sc, 0);
  875         ef_mii_writeb(sc, 1);
  876         ef_mii_writeb(sc, 0);
  877         ef_mii_writeb(sc, 1);
  878 
  879         for (i = 0x10; i; i >>= 1)
  880                 ef_mii_writeb(sc, (phy & i) ? 1 : 0);
  881 
  882         for (i = 0x10; i; i >>= 1)
  883                 ef_mii_writeb(sc, (reg & i) ? 1 : 0);
  884 
  885         ef_mii_writeb(sc, 1);
  886         ef_mii_writeb(sc, 0);
  887 
  888         for (i = 0x8000; i; i >>= 1)
  889                 ef_mii_writeb(sc, (val & i) ? 1 : 0);
  890 
  891         splx(s);
  892 }
  893 
  894 int
  895 ef_ifmedia_upd(struct ifnet *ifp)
  896 {
  897         struct ef_softc *sc = ifp->if_softc;
  898 
  899         mii_mediachg(&sc->sc_mii);
  900         return (0);
  901 }
  902 
  903 void
  904 ef_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
  905 {
  906         struct ef_softc *sc = ifp->if_softc;
  907 
  908         mii_pollstat(&sc->sc_mii);
  909         ifmr->ifm_status = sc->sc_mii.mii_media_status;
  910         ifmr->ifm_active = sc->sc_mii.mii_media_active;
  911 }
  912 
  913 void
  914 ef_miibus_statchg(struct device *self)
  915 {
  916         struct ef_softc *sc = (struct ef_softc *)self;
  917         int s;
  918 
  919         s = splnet();
  920         GO_WINDOW(3);
  921         /* Set duplex bit appropriately */
  922         if ((sc->sc_mii.mii_media_active & IFM_GMASK) == IFM_FDX)
  923                 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
  924                     EP_W3_MAC_CONTROL, 0x20);
  925         else
  926                 bus_space_write_1(sc->sc_iot, sc->sc_ioh,
  927                     EP_W3_MAC_CONTROL, 0x00);
  928         GO_WINDOW(7);
  929         splx(s);
  930 }
  931 
  932 void
  933 ef_tick(void *v)
  934 {
  935         struct ef_softc *sc = v;
  936         int s;
  937 
  938         s = splnet();
  939         mii_tick(&sc->sc_mii);
  940         splx(s);
  941         timeout_add_sec(&sc->sc_tick_tmo, 1);
  942 }

Cache object: db8da5db1f5a3d0b0b62f66b8570540d


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