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


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

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/lemac.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /* $NetBSD: lemac.c,v 1.30 2006/09/07 02:40:32 dogcow Exp $ */
    2 
    3 /*-
    4  * Copyright (c) 1994, 1995, 1997 Matt Thomas <matt@3am-software.com>
    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. The name of the author may not be used to endorse or promote products
   13  *    derived from this software without specific prior written permission
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   25  */
   26 
   27 /*
   28  * DEC EtherWORKS 3 Ethernet Controllers
   29  *
   30  * Written by Matt Thomas
   31  * BPF support code stolen directly from if_ec.c
   32  *
   33  *   This driver supports the LEMAC DE203/204/205 cards.
   34  */
   35 
   36 #include <sys/cdefs.h>
   37 __KERNEL_RCSID(0, "$NetBSD: lemac.c,v 1.30 2006/09/07 02:40:32 dogcow Exp $");
   38 
   39 #include "opt_inet.h"
   40 #include "rnd.h"
   41 
   42 #include <sys/param.h>
   43 #include <sys/systm.h>
   44 #include <sys/mbuf.h>
   45 #include <sys/protosw.h>
   46 #include <sys/socket.h>
   47 #include <sys/sockio.h>
   48 #include <sys/errno.h>
   49 #include <sys/malloc.h>
   50 #include <sys/device.h>
   51 #if NRND > 0
   52 #include <sys/rnd.h>
   53 #endif
   54 
   55 #include <net/if.h>
   56 #include <net/if_types.h>
   57 #include <net/if_dl.h>
   58 #include <net/route.h>
   59 #include <net/if_ether.h>
   60 #include <net/if_media.h>
   61 
   62 #ifdef INET
   63 #include <netinet/in.h>
   64 #include <netinet/in_systm.h>
   65 #include <netinet/in_var.h>
   66 #include <netinet/ip.h>
   67 #include <netinet/if_inarp.h>
   68 #endif
   69 
   70 
   71 #include <machine/bus.h>
   72 
   73 #include <dev/ic/lemacreg.h>
   74 #include <dev/ic/lemacvar.h>
   75 #if 0
   76 #include <i386/isa/decether.h>
   77 #endif
   78 
   79 #include <uvm/uvm_extern.h>
   80 
   81 #include "bpfilter.h"
   82 #if NBPFILTER > 0
   83 #include <net/bpf.h>
   84 #endif
   85 
   86 static void lemac_init(lemac_softc_t *sc);
   87 static void lemac_ifstart(struct ifnet *ifp);
   88 static void lemac_reset(lemac_softc_t *sc);
   89 static void lemac_rne_intr(lemac_softc_t *sc);
   90 static void lemac_tne_intr(lemac_softc_t *sc);
   91 static void lemac_txd_intr(lemac_softc_t *sc, unsigned cs_value);
   92 static void lemac_rxd_intr(lemac_softc_t *sc, unsigned cs_value);
   93 static int  lemac_read_eeprom(lemac_softc_t *sc);
   94 static void lemac_init_adapmem(lemac_softc_t *sc);
   95 
   96 static const u_int16_t lemac_allmulti_mctbl[LEMAC_MCTBL_SIZE/sizeof(u_int16_t)] =  {
   97     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
   98     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
   99     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
  100     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
  101     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
  102     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
  103     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
  104     0xFFFFU, 0xFFFFU, 0xFFFFU, 0xFFFFU,
  105 };
  106 
  107 /*
  108  * Some tuning/monitoring variables.
  109  */
  110 unsigned lemac_txmax = 16;
  111 
  112 static void
  113 lemac_rxd_intr(
  114     lemac_softc_t *sc,
  115     unsigned cs_value)
  116 {
  117     /*
  118      * Handle CS_RXD (Receiver disabled) here.
  119      *
  120      * Check Free Memory Queue Count. If not equal to zero
  121      * then just turn Receiver back on. If it is equal to
  122      * zero then check to see if transmitter is disabled.
  123      * Process transmit TXD loop once more.  If all else
  124      * fails then do software init (0xC0 to EEPROM Init)
  125      * and rebuild Free Memory Queue.
  126      */
  127 
  128     sc->sc_cntrs.cntr_rxd_intrs++;
  129 
  130     /*
  131      *  Re-enable Receiver.
  132      */
  133 
  134     cs_value &= ~LEMAC_CS_RXD;
  135     LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value);
  136 
  137     if (LEMAC_INB(sc, LEMAC_REG_FMC) > 0)
  138         return;
  139 
  140     if (cs_value & LEMAC_CS_TXD)
  141         lemac_txd_intr(sc, cs_value);
  142 
  143     if ((LEMAC_INB(sc, LEMAC_REG_CS) & LEMAC_CS_RXD) == 0)
  144         return;
  145 
  146     printf("%s: fatal RXD error, attempting recovery\n", sc->sc_if.if_xname);
  147 
  148     lemac_reset(sc);
  149     if (sc->sc_if.if_flags & IFF_UP) {
  150         lemac_init(sc);
  151         return;
  152     }
  153 
  154     /*
  155      *  Error during initialization.  Mark card as disabled.
  156      */
  157     printf("%s: recovery failed -- board disabled\n", sc->sc_if.if_xname);
  158 }
  159 
  160 static void
  161 lemac_tne_intr(
  162     lemac_softc_t *sc)
  163 {
  164     unsigned txcount = LEMAC_INB(sc, LEMAC_REG_TDC);
  165 
  166     sc->sc_cntrs.cntr_tne_intrs++;
  167     while (txcount-- > 0) {
  168         unsigned txsts = LEMAC_INB(sc, LEMAC_REG_TDQ);
  169         sc->sc_if.if_opackets++;                /* another one done */
  170         if ((txsts & (LEMAC_TDQ_LCL|LEMAC_TDQ_NCL))
  171                 || (txsts & LEMAC_TDQ_COL) == LEMAC_TDQ_EXCCOL) {
  172             if (txsts & LEMAC_TDQ_NCL)
  173                 sc->sc_flags &= ~LEMAC_LINKUP;
  174             sc->sc_if.if_oerrors++;
  175         } else {
  176             sc->sc_flags |= LEMAC_LINKUP;
  177             if ((txsts & LEMAC_TDQ_COL) != LEMAC_TDQ_NOCOL)
  178                 sc->sc_if.if_collisions++;
  179         }
  180     }
  181     sc->sc_if.if_flags &= ~IFF_OACTIVE;
  182     lemac_ifstart(&sc->sc_if);
  183 }
  184 
  185 static void
  186 lemac_txd_intr(
  187     lemac_softc_t *sc,
  188     unsigned cs_value)
  189 {
  190     /*
  191      * Read transmit status, remove transmit buffer from
  192      * transmit queue and place on free memory queue,
  193      * then reset transmitter.
  194      * Increment appropriate counters.
  195      */
  196 
  197     sc->sc_cntrs.cntr_txd_intrs++;
  198     if (sc->sc_txctl & LEMAC_TX_STP) {
  199         sc->sc_if.if_oerrors++;
  200         /* return page to free queue */
  201         LEMAC_OUTB(sc, LEMAC_REG_FMQ, LEMAC_INB(sc, LEMAC_REG_TDQ));
  202     }
  203 
  204     /* Turn back on transmitter if disabled */
  205     LEMAC_OUTB(sc, LEMAC_REG_CS, cs_value & ~LEMAC_CS_TXD);
  206     sc->sc_if.if_flags &= ~IFF_OACTIVE;
  207 }
  208 
  209 static int
  210 lemac_read_eeprom(
  211     lemac_softc_t *sc)
  212 {
  213     int word_off, cksum;
  214 
  215     u_char *ep;
  216 
  217     cksum = 0;
  218     ep = sc->sc_eeprom;
  219     for (word_off = 0; word_off < LEMAC_EEP_SIZE / 2; word_off++) {
  220         LEMAC_OUTB(sc, LEMAC_REG_PI1, word_off);
  221         LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEREAD);
  222 
  223         DELAY(LEMAC_EEP_DELAY);
  224 
  225         *ep = LEMAC_INB(sc, LEMAC_REG_EE1);     cksum += *ep++;
  226         *ep = LEMAC_INB(sc, LEMAC_REG_EE2);     cksum += *ep++;
  227     }
  228 
  229     /*
  230      *  Set up Transmit Control Byte for use later during transmit.
  231      */
  232 
  233     sc->sc_txctl |= LEMAC_TX_FLAGS;
  234 
  235     if ((sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_SQE) == 0)
  236         sc->sc_txctl &= ~LEMAC_TX_SQE;
  237 
  238     if (sc->sc_eeprom[LEMAC_EEP_SWFLAGS] & LEMAC_EEP_SW_LAB)
  239         sc->sc_txctl |= LEMAC_TX_LAB;
  240 
  241     memcpy(sc->sc_prodname, &sc->sc_eeprom[LEMAC_EEP_PRDNM], LEMAC_EEP_PRDNMSZ);
  242     sc->sc_prodname[LEMAC_EEP_PRDNMSZ] = '\0';
  243 
  244     return cksum % 256;
  245 }
  246 
  247 static void
  248 lemac_init_adapmem(
  249     lemac_softc_t *sc)
  250 {
  251     int pg, conf;
  252 
  253     conf = LEMAC_INB(sc, LEMAC_REG_CNF);
  254 
  255     if ((sc->sc_eeprom[LEMAC_EEP_SETUP] & LEMAC_EEP_ST_DRAM) == 0) {
  256         sc->sc_lastpage = 63;
  257         conf &= ~LEMAC_CNF_DRAM;
  258     } else {
  259         sc->sc_lastpage = 127;
  260         conf |= LEMAC_CNF_DRAM;
  261     }
  262 
  263     LEMAC_OUTB(sc, LEMAC_REG_CNF, conf);
  264 
  265     for (pg = 1; pg <= sc->sc_lastpage; pg++)
  266         LEMAC_OUTB(sc, LEMAC_REG_FMQ, pg);
  267 }
  268 
  269 static void
  270 lemac_input(
  271     lemac_softc_t *sc,
  272     bus_addr_t offset,
  273     size_t length)
  274 {
  275     struct ether_header eh;
  276     struct mbuf *m;
  277 
  278     if (length - sizeof(eh) > ETHERMTU
  279             || length - sizeof(eh) < ETHERMIN) {
  280         sc->sc_if.if_ierrors++;
  281         return;
  282     }
  283     if (LEMAC_USE_PIO_MODE(sc)) {
  284         LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(eh), (void *) &eh);
  285     } else {
  286         LEMAC_GETBUF16(sc, offset, sizeof(eh) / 2, (void *) &eh);
  287     }
  288 
  289     MGETHDR(m, M_DONTWAIT, MT_DATA);
  290     if (m == NULL) {
  291         sc->sc_if.if_ierrors++;
  292         return;
  293     }
  294     if (length + 2 > MHLEN) {
  295         MCLGET(m, M_DONTWAIT);
  296         if ((m->m_flags & M_EXT) == 0) {
  297             m_free(m);
  298             sc->sc_if.if_ierrors++;
  299             return;
  300         }
  301     }
  302     m->m_data += 2;
  303     memcpy(m->m_data, (caddr_t)&eh, sizeof(eh));
  304     if (LEMAC_USE_PIO_MODE(sc)) {
  305         LEMAC_INSB(sc, LEMAC_REG_DAT, length - sizeof(eh),
  306                    mtod(m, caddr_t) + sizeof(eh));
  307     } else {
  308         LEMAC_GETBUF16(sc, offset + sizeof(eh), (length - sizeof(eh)) / 2,
  309                       (void *) (mtod(m, caddr_t) + sizeof(eh)));
  310         if (length & 1)
  311             m->m_data[length - 1] = LEMAC_GET8(sc, offset + length - 1);
  312     }
  313 #if NBPFILTER > 0
  314     if (sc->sc_if.if_bpf != NULL) {
  315         m->m_pkthdr.len = m->m_len = length;
  316         bpf_mtap(sc->sc_if.if_bpf, m);
  317     }
  318     /*
  319      * If this is single cast but not to us
  320      * drop it!
  321      */
  322     if ((eh.ether_dhost[0] & 1) == 0
  323            && !LEMAC_ADDREQUAL(eh.ether_dhost, sc->sc_enaddr)) {
  324         m_freem(m);
  325         return;
  326     }
  327 #endif
  328     m->m_pkthdr.len = m->m_len = length;
  329     m->m_pkthdr.rcvif = &sc->sc_if;
  330     (*sc->sc_if.if_input)(&sc->sc_if, m);
  331 }
  332 
  333 static void
  334 lemac_rne_intr(
  335     lemac_softc_t *sc)
  336 {
  337     int rxcount;
  338 
  339     sc->sc_cntrs.cntr_rne_intrs++;
  340     rxcount = LEMAC_INB(sc, LEMAC_REG_RQC);
  341     while (rxcount--) {
  342         unsigned rxpg = LEMAC_INB(sc, LEMAC_REG_RQ);
  343         u_int32_t rxlen;
  344 
  345         sc->sc_if.if_ipackets++;
  346         if (LEMAC_USE_PIO_MODE(sc)) {
  347             LEMAC_OUTB(sc, LEMAC_REG_IOP, rxpg);
  348             LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
  349             LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
  350             LEMAC_INSB(sc, LEMAC_REG_DAT, sizeof(rxlen), (void *) &rxlen);
  351         } else {
  352             LEMAC_OUTB(sc, LEMAC_REG_MPN, rxpg);
  353             rxlen = LEMAC_GET32(sc, 0);
  354         }
  355         if (rxlen & LEMAC_RX_OK) {
  356             sc->sc_flags |= LEMAC_LINKUP;
  357             /*
  358              * Get receive length - subtract out checksum.
  359              */
  360             rxlen = ((rxlen >> 8) & 0x7FF) - 4;
  361             lemac_input(sc, sizeof(rxlen), rxlen);
  362         } else {
  363             sc->sc_if.if_ierrors++;
  364         }
  365         LEMAC_OUTB(sc, LEMAC_REG_FMQ, rxpg);  /* Return this page to Free Memory Queue */
  366     }  /* end while (recv_count--) */
  367 
  368     return;
  369 }
  370 
  371 /*
  372  *  This is the standard method of reading the DEC Address ROMS.
  373  *  I don't understand it but it does work.
  374  */
  375 static int
  376 lemac_read_macaddr(
  377     unsigned char *hwaddr,
  378     const bus_space_tag_t iot,
  379     const bus_space_handle_t ioh,
  380     const bus_addr_t ioreg,
  381     int skippat)
  382 {
  383     int cksum, rom_cksum;
  384     unsigned char addrbuf[6];
  385 
  386     if (!skippat) {
  387         int idx, idx2, found, octet;
  388         static u_char testpat[] = { 0xFF, 0, 0x55, 0xAA, 0xFF, 0, 0x55, 0xAA };
  389         idx2 = found = 0;
  390 
  391         for (idx = 0; idx < 32; idx++) {
  392             octet = bus_space_read_1(iot, ioh, ioreg);
  393 
  394             if (octet == testpat[idx2]) {
  395                 if (++idx2 == sizeof(testpat)) {
  396                     ++found;
  397                     break;
  398                 }
  399             } else {
  400                 idx2 = 0;
  401             }
  402         }
  403 
  404         if (!found)
  405             return -1;
  406     }
  407 
  408     if (hwaddr == NULL)
  409         hwaddr = addrbuf;
  410 
  411     cksum = 0;
  412     hwaddr[0] = bus_space_read_1(iot, ioh, ioreg);
  413     hwaddr[1] = bus_space_read_1(iot, ioh, ioreg);
  414 
  415     /* hardware address can't be multicast */
  416     if (hwaddr[0] & 1)
  417         return -1;
  418 
  419     cksum = *(u_short *) &hwaddr[0];
  420 
  421     hwaddr[2] = bus_space_read_1(iot, ioh, ioreg);
  422     hwaddr[3] = bus_space_read_1(iot, ioh, ioreg);
  423     cksum *= 2;
  424     if (cksum > 65535) cksum -= 65535;
  425     cksum += *(u_short *) &hwaddr[2];
  426     if (cksum > 65535) cksum -= 65535;
  427 
  428     hwaddr[4] = bus_space_read_1(iot, ioh, ioreg);
  429     hwaddr[5] = bus_space_read_1(iot, ioh, ioreg);
  430     cksum *= 2;
  431     if (cksum > 65535) cksum -= 65535;
  432     cksum += *(u_short *) &hwaddr[4];
  433     if (cksum >= 65535) cksum -= 65535;
  434 
  435     /* 00-00-00 is an illegal OUI */
  436     if (hwaddr[0] == 0 && hwaddr[1] == 0 && hwaddr[2] == 0)
  437         return -1;
  438 
  439     rom_cksum = bus_space_read_1(iot, ioh, ioreg);
  440     rom_cksum |= bus_space_read_1(iot, ioh, ioreg) << 8;
  441 
  442     if (cksum != rom_cksum)
  443         return -1;
  444     return 0;
  445 }
  446 
  447 static void
  448 lemac_multicast_op(
  449     u_int16_t *mctbl,
  450     const u_char *mca,
  451     int enable)
  452 {
  453     u_int idx, bit, crc;
  454 
  455     crc = ether_crc32_le(mca, ETHER_ADDR_LEN);
  456 
  457     /*
  458      * The following two lines convert the N bit index into a longword index
  459      * and a longword mask.
  460      */
  461 #if LEMAC_MCTBL_BITS < 0
  462     crc >>= (32 + LEMAC_MCTBL_BITS);
  463     crc &= (1 << -LEMAC_MCTBL_BITS) - 1;
  464 #else
  465     crc &= (1 << LEMAC_MCTBL_BITS) - 1;
  466 #endif
  467     bit = 1 << (crc & 0x0F);
  468     idx = crc >> 4;
  469 
  470     /*
  471      * Set or clear hash filter bit in our table.
  472      */
  473     if (enable) {
  474         mctbl[idx] |= bit;              /* Set Bit */
  475     } else {
  476         mctbl[idx] &= ~bit;             /* Clear Bit */
  477     }
  478 }
  479 
  480 static void
  481 lemac_multicast_filter(
  482     lemac_softc_t *sc)
  483 {
  484     struct ether_multistep step;
  485     struct ether_multi *enm;
  486 
  487     memset(sc->sc_mctbl, 0, LEMAC_MCTBL_BITS / 8);
  488 
  489     lemac_multicast_op(sc->sc_mctbl, etherbroadcastaddr, TRUE);
  490 
  491     ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
  492     while (enm != NULL) {
  493         if (!LEMAC_ADDREQUAL(enm->enm_addrlo, enm->enm_addrhi)) {
  494             sc->sc_flags |= LEMAC_ALLMULTI;
  495             sc->sc_if.if_flags |= IFF_ALLMULTI;
  496             return;
  497         }
  498         lemac_multicast_op(sc->sc_mctbl, enm->enm_addrlo, TRUE);
  499         ETHER_NEXT_MULTI(step, enm);
  500     }
  501     sc->sc_flags &= ~LEMAC_ALLMULTI;
  502     sc->sc_if.if_flags &= ~IFF_ALLMULTI;
  503 }
  504 
  505 /*
  506  * Do a hard reset of the board;
  507  */
  508 static void
  509 lemac_reset(
  510     lemac_softc_t * const sc)
  511 {
  512     unsigned data;
  513 
  514     /*
  515      * Initialize board..
  516      */
  517     sc->sc_flags &= ~LEMAC_LINKUP;
  518     sc->sc_if.if_flags &= ~IFF_OACTIVE;
  519     LEMAC_INTR_DISABLE(sc);
  520 
  521     LEMAC_OUTB(sc, LEMAC_REG_IOP, LEMAC_IOP_EEINIT);
  522     DELAY(LEMAC_EEP_DELAY);
  523 
  524     /*
  525      * Read EEPROM information.  NOTE - the placement of this function
  526      * is important because functions hereafter may rely on information
  527      * read from the EEPROM.
  528      */
  529     if ((data = lemac_read_eeprom(sc)) != LEMAC_EEP_CKSUM) {
  530         printf("%s: reset: EEPROM checksum failed (0x%x)\n",
  531                sc->sc_if.if_xname, data);
  532         return;
  533     }
  534 
  535     /*
  536      * Update the control register to reflect the media choice
  537      */
  538     data = LEMAC_INB(sc, LEMAC_REG_CTL);
  539     if ((data & (LEMAC_CTL_APD|LEMAC_CTL_PSL)) != sc->sc_ctlmode) {
  540         data &= ~(LEMAC_CTL_APD|LEMAC_CTL_PSL);
  541         data |= sc->sc_ctlmode;
  542         LEMAC_OUTB(sc, LEMAC_REG_CTL, data);
  543     }
  544 
  545     /*
  546      *  Force to 2K mode if not already configured.
  547      */
  548 
  549     data = LEMAC_INB(sc, LEMAC_REG_MBR);
  550     if (LEMAC_IS_2K_MODE(data)) {
  551         sc->sc_flags |= LEMAC_2K_MODE;
  552     } else if (LEMAC_IS_64K_MODE(data)) {
  553         data = (((data * 2) & 0xF) << 4);
  554         sc->sc_flags |= LEMAC_WAS_64K_MODE;
  555         LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
  556     } else if (LEMAC_IS_32K_MODE(data)) {
  557         data = ((data & 0xF) << 4);
  558         sc->sc_flags |= LEMAC_WAS_32K_MODE;
  559         LEMAC_OUTB(sc, LEMAC_REG_MBR, data);
  560     } else {
  561         sc->sc_flags |= LEMAC_PIO_MODE;
  562         /* PIO mode */
  563     }
  564 
  565     /*
  566      *  Initialize Free Memory Queue, Init mcast table with broadcast.
  567      */
  568 
  569     lemac_init_adapmem(sc);
  570     sc->sc_flags |= LEMAC_ALIVE;
  571 }
  572 
  573 static void
  574 lemac_init(
  575     lemac_softc_t * const sc)
  576 {
  577     if ((sc->sc_flags & LEMAC_ALIVE) == 0)
  578         return;
  579 
  580     /*
  581      * If the interface has the up flag
  582      */
  583     if (sc->sc_if.if_flags & IFF_UP) {
  584         int saved_cs = LEMAC_INB(sc, LEMAC_REG_CS);
  585         LEMAC_OUTB(sc, LEMAC_REG_CS, saved_cs | (LEMAC_CS_TXD | LEMAC_CS_RXD));
  586         LEMAC_OUTB(sc, LEMAC_REG_PA0, sc->sc_enaddr[0]);
  587         LEMAC_OUTB(sc, LEMAC_REG_PA1, sc->sc_enaddr[1]);
  588         LEMAC_OUTB(sc, LEMAC_REG_PA2, sc->sc_enaddr[2]);
  589         LEMAC_OUTB(sc, LEMAC_REG_PA3, sc->sc_enaddr[3]);
  590         LEMAC_OUTB(sc, LEMAC_REG_PA4, sc->sc_enaddr[4]);
  591         LEMAC_OUTB(sc, LEMAC_REG_PA5, sc->sc_enaddr[5]);
  592 
  593         LEMAC_OUTB(sc, LEMAC_REG_IC, LEMAC_INB(sc, LEMAC_REG_IC) | LEMAC_IC_IE);
  594 
  595         if (sc->sc_if.if_flags & IFF_PROMISC) {
  596             LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE | LEMAC_CS_PME);
  597         } else {
  598             LEMAC_INTR_DISABLE(sc);
  599             lemac_multicast_filter(sc);
  600             if (sc->sc_flags & LEMAC_ALLMULTI)
  601                 memcpy(sc->sc_mctbl, lemac_allmulti_mctbl,
  602                        sizeof(sc->sc_mctbl));
  603             if (LEMAC_USE_PIO_MODE(sc)) {
  604                 LEMAC_OUTB(sc, LEMAC_REG_IOP, 0);
  605                 LEMAC_OUTB(sc, LEMAC_REG_PI1, LEMAC_MCTBL_OFF & 0xFF);
  606                 LEMAC_OUTB(sc, LEMAC_REG_PI2, LEMAC_MCTBL_OFF >> 8);
  607                 LEMAC_OUTSB(sc, LEMAC_REG_DAT, sizeof(sc->sc_mctbl), (void *) sc->sc_mctbl);
  608             } else {
  609                 LEMAC_OUTB(sc, LEMAC_REG_MPN, 0);
  610                 LEMAC_PUTBUF8(sc, LEMAC_MCTBL_OFF, sizeof(sc->sc_mctbl), (void *) sc->sc_mctbl);
  611             }
  612 
  613             LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_MCE);
  614         }
  615 
  616         LEMAC_OUTB(sc, LEMAC_REG_CTL, LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
  617 
  618         LEMAC_INTR_ENABLE(sc);
  619         sc->sc_if.if_flags |= IFF_RUNNING;
  620         lemac_ifstart(&sc->sc_if);
  621     } else {
  622         LEMAC_OUTB(sc, LEMAC_REG_CS, LEMAC_CS_RXD|LEMAC_CS_TXD);
  623 
  624         LEMAC_INTR_DISABLE(sc);
  625         sc->sc_if.if_flags &= ~IFF_RUNNING;
  626     }
  627 }
  628 
  629 static void
  630 lemac_ifstart(
  631     struct ifnet *ifp)
  632 {
  633     lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
  634 
  635     if ((ifp->if_flags & IFF_RUNNING) == 0)
  636         return;
  637 
  638     LEMAC_INTR_DISABLE(sc);
  639 
  640     for (;;) {
  641         struct mbuf *m;
  642         struct mbuf *m0;
  643         int tx_pg;
  644 
  645         IFQ_POLL(&ifp->if_snd, m);
  646         if (m == NULL)
  647             break;
  648 
  649         if ((sc->sc_csr.csr_tqc = LEMAC_INB(sc, LEMAC_REG_TQC)) >= lemac_txmax) {
  650             sc->sc_cntrs.cntr_txfull++;
  651             ifp->if_flags |= IFF_OACTIVE;
  652             break;
  653         }
  654 
  655         /*
  656          * get free memory page
  657          */
  658         tx_pg = sc->sc_csr.csr_fmq = LEMAC_INB(sc, LEMAC_REG_FMQ);
  659         /*
  660          * Check for good transmit page.
  661          */
  662         if (tx_pg == 0 || tx_pg > sc->sc_lastpage) {
  663             sc->sc_cntrs.cntr_txnospc++;
  664             ifp->if_flags |= IFF_OACTIVE;
  665             break;
  666         }
  667 
  668         IFQ_DEQUEUE(&ifp->if_snd, m);
  669 
  670         /*
  671          * The first four bytes of each transmit buffer are for
  672          * control information.  The first byte is the control
  673          * byte, then the length (why not word aligned?), then
  674          * the offset to the buffer.
  675          */
  676 
  677         if (LEMAC_USE_PIO_MODE(sc)) {
  678             LEMAC_OUTB(sc, LEMAC_REG_IOP, tx_pg);       /* Shift 2K window. */
  679             LEMAC_OUTB(sc, LEMAC_REG_PI1, 0);
  680             LEMAC_OUTB(sc, LEMAC_REG_PI2, 0);
  681             LEMAC_OUTB(sc, LEMAC_REG_DAT, sc->sc_txctl);
  682             LEMAC_OUTB(sc, LEMAC_REG_DAT, (m->m_pkthdr.len >> 0) & 0xFF);
  683             LEMAC_OUTB(sc, LEMAC_REG_DAT, (m->m_pkthdr.len >> 8) & 0xFF);
  684             LEMAC_OUTB(sc, LEMAC_REG_DAT, LEMAC_TX_HDRSZ);
  685             for (m0 = m; m0 != NULL; m0 = m0->m_next)
  686                 LEMAC_OUTSB(sc, LEMAC_REG_DAT, m0->m_len, m0->m_data);
  687         } else {
  688             bus_size_t txoff = /* (mtod(m, u_int32_t) & (sizeof(u_int32_t) - 1)) + */ LEMAC_TX_HDRSZ;
  689             LEMAC_OUTB(sc, LEMAC_REG_MPN, tx_pg);       /* Shift 2K window. */
  690             LEMAC_PUT8(sc, 0, sc->sc_txctl);
  691             LEMAC_PUT8(sc, 1, (m->m_pkthdr.len >> 0) & 0xFF);
  692             LEMAC_PUT8(sc, 2, (m->m_pkthdr.len >> 8) & 0xFF);
  693             LEMAC_PUT8(sc, 3, txoff);
  694 
  695             /*
  696              * Copy the packet to the board
  697              */
  698             for (m0 = m; m0 != NULL; m0 = m0->m_next) {
  699 #if 0
  700                 LEMAC_PUTBUF8(sc, txoff, m0->m_len, m0->m_data);
  701                 txoff += m0->m_len;
  702 #else
  703                 const u_int8_t *cp = m0->m_data;
  704                 int len = m0->m_len;
  705 #if 0
  706                 if ((txoff & 3) == (((long)cp) & 3) && len >= 4) {
  707                     if (txoff & 3) {
  708                         int alen = (~txoff & 3);
  709                         LEMAC_PUTBUF8(sc, txoff, alen, cp);
  710                         cp += alen; txoff += alen; len -= alen;
  711                     }
  712                     if (len >= 4) {
  713                         LEMAC_PUTBUF32(sc, txoff, len / 4, cp);
  714                         cp += len & ~3; txoff += len & ~3; len &= 3;
  715                     }
  716                 }
  717 #endif
  718                 if ((txoff & 1) == (((long)cp) & 1) && len >= 2) {
  719                     if (txoff & 1) {
  720                         int alen = (~txoff & 1);
  721                         LEMAC_PUTBUF8(sc, txoff, alen, cp);
  722                         cp += alen; txoff += alen; len -= alen;
  723                     }
  724                     if (len >= 2) {
  725                         LEMAC_PUTBUF16(sc, txoff, len / 2, (const void *) cp);
  726                         cp += len & ~1; txoff += len & ~1; len &= 1;
  727                     }
  728                 }
  729                 if (len > 0) {
  730                     LEMAC_PUTBUF8(sc, txoff, len, cp);
  731                     txoff += len;
  732                 }
  733 #endif
  734             }
  735         }
  736 
  737         LEMAC_OUTB(sc, LEMAC_REG_TQ, tx_pg);    /* tell chip to transmit this packet */
  738 #if NBPFILTER > 0
  739         if (sc->sc_if.if_bpf != NULL)
  740             bpf_mtap(sc->sc_if.if_bpf, m);
  741 #endif
  742         m_freem(m);                     /* free the mbuf */
  743     }
  744     LEMAC_INTR_ENABLE(sc);
  745 }
  746 
  747 static int
  748 lemac_ifioctl(
  749     struct ifnet *ifp,
  750     u_long cmd,
  751     caddr_t data)
  752 {
  753     lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
  754     int s;
  755     int error = 0;
  756 
  757     s = splnet();
  758 
  759     switch (cmd) {
  760         case SIOCSIFADDR: {
  761             struct ifaddr *ifa = (struct ifaddr *)data;
  762 
  763             ifp->if_flags |= IFF_UP;
  764             lemac_init(sc);
  765             switch (ifa->ifa_addr->sa_family) {
  766 #ifdef INET
  767                 case AF_INET: {
  768                     arp_ifinit(&sc->sc_if, ifa);
  769                     break;
  770                 }
  771 #endif /* INET */
  772 
  773 
  774                 default: {
  775                     break;
  776                 }
  777             }
  778             break;
  779         }
  780 
  781         case SIOCSIFFLAGS: {
  782             lemac_init(sc);
  783             break;
  784         }
  785 
  786         case SIOCADDMULTI:
  787         case SIOCDELMULTI: {
  788             /*
  789              * Update multicast listeners
  790              */
  791             if (cmd == SIOCADDMULTI)
  792                 error = ether_addmulti((struct ifreq *)data, &sc->sc_ec);
  793             else
  794                 error = ether_delmulti((struct ifreq *)data, &sc->sc_ec);
  795 
  796             if (error == ENETRESET) {
  797                 /* reset multicast filtering */
  798                 if (ifp->if_flags & IFF_RUNNING)
  799                     lemac_init(sc);
  800                 error = 0;
  801             }
  802             break;
  803         }
  804 
  805         case SIOCSIFMEDIA:
  806         case SIOCGIFMEDIA: {
  807             error = ifmedia_ioctl(ifp, (struct ifreq *)data,
  808                                   &sc->sc_ifmedia, cmd);
  809             break;
  810         }
  811 
  812         default: {
  813             error = EINVAL;
  814             break;
  815         }
  816     }
  817 
  818     splx(s);
  819     return error;
  820 }
  821 
  822 static int
  823 lemac_ifmedia_change(
  824     struct ifnet * const ifp)
  825 {
  826     lemac_softc_t * const sc = LEMAC_IFP_TO_SOFTC(ifp);
  827     unsigned new_ctl;
  828 
  829     switch (IFM_SUBTYPE(sc->sc_ifmedia.ifm_media)) {
  830         case IFM_10_T: new_ctl = LEMAC_CTL_APD; break;
  831         case IFM_10_2:
  832         case IFM_10_5: new_ctl = LEMAC_CTL_APD|LEMAC_CTL_PSL; break;
  833         case IFM_AUTO: new_ctl = 0; break;
  834         default:       return EINVAL;
  835     }
  836     if (sc->sc_ctlmode != new_ctl) {
  837         sc->sc_ctlmode = new_ctl;
  838         lemac_reset(sc);
  839         if (sc->sc_if.if_flags & IFF_UP)
  840             lemac_init(sc);
  841     }
  842     return 0;
  843 }
  844 
  845 /*
  846  * Media status callback
  847  */
  848 static void
  849 lemac_ifmedia_status(
  850     struct ifnet * const ifp,
  851     struct ifmediareq *req)
  852 {
  853     lemac_softc_t *sc = LEMAC_IFP_TO_SOFTC(ifp);
  854     unsigned data = LEMAC_INB(sc, LEMAC_REG_CNF);
  855 
  856     req->ifm_status = IFM_AVALID;
  857     if (sc->sc_flags & LEMAC_LINKUP)
  858         req->ifm_status |= IFM_ACTIVE;
  859 
  860     if (sc->sc_ctlmode & LEMAC_CTL_APD) {
  861         if (sc->sc_ctlmode & LEMAC_CTL_PSL) {
  862             req->ifm_active = IFM_10_5;
  863         } else {
  864             req->ifm_active = IFM_10_T;
  865         }
  866     } else {
  867         /*
  868          * The link bit of the configuration register reflects the
  869          * current media choice when auto-port is enabled.
  870          */
  871         if (data & LEMAC_CNF_NOLINK) {
  872             req->ifm_active = IFM_10_5;
  873         } else {
  874             req->ifm_active = IFM_10_T;
  875         }
  876     }
  877 
  878     req->ifm_active |= IFM_ETHER;
  879 }
  880 
  881 int
  882 lemac_port_check(
  883     const bus_space_tag_t iot,
  884     const bus_space_handle_t ioh)
  885 {
  886     unsigned char hwaddr[6];
  887 
  888     if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 0) == 0)
  889         return 1;
  890     if (lemac_read_macaddr(hwaddr, iot, ioh, LEMAC_REG_APD, 1) == 0)
  891         return 1;
  892     return 0;
  893 }
  894 
  895 void
  896 lemac_info_get(
  897     const bus_space_tag_t iot,
  898     const bus_space_handle_t ioh,
  899     bus_addr_t *maddr_p,
  900     bus_size_t *msize_p,
  901     int *irq_p)
  902 {
  903     unsigned data;
  904 
  905     *irq_p = LEMAC_DECODEIRQ(bus_space_read_1(iot, ioh, LEMAC_REG_IC) & LEMAC_IC_IRQMSK);
  906 
  907     data = bus_space_read_1(iot, ioh, LEMAC_REG_MBR);
  908     if (LEMAC_IS_2K_MODE(data)) {
  909         *maddr_p = data * (2 * 1024) + (512 * 1024);
  910         *msize_p =  2 * 1024;
  911     } else if (LEMAC_IS_64K_MODE(data)) {
  912         *maddr_p = data * 64 * 1024;
  913         *msize_p = 64 * 1024;
  914     } else if (LEMAC_IS_32K_MODE(data)) {
  915         *maddr_p = data * 32 * 1024;
  916         *msize_p = 32* 1024;
  917     } else {
  918         *maddr_p = 0;
  919         *msize_p = 0;
  920     }
  921 }
  922 
  923 /*
  924  * What to do upon receipt of an interrupt.
  925  */
  926 int
  927 lemac_intr(
  928     void *arg)
  929 {
  930     lemac_softc_t * const sc = arg;
  931     int cs_value;
  932 
  933     LEMAC_INTR_DISABLE(sc);     /* Mask interrupts */
  934 
  935     /*
  936      * Determine cause of interrupt.  Receive events take
  937      * priority over Transmit.
  938      */
  939 
  940     cs_value = LEMAC_INB(sc, LEMAC_REG_CS);
  941 
  942     /*
  943      * Check for Receive Queue not being empty.
  944      * Check for Transmit Done Queue not being empty.
  945      */
  946 
  947     if (cs_value & LEMAC_CS_RNE)
  948         lemac_rne_intr(sc);
  949     if (cs_value & LEMAC_CS_TNE)
  950         lemac_tne_intr(sc);
  951 
  952     /*
  953      * Check for Transmitter Disabled.
  954      * Check for Receiver Disabled.
  955      */
  956 
  957     if (cs_value & LEMAC_CS_TXD)
  958         lemac_txd_intr(sc, cs_value);
  959     if (cs_value & LEMAC_CS_RXD)
  960         lemac_rxd_intr(sc, cs_value);
  961 
  962     /*
  963      * Toggle LED and unmask interrupts.
  964      */
  965 
  966     sc->sc_csr.csr_cs = LEMAC_INB(sc, LEMAC_REG_CS);
  967 
  968     LEMAC_OUTB(sc, LEMAC_REG_CTL, LEMAC_INB(sc, LEMAC_REG_CTL) ^ LEMAC_CTL_LED);
  969     LEMAC_INTR_ENABLE(sc);              /* Unmask interrupts */
  970 
  971 #if NRND > 0
  972     if (cs_value)
  973         rnd_add_uint32(&sc->rnd_source, cs_value);
  974 #endif
  975 
  976     return 1;
  977 }
  978 
  979 void
  980 lemac_shutdown(
  981     void *arg)
  982 {
  983     lemac_reset((lemac_softc_t *) arg);
  984 }
  985 
  986 static const char * const lemac_modes[4] = {
  987     "PIO mode (internal 2KB window)",
  988     "2KB window",
  989     "changed 32KB window to 2KB",
  990     "changed 64KB window to 2KB",
  991 };
  992 
  993 void
  994 lemac_ifattach(
  995     lemac_softc_t *sc)
  996 {
  997     struct ifnet * const ifp = &sc->sc_if;
  998 
  999     strcpy(ifp->if_xname, sc->sc_dv.dv_xname);
 1000 
 1001     lemac_reset(sc);
 1002 
 1003     (void) lemac_read_macaddr(sc->sc_enaddr, sc->sc_iot, sc->sc_ioh,
 1004                               LEMAC_REG_APD, 0);
 1005 
 1006     printf(": %s\n", sc->sc_prodname);
 1007 
 1008     printf("%s: address %s, %dKB RAM, %s\n",
 1009            ifp->if_xname,
 1010            ether_sprintf(sc->sc_enaddr),
 1011            sc->sc_lastpage * 2 + 2,
 1012            lemac_modes[sc->sc_flags & LEMAC_MODE_MASK]);
 1013 
 1014     ifp->if_softc = (void *) sc;
 1015     ifp->if_start = lemac_ifstart;
 1016     ifp->if_ioctl = lemac_ifioctl;
 1017 
 1018     ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX
 1019 #ifdef IFF_NOTRAILERS
 1020         | IFF_NOTRAILERS
 1021 #endif
 1022         | IFF_MULTICAST;
 1023 
 1024     if (sc->sc_flags & LEMAC_ALIVE) {
 1025         int media;
 1026 
 1027         IFQ_SET_READY(&ifp->if_snd);
 1028 
 1029         if_attach(ifp);
 1030         ether_ifattach(ifp, sc->sc_enaddr);
 1031 
 1032 #if NRND > 0
 1033         rnd_attach_source(&sc->rnd_source, sc->sc_dv.dv_xname,
 1034                           RND_TYPE_NET, 0);
 1035 #endif
 1036 
 1037         ifmedia_init(&sc->sc_ifmedia, 0,
 1038                      lemac_ifmedia_change,
 1039                      lemac_ifmedia_status);
 1040         if (sc->sc_prodname[4] == '5')  /* DE205 is UTP/AUI */
 1041             ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_AUTO, 0, 0);
 1042         if (sc->sc_prodname[4] != '3')  /* DE204 & 205 have UTP */
 1043             ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_T, 0, 0);
 1044         if (sc->sc_prodname[4] != '4')  /* DE203 & 205 have BNC */
 1045             ifmedia_add(&sc->sc_ifmedia, IFM_ETHER | IFM_10_5, 0, 0);
 1046         switch (sc->sc_prodname[4]) {
 1047             case '3': media = IFM_10_5; break;
 1048             case '4': media = IFM_10_T; break;
 1049             default:  media = IFM_AUTO; break;
 1050         }
 1051         ifmedia_set(&sc->sc_ifmedia, IFM_ETHER | media);
 1052     } else {
 1053         printf("%s: disabled due to error\n", ifp->if_xname);
 1054     }
 1055 }

Cache object: dc952f0fe7c81b540ea0006f46e4facd


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