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