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

Cache object: e710afa3c5bfac5773c8c0d1fa892ad9


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