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.35 2021/07/31 14:36:33 andvar 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.35 2021/07/31 14:36:33 andvar 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 
  124 #include <sys/param.h>
  125 #include <sys/systm.h>
  126 #include <sys/errno.h>
  127 #include <sys/ioctl.h>
  128 #include <sys/mbuf.h>
  129 #include <sys/socket.h>
  130 #include <sys/syslog.h>
  131 #include <sys/device.h>
  132 #include <sys/rndsource.h>
  133 
  134 #include <net/if.h>
  135 #include <net/if_dl.h>
  136 #include <net/if_types.h>
  137 #include <net/if_media.h>
  138 #include <net/if_ether.h>
  139 #include <net/bpf.h>
  140 
  141 #ifdef INET
  142 #include <netinet/in.h>
  143 #include <netinet/in_systm.h>
  144 #include <netinet/in_var.h>
  145 #include <netinet/ip.h>
  146 #include <netinet/if_inarp.h>
  147 #endif
  148 
  149 #include <sys/bus.h>
  150 
  151 #include <dev/ic/mb86950reg.h>
  152 #include <dev/ic/mb86950var.h>
  153 
  154 #ifndef __BUS_SPACE_HAS_STREAM_METHODS
  155 #define bus_space_write_stream_2        bus_space_write_2
  156 #define bus_space_write_multi_stream_2  bus_space_write_multi_2
  157 #define bus_space_read_multi_stream_2   bus_space_read_multi_2
  158 #endif /* __BUS_SPACE_HAS_STREAM_METHODS */
  159 
  160 /* Standard driver entry points.  These can be static. */
  161 int             mb86950_ioctl(struct ifnet *, u_long, void *);
  162 void    mb86950_init(struct mb86950_softc *);
  163 void    mb86950_start(struct ifnet *);
  164 void    mb86950_watchdog(struct ifnet *);
  165 void    mb86950_reset(struct mb86950_softc *);
  166 
  167 /* Local functions. */
  168 void    mb86950_stop(struct mb86950_softc *);
  169 void    mb86950_tint(struct mb86950_softc *, u_int8_t);
  170 void    mb86950_rint(struct mb86950_softc *, u_int8_t);
  171 int             mb86950_get_fifo(struct mb86950_softc *, u_int);
  172 ushort  mb86950_put_fifo(struct mb86950_softc *, struct mbuf *);
  173 void    mb86950_drain_fifo(struct mb86950_softc *);
  174 
  175 int             mb86950_mediachange(struct ifnet *);
  176 void    mb86950_mediastatus(struct ifnet *, struct ifmediareq *);
  177 
  178 
  179 #if ESTAR_DEBUG >= 1
  180 void    mb86950_dump(int, struct mb86950_softc *);
  181 #endif
  182 
  183 /********************************************************************/
  184 
  185 void
  186 mb86950_attach(struct mb86950_softc *sc, u_int8_t *myea)
  187 {
  188 
  189 #ifdef DIAGNOSTIC
  190         if (myea == NULL) {
  191                 printf("%s: ethernet address shouldn't be NULL\n",
  192                     device_xname(sc->sc_dev));
  193                 panic("NULL ethernet address");
  194         }
  195 #endif
  196 
  197         /* Initialize 86950. */
  198         mb86950_stop(sc);
  199 
  200         memcpy(sc->sc_enaddr, myea, sizeof(sc->sc_enaddr));
  201 
  202         sc->sc_stat |= ESTAR_STAT_ENABLED;
  203 }
  204 
  205 /*
  206  * Stop everything on the interface.
  207  *
  208  * All buffered packets, both transmitting and receiving,
  209  * if any, will be lost by stopping the interface.
  210  */
  211 void
  212 mb86950_stop(struct mb86950_softc *sc)
  213 {
  214         bus_space_tag_t bst = sc->sc_bst;
  215         bus_space_handle_t bsh = sc->sc_bsh;
  216 
  217         /* Stop interface hardware. */
  218         bus_space_write_1(bst, bsh, DLCR_CONFIG, DISABLE_DLC);
  219         delay(200);
  220 
  221         /* Disable interrupts. */
  222         bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, 0);
  223         bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, 0);
  224 
  225         /* Ack / Clear all interrupt status. */
  226         bus_space_write_1(bst, bsh, DLCR_TX_STAT, 0xff);
  227         bus_space_write_1(bst, bsh, DLCR_RX_STAT, 0xff);
  228 
  229         /* Clear DMA Bit */
  230         bus_space_write_2(bst, bsh, BMPR_DMA, 0);
  231 
  232         /* accept no packets */
  233         bus_space_write_1(bst, bsh, DLCR_TX_MODE, 0);
  234         bus_space_write_1(bst, bsh, DLCR_RX_MODE, 0);
  235 
  236         mb86950_drain_fifo(sc);
  237 }
  238 
  239 void
  240 mb86950_drain_fifo(struct mb86950_softc *sc)
  241 {
  242         bus_space_tag_t bst = sc->sc_bst;
  243         bus_space_handle_t bsh = sc->sc_bsh;
  244 
  245         /* Read data until bus read error (i.e. buffer empty). */
  246         /* XXX There ought to be a better way, eats CPU and bothers the chip */
  247         while (!(bus_space_read_1(bst, bsh, DLCR_RX_STAT) & RX_BUS_RD_ERR))
  248                 bus_space_read_2(bst, bsh, BMPR_FIFO);
  249         /* XXX */
  250 
  251         /* Clear Bus Rd Error */
  252         bus_space_write_1(bst, bsh, DLCR_RX_STAT, RX_BUS_RD_ERR);
  253 }
  254 
  255 /*
  256  * Install interface into kernel networking data structures
  257  */
  258 void
  259 mb86950_config(struct mb86950_softc *sc, int *media, int nmedia, int defmedia)
  260 {
  261         struct ifnet *ifp = &sc->sc_ec.ec_if;
  262         bus_space_tag_t bst = sc->sc_bst;
  263         bus_space_handle_t bsh = sc->sc_bsh;
  264 
  265         /* Initialize ifnet structure. */
  266         strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
  267         ifp->if_softc = sc;
  268         ifp->if_start = mb86950_start;
  269         ifp->if_ioctl = mb86950_ioctl;
  270         ifp->if_watchdog = mb86950_watchdog;
  271         ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX;
  272 
  273         IFQ_SET_READY(&ifp->if_snd);
  274 
  275         /* Initialize media goo. */
  276         /* XXX The Tiara LANCard uses board jumpers to change media.
  277          *       This code may have to be changed for other cards.
  278          */
  279         sc->sc_ec.ec_ifmedia = &sc->sc_media;
  280         ifmedia_init(&sc->sc_media, 0, mb86950_mediachange,
  281             mb86950_mediastatus);
  282         ifmedia_add(&sc->sc_media, IFM_ETHER | IFM_MANUAL, 0, NULL);
  283         ifmedia_set(&sc->sc_media, IFM_ETHER | IFM_MANUAL);
  284 
  285         /* Attach the interface. */
  286         if_attach(ifp);
  287         if_deferred_start_init(ifp, NULL);
  288 
  289         /* Feed the chip the station address. */
  290         bus_space_write_region_1(bst, bsh, DLCR_NODE_ID, sc->sc_enaddr,
  291             ETHER_ADDR_LEN);
  292 
  293         ether_ifattach(ifp, sc->sc_enaddr);
  294 
  295         rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
  296             RND_TYPE_NET, RND_FLAG_DEFAULT);
  297 
  298 /* XXX No! This doesn't work - DLCR6 of the mb86950 is different
  299 
  300         bus_space_write_1(bst, bsh, DLCR_CONFIG, 0x0f);
  301         buf_config = bus_space_read_1(bst, bsh, DLCR_CONFIG);
  302 
  303         sc->txb_count = ((buf_config & 0x0c) ? 2 : 1);
  304         sc->txb_size = 1024 * (2 << ((buf_config & 0x0c) ? (((buf_config & 0x0c) >> 2) - 1) : 0));
  305         sc->txb_free = (sc->txb_size * sc->txb_count) / 1500;
  306 
  307         sc->rxb_size = ((8 << (buf_config & 3)) * 1024) - (sc->txb_size * sc->txb_count);
  308         sc->rxb_max = sc->rxb_size / 64;
  309 
  310         printf("mb86950: Buffer Size %dKB with %d transmit buffer(s) %dKB each.\n",
  311                 (8 << (buf_config & 3)), sc->txb_count, (sc->txb_size / 1024));
  312         printf("         Transmit Buffer Space for %d maximum sized packet(s).\n",sc->txb_free);
  313         printf("         System Bus Width %d bits, Buffer Memory %d bits.\n",
  314                 ((buf_config & 0x20) ? 8 : 16),
  315                 ((buf_config & 0x10) ? 8 : 16));
  316 
  317 */
  318 
  319         /* Set reasonable values for number of packet flow control if not
  320          * set elsewhere */
  321         if (sc->txb_num_pkt == 0) sc->txb_num_pkt = 1;
  322         if (sc->rxb_num_pkt == 0) sc->rxb_num_pkt = 100;
  323 
  324         /* Print additional info when attached. */
  325         printf("%s: Ethernet address %s\n", device_xname(sc->sc_dev),
  326             ether_sprintf(sc->sc_enaddr));
  327 
  328         /* The attach is successful. */
  329         sc->sc_stat |= ESTAR_STAT_ATTACHED;
  330 }
  331 
  332 /*
  333  * Media change callback.
  334  */
  335 int
  336 mb86950_mediachange(struct ifnet *ifp)
  337 {
  338 
  339         struct mb86950_softc *sc = ifp->if_softc;
  340 
  341         if (sc->sc_mediachange)
  342                 return (*sc->sc_mediachange)(sc);
  343 
  344         return 0;
  345 }
  346 
  347 /*
  348  * Media status callback.
  349  */
  350 void
  351 mb86950_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
  352 {
  353         struct mb86950_softc *sc = ifp->if_softc;
  354 
  355         if ((sc->sc_stat & ESTAR_STAT_ENABLED) == 0) {
  356                 ifmr->ifm_active = IFM_ETHER | IFM_NONE;
  357                 ifmr->ifm_status = 0;
  358                 return;
  359         }
  360 
  361         if (sc->sc_mediastatus)
  362                 (*sc->sc_mediastatus)(sc, ifmr);
  363 
  364 }
  365 
  366 /*
  367  * Reset interface.
  368  */
  369 void
  370 mb86950_reset(struct mb86950_softc *sc)
  371 {
  372         int s;
  373 
  374         s = splnet();
  375         log(LOG_ERR, "%s: device reset\n", device_xname(sc->sc_dev));
  376         mb86950_stop(sc);
  377         mb86950_init(sc);
  378         splx(s);
  379 }
  380 
  381 /*
  382  * Device timeout/watchdog routine. Entered if the device neglects to
  383  * generate an interrupt after a transmit has been started on it.
  384  */
  385 void
  386 mb86950_watchdog(struct ifnet *ifp)
  387 {
  388         struct mb86950_softc *sc = ifp->if_softc;
  389         bus_space_tag_t bst = sc->sc_bst;
  390         bus_space_handle_t bsh = sc->sc_bsh;
  391         u_int8_t tstat;
  392 
  393         /* Verbose watchdog messages for debugging timeouts */
  394         if ((tstat = bus_space_read_1(bst, bsh, DLCR_TX_STAT)) != 0) {
  395                 if (tstat & TX_CR_LOST) {
  396                         if ((tstat & (TX_COL | TX_16COL)) == 0) {
  397                                  log(LOG_ERR, "%s: carrier lost\n",
  398                                     device_xname(sc->sc_dev));
  399                         } else {
  400                                 log(LOG_ERR, "%s: excessive collisions\n",
  401                                     device_xname(sc->sc_dev));
  402                         }
  403                 }
  404                 else if ((tstat & (TX_UNDERFLO | TX_BUS_WR_ERR)) != 0) {
  405                         log(LOG_ERR, "%s: tx fifo underflow/overflow\n",
  406                             device_xname(sc->sc_dev));
  407                 } else {
  408                         log(LOG_ERR, "%s: transmit error\n",
  409                             device_xname(sc->sc_dev));
  410                 }
  411         } else
  412                 log(LOG_ERR, "%s: device timeout\n", device_xname(sc->sc_dev));
  413 
  414         /*
  415          * Don't know how many packets are lost by this accident.
  416          *  ... So just errors = errors + 1
  417          */
  418         if_statinc(ifp, if_oerrors);
  419 
  420         mb86950_reset(sc);
  421 }
  422 
  423 /*
  424  ******************** IOCTL
  425  * Process an ioctl request.
  426  */
  427 int
  428 mb86950_ioctl(struct ifnet *ifp, unsigned long cmd, void *data)
  429 {
  430         struct mb86950_softc *sc = ifp->if_softc;
  431         struct ifaddr *ifa = (struct ifaddr *)data;
  432 
  433         int s, error = 0;
  434 
  435         s = splnet();
  436 
  437         switch (cmd) {
  438         case SIOCINITIFADDR:
  439                 /* XXX deprecated ? What should I use instead? */
  440                 if ((error = mb86950_enable(sc)) != 0)
  441                         break;
  442 
  443                 ifp->if_flags |= IFF_UP;
  444 
  445                 mb86950_init(sc);
  446                 switch (ifa->ifa_addr->sa_family) {
  447 
  448 #ifdef INET
  449                 case AF_INET:
  450                         arp_ifinit(ifp, ifa);
  451                         break;
  452 #endif
  453 
  454 
  455                 default:
  456                         break;
  457                 }
  458                 break;
  459 
  460         case SIOCSIFFLAGS:
  461                 if ((error = ifioctl_common(ifp, cmd, data)) != 0)
  462                         break;
  463                 /* XXX re-use ether_ioctl() */
  464                 switch (ifp->if_flags & (IFF_UP|IFF_RUNNING)) {
  465                 case IFF_RUNNING:
  466                         /*
  467                          * If interface is marked down and it is running, then
  468                          * stop it.
  469                          */
  470                         mb86950_stop(sc);
  471                         ifp->if_flags &= ~IFF_RUNNING;
  472                         mb86950_disable(sc);
  473                         break;
  474                 case IFF_UP:
  475                         /*
  476                          * If interface is marked up and it is stopped, then
  477                          * start it.
  478                          */
  479                         if ((error = mb86950_enable(sc)) != 0)
  480                                 break;
  481                         mb86950_init(sc);
  482                         break;
  483                 case IFF_UP|IFF_RUNNING:
  484                         /*
  485                          * Reset the interface to pick up changes in any other
  486                          * flags that affect hardware registers.
  487                          */
  488 #if 0
  489                         /* Setmode not supported */
  490                         mb86950_setmode(sc);
  491 #endif
  492                         break;
  493                 case 0:
  494                         break;
  495                 }
  496 
  497 #if ESTAR_DEBUG >= 1
  498                 /* "ifconfig fe0 debug" to print register dump. */
  499                 if (ifp->if_flags & IFF_DEBUG) {
  500                         log(LOG_INFO, "%s: SIOCSIFFLAGS(DEBUG)\n",
  501                             device_xname(sc->sc_dev));
  502                         mb86950_dump(LOG_DEBUG, sc);
  503                 }
  504 #endif
  505                 break;
  506 
  507         default:
  508                 error = ether_ioctl(ifp, cmd, data);
  509                 break;
  510         }
  511 
  512         splx(s);
  513         return error;
  514 }
  515 
  516 /*
  517  * Initialize device.
  518  */
  519 void
  520 mb86950_init(struct mb86950_softc *sc)
  521 {
  522         bus_space_tag_t bst = sc->sc_bst;
  523         bus_space_handle_t bsh = sc->sc_bsh;
  524         struct ifnet *ifp = &sc->sc_ec.ec_if;
  525 
  526         /* Reset transmitter flags. */
  527         ifp->if_flags &= ~IFF_OACTIVE;
  528         ifp->if_timer = 0;
  529         sc->txb_sched = 0;
  530 
  531         bus_space_write_1(bst, bsh, DLCR_TX_MODE, LBC);
  532         bus_space_write_1(bst, bsh, DLCR_RX_MODE, NORMAL_MODE);
  533 
  534         /* Enable interrupts. */
  535         bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, TX_MASK);
  536         bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, RX_MASK);
  537 
  538         /* Enable transmitter and receiver. */
  539         bus_space_write_1(bst, bsh, DLCR_CONFIG, ENABLE_DLC);
  540         delay(200);
  541 
  542         /* Set 'running' flag. */
  543         ifp->if_flags |= IFF_RUNNING;
  544 
  545         /* ...and attempt to start output. */
  546         mb86950_start(ifp);
  547 }
  548 
  549 void
  550 mb86950_start(struct ifnet *ifp)
  551 {
  552         struct mb86950_softc *sc = ifp->if_softc;
  553         bus_space_tag_t bst = sc->sc_bst;
  554         bus_space_handle_t bsh = sc->sc_bsh;
  555         struct mbuf *m;
  556         int len;
  557 
  558         if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
  559                 return;
  560 
  561         IF_DEQUEUE(&ifp->if_snd, m);
  562         if (m == 0)
  563                 return;
  564 
  565         /* Tap off here if there is a BPF listener. */
  566         bpf_mtap(ifp, m, BPF_D_OUT);
  567 
  568         /* Send the packet to the mb86950 */
  569         len = mb86950_put_fifo(sc,m);
  570         m_freem(m);
  571 
  572         /* XXX bus_space_barrier here ? */
  573         if (bus_space_read_1(bst, bsh, DLCR_TX_STAT)
  574             & (TX_UNDERFLO | TX_BUS_WR_ERR)) {
  575                 log(LOG_ERR, "%s: tx fifo underflow/overflow\n",
  576                     device_xname(sc->sc_dev));
  577         }
  578 
  579         bus_space_write_2(bst, bsh, BMPR_TX_LENGTH, len | TRANSMIT_START);
  580 
  581         bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, TX_MASK);
  582         /* XXX                          */
  583         sc->txb_sched++;
  584 
  585         /* We have space for 'n' transmit packets of size 'mtu. */
  586         if (sc->txb_sched > sc->txb_num_pkt) {
  587                 ifp->if_flags |= IFF_OACTIVE;
  588                 ifp->if_timer = 2;
  589         }
  590 }
  591 
  592 /*
  593  * Send packet - copy packet from mbuf to the fifo
  594  */
  595 u_short
  596 mb86950_put_fifo(struct mb86950_softc *sc, struct mbuf *m)
  597 {
  598         bus_space_tag_t bst = sc->sc_bst;
  599         bus_space_handle_t bsh = sc->sc_bsh;
  600         u_short *data;
  601         u_char savebyte[2];
  602         int len, len1, wantbyte;
  603         u_short totlen;
  604 
  605         memset(savebyte, 0, sizeof(savebyte));  /* XXX gcc */
  606 
  607         totlen = wantbyte = 0;
  608 
  609         for (; m != NULL; m = m->m_next) {
  610                 data = mtod(m, u_short *);
  611                 len = m->m_len;
  612                 if (len > 0) {
  613                         totlen += len;
  614 
  615                         /* Finish the last word. */
  616                         if (wantbyte) {
  617                                 savebyte[1] = *((u_char *)data);
  618                                 bus_space_write_2(bst, bsh, BMPR_FIFO,
  619                                     *savebyte);
  620                                 data = (u_short *)((u_char *)data + 1);
  621                                 len--;
  622                                 wantbyte = 0;
  623                         }
  624                         /* Output contiguous words. */
  625                         if (len > 1) {
  626                                 len1 = len/2;
  627                                 bus_space_write_multi_stream_2(bst, bsh,
  628                                     BMPR_FIFO, data, len1);
  629                                 data += len1;
  630                                 len &= 1;
  631                         }
  632                         /* Save last byte, if necessary. */
  633                         if (len == 1) {
  634                                 savebyte[0] = *((u_char *)data);
  635                                 wantbyte = 1;
  636                         }
  637                 }
  638         }
  639 
  640         if (wantbyte) {
  641                 savebyte[1] = 0;
  642                 bus_space_write_2(bst, bsh, BMPR_FIFO, *savebyte);
  643         }
  644 
  645         if (totlen < (ETHER_MIN_LEN - ETHER_CRC_LEN)) {
  646 
  647                 /* Fill the rest of the packet with zeros. */
  648                 /* XXX Replace this mess with something else, eats CPU */
  649                 /* The zero fill and last byte ought to be combined somehow */
  650                 for (len = totlen + 1; len < (ETHER_MIN_LEN - ETHER_CRC_LEN);
  651                      len += 2)
  652                         bus_space_write_2(bst, bsh, BMPR_FIFO, 0);
  653                 /* XXX                                       */
  654 
  655                 totlen = (ETHER_MIN_LEN - ETHER_CRC_LEN);
  656         }
  657 
  658         return totlen;
  659 }
  660 
  661 /*
  662  * Handle interrupts.
  663  * Ethernet interface interrupt processor
  664  */
  665 int
  666 mb86950_intr(void *arg)
  667 {
  668         struct mb86950_softc *sc = arg;
  669         bus_space_tag_t bst = sc->sc_bst;
  670         bus_space_handle_t bsh = sc->sc_bsh;
  671         struct ifnet *ifp = &sc->sc_ec.ec_if;
  672         u_int8_t tstat, rstat;
  673 
  674         /* Get interrupt status. */
  675         tstat = bus_space_read_1(bst, bsh, DLCR_TX_STAT);
  676         rstat = bus_space_read_1(bst, bsh, DLCR_RX_STAT);
  677 
  678         if (tstat == 0 && rstat == 0) return 0;
  679 
  680         /* Disable etherstar interrupts so that we won't miss anything. */
  681         bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, 0);
  682         bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, 0);
  683 
  684         /*
  685          * Handle transmitter interrupts. Handle these first because
  686          * the receiver will reset the board under some conditions.
  687          */
  688         if (tstat != 0) {
  689 
  690                 mb86950_tint(sc, tstat);
  691 
  692                 /* acknowledge transmit interrupt status. */
  693                 bus_space_write_1(bst, bsh, DLCR_TX_STAT, tstat);
  694 
  695         }
  696 
  697         /* Handle receiver interrupts. */
  698         if (rstat != 0) {
  699 
  700                 mb86950_rint(sc, rstat);
  701 
  702                 /* acknowledge receive interrupt status. */
  703                 bus_space_write_1(bst, bsh, DLCR_RX_STAT, rstat);
  704 
  705         }
  706 
  707         /* If tx still pending reset tx interrupt mask */
  708         if (sc->txb_sched > 0)
  709                 bus_space_write_1(bst, bsh, DLCR_TX_INT_EN, TX_MASK);
  710 
  711         /*
  712          * If it looks like the transmitter can take more data,
  713          * attempt to start output on the interface. This is done
  714          * after handling the receiver interrupt to give the
  715          * receive operation priority.
  716          */
  717 
  718         if ((ifp->if_flags & IFF_OACTIVE) == 0)
  719                 if_schedule_deferred_start(ifp);
  720 
  721         /* Set receive interrupts back */
  722         bus_space_write_1(bst, bsh, DLCR_RX_INT_EN, RX_MASK);
  723 
  724         return 1;
  725 }
  726 
  727 /* Transmission interrupt handler */
  728 void
  729 mb86950_tint(struct mb86950_softc *sc, u_int8_t tstat)
  730 {
  731         bus_space_tag_t bst = sc->sc_bst;
  732         bus_space_handle_t bsh = sc->sc_bsh;
  733         struct ifnet *ifp = &sc->sc_ec.ec_if;
  734         int col;
  735 
  736         if (tstat & (TX_UNDERFLO | TX_BUS_WR_ERR)) {
  737                 /* XXX What do we need to do here? reset ? */
  738                 if_statinc(ifp, if_oerrors);
  739         }
  740 
  741         /* Excessive collision */
  742         if (tstat & TX_16COL) {
  743                 if_statadd(ifp, if_collisions, 16);
  744                 /* 16 collisions means that the packet has been thrown away. */
  745                 if (sc->txb_sched > 0)
  746                         sc->txb_sched--;
  747         }
  748 
  749         /* Transmission complete. */
  750         if (tstat & TX_DONE) {
  751                 /* Successfully transmitted packets ++. */
  752                 if_statinc(ifp, if_opackets);
  753                 if (sc->txb_sched > 0)
  754                         sc->txb_sched--;
  755 
  756                 /* Collision count valid only when TX_DONE is set */
  757                 if (tstat & TX_COL) {
  758                         col = (bus_space_read_1(bst, bsh, DLCR_TX_MODE)
  759                             & COL_MASK) >> 4;
  760                         if_statadd(ifp, if_collisions, col);
  761                 }
  762         }
  763 
  764         if (sc->txb_sched == 0) {
  765                  /* Reset output active flag and stop timer. */
  766                  ifp->if_flags &= ~IFF_OACTIVE;
  767                  ifp->if_timer = 0;
  768         }
  769 }
  770 
  771 /* Receiver interrupt. */
  772 void
  773 mb86950_rint(struct mb86950_softc *sc, u_int8_t rstat)
  774 {
  775         bus_space_tag_t bst = sc->sc_bst;
  776         bus_space_handle_t bsh = sc->sc_bsh;
  777         struct ifnet *ifp = &sc->sc_ec.ec_if;
  778         u_int status, len;
  779         int i;
  780 
  781          /* Update statistics if this interrupt is caused by an error. */
  782          if (rstat & RX_ERR_MASK) {
  783 
  784                 /*
  785                  * Tried to read past end of fifo, should be harmless
  786                  * count everything else
  787                  */
  788                 if ((rstat & RX_BUS_RD_ERR) == 0) {
  789                         if_statinc(ifp, if_ierrors);
  790                 }
  791         }
  792 
  793         /*
  794          * mb86950 has a flag indicating "receive buffer empty."
  795          * We just loop checking the flag to pull out all received
  796          * packets.
  797          *
  798          * We limit the number of iterations to avoid infinite loop.
  799          * It can be caused by a very slow CPU (some broken
  800          * peripheral may insert incredible number of wait cycles)
  801          * or, worse, by a broken mb86950 chip.
  802          */
  803         for (i = 0; i < sc->rxb_num_pkt; i++) {
  804                 /* Stop the iteration if 86950 indicates no packets. */
  805                 if (bus_space_read_1(bst, bsh, DLCR_RX_MODE) & RX_BUF_EMTY)
  806                         break;
  807 
  808                 /* Receive packet status */
  809                 status = bus_space_read_2(bst, bsh, BMPR_FIFO);
  810 
  811                 /* Bad packet? */
  812                 if ((status & GOOD_PKT) == 0) {
  813                         if_statinc(ifp, if_ierrors);
  814                         mb86950_drain_fifo(sc);
  815                         continue;
  816                 }
  817 
  818                 /* Length valid ? */
  819                 len = bus_space_read_2(bst, bsh, BMPR_FIFO);
  820 
  821                 if (len > (ETHER_MAX_LEN - ETHER_CRC_LEN)
  822                     || len < ETHER_HDR_LEN) {
  823                         if_statinc(ifp, if_ierrors);
  824                         mb86950_drain_fifo(sc);
  825                         continue;
  826                 }
  827 
  828                 if (mb86950_get_fifo(sc, len) != 0) {
  829                         /* No mbufs? Drop packet. */
  830                         if_statinc(ifp, if_ierrors);
  831                         mb86950_drain_fifo(sc);
  832                         return;
  833                 }
  834         }
  835 }
  836 
  837 /*
  838  * Receive packet.
  839  * Retrieve packet from receive buffer and send to the next level up via
  840  * ether_input().
  841  * Returns 0 if success, -1 if error (i.e., mbuf allocation failure).
  842  */
  843 int
  844 mb86950_get_fifo(struct mb86950_softc *sc, u_int len)
  845 {
  846         bus_space_tag_t bst = sc->sc_bst;
  847         bus_space_handle_t bsh = sc->sc_bsh;
  848         struct ifnet *ifp = &sc->sc_ec.ec_if;
  849         struct mbuf *m;
  850 
  851         /* Allocate a header mbuf. */
  852         MGETHDR(m, M_DONTWAIT, MT_DATA);
  853         if (m == 0)
  854                 return -1;
  855 
  856         /* Round len to even value. */
  857         if (len & 1)
  858                 len++;
  859 
  860         m_set_rcvif(m, ifp);
  861         m->m_pkthdr.len = len;
  862 
  863         /* The following silliness is to make NFS happy. */
  864 #define EROUND  ((sizeof(struct ether_header) + 3) & ~3)
  865 #define EOFF    (EROUND - sizeof(struct ether_header))
  866 
  867         /*
  868          * Our strategy has one more problem.  There is a policy on
  869          * mbuf cluster allocation.  It says that we must have at
  870          * least MINCLSIZE (208 bytes) to allocate a cluster.  For a
  871          * packet of a size between (MHLEN - 2) to (MINCLSIZE - 2),
  872          * our code violates the rule...
  873          * On the other hand, the current code is short, simple,
  874          * and fast, however.  It does no harmful thing, just wastes
  875          * some memory.  Any comments?  FIXME.
  876          */
  877 
  878         /* Attach a cluster if this packet doesn't fit in a normal mbuf. */
  879         if (len > MHLEN - EOFF) {
  880                 MCLGET(m, M_DONTWAIT);
  881                 if ((m->m_flags & M_EXT) == 0) {
  882                         m_freem(m);
  883                         return -1;
  884                 }
  885         }
  886 
  887         /*
  888          * The following assumes there is room for the ether header in the
  889          * header mbuf.
  890          */
  891         m->m_data += EOFF;
  892 
  893         /* Set the length of this packet. */
  894         m->m_len = len;
  895 
  896         /* Get a packet. */
  897         bus_space_read_multi_stream_2(bst, bsh, BMPR_FIFO,
  898             mtod(m, u_int16_t *), (len + 1) >> 1);
  899 
  900         if_percpuq_enqueue(ifp->if_percpuq, m);
  901         return 0;
  902 }
  903 
  904 /*
  905  * Enable power on the interface.
  906  */
  907 int
  908 mb86950_enable(struct mb86950_softc *sc)
  909 {
  910 
  911         if ((sc->sc_stat & ESTAR_STAT_ENABLED) == 0 && sc->sc_enable != NULL) {
  912                 if ((*sc->sc_enable)(sc) != 0) {
  913                         aprint_error_dev(sc->sc_dev, "device enable failed\n");
  914                         return EIO;
  915                 }
  916         }
  917 
  918         sc->sc_stat |= ESTAR_STAT_ENABLED;
  919         return 0;
  920 }
  921 
  922 /*
  923  * Disable power on the interface.
  924  */
  925 void
  926 mb86950_disable(struct mb86950_softc *sc)
  927 {
  928 
  929         if ((sc->sc_stat & ESTAR_STAT_ENABLED) != 0 && sc->sc_disable != NULL) {
  930                 (*sc->sc_disable)(sc);
  931                 sc->sc_stat &= ~ESTAR_STAT_ENABLED;
  932         }
  933 }
  934 
  935 /*
  936  * mbe_activate:
  937  *
  938  *      Handle device activation/deactivation requests.
  939  */
  940 int
  941 mb86950_activate(device_t self, enum devact act)
  942 {
  943         struct mb86950_softc *sc = device_private(self);
  944 
  945         switch (act) {
  946         case DVACT_DEACTIVATE:
  947                 if_deactivate(&sc->sc_ec.ec_if);
  948                 return 0;
  949         default:
  950                 return EOPNOTSUPP;
  951         }
  952 }
  953 
  954 /*
  955  * mb86950_detach:
  956  *
  957  *      Detach a mb86950 interface.
  958  */
  959 int
  960 mb86950_detach(struct mb86950_softc *sc)
  961 {
  962         struct ifnet *ifp = &sc->sc_ec.ec_if;
  963 
  964         /* Succeed now if there's no work to do. */
  965         if ((sc->sc_stat & ESTAR_STAT_ATTACHED) == 0)
  966                 return 0;
  967 
  968         /* Unhook the entropy source. */
  969         rnd_detach_source(&sc->rnd_source);
  970 
  971         ether_ifdetach(ifp);
  972         if_detach(ifp);
  973 
  974         /* Delete all media. */
  975         ifmedia_fini(&sc->sc_media);
  976 
  977         return 0;
  978 }
  979 
  980 #if ESTAR_DEBUG >= 1
  981 void
  982 mb86950_dump(int level, struct mb86950_softc *sc)
  983 {
  984         bus_space_tag_t bst = sc->sc_bst;
  985         bus_space_handle_t bsh = sc->sc_bsh;
  986 
  987         log(level, "\tDLCR = %02x %02x %02x %02x %02x %02x %02x\n",
  988             bus_space_read_1(bst, bsh, DLCR_TX_STAT),
  989             bus_space_read_1(bst, bsh, DLCR_TX_INT_EN),
  990             bus_space_read_1(bst, bsh, DLCR_RX_STAT),
  991             bus_space_read_1(bst, bsh, DLCR_RX_INT_EN),
  992             bus_space_read_1(bst, bsh, DLCR_TX_MODE),
  993             bus_space_read_1(bst, bsh, DLCR_RX_MODE),
  994             bus_space_read_1(bst, bsh, DLCR_CONFIG));
  995 
  996         /* XXX BMPR2, 4 write only ?
  997         log(level, "\tBMPR = xxxx %04x %04x\n",
  998                 bus_space_read_2(bst, bsh, BMPR_TX_LENGTH),
  999                 bus_space_read_2(bst, bsh, BMPR_DMA));
 1000         */
 1001 }
 1002 #endif

Cache object: 649957207369ad0679c3f62bc4aaf66f


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