The Design and Implementation of the FreeBSD Operating System, Second Edition
Now available: The Design and Implementation of the FreeBSD Operating System (Second Edition)


[ source navigation ] [ diff markup ] [ identifier search ] [ freetext search ] [ file search ] [ list types ] [ track identifier ]

FreeBSD/Linux Kernel Cross Reference
sys/dev/ic/mb86950.c

Version: -  FREEBSD  -  FREEBSD-13-STABLE  -  FREEBSD-13-0  -  FREEBSD-12-STABLE  -  FREEBSD-12-0  -  FREEBSD-11-STABLE  -  FREEBSD-11-0  -  FREEBSD-10-STABLE  -  FREEBSD-10-0  -  FREEBSD-9-STABLE  -  FREEBSD-9-0  -  FREEBSD-8-STABLE  -  FREEBSD-8-0  -  FREEBSD-7-STABLE  -  FREEBSD-7-0  -  FREEBSD-6-STABLE  -  FREEBSD-6-0  -  FREEBSD-5-STABLE  -  FREEBSD-5-0  -  FREEBSD-4-STABLE  -  FREEBSD-3-STABLE  -  FREEBSD22  -  l41  -  OPENBSD  -  linux-2.6  -  MK84  -  PLAN9  -  xnu-8792 
SearchContext: -  none  -  3  -  10 

    1 /*      $NetBSD: mb86950.c,v 1.11 2008/04/08 12:07:26 cegger Exp $      */
    2 
    3 /*
    4  * All Rights Reserved, Copyright (C) Fujitsu Limited 1995
    5  *
    6  * This software may be used, modified, copied, distributed, and sold, in
    7  * both source and binary form provided that the above copyright, these
    8  * terms and the following disclaimer are retained.  The name of the author
    9  * and/or the contributor may not be used to endorse or promote products
   10  * derived from this software without specific prior written permission.
   11  *
   12  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND THE CONTRIBUTOR ``AS IS'' AND
   13  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
   14  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
   15  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR THE CONTRIBUTOR BE LIABLE
   16  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
   17  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
   18  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION.
   19  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
   20  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
   21  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
   22  * SUCH DAMAGE.
   23  */
   24 
   25 /*
   26  * Portions copyright (C) 1993, David Greenman.  This software may be used,
   27  * modified, copied, distributed, and sold, in both source and binary form
   28  * provided that the above copyright and these terms are retained.  Under no
   29  * circumstances is the author responsible for the proper functioning of this
   30  * software, nor does the author assume any responsibility for damages
   31  * incurred with its use.
   32  */
   33 
   34  /*
   35   * Portions copyright (c) 1995 Mika Kortelainen
   36   * All rights reserved.
   37   *
   38   * Redistribution and use in source and binary forms, with or without
   39   * modification, are permitted provided that the following conditions
   40   * are met:
   41   * 1. Redistributions of source code must retain the above copyright
   42   *    notice, this list of conditions and the following disclaimer.
   43   * 2. Redistributions in binary form must reproduce the above copyright
   44   *    notice, this list of conditions and the following disclaimer in the
   45   *    documentation and/or other materials provided with the distribution.
   46   * 3. All advertising materials mentioning features or use of this software
   47   *    must display the following acknowledgement:
   48   *      This product includes software developed by  Mika Kortelainen
   49   * 4. The name of the author may not be used to endorse or promote products
   50   *    derived from this software without specific prior written permission
   51   *
   52   * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
   53   * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
   54   * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
   55   * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
   56   * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
   57   * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
   58   * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
   59   * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
   60   * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
   61   * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
   62   */
   63 
   64  /*
   65   * Device driver for Fujitsu MB86960A/MB86965A based Ethernet cards.
   66   * Contributed by M.S. <seki@sysrap.cs.fujitsu.co.jp>
   67   */
   68 
   69 #include <sys/cdefs.h>
   70 __KERNEL_RCSID(0, "$NetBSD: mb86950.c,v 1.11 2008/04/08 12:07:26 cegger Exp $");
   71 
   72 /*
   73  * Device driver for Fujitsu mb86950 based Ethernet cards.
   74  * Adapted by Dave J. Barnes from various Internet sources including
   75  * mb86960.c (NetBSD), if_qn.c (NetBSD/Amiga), DOS Packet Driver (Brian Fisher,
   76  * Queens University), EtherBoot Driver (Ken Yap).
   77  */
   78 
   79 /* XXX There are still rough edges......
   80  *
   81  * (1) There is no watchdog timer for the transmitter. It's doubtful that
   82  *     transmit from the chip could be restarted without a hardware reset
   83  *     though. (Fixed - not fully tested)
   84  *
   85  * (2) The media interface callback goo is broke.  No big deal since to change
   86  *     from aui to bnc on the old Tiara LANCard requires moving 8 board jumpers.
   87  *     Other cards (SMC ?) using the EtherStar chip may support media change
   88  *     via software. (Fixed - tested)
   89  *
   90  * (3) The maximum outstanding transmit packets is set to 4.  What
   91  *     is a good limit of outstanding transmit packets for the EtherStar?
   92  *     Is there a way to tell how many bytes are remaining to be
   93  *     transmitted? [no]
   94 ---
   95         When the EtherStar was designed, CPU power was a fraction
   96         of what it is now.  The single EtherStar transmit buffer
   97         was fine.  It was unlikely that the CPU could outrun the
   98         EtherStar. However, things in 2004 are quite different.
   99         sc->txb_size is used to keep the CPU from overrunning the
  100         EtherStar.  At most allow one packet transmitting and one
  101         going into the fifo.
  102 
  103 ---
  104     No, that isn't right either :(
  105 
  106  * (4) Multicast isn't supported.  Feel free to add multicast code
  107  *     if you know how to make the EtherStar do multicast.  Otherwise
  108  *     you'd have to use promiscuous mode and do multicast in software. OUCH!
  109  *
  110  * (5) There are no bus_space_barrier calls used. Are they needed? Maybe not.
  111  *
  112  * (6) Access to the fifo assumes word (16 bit) mode.  Cards configured for
  113  *     byte wide fifo access will require driver code changes.
  114  *
  115  * Only the minimum code necessary to make the Tiara LANCard work
  116  * has been tested. Other cards may require more work, especially
  117  * byte mode fifo and if DMA is used.
  118  *
  119  * djb / 2004
  120  */
  121 
  122 #include "opt_inet.h"
  123 #include "bpfilter.h"
  124 #include "rnd.h"
  125 
  126 #include <sys/param.h>
  127 #include <sys/systm.h>
  128 #include <sys/errno.h>
  129 #include <sys/ioctl.h>
  130 #include <sys/mbuf.h>
  131 #include <sys/socket.h>
  132 #include <sys/syslog.h>
  133 #include <sys/device.h>
  134 #if NRND > 0
  135 #include <sys/rnd.h>
  136 #endif
  137 
  138 #include <net/if.h>
  139 #include <net/if_dl.h>
  140 #include <net/if_types.h>
  141 #include <net/if_media.h>
  142 #include <net/if_ether.h>
  143 
  144 #ifdef INET
  145 #include <netinet/in.h>
  146 #include <netinet/in_systm.h>
  147 #include <netinet/in_var.h>
  148 #include <netinet/ip.h>
  149 #include <netinet/if_inarp.h>
  150 #endif
  151 
  152 
  153 #if NBPFILTER > 0
  154 #include <net/bpf.h>
  155 #include <net/bpfdesc.h>
  156 #endif
  157 
  158 #include <sys/bus.h>
  159 
  160 #include <dev/ic/mb86950reg.h>
  161 #include <dev/ic/mb86950var.h>
  162 
  163 #ifndef __BUS_SPACE_HAS_STREAM_METHODS
  164 #define bus_space_write_stream_2        bus_space_write_2
  165 #define bus_space_write_multi_stream_2  bus_space_write_multi_2
  166 #define bus_space_read_multi_stream_2   bus_space_read_multi_2
  167 #endif /* __BUS_SPACE_HAS_STREAM_METHODS */
  168 
  169 /* Standard driver entry points.  These can be static. */
  170 int             mb86950_ioctl   __P((struct ifnet *, u_long, void *));
  171 void    mb86950_init    __P((struct mb86950_softc *));
  172 void    mb86950_start   __P((struct ifnet *));
  173 void    mb86950_watchdog __P((struct ifnet *));
  174 void    mb86950_reset   __P((struct mb86950_softc *));
  175 
  176 /* Local functions. */
  177 void    mb86950_stop __P((struct mb86950_softc *));
  178 void    mb86950_tint __P((struct mb86950_softc *, u_int8_t));
  179 void    mb86950_rint __P((struct mb86950_softc *, u_int8_t));
  180 int             mb86950_get_fifo __P((struct mb86950_softc *, u_int));
  181 ushort  mb86950_put_fifo __P((struct mb86950_softc *, struct mbuf *));
  182 void    mb86950_drain_fifo __P((struct mb86950_softc *));
  183 
  184 int             mb86950_mediachange __P((struct ifnet *));
  185 void    mb86950_mediastatus __P((struct ifnet *, struct ifmediareq *));
  186 
  187 
  188 #if ESTAR_DEBUG >= 1
  189 void    mb86950_dump __P((int, struct mb86950_softc *));
  190 #endif
  191 
  192 /********************************************************************/
  193 
  194 void
  195 mb86950_attach(sc, myea)
  196         struct mb86950_softc *sc;
  197         u_int8_t *myea;
  198 {
  199 
  200 #ifdef DIAGNOSTIC
  201         if (myea == NULL) {
  202                 printf("%s: ethernet address shouldn't be NULL\n",
  203                     device_xname(&sc->sc_dev));
  204                 panic("NULL ethernet address");
  205         }
  206 #endif
  207 
  208         /* Initialize 86950. */
  209         mb86950_stop(sc);
  210 
  211         memcpy(sc->sc_enaddr, myea, sizeof(sc->sc_enaddr));
  212 
  213         sc->sc_stat |= ESTAR_STAT_ENABLED;
  214 }
  215 
  216 /*
  217  * Stop everything on the interface.
  218  *
  219  * All buffered packets, both transmitting and receiving,
  220  * if any, will be lost by stopping the interface.
  221  */
  222 void
  223 mb86950_stop(sc)
  224         struct mb86950_softc *sc;
  225 {
  226         bus_space_tag_t bst = sc->sc_bst;
  227         bus_space_handle_t bsh = sc->sc_bsh;
  228 
  229         /* Stop interface hardware. */
  230         bus_space_write_1(bst, bsh, DLCR_CONFIG, DISABLE_DLC);
  231         delay(200);
  232 
  233         /* Disable interrupts. */
  234         bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, 0);
  235         bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, 0);
  236 
  237         /* Ack / Clear all interrupt status. */
  238         bus_space_write_1(bst, bsh, DLCR_TX_STAT, 0xff);
  239         bus_space_write_1(bst, bsh, DLCR_RX_STAT, 0xff);
  240 
  241         /* Clear DMA Bit */
  242     bus_space_write_2(bst, bsh, BMPR_DMA, 0);
  243 
  244     /* accept no packets */
  245         bus_space_write_1(bst, bsh, DLCR_TX_MODE, 0);
  246         bus_space_write_1(bst, bsh, DLCR_RX_MODE, 0);
  247 
  248     mb86950_drain_fifo(sc);
  249 
  250 }
  251 
  252 void
  253 mb86950_drain_fifo(sc)
  254         struct mb86950_softc *sc;
  255 {
  256         bus_space_tag_t bst = sc->sc_bst;
  257         bus_space_handle_t bsh = sc->sc_bsh;
  258 
  259         /* Read data until bus read error (i.e. buffer empty). */
  260         /* XXX There ought to be a better way, eats CPU and bothers the chip */
  261         while (!(bus_space_read_1(bst, bsh, DLCR_RX_STAT) & RX_BUS_RD_ERR))
  262                 bus_space_read_2(bst, bsh, BMPR_FIFO);
  263         /* XXX */
  264 
  265         /* Clear Bus Rd Error */
  266         bus_space_write_1(bst, bsh, DLCR_RX_STAT, RX_BUS_RD_ERR);
  267 }
  268 
  269 /*
  270  * Install interface into kernel networking data structures
  271  */
  272 void
  273 mb86950_config(struct mb86950_softc *sc, int *media,
  274     int nmedia, int defmedia)
  275 {
  276         struct ifnet *ifp = &sc->sc_ec.ec_if;
  277         bus_space_tag_t bst = sc->sc_bst;
  278         bus_space_handle_t bsh = sc->sc_bsh;
  279 
  280         /* Initialize ifnet structure. */
  281         strlcpy(ifp->if_xname, device_xname(&sc->sc_dev), IFNAMSIZ);
  282         ifp->if_softc = sc;
  283         ifp->if_start = mb86950_start;
  284         ifp->if_ioctl = mb86950_ioctl;
  285         ifp->if_watchdog = mb86950_watchdog;
  286         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_NOTRAILERS;
  287 
  288         IFQ_SET_READY(&ifp->if_snd);
  289 
  290         /* Initialize media goo. */
  291         /* XXX The Tiara LANCard uses board jumpers to change media.
  292          *       This code may have to be changed for other cards.
  293          */
  294         ifmedia_init(&sc->sc_media, 0, mb86950_mediachange, mb86950_mediastatus);
  295         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL);
  296         ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL);
  297 
  298         /* Attach the interface. */
  299         if_attach(ifp);
  300 
  301         /* Feed the chip the station address. */
  302         bus_space_write_region_1(bst, bsh, DLCR_NODE_ID, sc->sc_enaddr, ETHER_ADDR_LEN);
  303 
  304         ether_ifattach(ifp, sc->sc_enaddr);
  305 
  306 #if NRND > 0
  307         rnd_attach_source(&sc->rnd_source, device_xname(&sc->sc_dev),
  308             RND_TYPE_NET, 0);
  309 #endif
  310 
  311 /* XXX No! This doesn't work - DLCR6 of the mb86950 is different
  312 
  313         bus_space_write_1(bst, bsh, DLCR_CONFIG, 0x0f);
  314         buf_config = bus_space_read_1(bst, bsh, DLCR_CONFIG);
  315 
  316         sc->txb_count = ((buf_config & 0x0c) ? 2 : 1);
  317         sc->txb_size = 1024 * (2 << ((buf_config & 0x0c) ? (((buf_config & 0x0c) >> 2) - 1) : 0));
  318         sc->txb_free = (sc->txb_size * sc->txb_count) / 1500;
  319 
  320         sc->rxb_size = ((8 << (buf_config & 3)) * 1024) - (sc->txb_size * sc->txb_count);
  321         sc->rxb_max = sc->rxb_size / 64;
  322 
  323         printf("mb86950: Buffer Size %dKB with %d transmit buffer(s) %dKB each.\n",
  324                 (8 << (buf_config & 3)), sc->txb_count, (sc->txb_size / 1024));
  325         printf("         Transmit Buffer Space for %d maximum sized packet(s).\n",sc->txb_free);
  326         printf("         System Bus Width %d bits, Buffer Memory %d bits.\n",
  327                 ((buf_config & 0x20) ? 8 : 16),
  328                 ((buf_config & 0x10) ? 8 : 16));
  329 
  330 */
  331 
  332         /* Set reasonable values for number of packet flow control if not
  333          * set elsewhere */
  334         if (sc->txb_num_pkt == 0) sc->txb_num_pkt = 1;
  335         if (sc->rxb_num_pkt == 0) sc->rxb_num_pkt = 100;
  336 
  337         /* Print additional info when attached. */
  338         printf("%s: Ethernet address %s\n", device_xname(&sc->sc_dev),
  339             ether_sprintf(sc->sc_enaddr));
  340 
  341         /* The attach is successful. */
  342         sc->sc_stat |= ESTAR_STAT_ATTACHED;
  343 }
  344 
  345 /*
  346  * Media change callback.
  347  */
  348 int
  349 mb86950_mediachange(ifp)
  350         struct ifnet *ifp;
  351 {
  352 
  353         struct mb86950_softc *sc = ifp->if_softc;
  354 
  355         if (sc->sc_mediachange)
  356                 return ((*sc->sc_mediachange)(sc));
  357 
  358         return (0);
  359 }
  360 
  361 /*
  362  * Media status callback.
  363  */
  364 void
  365 mb86950_mediastatus(ifp, ifmr)
  366         struct ifnet *ifp;
  367         struct ifmediareq *ifmr;
  368 {
  369         struct mb86950_softc *sc = ifp->if_softc;
  370 
  371         if ((sc->sc_stat & ESTAR_STAT_ENABLED) == 0) {
  372                 ifmr->ifm_active = IFM_ETHER | IFM_NONE;
  373                 ifmr->ifm_status = 0;
  374                 return;
  375         }
  376 
  377         if (sc->sc_mediastatus)
  378                 (*sc->sc_mediastatus)(sc, ifmr);
  379 
  380 }
  381 
  382 /*
  383  * Reset interface.
  384  */
  385 void
  386 mb86950_reset(sc)
  387         struct mb86950_softc *sc;
  388 {
  389         int s;
  390 
  391         s = splnet();
  392         log(LOG_ERR, "%s: device reset\n", device_xname(&sc->sc_dev));
  393         mb86950_stop(sc);
  394         mb86950_init(sc);
  395         splx(s);
  396 }
  397 
  398 /*
  399  * Device timeout/watchdog routine. Entered if the device neglects to
  400  * generate an interrupt after a transmit has been started on it.
  401  */
  402 void
  403 mb86950_watchdog(ifp)
  404         struct ifnet *ifp;
  405 {
  406         struct mb86950_softc *sc = ifp->if_softc;
  407         bus_space_tag_t bst = sc->sc_bst;
  408         bus_space_handle_t bsh = sc->sc_bsh;
  409         u_int8_t tstat;
  410 
  411         /* verbose watchdog messages for debugging timeouts */
  412     if ((tstat = bus_space_read_1(bst, bsh, DLCR_TX_STAT)) != 0) {
  413                 if (tstat & TX_CR_LOST) {
  414                         if ((tstat & (TX_COL | TX_16COL)) == 0) {
  415                                  log(LOG_ERR, "%s: carrier lost\n",
  416                                     device_xname(&sc->sc_dev));
  417                         } else {
  418                                 log(LOG_ERR, "%s: excessive collisions\n",
  419                                     device_xname(&sc->sc_dev));
  420                         }
  421                 }
  422                 else if ((tstat & (TX_UNDERFLO | TX_BUS_WR_ERR)) != 0) {
  423                         log(LOG_ERR, "%s: tx fifo underflow/overflow\n",
  424                             device_xname(&sc->sc_dev));
  425                 } else {
  426                         log(LOG_ERR, "%s: transmit error\n",
  427                             device_xname(&sc->sc_dev));
  428                 }
  429         } else {
  430                 log(LOG_ERR, "%s: device timeout\n", device_xname(&sc->sc_dev));
  431         }
  432 
  433         /* Don't know how many packets are lost by this accident.
  434          *  ... So just errors = errors + 1
  435          */
  436         ifp->if_oerrors++;
  437 
  438         mb86950_reset(sc);
  439 
  440 }
  441 
  442 /*
  443  ******************** IOCTL
  444  * Process an ioctl request.
  445  */
  446 int
  447 mb86950_ioctl(ifp, cmd, data)
  448         struct ifnet *ifp;
  449         u_long cmd;
  450         void *data;
  451 {
  452         struct mb86950_softc *sc = ifp->if_softc;
  453         struct ifaddr *ifa = (struct ifaddr *)data;
  454         struct ifreq *ifr = (struct ifreq *)data;
  455 
  456         int s, error = 0;
  457 
  458         s = splnet();
  459 
  460         switch (cmd) {
  461         case SIOCSIFADDR:
  462                 /* XXX depreciated ? What should I use instead? */
  463                 if ((error = mb86950_enable(sc)) != 0)
  464                         break;
  465 
  466                 ifp->if_flags |= IFF_UP;
  467 
  468                 switch (ifa->ifa_addr->sa_family) {
  469 
  470 #ifdef INET
  471                 case AF_INET:
  472                         mb86950_init(sc);
  473                         arp_ifinit(ifp, ifa);
  474                         break;
  475 #endif
  476 
  477 
  478                 default:
  479                         mb86950_init(sc);
  480                         break;
  481                 }
  482                 break;
  483 
  484         case SIOCSIFFLAGS:
  485                 if ((ifp->if_flags & IFF_UP) == 0 &&
  486                     (ifp->if_flags & IFF_RUNNING) != 0) {
  487                         /*
  488                          * If interface is marked down and it is running, then
  489                          * stop it.
  490                          */
  491                         mb86950_stop(sc);
  492                         ifp->if_flags &= ~IFF_RUNNING;
  493                         mb86950_disable(sc);
  494 
  495                 } else if ((ifp->if_flags & IFF_UP) != 0 &&
  496                         (ifp->if_flags & IFF_RUNNING) == 0) {
  497                         /*
  498                          * If interface is marked up and it is stopped, then
  499                          * start it.
  500                          */
  501                         if ((error = mb86950_enable(sc)) != 0)
  502                                 break;
  503                         mb86950_init(sc);
  504 
  505                 } else if ((ifp->if_flags & IFF_UP) != 0) {
  506                         /*
  507                          * Reset the interface to pick up changes in any other
  508                          * flags that affect hardware registers.
  509                          */
  510 /* Setmode not supported
  511                         mb86950_setmode(sc);
  512 */
  513                 }
  514 
  515 #if ESTAR_DEBUG >= 1
  516                 /* "ifconfig fe0 debug" to print register dump. */
  517                 if (ifp->if_flags & IFF_DEBUG) {
  518                         log(LOG_INFO, "%s: SIOCSIFFLAGS(DEBUG)\n",
  519                             device_xname(&sc->sc_dev));
  520                         mb86950_dump(LOG_DEBUG, sc);
  521                 }
  522 #endif
  523                 break;
  524 
  525         case SIOCGIFMEDIA:
  526         case SIOCSIFMEDIA:
  527                 error = ifmedia_ioctl(ifp, ifr, &sc->sc_media, cmd);
  528                 break;
  529 
  530         default:
  531                 error = EINVAL;
  532                 break;
  533         }
  534 
  535         splx(s);
  536         return (error);
  537 }
  538 
  539 /*
  540  * Initialize device.
  541  */
  542 void
  543 mb86950_init(sc)
  544         struct mb86950_softc *sc;
  545 {
  546         bus_space_tag_t bst = sc->sc_bst;
  547         bus_space_handle_t bsh = sc->sc_bsh;
  548         struct ifnet *ifp = &sc->sc_ec.ec_if;
  549 
  550         /* Reset transmitter flags. */
  551         ifp->if_flags &= ~IFF_OACTIVE;
  552         ifp->if_timer = 0;
  553         sc->txb_sched = 0;
  554 
  555         bus_space_write_1(bst, bsh, DLCR_TX_MODE, LBC);
  556         bus_space_write_1(bst, bsh, DLCR_RX_MODE, NORMAL_MODE);
  557 
  558         /* Enable interrupts. */
  559         bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, TX_MASK);
  560         bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, RX_MASK);
  561 
  562         /* Enable transmitter and receiver. */
  563         bus_space_write_1(bst, bsh, DLCR_CONFIG, ENABLE_DLC);
  564         delay(200);
  565 
  566         /* Set 'running' flag. */
  567         ifp->if_flags |= IFF_RUNNING;
  568 
  569         /* ...and attempt to start output. */
  570         mb86950_start(ifp);
  571 
  572 }
  573 
  574 void
  575 mb86950_start(ifp)
  576         struct ifnet *ifp;
  577 {
  578         struct mb86950_softc *sc = ifp->if_softc;
  579     bus_space_tag_t bst = sc->sc_bst;
  580     bus_space_handle_t bsh = sc->sc_bsh;
  581         struct mbuf *m;
  582         int len;
  583 
  584         if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
  585                 return;
  586 
  587         IF_DEQUEUE(&ifp->if_snd, m);
  588         if (m == 0)
  589                 return;
  590 
  591 #if NBPFILTER > 0
  592         /* Tap off here if there is a BPF listener. */
  593         if (ifp->if_bpf)
  594                 bpf_mtap(ifp->if_bpf, m);
  595 #endif
  596 
  597         /* Send the packet to the mb86950 */
  598         len = mb86950_put_fifo(sc,m);
  599         m_freem(m);
  600 
  601         /* XXX bus_space_barrier here ? */
  602         if (bus_space_read_1(bst, bsh, DLCR_TX_STAT) & (TX_UNDERFLO | TX_BUS_WR_ERR)) {
  603                 log(LOG_ERR, "%s: tx fifo underflow/overflow\n", device_xname(&sc->sc_dev));
  604         }
  605 
  606         bus_space_write_2(bst, bsh, BMPR_TX_LENGTH, len | TRANSMIT_START);
  607 
  608         bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, TX_MASK);
  609         /* XXX                          */
  610         sc->txb_sched++;
  611 
  612         /* We have space for 'n' transmit packets of size 'mtu. */
  613         if (sc->txb_sched > sc->txb_num_pkt) {
  614                 ifp->if_flags |= IFF_OACTIVE;
  615                 ifp->if_timer = 2;
  616         }
  617 }
  618 
  619 /*
  620  * Send packet - copy packet from mbuf to the fifo
  621  */
  622 u_short
  623 mb86950_put_fifo(sc, m)
  624         struct mb86950_softc *sc;
  625         struct mbuf *m;
  626 {
  627         bus_space_tag_t bst = sc->sc_bst;
  628         bus_space_handle_t bsh = sc->sc_bsh;
  629         u_short *data;
  630         u_char savebyte[2];
  631         int len, len1, wantbyte;
  632         u_short totlen;
  633 
  634         memset(savebyte, 0, sizeof(savebyte));  /* XXX gcc */
  635 
  636         totlen = wantbyte = 0;
  637 
  638         for (; m != NULL; m = m->m_next) {
  639                 data = mtod(m, u_short *);
  640                 len = m->m_len;
  641                 if (len > 0) {
  642                         totlen += len;
  643 
  644                         /* Finish the last word. */
  645                         if (wantbyte) {
  646                                 savebyte[1] = *((u_char *)data);
  647                                 bus_space_write_2(bst, bsh, BMPR_FIFO, *savebyte);
  648                                 data = (u_short *)((u_char *)data + 1);
  649                                 len--;
  650                                 wantbyte = 0;
  651                         }
  652                         /* Output contiguous words. */
  653                         if (len > 1) {
  654                                 len1 = len/2;
  655                                 bus_space_write_multi_stream_2(bst, bsh, BMPR_FIFO, data, len1);
  656                                 data += len1;
  657                                 len &= 1;
  658                         }
  659                         /* Save last byte, if necessary. */
  660                         if (len == 1) {
  661                                 savebyte[0] = *((u_char *)data);
  662                                 wantbyte = 1;
  663                         }
  664                 }
  665         }
  666 
  667         if (wantbyte) {
  668                 savebyte[1] = 0;
  669                 bus_space_write_2(bst, bsh, BMPR_FIFO, *savebyte);
  670         }
  671 
  672         if (totlen < (ETHER_MIN_LEN - ETHER_CRC_LEN)) {
  673 
  674                 /* Fill the rest of the packet with zeros. */
  675                 /* XXX Replace this mess with something else, eats CPU */
  676                 /* The zero fill and last byte ought to be combined somehow */
  677                 for(len = totlen + 1; len < (ETHER_MIN_LEN - ETHER_CRC_LEN); len += 2)
  678                         bus_space_write_2(bst, bsh, BMPR_FIFO, 0);
  679                 /* XXX                                       */
  680 
  681                 totlen = (ETHER_MIN_LEN - ETHER_CRC_LEN);
  682         }
  683 
  684         return (totlen);
  685 }
  686 
  687 /*
  688  * Handle interrupts.
  689  * Ethernet interface interrupt processor
  690  */
  691 int
  692 mb86950_intr(arg)
  693         void *arg;
  694 {
  695         struct mb86950_softc *sc = arg;
  696         bus_space_tag_t bst = sc->sc_bst;
  697         bus_space_handle_t bsh = sc->sc_bsh;
  698         struct ifnet *ifp = &sc->sc_ec.ec_if;
  699         u_int8_t tstat, rstat;
  700 
  701         /* Get interrupt status. */
  702         tstat = bus_space_read_1(bst, bsh, DLCR_TX_STAT);
  703         rstat = bus_space_read_1(bst, bsh, DLCR_RX_STAT);
  704 
  705         if (tstat == 0 && rstat == 0) return (0);
  706 
  707         /* Disable etherstar interrupts so that we won't miss anything. */
  708         bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, 0);
  709         bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, 0);
  710 
  711         /*
  712          * Handle transmitter interrupts. Handle these first because
  713          * the receiver will reset the board under some conditions.
  714          */
  715         if (tstat != 0) {
  716 
  717                 mb86950_tint(sc, tstat);
  718 
  719                 /* acknowledge transmit interrupt status. */
  720                 bus_space_write_1(bst, bsh, DLCR_TX_STAT, tstat);
  721 
  722         }
  723 
  724         /* Handle receiver interrupts. */
  725         if (rstat != 0) {
  726 
  727                 mb86950_rint(sc, rstat);
  728 
  729                 /* acknowledge receive interrupt status. */
  730                 bus_space_write_1(bst, bsh, DLCR_RX_STAT, rstat);
  731 
  732         }
  733 
  734         /* If tx still pending reset tx interrupt mask */
  735         if (sc->txb_sched > 0)
  736                 bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, TX_MASK);
  737 
  738         /*
  739          * If it looks like the transmitter can take more data,
  740          * attempt to start output on the interface. This is done
  741          * after handling the receiver interrupt to give the
  742          * receive operation priority.
  743          */
  744 
  745         if ((ifp->if_flags & IFF_OACTIVE) == 0)
  746                 mb86950_start(ifp);
  747 
  748         /* Set receive interrupts back */
  749         bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, RX_MASK);
  750 
  751         return(1);
  752 }
  753 
  754 /* Transmission interrupt handler */
  755 void
  756 mb86950_tint(sc, tstat)
  757         struct mb86950_softc *sc;
  758         u_int8_t tstat;
  759 {
  760         bus_space_tag_t bst = sc->sc_bst;
  761         bus_space_handle_t bsh = sc->sc_bsh;
  762         struct ifnet *ifp = &sc->sc_ec.ec_if;
  763         int col;
  764 
  765         if (tstat & (TX_UNDERFLO | TX_BUS_WR_ERR)) {
  766                 /* XXX What do we need to do here? reset ? */
  767                 ifp->if_oerrors++;
  768         }
  769 
  770         /* excessive collision */
  771         if (tstat & TX_16COL) {
  772                 ifp->if_collisions += 16;
  773                 /* 16 collisions means that the packet has been thrown away. */
  774                 if (sc->txb_sched > 0)
  775                         sc->txb_sched--;
  776         }
  777 
  778         /* transmission complete. */
  779         if (tstat & TX_DONE) {
  780                 /* successfully transmitted packets ++. */
  781                 ifp->if_opackets++;
  782                 if (sc->txb_sched > 0)
  783                         sc->txb_sched--;
  784 
  785                 /* Collision count valid only when TX_DONE is set */
  786                 if (tstat & TX_COL) {
  787                         col = (bus_space_read_1(bst, bsh, DLCR_TX_MODE) & COL_MASK) >> 4;
  788                         ifp->if_collisions = ifp->if_collisions + col;
  789                 }
  790         }
  791 
  792         if (sc->txb_sched == 0) {
  793                  /* Reset output active flag and stop timer. */
  794                  ifp->if_flags &= ~IFF_OACTIVE;
  795                  ifp->if_timer = 0;
  796         }
  797 }
  798 
  799 /* receiver interrupt. */
  800 void
  801 mb86950_rint(sc, rstat)
  802         struct mb86950_softc *sc;
  803         u_int8_t rstat;
  804 {
  805         bus_space_tag_t bst = sc->sc_bst;
  806         bus_space_handle_t bsh = sc->sc_bsh;
  807         struct ifnet *ifp = &sc->sc_ec.ec_if;
  808         u_int status, len;
  809         int i;
  810 
  811          /* Update statistics if this interrupt is caused by an error. */
  812          if (rstat & RX_ERR_MASK) {
  813 
  814                 /* tried to read past end of fifo, should be harmless
  815                  * count everything else
  816                  */
  817                 if ((rstat & RX_BUS_RD_ERR) == 0) {
  818                         ifp->if_ierrors++;
  819                 }
  820         }
  821 
  822         /*
  823          * mb86950 has a flag indicating "receive buffer empty."
  824          * We just loop checking the flag to pull out all received
  825          * packets.
  826          *
  827          * We limit the number of iterrations to avoid infinite loop.
  828          * It can be caused by a very slow CPU (some broken
  829          * peripheral may insert incredible number of wait cycles)
  830          * or, worse, by a broken mb86950 chip.
  831          */
  832         for (i = 0; i < sc->rxb_num_pkt; i++) {
  833                 /* Stop the iterration if 86950 indicates no packets. */
  834                 if (bus_space_read_1(bst, bsh, DLCR_RX_MODE) & RX_BUF_EMTY)
  835                         break;
  836 
  837                 /* receive packet status */
  838                 status = bus_space_read_2(bst, bsh, BMPR_FIFO);
  839 
  840                 /* bad packet? */
  841                 if ((status & GOOD_PKT) == 0) {
  842                         ifp->if_ierrors++;
  843                         mb86950_drain_fifo(sc);
  844                         continue;
  845                 }
  846 
  847                 /* Length valid ? */
  848                 len = bus_space_read_2(bst, bsh, BMPR_FIFO);
  849 
  850                 if (len > (ETHER_MAX_LEN - ETHER_CRC_LEN) || len < ETHER_HDR_LEN) {
  851                         ifp->if_ierrors++;
  852                         mb86950_drain_fifo(sc);
  853                         continue;
  854                 }
  855 
  856                 if (mb86950_get_fifo(sc, len) != 0) {
  857                         /* No mbufs? Drop packet. */
  858                         ifp->if_ierrors++;
  859                         mb86950_drain_fifo(sc);
  860                         return;
  861                 }
  862 
  863                 /* Successfully received a packet.  Update stat. */
  864                 ifp->if_ipackets++;
  865         }
  866 }
  867 
  868 /*
  869  * Receive packet.
  870  * Retrieve packet from receive buffer and send to the next level up via
  871  * ether_input(). If there is a BPF listener, give a copy to BPF, too.
  872  * Returns 0 if success, -1 if error (i.e., mbuf allocation failure).
  873  */
  874 int
  875 mb86950_get_fifo(sc, len)
  876         struct mb86950_softc *sc;
  877         u_int len;
  878 {
  879         bus_space_tag_t bst = sc->sc_bst;
  880         bus_space_handle_t bsh = sc->sc_bsh;
  881         struct ifnet *ifp = &sc->sc_ec.ec_if;
  882         struct mbuf *m;
  883 
  884         /* Allocate a header mbuf. */
  885         MGETHDR(m, M_DONTWAIT, MT_DATA);
  886         if (m == 0)
  887                 return (-1);
  888 
  889         /*
  890          * Round len to even value.
  891          */
  892         if (len & 1)
  893                 len++;
  894 
  895         m->m_pkthdr.rcvif = ifp;
  896         m->m_pkthdr.len = len;
  897 
  898         /* The following silliness is to make NFS happy. */
  899 #define EROUND  ((sizeof(struct ether_header) + 3) & ~3)
  900 #define EOFF    (EROUND - sizeof(struct ether_header))
  901 
  902         /*
  903          * Our strategy has one more problem.  There is a policy on
  904          * mbuf cluster allocation.  It says that we must have at
  905          * least MINCLSIZE (208 bytes) to allocate a cluster.  For a
  906          * packet of a size between (MHLEN - 2) to (MINCLSIZE - 2),
  907          * our code violates the rule...
  908          * On the other hand, the current code is short, simple,
  909          * and fast, however.  It does no harmful thing, just wastes
  910          * some memory.  Any comments?  FIXME.
  911          */
  912 
  913         /* Attach a cluster if this packet doesn't fit in a normal mbuf. */
  914         if (len > MHLEN - EOFF) {
  915                 MCLGET(m, M_DONTWAIT);
  916                 if ((m->m_flags & M_EXT) == 0) {
  917                         m_freem(m);
  918                         return (-1);
  919                 }
  920         }
  921 
  922         /*
  923          * The following assumes there is room for the ether header in the
  924          * header mbuf.
  925          */
  926         m->m_data += EOFF;
  927 
  928         /* Set the length of this packet. */
  929         m->m_len = len;
  930 
  931         /* Get a packet. */
  932         bus_space_read_multi_stream_2(bst, bsh, BMPR_FIFO, mtod(m, u_int16_t *), (len + 1) >> 1);
  933 
  934 #if NBPFILTER > 0
  935         /*
  936          * Check if there's a BPF listener on this interface.  If so, hand off
  937          * the raw packet to bpf.
  938          */
  939         if (ifp->if_bpf)
  940                 bpf_mtap(ifp->if_bpf, m);
  941 #endif
  942 
  943         (*ifp->if_input)(ifp, m);
  944         return (0);
  945 }
  946 
  947 /*
  948  * Enable power on the interface.
  949  */
  950 int
  951 mb86950_enable(sc)
  952         struct mb86950_softc *sc;
  953 {
  954 
  955         if ((sc->sc_stat & ESTAR_STAT_ENABLED) == 0 && sc->sc_enable != NULL) {
  956                 if ((*sc->sc_enable)(sc) != 0) {
  957                         aprint_error_dev(&sc->sc_dev, "device enable failed\n");
  958                         return (EIO);
  959                 }
  960         }
  961 
  962         sc->sc_stat |= ESTAR_STAT_ENABLED;
  963         return (0);
  964 }
  965 
  966 /*
  967  * Disable power on the interface.
  968  */
  969 void
  970 mb86950_disable(sc)
  971         struct mb86950_softc *sc;
  972 {
  973 
  974         if ((sc->sc_stat & ESTAR_STAT_ENABLED) != 0 && sc->sc_disable != NULL) {
  975                 (*sc->sc_disable)(sc);
  976                 sc->sc_stat &= ~ESTAR_STAT_ENABLED;
  977         }
  978 }
  979 
  980 /*
  981  * mbe_activate:
  982  *
  983  *      Handle device activation/deactivation requests.
  984  */
  985 int
  986 mb86950_activate(self, act)
  987         struct device *self;
  988         enum devact act;
  989 {
  990         struct mb86950_softc *sc = (struct mb86950_softc *)self;
  991         int rv, s;
  992 
  993         rv = 0;
  994         s = splnet();
  995         switch (act) {
  996         case DVACT_ACTIVATE:
  997                 rv = EOPNOTSUPP;
  998                 break;
  999 
 1000         case DVACT_DEACTIVATE:
 1001                 if_deactivate(&sc->sc_ec.ec_if);
 1002                 break;
 1003         }
 1004         splx(s);
 1005         return (rv);
 1006 }
 1007 
 1008 /*
 1009  * mb86950_detach:
 1010  *
 1011  *      Detach a mb86950 interface.
 1012  */
 1013 int
 1014 mb86950_detach(sc)
 1015         struct mb86950_softc *sc;
 1016 {
 1017         struct ifnet *ifp = &sc->sc_ec.ec_if;
 1018 
 1019         /* Succeed now if there's no work to do. */
 1020         if ((sc->sc_stat & ESTAR_STAT_ATTACHED) == 0)
 1021                 return (0);
 1022 
 1023         /* Delete all media. */
 1024         ifmedia_delete_instance(&sc->sc_media, IFM_INST_ANY);
 1025 
 1026 #if NRND > 0
 1027         /* Unhook the entropy source. */
 1028         rnd_detach_source(&sc->rnd_source);
 1029 #endif
 1030         ether_ifdetach(ifp);
 1031         if_detach(ifp);
 1032 
 1033         return (0);
 1034 }
 1035 
 1036 #if ESTAR_DEBUG >= 1
 1037 void
 1038 mb86950_dump(level, sc)
 1039         int level;
 1040         struct mb86950_softc *sc;
 1041 {
 1042         bus_space_tag_t bst = sc->sc_bst;
 1043         bus_space_handle_t bsh = sc->sc_bsh;
 1044 
 1045         log(level, "\tDLCR = %02x %02x %02x %02x %02x %02x %02x\n",
 1046             bus_space_read_1(bst, bsh, DLCR_TX_STAT),
 1047             bus_space_read_1(bst, bsh, DLCR_TX_INT_EN),
 1048             bus_space_read_1(bst, bsh, DLCR_RX_STAT),
 1049             bus_space_read_1(bst, bsh, DLCR_RX_INT_EN),
 1050             bus_space_read_1(bst, bsh, DLCR_TX_MODE),
 1051             bus_space_read_1(bst, bsh, DLCR_RX_MODE),
 1052             bus_space_read_1(bst, bsh, DLCR_CONFIG));
 1053 
 1054         /* XXX BMPR2, 4 write only ?
 1055         log(level, "\tBMPR = xxxx %04x %04x\n",
 1056                 bus_space_read_2(bst, bsh, BMPR_TX_LENGTH),
 1057                 bus_space_read_2(bst, bsh, BMPR_DMA));
 1058         */
 1059 }
 1060 #endif

Cache object: 3fba9a9ce48fd736f5c69fbc4623953a


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