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