root/dev/ic/lemac.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. lemac_rxd_intr
  2. lemac_tne_intr
  3. lemac_txd_intr
  4. lemac_read_eeprom
  5. lemac_init_adapmem
  6. lemac_input
  7. lemac_rne_intr
  8. lemac_read_macaddr
  9. lemac_multicast_op
  10. lemac_multicast_filter
  11. lemac_reset
  12. lemac_init
  13. lemac_ifstart
  14. lemac_ifioctl
  15. lemac_ifmedia_change
  16. lemac_ifmedia_status
  17. lemac_port_check
  18. lemac_info_get
  19. lemac_intr
  20. lemac_shutdown
  21. lemac_ifattach

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

/* [<][>][^][v][top][bottom][index][help] */