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

Cache object: 942310985e91b9ce4856f49c1da61337


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