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/my/if_my.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 /*-
    2  * Written by: yen_cw@myson.com.tw
    3  * Copyright (c) 2002 Myson Technology Inc.
    4  * All rights reserved.
    5  *
    6  * Redistribution and use in source and binary forms, with or without
    7  * modification, are permitted provided that the following conditions
    8  * are met:
    9  * 1. Redistributions of source code must retain the above copyright
   10  *    notice, this list of conditions, and the following disclaimer,
   11  *    without modification, immediately at the beginning of the file.
   12  * 2. The name of the author may not be used to endorse or promote products
   13  *    derived from this software without specific prior written permission.
   14  *
   15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
   16  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   17  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   18  * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE FOR
   19  * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   20  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
   22  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   23  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   24  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   25  * SUCH DAMAGE.
   26  *
   27  * Myson fast ethernet PCI NIC driver, available at: http://www.myson.com.tw/
   28  */
   29 
   30 #include <sys/cdefs.h>
   31 __FBSDID("$FreeBSD: releng/5.2/sys/dev/my/if_my.c 122689 2003-11-14 19:00:32Z sam $");
   32 
   33 #include <sys/param.h>
   34 #include <sys/systm.h>
   35 #include <sys/sockio.h>
   36 #include <sys/mbuf.h>
   37 #include <sys/malloc.h>
   38 #include <sys/kernel.h>
   39 #include <sys/socket.h>
   40 #include <sys/queue.h>
   41 #include <sys/types.h>
   42 #include <sys/bus.h>
   43 #include <sys/module.h>
   44 #include <sys/lock.h>
   45 #include <sys/mutex.h>
   46 
   47 #define NBPFILTER       1
   48 
   49 #include <net/if.h>
   50 #include <net/if_arp.h>
   51 #include <net/ethernet.h>
   52 #include <net/if_media.h>
   53 #include <net/if_dl.h>
   54 #include <net/bpf.h>
   55 
   56 #include <vm/vm.h>              /* for vtophys */
   57 #include <vm/pmap.h>            /* for vtophys */
   58 #include <machine/clock.h>      /* for DELAY */
   59 #include <machine/bus_memio.h>
   60 #include <machine/bus_pio.h>
   61 #include <machine/bus.h>
   62 #include <machine/resource.h>
   63 #include <sys/bus.h>
   64 #include <sys/rman.h>
   65 
   66 #include <dev/pci/pcireg.h>
   67 #include <dev/pci/pcivar.h>
   68 
   69 #include <dev/mii/mii.h>
   70 #include <dev/mii/miivar.h>
   71 
   72 #include "miibus_if.h"
   73 
   74 /*
   75  * #define MY_USEIOSPACE
   76  */
   77 
   78 static int      MY_USEIOSPACE = 1;
   79 
   80 #if (MY_USEIOSPACE)
   81 #define MY_RES                  SYS_RES_IOPORT
   82 #define MY_RID                  MY_PCI_LOIO
   83 #else
   84 #define MY_RES                  SYS_RES_MEMORY
   85 #define MY_RID                  MY_PCI_LOMEM
   86 #endif
   87 
   88 
   89 #include <dev/my/if_myreg.h>
   90 
   91 #ifndef lint
   92 static          const char rcsid[] =
   93 "$Id: if_my.c,v 1.16 2003/04/15 06:37:25 mdodd Exp $";
   94 #endif
   95 
   96 /*
   97  * Various supported device vendors/types and their names.
   98  */
   99 struct my_type *my_info_tmp;
  100 static struct my_type my_devs[] = {
  101         {MYSONVENDORID, MTD800ID, "Myson MTD80X Based Fast Ethernet Card"},
  102         {MYSONVENDORID, MTD803ID, "Myson MTD80X Based Fast Ethernet Card"},
  103         {MYSONVENDORID, MTD891ID, "Myson MTD89X Based Giga Ethernet Card"},
  104         {0, 0, NULL}
  105 };
  106 
  107 /*
  108  * Various supported PHY vendors/types and their names. Note that this driver
  109  * will work with pretty much any MII-compliant PHY, so failure to positively
  110  * identify the chip is not a fatal error.
  111  */
  112 static struct my_type my_phys[] = {
  113         {MysonPHYID0, MysonPHYID0, "<MYSON MTD981>"},
  114         {SeeqPHYID0, SeeqPHYID0, "<SEEQ 80225>"},
  115         {AhdocPHYID0, AhdocPHYID0, "<AHDOC 101>"},
  116         {MarvellPHYID0, MarvellPHYID0, "<MARVELL 88E1000>"},
  117         {LevelOnePHYID0, LevelOnePHYID0, "<LevelOne LXT1000>"},
  118         {0, 0, "<MII-compliant physical interface>"}
  119 };
  120 
  121 static int      my_probe(device_t);
  122 static int      my_attach(device_t);
  123 static int      my_detach(device_t);
  124 static int      my_newbuf(struct my_softc *, struct my_chain_onefrag *);
  125 static int      my_encap(struct my_softc *, struct my_chain *, struct mbuf *);
  126 static void     my_rxeof(struct my_softc *);
  127 static void     my_txeof(struct my_softc *);
  128 static void     my_txeoc(struct my_softc *);
  129 static void     my_intr(void *);
  130 static void     my_start(struct ifnet *);
  131 static int      my_ioctl(struct ifnet *, u_long, caddr_t);
  132 static void     my_init(void *);
  133 static void     my_stop(struct my_softc *);
  134 static void     my_watchdog(struct ifnet *);
  135 static void     my_shutdown(device_t);
  136 static int      my_ifmedia_upd(struct ifnet *);
  137 static void     my_ifmedia_sts(struct ifnet *, struct ifmediareq *);
  138 static u_int16_t my_phy_readreg(struct my_softc *, int);
  139 static void     my_phy_writereg(struct my_softc *, int, int);
  140 static void     my_autoneg_xmit(struct my_softc *);
  141 static void     my_autoneg_mii(struct my_softc *, int, int);
  142 static void     my_setmode_mii(struct my_softc *, int);
  143 static void     my_getmode_mii(struct my_softc *);
  144 static void     my_setcfg(struct my_softc *, int);
  145 static u_int32_t my_mchash(caddr_t);
  146 static void     my_setmulti(struct my_softc *);
  147 static void     my_reset(struct my_softc *);
  148 static int      my_list_rx_init(struct my_softc *);
  149 static int      my_list_tx_init(struct my_softc *);
  150 static long     my_send_cmd_to_phy(struct my_softc *, int, int);
  151 
  152 #define MY_SETBIT(sc, reg, x) CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | (x))
  153 #define MY_CLRBIT(sc, reg, x) CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~(x))
  154 
  155 static device_method_t my_methods[] = {
  156         /* Device interface */
  157         DEVMETHOD(device_probe, my_probe),
  158         DEVMETHOD(device_attach, my_attach),
  159         DEVMETHOD(device_detach, my_detach),
  160         DEVMETHOD(device_shutdown, my_shutdown),
  161 
  162         {0, 0}
  163 };
  164 
  165 static driver_t my_driver = {
  166         "my",
  167         my_methods,
  168         sizeof(struct my_softc)
  169 };
  170 
  171 static devclass_t my_devclass;
  172 
  173 DRIVER_MODULE(my, pci, my_driver, my_devclass, 0, 0);
  174 MODULE_DEPEND(my, pci, 1, 1, 1);
  175 MODULE_DEPEND(my, ether, 1, 1, 1);
  176 
  177 static long
  178 my_send_cmd_to_phy(struct my_softc * sc, int opcode, int regad)
  179 {
  180         long            miir;
  181         int             i;
  182         int             mask, data;
  183 
  184         MY_LOCK(sc);
  185 
  186         /* enable MII output */
  187         miir = CSR_READ_4(sc, MY_MANAGEMENT);
  188         miir &= 0xfffffff0;
  189 
  190         miir |= MY_MASK_MIIR_MII_WRITE + MY_MASK_MIIR_MII_MDO;
  191 
  192         /* send 32 1's preamble */
  193         for (i = 0; i < 32; i++) {
  194                 /* low MDC; MDO is already high (miir) */
  195                 miir &= ~MY_MASK_MIIR_MII_MDC;
  196                 CSR_WRITE_4(sc, MY_MANAGEMENT, miir);
  197 
  198                 /* high MDC */
  199                 miir |= MY_MASK_MIIR_MII_MDC;
  200                 CSR_WRITE_4(sc, MY_MANAGEMENT, miir);
  201         }
  202 
  203         /* calculate ST+OP+PHYAD+REGAD+TA */
  204         data = opcode | (sc->my_phy_addr << 7) | (regad << 2);
  205 
  206         /* sent out */
  207         mask = 0x8000;
  208         while (mask) {
  209                 /* low MDC, prepare MDO */
  210                 miir &= ~(MY_MASK_MIIR_MII_MDC + MY_MASK_MIIR_MII_MDO);
  211                 if (mask & data)
  212                         miir |= MY_MASK_MIIR_MII_MDO;
  213 
  214                 CSR_WRITE_4(sc, MY_MANAGEMENT, miir);
  215                 /* high MDC */
  216                 miir |= MY_MASK_MIIR_MII_MDC;
  217                 CSR_WRITE_4(sc, MY_MANAGEMENT, miir);
  218                 DELAY(30);
  219 
  220                 /* next */
  221                 mask >>= 1;
  222                 if (mask == 0x2 && opcode == MY_OP_READ)
  223                         miir &= ~MY_MASK_MIIR_MII_WRITE;
  224         }
  225 
  226         MY_UNLOCK(sc);
  227         return miir;
  228 }
  229 
  230 
  231 static          u_int16_t
  232 my_phy_readreg(struct my_softc * sc, int reg)
  233 {
  234         long            miir;
  235         int             mask, data;
  236 
  237         MY_LOCK(sc);
  238 
  239         if (sc->my_info->my_did == MTD803ID)
  240                 data = CSR_READ_2(sc, MY_PHYBASE + reg * 2);
  241         else {
  242                 miir = my_send_cmd_to_phy(sc, MY_OP_READ, reg);
  243 
  244                 /* read data */
  245                 mask = 0x8000;
  246                 data = 0;
  247                 while (mask) {
  248                         /* low MDC */
  249                         miir &= ~MY_MASK_MIIR_MII_MDC;
  250                         CSR_WRITE_4(sc, MY_MANAGEMENT, miir);
  251 
  252                         /* read MDI */
  253                         miir = CSR_READ_4(sc, MY_MANAGEMENT);
  254                         if (miir & MY_MASK_MIIR_MII_MDI)
  255                                 data |= mask;
  256 
  257                         /* high MDC, and wait */
  258                         miir |= MY_MASK_MIIR_MII_MDC;
  259                         CSR_WRITE_4(sc, MY_MANAGEMENT, miir);
  260                         DELAY(30);
  261 
  262                         /* next */
  263                         mask >>= 1;
  264                 }
  265 
  266                 /* low MDC */
  267                 miir &= ~MY_MASK_MIIR_MII_MDC;
  268                 CSR_WRITE_4(sc, MY_MANAGEMENT, miir);
  269         }
  270 
  271         MY_UNLOCK(sc);
  272         return (u_int16_t) data;
  273 }
  274 
  275 
  276 static void
  277 my_phy_writereg(struct my_softc * sc, int reg, int data)
  278 {
  279         long            miir;
  280         int             mask;
  281 
  282         MY_LOCK(sc);
  283 
  284         if (sc->my_info->my_did == MTD803ID)
  285                 CSR_WRITE_2(sc, MY_PHYBASE + reg * 2, data);
  286         else {
  287                 miir = my_send_cmd_to_phy(sc, MY_OP_WRITE, reg);
  288 
  289                 /* write data */
  290                 mask = 0x8000;
  291                 while (mask) {
  292                         /* low MDC, prepare MDO */
  293                         miir &= ~(MY_MASK_MIIR_MII_MDC + MY_MASK_MIIR_MII_MDO);
  294                         if (mask & data)
  295                                 miir |= MY_MASK_MIIR_MII_MDO;
  296                         CSR_WRITE_4(sc, MY_MANAGEMENT, miir);
  297                         DELAY(1);
  298 
  299                         /* high MDC */
  300                         miir |= MY_MASK_MIIR_MII_MDC;
  301                         CSR_WRITE_4(sc, MY_MANAGEMENT, miir);
  302                         DELAY(1);
  303 
  304                         /* next */
  305                         mask >>= 1;
  306                 }
  307 
  308                 /* low MDC */
  309                 miir &= ~MY_MASK_MIIR_MII_MDC;
  310                 CSR_WRITE_4(sc, MY_MANAGEMENT, miir);
  311         }
  312         MY_UNLOCK(sc);
  313         return;
  314 }
  315 
  316 static u_int32_t
  317 my_mchash(caddr_t addr)
  318 {
  319         u_int32_t       crc, carry;
  320         int             idx, bit;
  321         u_int8_t        data;
  322 
  323         /* Compute CRC for the address value. */
  324         crc = 0xFFFFFFFF;       /* initial value */
  325 
  326         for (idx = 0; idx < 6; idx++) {
  327                 for (data = *addr++, bit = 0; bit < 8; bit++, data >>= 1) {
  328                         carry = ((crc & 0x80000000) ? 1 : 0) ^ (data & 0x01);
  329                         crc <<= 1;
  330                         if (carry)
  331                                 crc = (crc ^ 0x04c11db6) | carry;
  332                 }
  333         }
  334 
  335         /*
  336          * return the filter bit position Note: I arrived at the following
  337          * nonsense through experimentation. It's not the usual way to
  338          * generate the bit position but it's the only thing I could come up
  339          * with that works.
  340          */
  341         return (~(crc >> 26) & 0x0000003F);
  342 }
  343 
  344 
  345 /*
  346  * Program the 64-bit multicast hash filter.
  347  */
  348 static void
  349 my_setmulti(struct my_softc * sc)
  350 {
  351         struct ifnet   *ifp;
  352         int             h = 0;
  353         u_int32_t       hashes[2] = {0, 0};
  354         struct ifmultiaddr *ifma;
  355         u_int32_t       rxfilt;
  356         int             mcnt = 0;
  357 
  358         MY_LOCK(sc);
  359 
  360         ifp = &sc->arpcom.ac_if;
  361 
  362         rxfilt = CSR_READ_4(sc, MY_TCRRCR);
  363 
  364         if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
  365                 rxfilt |= MY_AM;
  366                 CSR_WRITE_4(sc, MY_TCRRCR, rxfilt);
  367                 CSR_WRITE_4(sc, MY_MAR0, 0xFFFFFFFF);
  368                 CSR_WRITE_4(sc, MY_MAR1, 0xFFFFFFFF);
  369 
  370                 MY_UNLOCK(sc);
  371 
  372                 return;
  373         }
  374         /* first, zot all the existing hash bits */
  375         CSR_WRITE_4(sc, MY_MAR0, 0);
  376         CSR_WRITE_4(sc, MY_MAR1, 0);
  377 
  378         /* now program new ones */
  379         TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
  380                 if (ifma->ifma_addr->sa_family != AF_LINK)
  381                         continue;
  382                 h = my_mchash(LLADDR((struct sockaddr_dl *) ifma->ifma_addr));
  383                 if (h < 32)
  384                         hashes[0] |= (1 << h);
  385                 else
  386                         hashes[1] |= (1 << (h - 32));
  387                 mcnt++;
  388         }
  389 
  390         if (mcnt)
  391                 rxfilt |= MY_AM;
  392         else
  393                 rxfilt &= ~MY_AM;
  394         CSR_WRITE_4(sc, MY_MAR0, hashes[0]);
  395         CSR_WRITE_4(sc, MY_MAR1, hashes[1]);
  396         CSR_WRITE_4(sc, MY_TCRRCR, rxfilt);
  397         MY_UNLOCK(sc);
  398         return;
  399 }
  400 
  401 /*
  402  * Initiate an autonegotiation session.
  403  */
  404 static void
  405 my_autoneg_xmit(struct my_softc * sc)
  406 {
  407         u_int16_t       phy_sts = 0;
  408 
  409         MY_LOCK(sc);
  410 
  411         my_phy_writereg(sc, PHY_BMCR, PHY_BMCR_RESET);
  412         DELAY(500);
  413         while (my_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_RESET);
  414 
  415         phy_sts = my_phy_readreg(sc, PHY_BMCR);
  416         phy_sts |= PHY_BMCR_AUTONEGENBL | PHY_BMCR_AUTONEGRSTR;
  417         my_phy_writereg(sc, PHY_BMCR, phy_sts);
  418 
  419         MY_UNLOCK(sc);
  420         return;
  421 }
  422 
  423 
  424 /*
  425  * Invoke autonegotiation on a PHY.
  426  */
  427 static void
  428 my_autoneg_mii(struct my_softc * sc, int flag, int verbose)
  429 {
  430         u_int16_t       phy_sts = 0, media, advert, ability;
  431         u_int16_t       ability2 = 0;
  432         struct ifnet   *ifp;
  433         struct ifmedia *ifm;
  434 
  435         MY_LOCK(sc);
  436 
  437         ifm = &sc->ifmedia;
  438         ifp = &sc->arpcom.ac_if;
  439 
  440         ifm->ifm_media = IFM_ETHER | IFM_AUTO;
  441 
  442 #ifndef FORCE_AUTONEG_TFOUR
  443         /*
  444          * First, see if autoneg is supported. If not, there's no point in
  445          * continuing.
  446          */
  447         phy_sts = my_phy_readreg(sc, PHY_BMSR);
  448         if (!(phy_sts & PHY_BMSR_CANAUTONEG)) {
  449                 if (verbose)
  450                         printf("my%d: autonegotiation not supported\n",
  451                             sc->my_unit);
  452                 ifm->ifm_media = IFM_ETHER | IFM_10_T | IFM_HDX;
  453                 MY_UNLOCK(sc);
  454                 return;
  455         }
  456 #endif
  457         switch (flag) {
  458         case MY_FLAG_FORCEDELAY:
  459                 /*
  460                  * XXX Never use this option anywhere but in the probe
  461                  * routine: making the kernel stop dead in its tracks for
  462                  * three whole seconds after we've gone multi-user is really
  463                  * bad manners.
  464                  */
  465                 my_autoneg_xmit(sc);
  466                 DELAY(5000000);
  467                 break;
  468         case MY_FLAG_SCHEDDELAY:
  469                 /*
  470                  * Wait for the transmitter to go idle before starting an
  471                  * autoneg session, otherwise my_start() may clobber our
  472                  * timeout, and we don't want to allow transmission during an
  473                  * autoneg session since that can screw it up.
  474                  */
  475                 if (sc->my_cdata.my_tx_head != NULL) {
  476                         sc->my_want_auto = 1;
  477                         MY_UNLOCK(sc);
  478                         return;
  479                 }
  480                 my_autoneg_xmit(sc);
  481                 ifp->if_timer = 5;
  482                 sc->my_autoneg = 1;
  483                 sc->my_want_auto = 0;
  484                 MY_UNLOCK(sc);
  485                 return;
  486         case MY_FLAG_DELAYTIMEO:
  487                 ifp->if_timer = 0;
  488                 sc->my_autoneg = 0;
  489                 break;
  490         default:
  491                 printf("my%d: invalid autoneg flag: %d\n", sc->my_unit, flag);
  492                 MY_UNLOCK(sc);
  493                 return;
  494         }
  495 
  496         if (my_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_AUTONEGCOMP) {
  497                 if (verbose)
  498                         printf("my%d: autoneg complete, ", sc->my_unit);
  499                 phy_sts = my_phy_readreg(sc, PHY_BMSR);
  500         } else {
  501                 if (verbose)
  502                         printf("my%d: autoneg not complete, ", sc->my_unit);
  503         }
  504 
  505         media = my_phy_readreg(sc, PHY_BMCR);
  506 
  507         /* Link is good. Report modes and set duplex mode. */
  508         if (my_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT) {
  509                 if (verbose)
  510                         printf("my%d: link status good. ", sc->my_unit);
  511                 advert = my_phy_readreg(sc, PHY_ANAR);
  512                 ability = my_phy_readreg(sc, PHY_LPAR);
  513                 if ((sc->my_pinfo->my_vid == MarvellPHYID0) ||
  514                     (sc->my_pinfo->my_vid == LevelOnePHYID0)) {
  515                         ability2 = my_phy_readreg(sc, PHY_1000SR);
  516                         if (ability2 & PHY_1000SR_1000BTXFULL) {
  517                                 advert = 0;
  518                                 ability = 0;
  519                                 /*
  520                                  * this version did not support 1000M,
  521                                  * ifm->ifm_media =
  522                                  * IFM_ETHER|IFM_1000_T|IFM_FDX;
  523                                  */
  524                                 ifm->ifm_media =
  525                                     IFM_ETHER | IFM_100_TX | IFM_FDX;
  526                                 media &= ~PHY_BMCR_SPEEDSEL;
  527                                 media |= PHY_BMCR_1000;
  528                                 media |= PHY_BMCR_DUPLEX;
  529                                 printf("(full-duplex, 1000Mbps)\n");
  530                         } else if (ability2 & PHY_1000SR_1000BTXHALF) {
  531                                 advert = 0;
  532                                 ability = 0;
  533                                 /*
  534                                  * this version did not support 1000M,
  535                                  * ifm->ifm_media = IFM_ETHER|IFM_1000_T;
  536                                  */
  537                                 ifm->ifm_media = IFM_ETHER | IFM_100_TX;
  538                                 media &= ~PHY_BMCR_SPEEDSEL;
  539                                 media &= ~PHY_BMCR_DUPLEX;
  540                                 media |= PHY_BMCR_1000;
  541                                 printf("(half-duplex, 1000Mbps)\n");
  542                         }
  543                 }
  544                 if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4) {
  545                         ifm->ifm_media = IFM_ETHER | IFM_100_T4;
  546                         media |= PHY_BMCR_SPEEDSEL;
  547                         media &= ~PHY_BMCR_DUPLEX;
  548                         printf("(100baseT4)\n");
  549                 } else if (advert & PHY_ANAR_100BTXFULL &&
  550                            ability & PHY_ANAR_100BTXFULL) {
  551                         ifm->ifm_media = IFM_ETHER | IFM_100_TX | IFM_FDX;
  552                         media |= PHY_BMCR_SPEEDSEL;
  553                         media |= PHY_BMCR_DUPLEX;
  554                         printf("(full-duplex, 100Mbps)\n");
  555                 } else if (advert & PHY_ANAR_100BTXHALF &&
  556                            ability & PHY_ANAR_100BTXHALF) {
  557                         ifm->ifm_media = IFM_ETHER | IFM_100_TX | IFM_HDX;
  558                         media |= PHY_BMCR_SPEEDSEL;
  559                         media &= ~PHY_BMCR_DUPLEX;
  560                         printf("(half-duplex, 100Mbps)\n");
  561                 } else if (advert & PHY_ANAR_10BTFULL &&
  562                            ability & PHY_ANAR_10BTFULL) {
  563                         ifm->ifm_media = IFM_ETHER | IFM_10_T | IFM_FDX;
  564                         media &= ~PHY_BMCR_SPEEDSEL;
  565                         media |= PHY_BMCR_DUPLEX;
  566                         printf("(full-duplex, 10Mbps)\n");
  567                 } else if (advert) {
  568                         ifm->ifm_media = IFM_ETHER | IFM_10_T | IFM_HDX;
  569                         media &= ~PHY_BMCR_SPEEDSEL;
  570                         media &= ~PHY_BMCR_DUPLEX;
  571                         printf("(half-duplex, 10Mbps)\n");
  572                 }
  573                 media &= ~PHY_BMCR_AUTONEGENBL;
  574 
  575                 /* Set ASIC's duplex mode to match the PHY. */
  576                 my_phy_writereg(sc, PHY_BMCR, media);
  577                 my_setcfg(sc, media);
  578         } else {
  579                 if (verbose)
  580                         printf("my%d: no carrier\n", sc->my_unit);
  581         }
  582 
  583         my_init(sc);
  584         if (sc->my_tx_pend) {
  585                 sc->my_autoneg = 0;
  586                 sc->my_tx_pend = 0;
  587                 my_start(ifp);
  588         }
  589         MY_UNLOCK(sc);
  590         return;
  591 }
  592 
  593 /*
  594  * To get PHY ability.
  595  */
  596 static void
  597 my_getmode_mii(struct my_softc * sc)
  598 {
  599         u_int16_t       bmsr;
  600         struct ifnet   *ifp;
  601 
  602         MY_LOCK(sc);
  603         ifp = &sc->arpcom.ac_if;
  604         bmsr = my_phy_readreg(sc, PHY_BMSR);
  605         if (bootverbose)
  606                 printf("my%d: PHY status word: %x\n", sc->my_unit, bmsr);
  607 
  608         /* fallback */
  609         sc->ifmedia.ifm_media = IFM_ETHER | IFM_10_T | IFM_HDX;
  610 
  611         if (bmsr & PHY_BMSR_10BTHALF) {
  612                 if (bootverbose)
  613                         printf("my%d: 10Mbps half-duplex mode supported\n",
  614                                sc->my_unit);
  615                 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_T | IFM_HDX,
  616                     0, NULL);
  617                 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_T, 0, NULL);
  618         }
  619         if (bmsr & PHY_BMSR_10BTFULL) {
  620                 if (bootverbose)
  621                         printf("my%d: 10Mbps full-duplex mode supported\n",
  622                             sc->my_unit);
  623 
  624                 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_10_T | IFM_FDX,
  625                     0, NULL);
  626                 sc->ifmedia.ifm_media = IFM_ETHER | IFM_10_T | IFM_FDX;
  627         }
  628         if (bmsr & PHY_BMSR_100BTXHALF) {
  629                 if (bootverbose)
  630                         printf("my%d: 100Mbps half-duplex mode supported\n",
  631                                sc->my_unit);
  632                 ifp->if_baudrate = 100000000;
  633                 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_100_TX, 0, NULL);
  634                 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_100_TX | IFM_HDX,
  635                             0, NULL);
  636                 sc->ifmedia.ifm_media = IFM_ETHER | IFM_100_TX | IFM_HDX;
  637         }
  638         if (bmsr & PHY_BMSR_100BTXFULL) {
  639                 if (bootverbose)
  640                         printf("my%d: 100Mbps full-duplex mode supported\n",
  641                             sc->my_unit);
  642                 ifp->if_baudrate = 100000000;
  643                 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_100_TX | IFM_FDX,
  644                     0, NULL);
  645                 sc->ifmedia.ifm_media = IFM_ETHER | IFM_100_TX | IFM_FDX;
  646         }
  647         /* Some also support 100BaseT4. */
  648         if (bmsr & PHY_BMSR_100BT4) {
  649                 if (bootverbose)
  650                         printf("my%d: 100baseT4 mode supported\n", sc->my_unit);
  651                 ifp->if_baudrate = 100000000;
  652                 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_100_T4, 0, NULL);
  653                 sc->ifmedia.ifm_media = IFM_ETHER | IFM_100_T4;
  654 #ifdef FORCE_AUTONEG_TFOUR
  655                 if (bootverbose)
  656                         printf("my%d: forcing on autoneg support for BT4\n",
  657                             sc->my_unit);
  658                 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_AUTO, 0 NULL):
  659                 sc->ifmedia.ifm_media = IFM_ETHER | IFM_AUTO;
  660 #endif
  661         }
  662 #if 0                           /* this version did not support 1000M, */
  663         if (sc->my_pinfo->my_vid == MarvellPHYID0) {
  664                 if (bootverbose)
  665                         printf("my%d: 1000Mbps half-duplex mode supported\n",
  666                                sc->my_unit);
  667 
  668                 ifp->if_baudrate = 1000000000;
  669                 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_1000_T, 0, NULL);
  670                 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_1000_T | IFM_HDX,
  671                     0, NULL);
  672                 if (bootverbose)
  673                         printf("my%d: 1000Mbps full-duplex mode supported\n",
  674                            sc->my_unit);
  675                 ifp->if_baudrate = 1000000000;
  676                 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_1000_T | IFM_FDX,
  677                     0, NULL);
  678                 sc->ifmedia.ifm_media = IFM_ETHER | IFM_1000_T | IFM_FDX;
  679         }
  680 #endif
  681         if (bmsr & PHY_BMSR_CANAUTONEG) {
  682                 if (bootverbose)
  683                         printf("my%d: autoneg supported\n", sc->my_unit);
  684                 ifmedia_add(&sc->ifmedia, IFM_ETHER | IFM_AUTO, 0, NULL);
  685                 sc->ifmedia.ifm_media = IFM_ETHER | IFM_AUTO;
  686         }
  687         MY_UNLOCK(sc);
  688         return;
  689 }
  690 
  691 /*
  692  * Set speed and duplex mode.
  693  */
  694 static void
  695 my_setmode_mii(struct my_softc * sc, int media)
  696 {
  697         u_int16_t       bmcr;
  698         struct ifnet   *ifp;
  699 
  700         MY_LOCK(sc);
  701         ifp = &sc->arpcom.ac_if;
  702         /*
  703          * If an autoneg session is in progress, stop it.
  704          */
  705         if (sc->my_autoneg) {
  706                 printf("my%d: canceling autoneg session\n", sc->my_unit);
  707                 ifp->if_timer = sc->my_autoneg = sc->my_want_auto = 0;
  708                 bmcr = my_phy_readreg(sc, PHY_BMCR);
  709                 bmcr &= ~PHY_BMCR_AUTONEGENBL;
  710                 my_phy_writereg(sc, PHY_BMCR, bmcr);
  711         }
  712         printf("my%d: selecting MII, ", sc->my_unit);
  713         bmcr = my_phy_readreg(sc, PHY_BMCR);
  714         bmcr &= ~(PHY_BMCR_AUTONEGENBL | PHY_BMCR_SPEEDSEL | PHY_BMCR_1000 |
  715                   PHY_BMCR_DUPLEX | PHY_BMCR_LOOPBK);
  716 
  717 #if 0                           /* this version did not support 1000M, */
  718         if (IFM_SUBTYPE(media) == IFM_1000_T) {
  719                 printf("1000Mbps/T4, half-duplex\n");
  720                 bmcr &= ~PHY_BMCR_SPEEDSEL;
  721                 bmcr &= ~PHY_BMCR_DUPLEX;
  722                 bmcr |= PHY_BMCR_1000;
  723         }
  724 #endif
  725         if (IFM_SUBTYPE(media) == IFM_100_T4) {
  726                 printf("100Mbps/T4, half-duplex\n");
  727                 bmcr |= PHY_BMCR_SPEEDSEL;
  728                 bmcr &= ~PHY_BMCR_DUPLEX;
  729         }
  730         if (IFM_SUBTYPE(media) == IFM_100_TX) {
  731                 printf("100Mbps, ");
  732                 bmcr |= PHY_BMCR_SPEEDSEL;
  733         }
  734         if (IFM_SUBTYPE(media) == IFM_10_T) {
  735                 printf("10Mbps, ");
  736                 bmcr &= ~PHY_BMCR_SPEEDSEL;
  737         }
  738         if ((media & IFM_GMASK) == IFM_FDX) {
  739                 printf("full duplex\n");
  740                 bmcr |= PHY_BMCR_DUPLEX;
  741         } else {
  742                 printf("half duplex\n");
  743                 bmcr &= ~PHY_BMCR_DUPLEX;
  744         }
  745         my_phy_writereg(sc, PHY_BMCR, bmcr);
  746         my_setcfg(sc, bmcr);
  747         MY_UNLOCK(sc);
  748         return;
  749 }
  750 
  751 /*
  752  * The Myson manual states that in order to fiddle with the 'full-duplex' and
  753  * '100Mbps' bits in the netconfig register, we first have to put the
  754  * transmit and/or receive logic in the idle state.
  755  */
  756 static void
  757 my_setcfg(struct my_softc * sc, int bmcr)
  758 {
  759         int             i, restart = 0;
  760 
  761         MY_LOCK(sc);
  762         if (CSR_READ_4(sc, MY_TCRRCR) & (MY_TE | MY_RE)) {
  763                 restart = 1;
  764                 MY_CLRBIT(sc, MY_TCRRCR, (MY_TE | MY_RE));
  765                 for (i = 0; i < MY_TIMEOUT; i++) {
  766                         DELAY(10);
  767                         if (!(CSR_READ_4(sc, MY_TCRRCR) &
  768                             (MY_TXRUN | MY_RXRUN)))
  769                                 break;
  770                 }
  771                 if (i == MY_TIMEOUT)
  772                         printf("my%d: failed to force tx and rx to idle \n",
  773                             sc->my_unit);
  774         }
  775         MY_CLRBIT(sc, MY_TCRRCR, MY_PS1000);
  776         MY_CLRBIT(sc, MY_TCRRCR, MY_PS10);
  777         if (bmcr & PHY_BMCR_1000)
  778                 MY_SETBIT(sc, MY_TCRRCR, MY_PS1000);
  779         else if (!(bmcr & PHY_BMCR_SPEEDSEL))
  780                 MY_SETBIT(sc, MY_TCRRCR, MY_PS10);
  781         if (bmcr & PHY_BMCR_DUPLEX)
  782                 MY_SETBIT(sc, MY_TCRRCR, MY_FD);
  783         else
  784                 MY_CLRBIT(sc, MY_TCRRCR, MY_FD);
  785         if (restart)
  786                 MY_SETBIT(sc, MY_TCRRCR, MY_TE | MY_RE);
  787         MY_UNLOCK(sc);
  788         return;
  789 }
  790 
  791 static void
  792 my_reset(struct my_softc * sc)
  793 {
  794         register int    i;
  795 
  796         MY_LOCK(sc);
  797         MY_SETBIT(sc, MY_BCR, MY_SWR);
  798         for (i = 0; i < MY_TIMEOUT; i++) {
  799                 DELAY(10);
  800                 if (!(CSR_READ_4(sc, MY_BCR) & MY_SWR))
  801                         break;
  802         }
  803         if (i == MY_TIMEOUT)
  804                 printf("m0x%d: reset never completed!\n", sc->my_unit);
  805 
  806         /* Wait a little while for the chip to get its brains in order. */
  807         DELAY(1000);
  808         MY_UNLOCK(sc);
  809         return;
  810 }
  811 
  812 /*
  813  * Probe for a Myson chip. Check the PCI vendor and device IDs against our
  814  * list and return a device name if we find a match.
  815  */
  816 static int
  817 my_probe(device_t dev)
  818 {
  819         struct my_type *t;
  820 
  821         t = my_devs;
  822         while (t->my_name != NULL) {
  823                 if ((pci_get_vendor(dev) == t->my_vid) &&
  824                     (pci_get_device(dev) == t->my_did)) {
  825                         device_set_desc(dev, t->my_name);
  826                         my_info_tmp = t;
  827                         return (0);
  828                 }
  829                 t++;
  830         }
  831         return (ENXIO);
  832 }
  833 
  834 /*
  835  * Attach the interface. Allocate softc structures, do ifmedia setup and
  836  * ethernet/BPF attach.
  837  */
  838 static int
  839 my_attach(device_t dev)
  840 {
  841         int             s, i;
  842         u_char          eaddr[ETHER_ADDR_LEN];
  843         u_int32_t       command, iobase;
  844         struct my_softc *sc;
  845         struct ifnet   *ifp;
  846         int             media = IFM_ETHER | IFM_100_TX | IFM_FDX;
  847         unsigned int    round;
  848         caddr_t         roundptr;
  849         struct my_type *p;
  850         u_int16_t       phy_vid, phy_did, phy_sts = 0;
  851         int             rid, unit, error = 0;
  852 
  853         s = splimp();
  854         sc = device_get_softc(dev);
  855         unit = device_get_unit(dev);
  856         if (sc == NULL) {
  857                 printf("my%d: no memory for softc struct!\n", unit);
  858                 error = ENXIO;
  859                 goto fail;
  860 
  861         }
  862         bzero(sc, sizeof(struct my_softc));
  863         mtx_init(&sc->my_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
  864             MTX_DEF | MTX_RECURSE);
  865         MY_LOCK(sc);
  866 
  867         /*
  868          * Map control/status registers.
  869          */
  870 #if 0
  871         command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
  872         command |= (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
  873         pci_write_config(dev, PCI_COMMAND_STATUS_REG, command & 0x000000ff, 4);
  874         command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
  875 #endif
  876         command = pci_read_config(dev, PCIR_COMMAND, 4);
  877         command |= (PCIM_CMD_PORTEN | PCIM_CMD_MEMEN | PCIM_CMD_BUSMASTEREN);
  878         pci_write_config(dev, PCIR_COMMAND, command & 0x000000ff, 4);
  879         command = pci_read_config(dev, PCIR_COMMAND, 4);
  880 
  881         if (my_info_tmp->my_did == MTD800ID) {
  882                 iobase = pci_read_config(dev, MY_PCI_LOIO, 4);
  883                 if (iobase & 0x300)
  884                         MY_USEIOSPACE = 0;
  885         }
  886         if (MY_USEIOSPACE) {
  887                 if (!(command & PCIM_CMD_PORTEN)) {
  888                         printf("my%d: failed to enable I/O ports!\n", unit);
  889                         free(sc, M_DEVBUF);
  890                         error = ENXIO;
  891                         goto fail;
  892                 }
  893 #if 0
  894                 if (!pci_map_port(config_id, MY_PCI_LOIO, (u_int16_t *) & (sc->my_bhandle))) {
  895                         printf("my%d: couldn't map ports\n", unit);
  896                         error = ENXIO;
  897                         goto fail;
  898                 }
  899                   
  900                 sc->my_btag = I386_BUS_SPACE_IO;
  901 #endif
  902         } else {
  903                 if (!(command & PCIM_CMD_MEMEN)) {
  904                         printf("my%d: failed to enable memory mapping!\n",
  905                             unit);
  906                         error = ENXIO;
  907                         goto fail;
  908                 }
  909 #if 0
  910                  if (!pci_map_mem(config_id, MY_PCI_LOMEM, &vbase, &pbase)) {
  911                         printf ("my%d: couldn't map memory\n", unit);
  912                         error = ENXIO;
  913                         goto fail;
  914                 }
  915                 sc->my_btag = I386_BUS_SPACE_MEM;
  916                 sc->my_bhandle = vbase;
  917 #endif
  918         }
  919 
  920         rid = MY_RID;
  921         sc->my_res = bus_alloc_resource(dev, MY_RES, &rid,
  922                                         0, ~0, 1, RF_ACTIVE);
  923 
  924         if (sc->my_res == NULL) {
  925                 printf("my%d: couldn't map ports/memory\n", unit);
  926                 error = ENXIO;
  927                 goto fail;
  928         }
  929         sc->my_btag = rman_get_bustag(sc->my_res);
  930         sc->my_bhandle = rman_get_bushandle(sc->my_res);
  931 
  932         rid = 0;
  933         sc->my_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
  934                                         RF_SHAREABLE | RF_ACTIVE);
  935 
  936         if (sc->my_irq == NULL) {
  937                 printf("my%d: couldn't map interrupt\n", unit);
  938                 bus_release_resource(dev, MY_RES, MY_RID, sc->my_res);
  939                 error = ENXIO;
  940                 goto fail;
  941         }
  942         error = bus_setup_intr(dev, sc->my_irq, INTR_TYPE_NET,
  943                                my_intr, sc, &sc->my_intrhand);
  944 
  945         if (error) {
  946                 bus_release_resource(dev, SYS_RES_IRQ, 0, sc->my_irq);
  947                 bus_release_resource(dev, MY_RES, MY_RID, sc->my_res);
  948                 printf("my%d: couldn't set up irq\n", unit);
  949                 goto fail;
  950         }
  951         callout_handle_init(&sc->my_stat_ch);
  952 
  953         sc->my_info = my_info_tmp;
  954 
  955         /* Reset the adapter. */
  956         my_reset(sc);
  957 
  958         /*
  959          * Get station address
  960          */
  961         for (i = 0; i < ETHER_ADDR_LEN; ++i)
  962                 eaddr[i] = CSR_READ_1(sc, MY_PAR0 + i);
  963 
  964         /*
  965          * A Myson chip was detected. Inform the world.
  966          */
  967         printf("my%d: Ethernet address: %6D\n", unit, eaddr, ":");
  968 
  969         sc->my_unit = unit;
  970         bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
  971 
  972         sc->my_ldata_ptr = malloc(sizeof(struct my_list_data) + 8,
  973                                   M_DEVBUF, M_NOWAIT);
  974         if (sc->my_ldata_ptr == NULL) {
  975                 free(sc, M_DEVBUF);
  976                 printf("my%d: no memory for list buffers!\n", unit);
  977                 error = ENXIO;
  978                 goto fail;
  979         }
  980         sc->my_ldata = (struct my_list_data *) sc->my_ldata_ptr;
  981         round = (uintptr_t)sc->my_ldata_ptr & 0xF;
  982         roundptr = sc->my_ldata_ptr;
  983         for (i = 0; i < 8; i++) {
  984                 if (round % 8) {
  985                         round++;
  986                         roundptr++;
  987                 } else
  988                         break;
  989         }
  990         sc->my_ldata = (struct my_list_data *) roundptr;
  991         bzero(sc->my_ldata, sizeof(struct my_list_data));
  992 
  993         ifp = &sc->arpcom.ac_if;
  994         ifp->if_softc = sc;
  995         if_initname(ifp, device_get_name(dev), device_get_unit(dev));
  996         ifp->if_mtu = ETHERMTU;
  997         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
  998         ifp->if_ioctl = my_ioctl;
  999         ifp->if_output = ether_output;
 1000         ifp->if_start = my_start;
 1001         ifp->if_watchdog = my_watchdog;
 1002         ifp->if_init = my_init;
 1003         ifp->if_baudrate = 10000000;
 1004         ifp->if_snd.ifq_maxlen = IFQ_MAXLEN;
 1005 
 1006         if (sc->my_info->my_did == MTD803ID)
 1007                 sc->my_pinfo = my_phys;
 1008         else {
 1009                 if (bootverbose)
 1010                         printf("my%d: probing for a PHY\n", sc->my_unit);
 1011                 for (i = MY_PHYADDR_MIN; i < MY_PHYADDR_MAX + 1; i++) {
 1012                         if (bootverbose)
 1013                                 printf("my%d: checking address: %d\n",
 1014                                     sc->my_unit, i);
 1015                         sc->my_phy_addr = i;
 1016                         phy_sts = my_phy_readreg(sc, PHY_BMSR);
 1017                         if ((phy_sts != 0) && (phy_sts != 0xffff))
 1018                                 break;
 1019                         else
 1020                                 phy_sts = 0;
 1021                 }
 1022                 if (phy_sts) {
 1023                         phy_vid = my_phy_readreg(sc, PHY_VENID);
 1024                         phy_did = my_phy_readreg(sc, PHY_DEVID);
 1025                         if (bootverbose) {
 1026                                 printf("my%d: found PHY at address %d, ",
 1027                                     sc->my_unit, sc->my_phy_addr);
 1028                                 printf("vendor id: %x device id: %x\n",
 1029                                     phy_vid, phy_did);
 1030                         }
 1031                         p = my_phys;
 1032                         while (p->my_vid) {
 1033                                 if (phy_vid == p->my_vid) {
 1034                                         sc->my_pinfo = p;
 1035                                         break;
 1036                                 }
 1037                                 p++;
 1038                         }
 1039                         if (sc->my_pinfo == NULL)
 1040                                 sc->my_pinfo = &my_phys[PHY_UNKNOWN];
 1041                         if (bootverbose)
 1042                                 printf("my%d: PHY type: %s\n",
 1043                                        sc->my_unit, sc->my_pinfo->my_name);
 1044                 } else {
 1045                         printf("my%d: MII without any phy!\n", sc->my_unit);
 1046                         error = ENXIO;
 1047                         goto fail;
 1048                 }
 1049         }
 1050 
 1051         /* Do ifmedia setup. */
 1052         ifmedia_init(&sc->ifmedia, 0, my_ifmedia_upd, my_ifmedia_sts);
 1053         my_getmode_mii(sc);
 1054         my_autoneg_mii(sc, MY_FLAG_FORCEDELAY, 1);
 1055         media = sc->ifmedia.ifm_media;
 1056         my_stop(sc);
 1057         ifmedia_set(&sc->ifmedia, media);
 1058 
 1059         ether_ifattach(ifp, eaddr);
 1060 
 1061 #if 0
 1062         at_shutdown(my_shutdown, sc, SHUTDOWN_POST_SYNC);
 1063         shutdownhook_establish(my_shutdown, sc);
 1064 #endif
 1065          
 1066         MY_UNLOCK(sc);
 1067         return (0);
 1068 
 1069 fail:
 1070         MY_UNLOCK(sc);
 1071         mtx_destroy(&sc->my_mtx);
 1072         splx(s);
 1073         return (error);
 1074 }
 1075 
 1076 static int
 1077 my_detach(device_t dev)
 1078 {
 1079         struct my_softc *sc;
 1080         struct ifnet   *ifp;
 1081         int             s;
 1082 
 1083         s = splimp();
 1084         sc = device_get_softc(dev);
 1085         MY_LOCK(sc);
 1086         ifp = &sc->arpcom.ac_if;
 1087         ether_ifdetach(ifp);
 1088         my_stop(sc);
 1089 
 1090 #if 0
 1091         bus_generic_detach(dev);
 1092         device_delete_child(dev, sc->rl_miibus);
 1093 #endif
 1094 
 1095         bus_teardown_intr(dev, sc->my_irq, sc->my_intrhand);
 1096         bus_release_resource(dev, SYS_RES_IRQ, 0, sc->my_irq);
 1097         bus_release_resource(dev, MY_RES, MY_RID, sc->my_res);
 1098 #if 0
 1099         contigfree(sc->my_cdata.my_rx_buf, MY_RXBUFLEN + 32, M_DEVBUF);
 1100 #endif
 1101         free(sc, M_DEVBUF);
 1102         MY_UNLOCK(sc);
 1103         splx(s);
 1104         mtx_destroy(&sc->my_mtx);
 1105         return (0);
 1106 }
 1107 
 1108 
 1109 /*
 1110  * Initialize the transmit descriptors.
 1111  */
 1112 static int
 1113 my_list_tx_init(struct my_softc * sc)
 1114 {
 1115         struct my_chain_data *cd;
 1116         struct my_list_data *ld;
 1117         int             i;
 1118 
 1119         MY_LOCK(sc);
 1120         cd = &sc->my_cdata;
 1121         ld = sc->my_ldata;
 1122         for (i = 0; i < MY_TX_LIST_CNT; i++) {
 1123                 cd->my_tx_chain[i].my_ptr = &ld->my_tx_list[i];
 1124                 if (i == (MY_TX_LIST_CNT - 1))
 1125                         cd->my_tx_chain[i].my_nextdesc = &cd->my_tx_chain[0];
 1126                 else
 1127                         cd->my_tx_chain[i].my_nextdesc =
 1128                             &cd->my_tx_chain[i + 1];
 1129         }
 1130         cd->my_tx_free = &cd->my_tx_chain[0];
 1131         cd->my_tx_tail = cd->my_tx_head = NULL;
 1132         MY_UNLOCK(sc);
 1133         return (0);
 1134 }
 1135 
 1136 /*
 1137  * Initialize the RX descriptors and allocate mbufs for them. Note that we
 1138  * arrange the descriptors in a closed ring, so that the last descriptor
 1139  * points back to the first.
 1140  */
 1141 static int
 1142 my_list_rx_init(struct my_softc * sc)
 1143 {
 1144         struct my_chain_data *cd;
 1145         struct my_list_data *ld;
 1146         int             i;
 1147 
 1148         MY_LOCK(sc);
 1149         cd = &sc->my_cdata;
 1150         ld = sc->my_ldata;
 1151         for (i = 0; i < MY_RX_LIST_CNT; i++) {
 1152                 cd->my_rx_chain[i].my_ptr =
 1153                     (struct my_desc *) & ld->my_rx_list[i];
 1154                 if (my_newbuf(sc, &cd->my_rx_chain[i]) == ENOBUFS) {
 1155                         MY_UNLOCK(sc);
 1156                         return (ENOBUFS);
 1157                 }
 1158                 if (i == (MY_RX_LIST_CNT - 1)) {
 1159                         cd->my_rx_chain[i].my_nextdesc = &cd->my_rx_chain[0];
 1160                         ld->my_rx_list[i].my_next = vtophys(&ld->my_rx_list[0]);
 1161                 } else {
 1162                         cd->my_rx_chain[i].my_nextdesc =
 1163                             &cd->my_rx_chain[i + 1];
 1164                         ld->my_rx_list[i].my_next =
 1165                             vtophys(&ld->my_rx_list[i + 1]);
 1166                 }
 1167         }
 1168         cd->my_rx_head = &cd->my_rx_chain[0];
 1169         MY_UNLOCK(sc);
 1170         return (0);
 1171 }
 1172 
 1173 /*
 1174  * Initialize an RX descriptor and attach an MBUF cluster.
 1175  */
 1176 static int
 1177 my_newbuf(struct my_softc * sc, struct my_chain_onefrag * c)
 1178 {
 1179         struct mbuf    *m_new = NULL;
 1180 
 1181         MY_LOCK(sc);
 1182         MGETHDR(m_new, M_DONTWAIT, MT_DATA);
 1183         if (m_new == NULL) {
 1184                 printf("my%d: no memory for rx list -- packet dropped!\n",
 1185                        sc->my_unit);
 1186                 MY_UNLOCK(sc);
 1187                 return (ENOBUFS);
 1188         }
 1189         MCLGET(m_new, M_DONTWAIT);
 1190         if (!(m_new->m_flags & M_EXT)) {
 1191                 printf("my%d: no memory for rx list -- packet dropped!\n",
 1192                        sc->my_unit);
 1193                 m_freem(m_new);
 1194                 MY_UNLOCK(sc);
 1195                 return (ENOBUFS);
 1196         }
 1197         c->my_mbuf = m_new;
 1198         c->my_ptr->my_data = vtophys(mtod(m_new, caddr_t));
 1199         c->my_ptr->my_ctl = (MCLBYTES - 1) << MY_RBSShift;
 1200         c->my_ptr->my_status = MY_OWNByNIC;
 1201         MY_UNLOCK(sc);
 1202         return (0);
 1203 }
 1204 
 1205 /*
 1206  * A frame has been uploaded: pass the resulting mbuf chain up to the higher
 1207  * level protocols.
 1208  */
 1209 static void
 1210 my_rxeof(struct my_softc * sc)
 1211 {
 1212         struct ether_header *eh;
 1213         struct mbuf    *m;
 1214         struct ifnet   *ifp;
 1215         struct my_chain_onefrag *cur_rx;
 1216         int             total_len = 0;
 1217         u_int32_t       rxstat;
 1218 
 1219         MY_LOCK(sc);
 1220         ifp = &sc->arpcom.ac_if;
 1221         while (!((rxstat = sc->my_cdata.my_rx_head->my_ptr->my_status)
 1222             & MY_OWNByNIC)) {
 1223                 cur_rx = sc->my_cdata.my_rx_head;
 1224                 sc->my_cdata.my_rx_head = cur_rx->my_nextdesc;
 1225 
 1226                 if (rxstat & MY_ES) {   /* error summary: give up this rx pkt */
 1227                         ifp->if_ierrors++;
 1228                         cur_rx->my_ptr->my_status = MY_OWNByNIC;
 1229                         continue;
 1230                 }
 1231                 /* No errors; receive the packet. */
 1232                 total_len = (rxstat & MY_FLNGMASK) >> MY_FLNGShift;
 1233                 total_len -= ETHER_CRC_LEN;
 1234 
 1235                 if (total_len < MINCLSIZE) {
 1236                         m = m_devget(mtod(cur_rx->my_mbuf, char *),
 1237                             total_len, 0, ifp, NULL);
 1238                         cur_rx->my_ptr->my_status = MY_OWNByNIC;
 1239                         if (m == NULL) {
 1240                                 ifp->if_ierrors++;
 1241                                 continue;
 1242                         }
 1243                 } else {
 1244                         m = cur_rx->my_mbuf;
 1245                         /*
 1246                          * Try to conjure up a new mbuf cluster. If that
 1247                          * fails, it means we have an out of memory condition
 1248                          * and should leave the buffer in place and continue.
 1249                          * This will result in a lost packet, but there's
 1250                          * little else we can do in this situation.
 1251                          */
 1252                         if (my_newbuf(sc, cur_rx) == ENOBUFS) {
 1253                                 ifp->if_ierrors++;
 1254                                 cur_rx->my_ptr->my_status = MY_OWNByNIC;
 1255                                 continue;
 1256                         }
 1257                         m->m_pkthdr.rcvif = ifp;
 1258                         m->m_pkthdr.len = m->m_len = total_len;
 1259                 }
 1260                 ifp->if_ipackets++;
 1261                 eh = mtod(m, struct ether_header *);
 1262 #if NBPFILTER > 0
 1263                 /*
 1264                  * Handle BPF listeners. Let the BPF user see the packet, but
 1265                  * don't pass it up to the ether_input() layer unless it's a
 1266                  * broadcast packet, multicast packet, matches our ethernet
 1267                  * address or the interface is in promiscuous mode.
 1268                  */
 1269                 if (ifp->if_bpf) {
 1270                         BPF_MTAP(ifp, m);
 1271                         if (ifp->if_flags & IFF_PROMISC &&
 1272                             (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
 1273                                 ETHER_ADDR_LEN) &&
 1274                              (eh->ether_dhost[0] & 1) == 0)) {
 1275                                 m_freem(m);
 1276                                 continue;
 1277                         }
 1278                 }
 1279 #endif
 1280                 MY_UNLOCK(sc);
 1281                 (*ifp->if_input)(ifp, m);
 1282                 MY_LOCK(sc);
 1283         }
 1284         MY_UNLOCK(sc);
 1285         return;
 1286 }
 1287 
 1288 
 1289 /*
 1290  * A frame was downloaded to the chip. It's safe for us to clean up the list
 1291  * buffers.
 1292  */
 1293 static void
 1294 my_txeof(struct my_softc * sc)
 1295 {
 1296         struct my_chain *cur_tx;
 1297         struct ifnet   *ifp;
 1298 
 1299         MY_LOCK(sc);
 1300         ifp = &sc->arpcom.ac_if;
 1301         /* Clear the timeout timer. */
 1302         ifp->if_timer = 0;
 1303         if (sc->my_cdata.my_tx_head == NULL) {
 1304                 MY_UNLOCK(sc);
 1305                 return;
 1306         }
 1307         /*
 1308          * Go through our tx list and free mbufs for those frames that have
 1309          * been transmitted.
 1310          */
 1311         while (sc->my_cdata.my_tx_head->my_mbuf != NULL) {
 1312                 u_int32_t       txstat;
 1313 
 1314                 cur_tx = sc->my_cdata.my_tx_head;
 1315                 txstat = MY_TXSTATUS(cur_tx);
 1316                 if ((txstat & MY_OWNByNIC) || txstat == MY_UNSENT)
 1317                         break;
 1318                 if (!(CSR_READ_4(sc, MY_TCRRCR) & MY_Enhanced)) {
 1319                         if (txstat & MY_TXERR) {
 1320                                 ifp->if_oerrors++;
 1321                                 if (txstat & MY_EC) /* excessive collision */
 1322                                         ifp->if_collisions++;
 1323                                 if (txstat & MY_LC)     /* late collision */
 1324                                         ifp->if_collisions++;
 1325                         }
 1326                         ifp->if_collisions += (txstat & MY_NCRMASK) >>
 1327                             MY_NCRShift;
 1328                 }
 1329                 ifp->if_opackets++;
 1330                 m_freem(cur_tx->my_mbuf);
 1331                 cur_tx->my_mbuf = NULL;
 1332                 if (sc->my_cdata.my_tx_head == sc->my_cdata.my_tx_tail) {
 1333                         sc->my_cdata.my_tx_head = NULL;
 1334                         sc->my_cdata.my_tx_tail = NULL;
 1335                         break;
 1336                 }
 1337                 sc->my_cdata.my_tx_head = cur_tx->my_nextdesc;
 1338         }
 1339         if (CSR_READ_4(sc, MY_TCRRCR) & MY_Enhanced) {
 1340                 ifp->if_collisions += (CSR_READ_4(sc, MY_TSR) & MY_NCRMask);
 1341         }
 1342         MY_UNLOCK(sc);
 1343         return;
 1344 }
 1345 
 1346 /*
 1347  * TX 'end of channel' interrupt handler.
 1348  */
 1349 static void
 1350 my_txeoc(struct my_softc * sc)
 1351 {
 1352         struct ifnet   *ifp;
 1353 
 1354         MY_LOCK(sc);
 1355         ifp = &sc->arpcom.ac_if;
 1356         ifp->if_timer = 0;
 1357         if (sc->my_cdata.my_tx_head == NULL) {
 1358                 ifp->if_flags &= ~IFF_OACTIVE;
 1359                 sc->my_cdata.my_tx_tail = NULL;
 1360                 if (sc->my_want_auto)
 1361                         my_autoneg_mii(sc, MY_FLAG_SCHEDDELAY, 1);
 1362         } else {
 1363                 if (MY_TXOWN(sc->my_cdata.my_tx_head) == MY_UNSENT) {
 1364                         MY_TXOWN(sc->my_cdata.my_tx_head) = MY_OWNByNIC;
 1365                         ifp->if_timer = 5;
 1366                         CSR_WRITE_4(sc, MY_TXPDR, 0xFFFFFFFF);
 1367                 }
 1368         }
 1369         MY_UNLOCK(sc);
 1370         return;
 1371 }
 1372 
 1373 static void
 1374 my_intr(void *arg)
 1375 {
 1376         struct my_softc *sc;
 1377         struct ifnet   *ifp;
 1378         u_int32_t       status;
 1379 
 1380         sc = arg;
 1381         MY_LOCK(sc);
 1382         ifp = &sc->arpcom.ac_if;
 1383         if (!(ifp->if_flags & IFF_UP)) {
 1384                 MY_UNLOCK(sc);
 1385                 return;
 1386         }
 1387         /* Disable interrupts. */
 1388         CSR_WRITE_4(sc, MY_IMR, 0x00000000);
 1389 
 1390         for (;;) {
 1391                 status = CSR_READ_4(sc, MY_ISR);
 1392                 status &= MY_INTRS;
 1393                 if (status)
 1394                         CSR_WRITE_4(sc, MY_ISR, status);
 1395                 else
 1396                         break;
 1397 
 1398                 if (status & MY_RI)     /* receive interrupt */
 1399                         my_rxeof(sc);
 1400 
 1401                 if ((status & MY_RBU) || (status & MY_RxErr)) {
 1402                         /* rx buffer unavailable or rx error */
 1403                         ifp->if_ierrors++;
 1404 #ifdef foo
 1405                         my_stop(sc);
 1406                         my_reset(sc);
 1407                         my_init(sc);
 1408 #endif
 1409                 }
 1410                 if (status & MY_TI)     /* tx interrupt */
 1411                         my_txeof(sc);
 1412                 if (status & MY_ETI)    /* tx early interrupt */
 1413                         my_txeof(sc);
 1414                 if (status & MY_TBU)    /* tx buffer unavailable */
 1415                         my_txeoc(sc);
 1416 
 1417 #if 0                           /* 90/1/18 delete */
 1418                 if (status & MY_FBE) {
 1419                         my_reset(sc);
 1420                         my_init(sc);
 1421                 }
 1422 #endif
 1423 
 1424         }
 1425 
 1426         /* Re-enable interrupts. */
 1427         CSR_WRITE_4(sc, MY_IMR, MY_INTRS);
 1428         if (ifp->if_snd.ifq_head != NULL)
 1429                 my_start(ifp);
 1430         MY_UNLOCK(sc);
 1431         return;
 1432 }
 1433 
 1434 /*
 1435  * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
 1436  * pointers to the fragment pointers.
 1437  */
 1438 static int
 1439 my_encap(struct my_softc * sc, struct my_chain * c, struct mbuf * m_head)
 1440 {
 1441         struct my_desc *f = NULL;
 1442         int             total_len;
 1443         struct mbuf    *m, *m_new = NULL;
 1444 
 1445         MY_LOCK(sc);
 1446         /* calculate the total tx pkt length */
 1447         total_len = 0;
 1448         for (m = m_head; m != NULL; m = m->m_next)
 1449                 total_len += m->m_len;
 1450         /*
 1451          * Start packing the mbufs in this chain into the fragment pointers.
 1452          * Stop when we run out of fragments or hit the end of the mbuf
 1453          * chain.
 1454          */
 1455         m = m_head;
 1456         MGETHDR(m_new, M_DONTWAIT, MT_DATA);
 1457         if (m_new == NULL) {
 1458                 printf("my%d: no memory for tx list", sc->my_unit);
 1459                 MY_UNLOCK(sc);
 1460                 return (1);
 1461         }
 1462         if (m_head->m_pkthdr.len > MHLEN) {
 1463                 MCLGET(m_new, M_DONTWAIT);
 1464                 if (!(m_new->m_flags & M_EXT)) {
 1465                         m_freem(m_new);
 1466                         printf("my%d: no memory for tx list", sc->my_unit);
 1467                         MY_UNLOCK(sc);
 1468                         return (1);
 1469                 }
 1470         }
 1471         m_copydata(m_head, 0, m_head->m_pkthdr.len, mtod(m_new, caddr_t));
 1472         m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
 1473         m_freem(m_head);
 1474         m_head = m_new;
 1475         f = &c->my_ptr->my_frag[0];
 1476         f->my_status = 0;
 1477         f->my_data = vtophys(mtod(m_new, caddr_t));
 1478         total_len = m_new->m_len;
 1479         f->my_ctl = MY_TXFD | MY_TXLD | MY_CRCEnable | MY_PADEnable;
 1480         f->my_ctl |= total_len << MY_PKTShift;  /* pkt size */
 1481         f->my_ctl |= total_len; /* buffer size */
 1482         /* 89/12/29 add, for mtd891 *//* [ 89? ] */
 1483         if (sc->my_info->my_did == MTD891ID)
 1484                 f->my_ctl |= MY_ETIControl | MY_RetryTxLC;
 1485         c->my_mbuf = m_head;
 1486         c->my_lastdesc = 0;
 1487         MY_TXNEXT(c) = vtophys(&c->my_nextdesc->my_ptr->my_frag[0]);
 1488         MY_UNLOCK(sc);
 1489         return (0);
 1490 }
 1491 
 1492 /*
 1493  * Main transmit routine. To avoid having to do mbuf copies, we put pointers
 1494  * to the mbuf data regions directly in the transmit lists. We also save a
 1495  * copy of the pointers since the transmit list fragment pointers are
 1496  * physical addresses.
 1497  */
 1498 static void
 1499 my_start(struct ifnet * ifp)
 1500 {
 1501         struct my_softc *sc;
 1502         struct mbuf    *m_head = NULL;
 1503         struct my_chain *cur_tx = NULL, *start_tx;
 1504 
 1505         sc = ifp->if_softc;
 1506         MY_LOCK(sc);
 1507         if (sc->my_autoneg) {
 1508                 sc->my_tx_pend = 1;
 1509                 MY_UNLOCK(sc);
 1510                 return;
 1511         }
 1512         /*
 1513          * Check for an available queue slot. If there are none, punt.
 1514          */
 1515         if (sc->my_cdata.my_tx_free->my_mbuf != NULL) {
 1516                 ifp->if_flags |= IFF_OACTIVE;
 1517                 MY_UNLOCK(sc);
 1518                 return;
 1519         }
 1520         start_tx = sc->my_cdata.my_tx_free;
 1521         while (sc->my_cdata.my_tx_free->my_mbuf == NULL) {
 1522                 IF_DEQUEUE(&ifp->if_snd, m_head);
 1523                 if (m_head == NULL)
 1524                         break;
 1525 
 1526                 /* Pick a descriptor off the free list. */
 1527                 cur_tx = sc->my_cdata.my_tx_free;
 1528                 sc->my_cdata.my_tx_free = cur_tx->my_nextdesc;
 1529 
 1530                 /* Pack the data into the descriptor. */
 1531                 my_encap(sc, cur_tx, m_head);
 1532 
 1533                 if (cur_tx != start_tx)
 1534                         MY_TXOWN(cur_tx) = MY_OWNByNIC;
 1535 #if NBPFILTER > 0
 1536                 /*
 1537                  * If there's a BPF listener, bounce a copy of this frame to
 1538                  * him.
 1539                  */
 1540                 BPF_MTAP(ifp, cur_tx->my_mbuf);
 1541 #endif
 1542         }
 1543         /*
 1544          * If there are no packets queued, bail.
 1545          */
 1546         if (cur_tx == NULL) {
 1547                 MY_UNLOCK(sc);
 1548                 return;
 1549         }
 1550         /*
 1551          * Place the request for the upload interrupt in the last descriptor
 1552          * in the chain. This way, if we're chaining several packets at once,
 1553          * we'll only get an interupt once for the whole chain rather than
 1554          * once for each packet.
 1555          */
 1556         MY_TXCTL(cur_tx) |= MY_TXIC;
 1557         cur_tx->my_ptr->my_frag[0].my_ctl |= MY_TXIC;
 1558         sc->my_cdata.my_tx_tail = cur_tx;
 1559         if (sc->my_cdata.my_tx_head == NULL)
 1560                 sc->my_cdata.my_tx_head = start_tx;
 1561         MY_TXOWN(start_tx) = MY_OWNByNIC;
 1562         CSR_WRITE_4(sc, MY_TXPDR, 0xFFFFFFFF);  /* tx polling demand */
 1563 
 1564         /*
 1565          * Set a timeout in case the chip goes out to lunch.
 1566          */
 1567         ifp->if_timer = 5;
 1568         MY_UNLOCK(sc);
 1569         return;
 1570 }
 1571 
 1572 static void
 1573 my_init(void *xsc)
 1574 {
 1575         struct my_softc *sc = xsc;
 1576         struct ifnet   *ifp = &sc->arpcom.ac_if;
 1577         int             s;
 1578         u_int16_t       phy_bmcr = 0;
 1579 
 1580         MY_LOCK(sc);
 1581         if (sc->my_autoneg) {
 1582                 MY_UNLOCK(sc);
 1583                 return;
 1584         }
 1585         s = splimp();
 1586         if (sc->my_pinfo != NULL)
 1587                 phy_bmcr = my_phy_readreg(sc, PHY_BMCR);
 1588         /*
 1589          * Cancel pending I/O and free all RX/TX buffers.
 1590          */
 1591         my_stop(sc);
 1592         my_reset(sc);
 1593 
 1594         /*
 1595          * Set cache alignment and burst length.
 1596          */
 1597 #if 0                           /* 89/9/1 modify,  */
 1598         CSR_WRITE_4(sc, MY_BCR, MY_RPBLE512);
 1599         CSR_WRITE_4(sc, MY_TCRRCR, MY_TFTSF);
 1600 #endif
 1601         CSR_WRITE_4(sc, MY_BCR, MY_PBL8);
 1602         CSR_WRITE_4(sc, MY_TCRRCR, MY_TFTSF | MY_RBLEN | MY_RPBLE512);
 1603         /*
 1604          * 89/12/29 add, for mtd891,
 1605          */
 1606         if (sc->my_info->my_did == MTD891ID) {
 1607                 MY_SETBIT(sc, MY_BCR, MY_PROG);
 1608                 MY_SETBIT(sc, MY_TCRRCR, MY_Enhanced);
 1609         }
 1610         my_setcfg(sc, phy_bmcr);
 1611         /* Init circular RX list. */
 1612         if (my_list_rx_init(sc) == ENOBUFS) {
 1613                 printf("my%d: init failed: no memory for rx buffers\n",
 1614                     sc->my_unit);
 1615                 my_stop(sc);
 1616                 (void)splx(s);
 1617                 MY_UNLOCK(sc);
 1618                 return;
 1619         }
 1620         /* Init TX descriptors. */
 1621         my_list_tx_init(sc);
 1622 
 1623         /* If we want promiscuous mode, set the allframes bit. */
 1624         if (ifp->if_flags & IFF_PROMISC)
 1625                 MY_SETBIT(sc, MY_TCRRCR, MY_PROM);
 1626         else
 1627                 MY_CLRBIT(sc, MY_TCRRCR, MY_PROM);
 1628 
 1629         /*
 1630          * Set capture broadcast bit to capture broadcast frames.
 1631          */
 1632         if (ifp->if_flags & IFF_BROADCAST)
 1633                 MY_SETBIT(sc, MY_TCRRCR, MY_AB);
 1634         else
 1635                 MY_CLRBIT(sc, MY_TCRRCR, MY_AB);
 1636 
 1637         /*
 1638          * Program the multicast filter, if necessary.
 1639          */
 1640         my_setmulti(sc);
 1641 
 1642         /*
 1643          * Load the address of the RX list.
 1644          */
 1645         MY_CLRBIT(sc, MY_TCRRCR, MY_RE);
 1646         CSR_WRITE_4(sc, MY_RXLBA, vtophys(&sc->my_ldata->my_rx_list[0]));
 1647 
 1648         /*
 1649          * Enable interrupts.
 1650          */
 1651         CSR_WRITE_4(sc, MY_IMR, MY_INTRS);
 1652         CSR_WRITE_4(sc, MY_ISR, 0xFFFFFFFF);
 1653 
 1654         /* Enable receiver and transmitter. */
 1655         MY_SETBIT(sc, MY_TCRRCR, MY_RE);
 1656         MY_CLRBIT(sc, MY_TCRRCR, MY_TE);
 1657         CSR_WRITE_4(sc, MY_TXLBA, vtophys(&sc->my_ldata->my_tx_list[0]));
 1658         MY_SETBIT(sc, MY_TCRRCR, MY_TE);
 1659 
 1660         /* Restore state of BMCR */
 1661         if (sc->my_pinfo != NULL)
 1662                 my_phy_writereg(sc, PHY_BMCR, phy_bmcr);
 1663         ifp->if_flags |= IFF_RUNNING;
 1664         ifp->if_flags &= ~IFF_OACTIVE;
 1665         (void)splx(s);
 1666         MY_UNLOCK(sc);
 1667         return;
 1668 }
 1669 
 1670 /*
 1671  * Set media options.
 1672  */
 1673 
 1674 static int
 1675 my_ifmedia_upd(struct ifnet * ifp)
 1676 {
 1677         struct my_softc *sc;
 1678         struct ifmedia *ifm;
 1679 
 1680         sc = ifp->if_softc;
 1681         MY_LOCK(sc);
 1682         ifm = &sc->ifmedia;
 1683         if (IFM_TYPE(ifm->ifm_media) != IFM_ETHER) {
 1684                 MY_UNLOCK(sc);
 1685                 return (EINVAL);
 1686         }
 1687         if (IFM_SUBTYPE(ifm->ifm_media) == IFM_AUTO)
 1688                 my_autoneg_mii(sc, MY_FLAG_SCHEDDELAY, 1);
 1689         else
 1690                 my_setmode_mii(sc, ifm->ifm_media);
 1691         MY_UNLOCK(sc);
 1692         return (0);
 1693 }
 1694 
 1695 /*
 1696  * Report current media status.
 1697  */
 1698 
 1699 static void
 1700 my_ifmedia_sts(struct ifnet * ifp, struct ifmediareq * ifmr)
 1701 {
 1702         struct my_softc *sc;
 1703         u_int16_t advert = 0, ability = 0;
 1704 
 1705         sc = ifp->if_softc;
 1706         MY_LOCK(sc);
 1707         ifmr->ifm_active = IFM_ETHER;
 1708         if (!(my_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_AUTONEGENBL)) {
 1709 #if 0                           /* this version did not support 1000M, */
 1710                 if (my_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_1000)
 1711                         ifmr->ifm_active = IFM_ETHER | IFM_1000TX;
 1712 #endif
 1713                 if (my_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_SPEEDSEL)
 1714                         ifmr->ifm_active = IFM_ETHER | IFM_100_TX;
 1715                 else
 1716                         ifmr->ifm_active = IFM_ETHER | IFM_10_T;
 1717                 if (my_phy_readreg(sc, PHY_BMCR) & PHY_BMCR_DUPLEX)
 1718                         ifmr->ifm_active |= IFM_FDX;
 1719                 else
 1720                         ifmr->ifm_active |= IFM_HDX;
 1721 
 1722                 MY_UNLOCK(sc);
 1723                 return;
 1724         }
 1725         ability = my_phy_readreg(sc, PHY_LPAR);
 1726         advert = my_phy_readreg(sc, PHY_ANAR);
 1727 
 1728 #if 0                           /* this version did not support 1000M, */
 1729         if (sc->my_pinfo->my_vid = MarvellPHYID0) {
 1730                 ability2 = my_phy_readreg(sc, PHY_1000SR);
 1731                 if (ability2 & PHY_1000SR_1000BTXFULL) {
 1732                         advert = 0;
 1733                         ability = 0;
 1734                         ifmr->ifm_active = IFM_ETHER|IFM_1000_T|IFM_FDX;
 1735                 } else if (ability & PHY_1000SR_1000BTXHALF) {
 1736                         advert = 0;
 1737                         ability = 0;
 1738                         ifmr->ifm_active = IFM_ETHER|IFM_1000_T|IFM_HDX;
 1739                 }
 1740         }
 1741 #endif
 1742         if (advert & PHY_ANAR_100BT4 && ability & PHY_ANAR_100BT4)
 1743                 ifmr->ifm_active = IFM_ETHER | IFM_100_T4;
 1744         else if (advert & PHY_ANAR_100BTXFULL && ability & PHY_ANAR_100BTXFULL)
 1745                 ifmr->ifm_active = IFM_ETHER | IFM_100_TX | IFM_FDX;
 1746         else if (advert & PHY_ANAR_100BTXHALF && ability & PHY_ANAR_100BTXHALF)
 1747                 ifmr->ifm_active = IFM_ETHER | IFM_100_TX | IFM_HDX;
 1748         else if (advert & PHY_ANAR_10BTFULL && ability & PHY_ANAR_10BTFULL)
 1749                 ifmr->ifm_active = IFM_ETHER | IFM_10_T | IFM_FDX;
 1750         else if (advert & PHY_ANAR_10BTHALF && ability & PHY_ANAR_10BTHALF)
 1751                 ifmr->ifm_active = IFM_ETHER | IFM_10_T | IFM_HDX;
 1752         MY_UNLOCK(sc);
 1753         return;
 1754 }
 1755 
 1756 static int
 1757 my_ioctl(struct ifnet * ifp, u_long command, caddr_t data)
 1758 {
 1759         struct my_softc *sc = ifp->if_softc;
 1760         struct ifreq   *ifr = (struct ifreq *) data;
 1761         int             s, error = 0;
 1762 
 1763         s = splimp();
 1764         MY_LOCK(sc);
 1765         switch (command) {
 1766         case SIOCSIFFLAGS:
 1767                 if (ifp->if_flags & IFF_UP)
 1768                         my_init(sc);
 1769                 else if (ifp->if_flags & IFF_RUNNING)
 1770                         my_stop(sc);
 1771                 error = 0;
 1772                 break;
 1773         case SIOCADDMULTI:
 1774         case SIOCDELMULTI:
 1775                 my_setmulti(sc);
 1776                 error = 0;
 1777                 break;
 1778         case SIOCGIFMEDIA:
 1779         case SIOCSIFMEDIA:
 1780                 error = ifmedia_ioctl(ifp, ifr, &sc->ifmedia, command);
 1781                 break;
 1782         default:
 1783                 error = ether_ioctl(ifp, command, data);
 1784                 break;
 1785         }
 1786         MY_UNLOCK(sc);
 1787         (void)splx(s);
 1788         return (error);
 1789 }
 1790 
 1791 static void
 1792 my_watchdog(struct ifnet * ifp)
 1793 {
 1794         struct my_softc *sc;
 1795 
 1796         sc = ifp->if_softc;
 1797         MY_LOCK(sc);
 1798         if (sc->my_autoneg) {
 1799                 my_autoneg_mii(sc, MY_FLAG_DELAYTIMEO, 1);
 1800                 MY_UNLOCK(sc);
 1801                 return;
 1802         }
 1803         ifp->if_oerrors++;
 1804         printf("my%d: watchdog timeout\n", sc->my_unit);
 1805         if (!(my_phy_readreg(sc, PHY_BMSR) & PHY_BMSR_LINKSTAT))
 1806                 printf("my%d: no carrier - transceiver cable problem?\n",
 1807                     sc->my_unit);
 1808         my_stop(sc);
 1809         my_reset(sc);
 1810         my_init(sc);
 1811         if (ifp->if_snd.ifq_head != NULL)
 1812                 my_start(ifp);
 1813         MY_LOCK(sc);
 1814         return;
 1815 }
 1816 
 1817 
 1818 /*
 1819  * Stop the adapter and free any mbufs allocated to the RX and TX lists.
 1820  */
 1821 static void
 1822 my_stop(struct my_softc * sc)
 1823 {
 1824         register int    i;
 1825         struct ifnet   *ifp;
 1826 
 1827         MY_LOCK(sc);
 1828         ifp = &sc->arpcom.ac_if;
 1829         ifp->if_timer = 0;
 1830 
 1831         MY_CLRBIT(sc, MY_TCRRCR, (MY_RE | MY_TE));
 1832         CSR_WRITE_4(sc, MY_IMR, 0x00000000);
 1833         CSR_WRITE_4(sc, MY_TXLBA, 0x00000000);
 1834         CSR_WRITE_4(sc, MY_RXLBA, 0x00000000);
 1835 
 1836         /*
 1837          * Free data in the RX lists.
 1838          */
 1839         for (i = 0; i < MY_RX_LIST_CNT; i++) {
 1840                 if (sc->my_cdata.my_rx_chain[i].my_mbuf != NULL) {
 1841                         m_freem(sc->my_cdata.my_rx_chain[i].my_mbuf);
 1842                         sc->my_cdata.my_rx_chain[i].my_mbuf = NULL;
 1843                 }
 1844         }
 1845         bzero((char *)&sc->my_ldata->my_rx_list,
 1846             sizeof(sc->my_ldata->my_rx_list));
 1847         /*
 1848          * Free the TX list buffers.
 1849          */
 1850         for (i = 0; i < MY_TX_LIST_CNT; i++) {
 1851                 if (sc->my_cdata.my_tx_chain[i].my_mbuf != NULL) {
 1852                         m_freem(sc->my_cdata.my_tx_chain[i].my_mbuf);
 1853                         sc->my_cdata.my_tx_chain[i].my_mbuf = NULL;
 1854                 }
 1855         }
 1856         bzero((char *)&sc->my_ldata->my_tx_list,
 1857             sizeof(sc->my_ldata->my_tx_list));
 1858         ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
 1859         MY_UNLOCK(sc);
 1860         return;
 1861 }
 1862 
 1863 /*
 1864  * Stop all chip I/O so that the kernel's probe routines don't get confused
 1865  * by errant DMAs when rebooting.
 1866  */
 1867 static void
 1868 my_shutdown(device_t dev)
 1869 {
 1870         struct my_softc *sc;
 1871 
 1872         sc = device_get_softc(dev);
 1873         my_stop(sc);
 1874         return;
 1875 }

Cache object: c1b08edf8ce7cbb877e14caeef003f5f


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