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

Cache object: e93a5a005390bb3662d539bd923a2449


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