root/dev/ic/mtd8xx.c

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

DEFINITIONS

This source file includes following definitions.
  1. mtd_attach
  2. mtd_ifmedia_upd
  3. mtd_ifmedia_sts
  4. mtd_mii_command
  5. mtd_miibus_readreg
  6. mtd_miibus_writereg
  7. mtd_miibus_statchg
  8. mtd_setmulti
  9. mtd_encap
  10. mtd_list_tx_init
  11. mtd_list_rx_init
  12. mtd_newbuf
  13. mtd_reset
  14. mtd_ioctl
  15. mtd_init
  16. mtd_start
  17. mtd_stop
  18. mtd_watchdog
  19. mtd_intr
  20. mtd_rxeof
  21. mtd_rx_resync
  22. mtd_txeof

    1 /*      $OpenBSD: mtd8xx.c,v 1.12 2006/03/25 22:41:43 djm Exp $ */
    2 
    3 /*
    4  * Copyright (c) 2003 Oleg Safiullin <form@pdp11.org.ru>
    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 unmodified, this list of conditions, and the following
   12  *    disclaimer.
   13  * 2. Redistributions in binary form must reproduce the above copyright
   14  *    notice, this list of conditions and the following disclaimer in the
   15  *    documentation and/or other materials provided with the distribution.
   16  *
   17  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   20  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
   21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   27  * SUCH DAMAGE.
   28  *
   29  */
   30 
   31 #include "bpfilter.h"
   32 
   33 #include <sys/param.h>
   34 #include <sys/mbuf.h>
   35 #include <sys/systm.h>
   36 #include <sys/device.h>
   37 #include <sys/socket.h>
   38 #include <sys/ioctl.h>
   39 
   40 #include <net/if.h>
   41 #include <net/if_media.h>
   42 
   43 #if NBPFILTER > 0
   44 #include <net/bpf.h>
   45 #endif
   46 
   47 #ifdef INET
   48 #include <netinet/in.h>
   49 #include <netinet/if_ether.h>
   50 #endif
   51 
   52 #include <machine/bus.h>
   53 
   54 #include <dev/mii/mii.h>
   55 #include <dev/mii/miivar.h>
   56 
   57 #include <dev/pci/pcidevs.h>
   58 #include <dev/pci/pcivar.h>
   59 
   60 #include <dev/ic/mtd8xxreg.h>
   61 #include <dev/ic/mtd8xxvar.h>
   62 
   63 
   64 static int mtd_ifmedia_upd(struct ifnet *);
   65 static void mtd_ifmedia_sts(struct ifnet *, struct ifmediareq *);
   66 
   67 static u_int32_t mtd_mii_command(struct mtd_softc *, int, int, int);
   68 static int mtd_miibus_readreg(struct device *, int, int);
   69 static void mtd_miibus_writereg(struct device *, int, int, int);
   70 static void mtd_miibus_statchg(struct device *);
   71 static void mtd_setmulti(struct mtd_softc *);
   72 
   73 static int mtd_encap(struct mtd_softc *, struct mbuf *, u_int32_t *);
   74 static int mtd_list_rx_init(struct mtd_softc *);
   75 static void mtd_list_tx_init(struct mtd_softc *);
   76 static int mtd_newbuf(struct mtd_softc *, int, struct mbuf *);
   77 
   78 static void mtd_reset(struct mtd_softc *sc);
   79 static int mtd_ioctl(struct ifnet *, u_long, caddr_t);
   80 static void mtd_init(struct ifnet *);
   81 static void mtd_start(struct ifnet *);
   82 static void mtd_stop(struct ifnet *);
   83 static void mtd_watchdog(struct ifnet *);
   84 
   85 static void mtd_rxeof(struct mtd_softc *);
   86 static int mtd_rx_resync(struct mtd_softc *);
   87 static void mtd_txeof(struct mtd_softc *);
   88 
   89 
   90 void
   91 mtd_attach(struct mtd_softc *sc)
   92 {
   93         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
   94         u_int32_t enaddr[2];
   95         int i;
   96 
   97         /* Reset the adapter. */
   98         mtd_reset(sc);
   99 
  100         if (bus_dmamem_alloc(sc->sc_dmat, sizeof(struct mtd_list_data),
  101             PAGE_SIZE, 0, sc->sc_listseg, 1, &sc->sc_listnseg,
  102             BUS_DMA_NOWAIT) != 0) {
  103                 printf(": can't alloc list mem\n");
  104                 return;
  105         }
  106         if (bus_dmamem_map(sc->sc_dmat, sc->sc_listseg, sc->sc_listnseg,
  107             sizeof(struct mtd_list_data), &sc->sc_listkva,
  108             BUS_DMA_NOWAIT) != 0) {
  109                 printf(": can't map list mem\n");
  110                 return;
  111         }
  112         if (bus_dmamap_create(sc->sc_dmat, sizeof(struct mtd_list_data), 1,
  113             sizeof(struct mtd_list_data), 0, BUS_DMA_NOWAIT,
  114             &sc->sc_listmap) != 0) {
  115                 printf(": can't alloc list map\n");
  116                 return;
  117         }
  118         if (bus_dmamap_load(sc->sc_dmat, sc->sc_listmap, sc->sc_listkva,
  119             sizeof(struct mtd_list_data), NULL, BUS_DMA_NOWAIT) != 0) {
  120                 printf(": can't load list map\n");
  121                 return;
  122         }
  123         sc->mtd_ldata = (struct mtd_list_data *)sc->sc_listkva;
  124         bzero(sc->mtd_ldata, sizeof(struct mtd_list_data));
  125 
  126         for (i = 0; i < MTD_RX_LIST_CNT; i++) {
  127                 if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES,
  128                     0, BUS_DMA_NOWAIT,
  129                     &sc->mtd_cdata.mtd_rx_chain[i].sd_map) != 0) {
  130                         printf(": can't create rx map\n");
  131                         return;
  132                 }
  133         }
  134         if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1, MCLBYTES, 0,
  135             BUS_DMA_NOWAIT, &sc->sc_rx_sparemap) != 0) {
  136                 printf(": can't create rx spare map\n");
  137                 return;
  138         }
  139 
  140         for (i = 0; i < MTD_TX_LIST_CNT; i++) {
  141                 if (bus_dmamap_create(sc->sc_dmat, MCLBYTES,
  142                     MTD_TX_LIST_CNT - 5, MCLBYTES, 0, BUS_DMA_NOWAIT,
  143                     &sc->mtd_cdata.mtd_tx_chain[i].sd_map) != 0) {
  144                         printf(": can't create tx map\n");
  145                         return;
  146                 }
  147         }
  148         if (bus_dmamap_create(sc->sc_dmat, MCLBYTES, MTD_TX_LIST_CNT - 5,
  149             MCLBYTES, 0, BUS_DMA_NOWAIT, &sc->sc_tx_sparemap) != 0) {
  150                 printf(": can't create tx spare map\n");
  151                 return;
  152         }
  153 
  154 
  155         /* Get station address. */
  156         enaddr[0] = letoh32(CSR_READ_4(MTD_PAR0));
  157         enaddr[1] = letoh32(CSR_READ_4(MTD_PAR4));
  158         bcopy(enaddr, sc->sc_arpcom.ac_enaddr, ETHER_ADDR_LEN);
  159         printf(" address %s\n", ether_sprintf(sc->sc_arpcom.ac_enaddr));
  160 
  161         /* Initialize interface */
  162         ifp->if_softc = sc;
  163         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  164         ifp->if_ioctl = mtd_ioctl;
  165         ifp->if_start = mtd_start;
  166         ifp->if_watchdog = mtd_watchdog;
  167         ifp->if_baudrate = 10000000;
  168         IFQ_SET_READY(&ifp->if_snd);
  169         bcopy(sc->sc_dev.dv_xname, ifp->if_xname, IFNAMSIZ);
  170 
  171         ifp->if_capabilities = IFCAP_VLAN_MTU;
  172 
  173         /*
  174          * Initialize our media structures and probe the MII.
  175          */
  176         sc->sc_mii.mii_ifp = ifp;
  177         sc->sc_mii.mii_readreg = mtd_miibus_readreg;
  178         sc->sc_mii.mii_writereg = mtd_miibus_writereg;
  179         sc->sc_mii.mii_statchg = mtd_miibus_statchg;
  180         ifmedia_init(&sc->sc_mii.mii_media, 0, mtd_ifmedia_upd,
  181             mtd_ifmedia_sts);
  182         mii_attach(&sc->sc_dev, &sc->sc_mii, 0xffffffff, MII_PHY_ANY,
  183             MII_OFFSET_ANY, 0);
  184         if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) {
  185                 ifmedia_add(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE, 0,
  186                     NULL);
  187                 ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_NONE);
  188         } else
  189                 ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER | IFM_AUTO);
  190 
  191         /*
  192          * Attach us everywhere
  193          */
  194         if_attach(ifp);
  195         ether_ifattach(ifp);
  196 }
  197 
  198 
  199 static int
  200 mtd_ifmedia_upd(struct ifnet *ifp)
  201 {
  202         struct mtd_softc *sc = ifp->if_softc;
  203 
  204         return (mii_mediachg(&sc->sc_mii));
  205 }
  206 
  207 
  208 static void
  209 mtd_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
  210 {
  211         struct mtd_softc *sc = ifp->if_softc;
  212 
  213         mii_pollstat(&sc->sc_mii);
  214         ifmr->ifm_active = sc->sc_mii.mii_media_active;
  215         ifmr->ifm_status = sc->sc_mii.mii_media_status;
  216 }
  217 
  218 
  219 static u_int32_t
  220 mtd_mii_command(struct mtd_softc *sc, int opcode, int phy, int reg)
  221 {
  222         u_int32_t miir, mask, data;
  223         int i;
  224 
  225         miir = (CSR_READ_4(MTD_MIIMGT) & ~MIIMGT_MASK) | MIIMGT_WRITE |
  226             MIIMGT_MDO;
  227 
  228         for (i = 0; i < 32; i++) {
  229                 miir &= ~MIIMGT_MDC;
  230                 CSR_WRITE_4(MTD_MIIMGT, miir);
  231                 miir |= MIIMGT_MDC;
  232                 CSR_WRITE_4(MTD_MIIMGT, miir);
  233         }
  234 
  235         data = opcode | (phy << 7) | (reg << 2);
  236 
  237         for (mask = 0; mask; mask >>= 1) {
  238                 miir &= ~(MIIMGT_MDC | MIIMGT_MDO);
  239                 if (mask & data)
  240                         miir |= MIIMGT_MDO;
  241                 CSR_WRITE_4(MTD_MIIMGT, miir);
  242                 miir |= MIIMGT_MDC;
  243                 CSR_WRITE_4(MTD_MIIMGT, miir);
  244                 DELAY(30);
  245 
  246                 if (mask == 0x4 && opcode == MII_OPCODE_RD)
  247                         miir &= ~MIIMGT_WRITE;
  248         }
  249         return (miir);
  250 }
  251 
  252 
  253 
  254 static int
  255 mtd_miibus_readreg(struct device *self, int phy, int reg)
  256 {
  257         struct mtd_softc *sc = (void *)self;
  258 
  259         if (sc->sc_devid == PCI_PRODUCT_MYSON_MTD803)
  260                 return (phy ? 0 : (int)CSR_READ_2(MTD_PHYCSR + (reg << 1)));
  261         else {
  262                 u_int32_t miir, mask, data;
  263 
  264                 miir = mtd_mii_command(sc, MII_OPCODE_RD, phy, reg);
  265                 for (mask = 0x8000, data = 0; mask; mask >>= 1) {
  266                         miir &= ~MIIMGT_MDC;
  267                         CSR_WRITE_4(MTD_MIIMGT, miir);
  268                         miir = CSR_READ_4(MTD_MIIMGT);
  269                         if (miir & MIIMGT_MDI)
  270                                 data |= mask;
  271                         miir |= MIIMGT_MDC;
  272                         CSR_WRITE_4(MTD_MIIMGT, miir);
  273                         DELAY(30);
  274                 }
  275                 miir &= ~MIIMGT_MDC;
  276                 CSR_WRITE_4(MTD_MIIMGT, miir);
  277 
  278                 return ((int)data);
  279         }
  280 }
  281 
  282 
  283 static void
  284 mtd_miibus_writereg(struct device *self, int phy, int reg, int val)
  285 {
  286         struct mtd_softc *sc = (void *)self;
  287 
  288         if (sc->sc_devid == PCI_PRODUCT_MYSON_MTD803) {
  289                 if (!phy)
  290                         CSR_WRITE_2(MTD_PHYCSR + (reg << 1), val);
  291         } else {
  292                 u_int32_t miir, mask;
  293 
  294                 miir = mtd_mii_command(sc, MII_OPCODE_WR, phy, reg);
  295                 for (mask = 0x8000; mask; mask >>= 1) {
  296                         miir &= ~(MIIMGT_MDC | MIIMGT_MDO);
  297                         if (mask & (u_int32_t)val)
  298                                 miir |= MIIMGT_MDO;
  299                         CSR_WRITE_4(MTD_MIIMGT, miir);
  300                         miir |= MIIMGT_MDC;
  301                         CSR_WRITE_4(MTD_MIIMGT, miir);
  302                         DELAY(1);
  303                 }
  304                 miir &= ~MIIMGT_MDC;
  305                 CSR_WRITE_4(MTD_MIIMGT, miir);
  306         }
  307 }
  308 
  309 
  310 static void
  311 mtd_miibus_statchg(struct device *self)
  312 {
  313         /* NOTHING */
  314 }
  315 
  316 
  317 void
  318 mtd_setmulti(struct mtd_softc *sc)
  319 {
  320         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  321         u_int32_t rxfilt, crc, hash[2] = { 0, 0 };
  322         struct ether_multistep step;
  323         struct ether_multi *enm;
  324         int mcnt = 0;
  325 
  326 allmulti:
  327         rxfilt = CSR_READ_4(MTD_TCRRCR) & ~RCR_AM;
  328         if (ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) {
  329                 rxfilt |= RCR_AM;
  330                 CSR_WRITE_4(MTD_TCRRCR, rxfilt);
  331                 CSR_WRITE_4(MTD_MAR0, 0xffffffff);
  332                 CSR_WRITE_4(MTD_MAR4, 0xffffffff);
  333                 return;
  334         }
  335 
  336         /* First, zot all the existing hash bits. */
  337         CSR_WRITE_4(MTD_MAR0, 0);
  338         CSR_WRITE_4(MTD_MAR4, 0);
  339 
  340         /* Now program new ones. */
  341         ETHER_FIRST_MULTI(step, &sc->sc_arpcom, enm);
  342         while (enm != NULL) {
  343                 if (bcmp(enm->enm_addrlo, enm->enm_addrhi, ETHER_ADDR_LEN)) {
  344                         ifp->if_flags |= IFF_ALLMULTI;
  345                         goto allmulti;
  346                 }
  347                 crc = ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26;
  348                 hash[crc >> 5] |= 1 << (crc & 0xf);
  349                 ++mcnt;
  350                 ETHER_NEXT_MULTI(step, enm);
  351         }
  352 
  353         if (mcnt)
  354                 rxfilt |= RCR_AM;
  355         CSR_WRITE_4(MTD_MAR0, hash[0]);
  356         CSR_WRITE_4(MTD_MAR4, hash[1]);
  357         CSR_WRITE_4(MTD_TCRRCR, rxfilt);
  358 }
  359 
  360 
  361 /*
  362  * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
  363  * pointers to the fragment pointers.
  364  */
  365 int
  366 mtd_encap(struct mtd_softc *sc, struct mbuf *m_head, u_int32_t *txidx)
  367 {
  368         struct mtd_tx_desc *f = NULL;
  369         int frag, cur, cnt = 0, i, total_len = 0;
  370         bus_dmamap_t map;
  371 
  372         /*
  373          * Start packing the mbufs in this chain into
  374          * the fragment pointers. Stop when we run out
  375          * of fragments or hit the end of the mbuf chain.
  376          */
  377         map = sc->sc_tx_sparemap;
  378 
  379         if (bus_dmamap_load_mbuf(sc->sc_dmat, map,
  380             m_head, BUS_DMA_NOWAIT) != 0)
  381                 return (1);
  382 
  383         cur = frag = *txidx;
  384 
  385         for (i = 0; i < map->dm_nsegs; i++) {
  386                 if ((MTD_TX_LIST_CNT -
  387                     (sc->mtd_cdata.mtd_tx_cnt + cnt)) < 5) {
  388                         bus_dmamap_unload(sc->sc_dmat, map);
  389                         return (1);
  390                 }
  391 
  392                 f = &sc->mtd_ldata->mtd_tx_list[frag];
  393                 f->td_tcw = htole32(map->dm_segs[i].ds_len);
  394                 total_len += map->dm_segs[i].ds_len;
  395                 if (cnt == 0) {
  396                         f->td_tsw = 0;
  397                         f->td_tcw |= htole32(TCW_FD | TCW_CRC | TCW_PAD);
  398                 } else
  399                         f->td_tsw = htole32(TSW_OWN);
  400                 f->td_buf = htole32(map->dm_segs[i].ds_addr);
  401                 cur = frag;
  402                 frag = (frag + 1) % MTD_TX_LIST_CNT;
  403                 cnt++;
  404         }
  405 
  406         sc->mtd_cdata.mtd_tx_cnt += cnt;
  407         sc->mtd_cdata.mtd_tx_chain[cur].sd_mbuf = m_head;
  408         sc->sc_tx_sparemap = sc->mtd_cdata.mtd_tx_chain[cur].sd_map;
  409         sc->mtd_cdata.mtd_tx_chain[cur].sd_map = map;
  410         sc->mtd_ldata->mtd_tx_list[cur].td_tcw |= htole32(TCW_LD | TCW_IC);
  411         if (sc->sc_devid == PCI_PRODUCT_MYSON_MTD891)
  412                 sc->mtd_ldata->mtd_tx_list[cur].td_tcw |=
  413                     htole32(TCW_EIC | TCW_RTLC);
  414 
  415         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
  416             BUS_DMASYNC_PREWRITE);
  417 
  418         sc->mtd_ldata->mtd_tx_list[*txidx].td_tsw = htole32(TSW_OWN);
  419         sc->mtd_ldata->mtd_tx_list[*txidx].td_tcw |=
  420             htole32(total_len << TCW_PKTS_SHIFT);
  421 
  422         bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap,
  423             offsetof(struct mtd_list_data, mtd_tx_list[0]),
  424             sizeof(struct mtd_tx_desc) * MTD_TX_LIST_CNT,
  425             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  426 
  427         *txidx = frag;
  428 
  429         return (0);
  430 }
  431 
  432 
  433 /*
  434  * Initialize the transmit descriptors.
  435  */
  436 static void
  437 mtd_list_tx_init(struct mtd_softc *sc)
  438 {
  439         struct mtd_chain_data *cd;
  440         struct mtd_list_data *ld;
  441         int i;
  442 
  443         cd = &sc->mtd_cdata;
  444         ld = sc->mtd_ldata;
  445         for (i = 0; i < MTD_TX_LIST_CNT; i++) {
  446                 cd->mtd_tx_chain[i].sd_mbuf = NULL;
  447                 ld->mtd_tx_list[i].td_tsw = 0;
  448                 ld->mtd_tx_list[i].td_tcw = 0;
  449                 ld->mtd_tx_list[i].td_buf = 0;
  450                 ld->mtd_tx_list[i].td_next = htole32(
  451                     sc->sc_listmap->dm_segs[0].ds_addr +
  452                     offsetof(struct mtd_list_data,
  453                     mtd_tx_list[(i + 1) % MTD_TX_LIST_CNT]));
  454         }
  455 
  456         cd->mtd_tx_prod = cd->mtd_tx_cons = cd->mtd_tx_cnt = 0;
  457 }
  458 
  459 
  460 /*
  461  * Initialize the RX descriptors and allocate mbufs for them. Note that
  462  * we arrange the descriptors in a closed ring, so that the last descriptor
  463  * points back to the first.
  464  */
  465 static int
  466 mtd_list_rx_init(struct mtd_softc *sc)
  467 {
  468         struct mtd_list_data *ld;
  469         int i;
  470 
  471         ld = sc->mtd_ldata;
  472 
  473         for (i = 0; i < MTD_RX_LIST_CNT; i++) {
  474                 if (mtd_newbuf(sc, i, NULL))
  475                         return (1);
  476                 ld->mtd_rx_list[i].rd_next = htole32(
  477                     sc->sc_listmap->dm_segs[0].ds_addr +
  478                     offsetof(struct mtd_list_data,
  479                     mtd_rx_list[(i + 1) % MTD_RX_LIST_CNT])
  480                 );
  481         }
  482 
  483         sc->mtd_cdata.mtd_rx_prod = 0;
  484 
  485         return (0);
  486 }
  487 
  488 
  489 /*
  490  * Initialize an RX descriptor and attach an MBUF cluster.
  491  */
  492 static int
  493 mtd_newbuf(struct mtd_softc *sc, int i, struct mbuf *m)
  494 {
  495         struct mbuf *m_new = NULL;
  496         struct mtd_rx_desc *c;
  497         bus_dmamap_t map;
  498 
  499         c = &sc->mtd_ldata->mtd_rx_list[i];
  500 
  501         if (m == NULL) {
  502                 MGETHDR(m_new, M_DONTWAIT, MT_DATA);
  503                 if (m_new == NULL)
  504                         return (1);
  505 
  506                 MCLGET(m_new, M_DONTWAIT);
  507                 if (!(m_new->m_flags & M_EXT)) {
  508                         m_freem(m_new);
  509                         return (1);
  510                 }
  511                 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
  512                 if (bus_dmamap_load(sc->sc_dmat, sc->sc_rx_sparemap,
  513                     mtod(m_new, caddr_t), MCLBYTES, NULL,
  514                     BUS_DMA_NOWAIT) != 0) {
  515                         m_freem(m_new);
  516                         return (1);
  517                 }
  518                 map = sc->mtd_cdata.mtd_rx_chain[i].sd_map;
  519                 sc->mtd_cdata.mtd_rx_chain[i].sd_map = sc->sc_rx_sparemap;
  520                 sc->sc_rx_sparemap = map;
  521         } else {
  522                 m_new = m;
  523                 m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
  524                 m_new->m_data = m_new->m_ext.ext_buf;
  525         }
  526 
  527         m_adj(m_new, sizeof(u_int64_t));
  528 
  529         bus_dmamap_sync(sc->sc_dmat, sc->mtd_cdata.mtd_rx_chain[i].sd_map, 0,
  530             sc->mtd_cdata.mtd_rx_chain[i].sd_map->dm_mapsize,
  531             BUS_DMASYNC_PREREAD);
  532 
  533         sc->mtd_cdata.mtd_rx_chain[i].sd_mbuf = m_new;
  534         c->rd_buf = htole32(
  535             sc->mtd_cdata.mtd_rx_chain[i].sd_map->dm_segs[0].ds_addr +
  536             sizeof(u_int64_t));
  537         c->rd_rcw = htole32(ETHER_MAX_DIX_LEN);
  538         c->rd_rsr = htole32(RSR_OWN);
  539 
  540         bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap,
  541             offsetof(struct mtd_list_data, mtd_rx_list[i]),
  542             sizeof(struct mtd_rx_desc),
  543             BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
  544 
  545         return (0);
  546 }
  547 
  548 
  549 static void
  550 mtd_reset(struct mtd_softc *sc)
  551 {
  552         int i;
  553 
  554         /* Set software reset bit */
  555         CSR_WRITE_4(MTD_BCR, BCR_SWR);
  556 
  557         /*
  558          * Wait until software reset completed.
  559          */
  560         for (i = 0; i < MTD_TIMEOUT; ++i) {
  561                 DELAY(10);
  562                 if (!(CSR_READ_4(MTD_BCR) & BCR_SWR)) {
  563                         /*
  564                          * Wait a little while for the chip to get
  565                          * its brains in order.
  566                          */
  567                         DELAY(1000);
  568                         return;
  569                 }
  570         }
  571 
  572         /* Reset timed out. */
  573         printf("%s: reset never completed!\n", sc->sc_dev.dv_xname);
  574 }
  575 
  576 
  577 static int
  578 mtd_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
  579 {
  580         struct mtd_softc *sc = ifp->if_softc;
  581         struct ifreq *ifr = (struct ifreq *)data;
  582         struct ifaddr *ifa = (struct ifaddr *)data;
  583         int s, error;
  584 
  585         s = splnet();
  586         if ((error = ether_ioctl(ifp, &sc->sc_arpcom, command, data)) > 0) {
  587                 splx(s);
  588                 return (error);
  589         }
  590 
  591         switch (command) {
  592         case SIOCSIFADDR:
  593                 ifp->if_flags |= IFF_UP;
  594                 mtd_init(ifp);
  595                 switch (ifa->ifa_addr->sa_family) {
  596 #ifdef INET
  597                 case AF_INET:
  598                         arp_ifinit(&sc->sc_arpcom, ifa);
  599                         break;
  600 #endif /* INET */
  601                 }
  602                 break;
  603         case SIOCSIFMTU:
  604                 if (ifr->ifr_mtu >= ETHERMIN && ifr->ifr_mtu <= ETHERMTU)
  605                         ifp->if_mtu = ifr->ifr_mtu;
  606                 else
  607                         error = EINVAL;
  608                 break;
  609 
  610         case SIOCSIFFLAGS:
  611                 if (ifp->if_flags & IFF_UP)
  612                         mtd_init(ifp);
  613                 else {
  614                         if (ifp->if_flags & IFF_RUNNING)
  615                                 mtd_stop(ifp);
  616                 }
  617                 error = 0;
  618                 break;
  619         case SIOCADDMULTI:
  620         case SIOCDELMULTI:
  621                 error = (command == SIOCADDMULTI) ?
  622                     ether_addmulti(ifr, &sc->sc_arpcom) :
  623                     ether_delmulti(ifr, &sc->sc_arpcom);
  624 
  625                 if (error == ENETRESET) {
  626                         /*
  627                          * Multicast list has changed; set the hardware
  628                          * filter accordingly.
  629                          */
  630                         if (ifp->if_flags & IFF_RUNNING)
  631                                 mtd_setmulti(sc);
  632                         error = 0;
  633                 }
  634                 break;
  635         case SIOCGIFMEDIA:
  636         case SIOCSIFMEDIA:
  637                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, command);
  638                 break;
  639         default:
  640                 error = EINVAL;
  641                 break;
  642         }
  643 
  644         splx(s);
  645         return (error);
  646 }
  647 
  648 
  649 static void
  650 mtd_init(struct ifnet *ifp)
  651 {
  652         struct mtd_softc *sc = ifp->if_softc;
  653         int s;
  654 
  655         s = splnet();
  656 
  657         /*
  658          * Cancel pending I/O and free all RX/TX buffers.
  659          */
  660         mtd_stop(ifp);
  661 
  662         /*
  663          * Set cache alignment and burst length.
  664          */
  665         CSR_WRITE_4(MTD_BCR, BCR_PBL8);
  666         CSR_WRITE_4(MTD_TCRRCR, TCR_TFTSF | RCR_RBLEN | RCR_RPBL512);
  667         if (sc->sc_devid == PCI_PRODUCT_MYSON_MTD891) {
  668                 CSR_SETBIT(MTD_BCR, BCR_PROG);
  669                 CSR_SETBIT(MTD_TCRRCR, TCR_ENHANCED);
  670         }
  671 
  672         if (ifp->if_flags & IFF_PROMISC)
  673                 CSR_SETBIT(MTD_TCRRCR, RCR_PROM);
  674         else
  675                 CSR_CLRBIT(MTD_TCRRCR, RCR_PROM);
  676 
  677         if (ifp->if_flags & IFF_BROADCAST)
  678                 CSR_SETBIT(MTD_TCRRCR, RCR_AB);
  679         else
  680                 CSR_CLRBIT(MTD_TCRRCR, RCR_AB);
  681 
  682         mtd_setmulti(sc);
  683 
  684         if (mtd_list_rx_init(sc)) {
  685                 printf("%s: can't allocate memeory for rx buffers\n",
  686                     sc->sc_dev.dv_xname);
  687                 splx(s);
  688                 return;
  689         }
  690         mtd_list_tx_init(sc);
  691 
  692         CSR_WRITE_4(MTD_RXLBA, sc->sc_listmap->dm_segs[0].ds_addr +
  693             offsetof(struct mtd_list_data, mtd_rx_list[0]));
  694         CSR_WRITE_4(MTD_TXLBA, sc->sc_listmap->dm_segs[0].ds_addr +
  695             offsetof(struct mtd_list_data, mtd_tx_list[0]));
  696 
  697         /*
  698          * Enable interrupts.
  699          */
  700         CSR_WRITE_4(MTD_IMR, IMR_INTRS);
  701         CSR_WRITE_4(MTD_ISR, 0xffffffff);
  702 
  703         /* Enable receiver and transmitter */
  704         CSR_SETBIT(MTD_TCRRCR, TCR_TE | RCR_RE);
  705         CSR_WRITE_4(MTD_RXPDR, 0xffffffff);
  706 
  707         ifp->if_flags |= IFF_RUNNING;
  708         ifp->if_flags &= ~IFF_OACTIVE;
  709         splx(s);
  710 }
  711 
  712 
  713 /*
  714  * Main transmit routine. To avoid having to do mbuf copies, we put pointers
  715  * to the mbuf data regions directly in the transmit lists. We also save a
  716  * copy of the pointers since the transmit list fragment pointers are
  717  * physical addresses.
  718  */
  719 static void
  720 mtd_start(struct ifnet *ifp)
  721 {
  722         struct mtd_softc *sc = ifp->if_softc;
  723         struct mbuf *m_head = NULL;
  724         int idx;
  725 
  726         if (sc->mtd_cdata.mtd_tx_cnt) {
  727                 ifp->if_flags |= IFF_OACTIVE;
  728                 return;
  729         }
  730 
  731         idx = sc->mtd_cdata.mtd_tx_prod;
  732         while (sc->mtd_cdata.mtd_tx_chain[idx].sd_mbuf == NULL) {
  733                 IFQ_DEQUEUE(&ifp->if_snd, m_head);
  734                 if (m_head == NULL)
  735                         break;
  736 
  737                 if (mtd_encap(sc, m_head, &idx)) {
  738                         ifp->if_flags |= IFF_OACTIVE;
  739                         break;
  740                 }
  741 
  742                 /*
  743                  * If there's a BPF listener, bounce a copy of this frame
  744                  * to him.
  745                  */
  746 #if NBPFILTER > 0
  747                 if (ifp->if_bpf != NULL)
  748                         bpf_mtap(ifp->if_bpf, m_head, BPF_DIRECTION_OUT);
  749 #endif
  750         }
  751 
  752         if (idx == sc->mtd_cdata.mtd_tx_prod)
  753                 return;
  754 
  755         /* Transmit */
  756         sc->mtd_cdata.mtd_tx_prod = idx;
  757         CSR_WRITE_4(MTD_TXPDR, 0xffffffff);
  758 
  759         /*
  760          * Set a timeout in case the chip goes out to lunch.
  761          */
  762         ifp->if_timer = 5;
  763 }
  764 
  765 
  766 static void
  767 mtd_stop(struct ifnet *ifp)
  768 {
  769         struct mtd_softc *sc = ifp->if_softc;
  770         int i;
  771 
  772         ifp->if_timer = 0;
  773         ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
  774 
  775         CSR_CLRBIT(MTD_TCRRCR, (RCR_RE | TCR_TE));
  776         CSR_WRITE_4(MTD_IMR, 0);
  777         CSR_WRITE_4(MTD_TXLBA, 0);
  778         CSR_WRITE_4(MTD_RXLBA, 0);
  779 
  780         /*
  781          * Free data in the RX lists.
  782          */
  783         for (i = 0; i < MTD_RX_LIST_CNT; i++) {
  784                 if (sc->mtd_cdata.mtd_rx_chain[i].sd_map->dm_nsegs != 0) {
  785                         bus_dmamap_t map = sc->mtd_cdata.mtd_rx_chain[i].sd_map;
  786 
  787                         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
  788                             BUS_DMASYNC_POSTREAD);
  789                         bus_dmamap_unload(sc->sc_dmat, map);
  790                 }
  791                 if (sc->mtd_cdata.mtd_rx_chain[i].sd_mbuf != NULL) {
  792                         m_freem(sc->mtd_cdata.mtd_rx_chain[i].sd_mbuf);
  793                         sc->mtd_cdata.mtd_rx_chain[i].sd_mbuf = NULL;
  794                 }
  795         }
  796         bzero((char *)&sc->mtd_ldata->mtd_rx_list,
  797                 sizeof(sc->mtd_ldata->mtd_rx_list));
  798 
  799         /*
  800          * Free the TX list buffers.
  801          */
  802         for (i = 0; i < MTD_TX_LIST_CNT; i++) {
  803                 if (sc->mtd_cdata.mtd_tx_chain[i].sd_map->dm_nsegs != 0) {
  804                         bus_dmamap_t map = sc->mtd_cdata.mtd_tx_chain[i].sd_map;
  805 
  806                         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
  807                             BUS_DMASYNC_POSTWRITE);
  808                         bus_dmamap_unload(sc->sc_dmat, map);
  809                 }
  810                 if (sc->mtd_cdata.mtd_tx_chain[i].sd_mbuf != NULL) {
  811                         m_freem(sc->mtd_cdata.mtd_tx_chain[i].sd_mbuf);
  812                         sc->mtd_cdata.mtd_tx_chain[i].sd_mbuf = NULL;
  813                 }
  814         }
  815 
  816         bzero((char *)&sc->mtd_ldata->mtd_tx_list,
  817                 sizeof(sc->mtd_ldata->mtd_tx_list));
  818 
  819 }
  820 
  821 
  822 static void
  823 mtd_watchdog(struct ifnet *ifp)
  824 {
  825         struct mtd_softc *sc = ifp->if_softc;
  826 
  827         ifp->if_oerrors++;
  828         printf("%s: watchdog timeout\n", sc->sc_dev.dv_xname);
  829 
  830         mtd_stop(ifp);
  831         mtd_reset(sc);
  832         mtd_init(ifp);
  833 
  834         if (!IFQ_IS_EMPTY(&ifp->if_snd))
  835                 mtd_start(ifp);
  836 }
  837 
  838 
  839 int
  840 mtd_intr(void *xsc)
  841 {
  842         struct mtd_softc *sc = xsc;
  843         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
  844         u_int32_t status;
  845         int claimed = 0;
  846 
  847         /* Supress unwanted interrupts */
  848         if (!(ifp->if_flags & IFF_RUNNING)) {
  849                 if (CSR_READ_4(MTD_ISR) & ISR_INTRS)
  850                         mtd_stop(ifp);
  851                 return (claimed);
  852         }
  853 
  854         /* Disable interrupts. */
  855         CSR_WRITE_4(MTD_IMR, 0);
  856 
  857         while((status = CSR_READ_4(MTD_ISR)) & ISR_INTRS) {
  858                 claimed = 1;
  859 
  860                 CSR_WRITE_4(MTD_ISR, status);
  861 
  862                 /* RX interrupt. */
  863                 if (status & ISR_RI) {
  864                         int curpkts = ifp->if_ipackets;
  865 
  866                         mtd_rxeof(sc);
  867                         if (curpkts == ifp->if_ipackets)
  868                                 while(mtd_rx_resync(sc))
  869                                         mtd_rxeof(sc);
  870                 }
  871 
  872                 /* RX error interrupt. */
  873                 if (status & (ISR_RXERI | ISR_RBU))
  874                         ifp->if_ierrors++;
  875 
  876                 /* TX interrupt. */
  877                 if (status & (ISR_TI | ISR_ETI | ISR_TBU))
  878                         mtd_txeof(sc);
  879 
  880                 /* Fatal bus error interrupt. */
  881                 if (status & ISR_FBE) {
  882                         mtd_reset(sc);
  883                         mtd_start(ifp);
  884                 }
  885         }
  886 
  887         /* Re-enable interrupts. */
  888         CSR_WRITE_4(MTD_IMR, IMR_INTRS);
  889 
  890         if (!IFQ_IS_EMPTY(&ifp->if_snd))
  891                 mtd_start(ifp);
  892 
  893         return (claimed);
  894 }
  895 
  896 
  897 /*
  898  * A frame has been uploaded: pass the resulting mbuf chain up to
  899  * the higher level protocols.
  900  */
  901 static void
  902 mtd_rxeof(struct mtd_softc *sc)
  903 {
  904         struct mbuf *m;
  905         struct ifnet *ifp;
  906         struct mtd_rx_desc *cur_rx;
  907         int i, total_len = 0;
  908         u_int32_t rxstat;
  909 
  910         ifp = &sc->sc_arpcom.ac_if;
  911         i = sc->mtd_cdata.mtd_rx_prod;
  912 
  913         while(!(sc->mtd_ldata->mtd_rx_list[i].rd_rsr & htole32(RSR_OWN))) {
  914                 struct mbuf *m0 = NULL;
  915 
  916                 bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap,
  917                     offsetof(struct mtd_list_data, mtd_rx_list[i]),
  918                     sizeof(struct mtd_rx_desc),
  919                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
  920 
  921                 cur_rx = &sc->mtd_ldata->mtd_rx_list[i];
  922                 rxstat = letoh32(cur_rx->rd_rsr);
  923                 m = sc->mtd_cdata.mtd_rx_chain[i].sd_mbuf;
  924                 total_len = RSR_FLNG_GET(rxstat);
  925 
  926                 sc->mtd_cdata.mtd_rx_chain[i].sd_mbuf = NULL;
  927 
  928                 /*
  929                  * If an error occurs, update stats, clear the
  930                  * status word and leave the mbuf cluster in place:
  931                  * it should simply get re-used next time this descriptor
  932                  * comes up in the ring.
  933                  */
  934                 if (rxstat & RSR_RXER) {
  935                         ifp->if_ierrors++;
  936                         mtd_newbuf(sc, i, m);
  937                         if (rxstat & RSR_CRC) {
  938                                 i = (i + 1) % MTD_RX_LIST_CNT;
  939                                 continue;
  940                         } else {
  941                                 mtd_init(ifp);
  942                                 return;
  943                         }
  944                 }
  945 
  946                 /* No errors; receive the packet. */    
  947                 total_len -= ETHER_CRC_LEN;
  948 
  949                 bus_dmamap_sync(sc->sc_dmat, sc->mtd_cdata.mtd_rx_chain[i].sd_map,
  950                     0, sc->mtd_cdata.mtd_rx_chain[i].sd_map->dm_mapsize,
  951                     BUS_DMASYNC_POSTREAD);
  952 
  953                 m0 = m_devget(mtod(m, char *) - ETHER_ALIGN, total_len + ETHER_ALIGN,
  954                     0, ifp, NULL);
  955                 mtd_newbuf(sc, i, m);
  956                 i = (i + 1) % MTD_RX_LIST_CNT;
  957                 if (m0 == NULL) {
  958                         ifp->if_ierrors++;
  959                         continue;
  960                 }
  961                 m_adj(m0, ETHER_ALIGN);
  962                 m = m0;
  963 
  964                 ifp->if_ipackets++;
  965 
  966 #if NBPFILTER > 0
  967                 if (ifp->if_bpf)
  968                         bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN);
  969 #endif
  970                 ether_input_mbuf(ifp, m);
  971         }
  972 
  973         sc->mtd_cdata.mtd_rx_prod = i;
  974 }
  975 
  976 
  977 /*
  978  * This routine searches the RX ring for dirty descriptors in the
  979  * event that the rxeof routine falls out of sync with the chip's
  980  * current descriptor pointer. This may happen sometimes as a result
  981  * of a "no RX buffer available" condition that happens when the chip
  982  * consumes all of the RX buffers before the driver has a chance to
  983  * process the RX ring. This routine may need to be called more than
  984  * once to bring the driver back in sync with the chip, however we
  985  * should still be getting RX DONE interrupts to drive the search
  986  * for new packets in the RX ring, so we should catch up eventually.
  987  */
  988 static int
  989 mtd_rx_resync(sc)
  990         struct mtd_softc *sc;
  991 {
  992         int i, pos;
  993         struct mtd_rx_desc *cur_rx;
  994 
  995         pos = sc->mtd_cdata.mtd_rx_prod;
  996 
  997         for (i = 0; i < MTD_RX_LIST_CNT; i++) {
  998                 bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap,
  999                     offsetof(struct mtd_list_data, mtd_rx_list[pos]),
 1000                     sizeof(struct mtd_rx_desc),
 1001                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 1002 
 1003                 cur_rx = &sc->mtd_ldata->mtd_rx_list[pos];
 1004                 if (!(cur_rx->rd_rsr & htole32(RSR_OWN)))
 1005                         break;
 1006                 pos = (pos + 1) % MTD_RX_LIST_CNT;
 1007         }
 1008 
 1009         /* If the ring really is empty, then just return. */
 1010         if (i == MTD_RX_LIST_CNT)
 1011                 return (0);
 1012 
 1013         /* We've fallen behind the chip: catch it. */
 1014         sc->mtd_cdata.mtd_rx_prod = pos;
 1015 
 1016         return (EAGAIN);
 1017 }
 1018 
 1019 
 1020 /*
 1021  * A frame was downloaded to the chip. It's safe for us to clean up
 1022  * the list buffers.
 1023  */
 1024 static void
 1025 mtd_txeof(struct mtd_softc *sc)
 1026 {
 1027         struct mtd_tx_desc *cur_tx = NULL;
 1028         struct ifnet *ifp = &sc->sc_arpcom.ac_if;
 1029         int idx;
 1030 
 1031         /* Clear the timeout timer. */
 1032         ifp->if_timer = 0;
 1033 
 1034         /*
 1035          * Go through our tx list and free mbufs for those
 1036          * frames that have been transmitted.
 1037          */
 1038         idx = sc->mtd_cdata.mtd_tx_cons;
 1039         while(idx != sc->mtd_cdata.mtd_tx_prod) {
 1040                 u_int32_t txstat;
 1041 
 1042                 bus_dmamap_sync(sc->sc_dmat, sc->sc_listmap,
 1043                     offsetof(struct mtd_list_data, mtd_tx_list[idx]),
 1044                     sizeof(struct mtd_tx_desc),
 1045                     BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
 1046 
 1047                 cur_tx = &sc->mtd_ldata->mtd_tx_list[idx];
 1048                 txstat = letoh32(cur_tx->td_tsw);
 1049 
 1050                 if (txstat & TSW_OWN || txstat == TSW_UNSENT)
 1051                         break;
 1052 
 1053                 if (!(cur_tx->td_tcw & htole32(TCW_LD))) {
 1054                         sc->mtd_cdata.mtd_tx_cnt--;
 1055                         idx = (idx + 1) % MTD_TX_LIST_CNT;
 1056                         continue;
 1057                 }
 1058 
 1059                 if (CSR_READ_4(MTD_TCRRCR) & TCR_ENHANCED)
 1060                         ifp->if_collisions += TSR_NCR_GET(CSR_READ_4(MTD_TSR));
 1061                 else {
 1062                         if (txstat & TSW_TXERR) {
 1063                                 ifp->if_oerrors++;
 1064                                 if (txstat & TSW_EC)
 1065                                         ifp->if_collisions++;
 1066                                 if (txstat & TSW_LC)
 1067                                         ifp->if_collisions++;
 1068                         }
 1069                         ifp->if_collisions += TSW_NCR_GET(txstat);
 1070                 }
 1071 
 1072                 ifp->if_opackets++;
 1073                 if (sc->mtd_cdata.mtd_tx_chain[idx].sd_map->dm_nsegs != 0) {
 1074                         bus_dmamap_t map =
 1075                             sc->mtd_cdata.mtd_tx_chain[idx].sd_map;
 1076                         bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
 1077                             BUS_DMASYNC_POSTWRITE);
 1078                         bus_dmamap_unload(sc->sc_dmat, map);
 1079                 }
 1080                 if (sc->mtd_cdata.mtd_tx_chain[idx].sd_mbuf != NULL) {
 1081                         m_freem(sc->mtd_cdata.mtd_tx_chain[idx].sd_mbuf);
 1082                         sc->mtd_cdata.mtd_tx_chain[idx].sd_mbuf = NULL;
 1083                 }
 1084                 sc->mtd_cdata.mtd_tx_cnt--;
 1085                 idx = (idx + 1) % MTD_TX_LIST_CNT;
 1086         }
 1087 
 1088         if (cur_tx != NULL) {
 1089                 ifp->if_flags &= ~IFF_OACTIVE;
 1090                 sc->mtd_cdata.mtd_tx_cons = idx;
 1091         } else
 1092                 if (sc->mtd_ldata->mtd_tx_list[idx].td_tsw ==
 1093                     htole32(TSW_UNSENT)) {
 1094                         sc->mtd_ldata->mtd_tx_list[idx].td_tsw =
 1095                             htole32(TSW_OWN);
 1096                         ifp->if_timer = 5;
 1097                         CSR_WRITE_4(MTD_TXPDR, 0xffffffff);
 1098                 }
 1099 }
 1100 
 1101 struct cfdriver mtd_cd = {
 1102         0, "mtd", DV_IFNET
 1103 };

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