Home | History | Annotate | Line # | Download | only in ic
dwc_gmac.c revision 1.43.2.2
      1  1.43.2.2  jdolecek /* $NetBSD: dwc_gmac.c,v 1.43.2.2 2017/12/03 11:37:03 jdolecek Exp $ */
      2  1.43.2.2  jdolecek 
      3  1.43.2.2  jdolecek /*-
      4  1.43.2.2  jdolecek  * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc.
      5  1.43.2.2  jdolecek  * All rights reserved.
      6  1.43.2.2  jdolecek  *
      7  1.43.2.2  jdolecek  * This code is derived from software contributed to The NetBSD Foundation
      8  1.43.2.2  jdolecek  * by Matt Thomas of 3am Software Foundry and Martin Husemann.
      9  1.43.2.2  jdolecek  *
     10  1.43.2.2  jdolecek  * Redistribution and use in source and binary forms, with or without
     11  1.43.2.2  jdolecek  * modification, are permitted provided that the following conditions
     12  1.43.2.2  jdolecek  * are met:
     13  1.43.2.2  jdolecek  * 1. Redistributions of source code must retain the above copyright
     14  1.43.2.2  jdolecek  *    notice, this list of conditions and the following disclaimer.
     15  1.43.2.2  jdolecek  * 2. Redistributions in binary form must reproduce the above copyright
     16  1.43.2.2  jdolecek  *    notice, this list of conditions and the following disclaimer in the
     17  1.43.2.2  jdolecek  *    documentation and/or other materials provided with the distribution.
     18  1.43.2.2  jdolecek  *
     19  1.43.2.2  jdolecek  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
     20  1.43.2.2  jdolecek  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
     21  1.43.2.2  jdolecek  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
     22  1.43.2.2  jdolecek  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
     23  1.43.2.2  jdolecek  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
     24  1.43.2.2  jdolecek  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
     25  1.43.2.2  jdolecek  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
     26  1.43.2.2  jdolecek  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
     27  1.43.2.2  jdolecek  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
     28  1.43.2.2  jdolecek  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
     29  1.43.2.2  jdolecek  * POSSIBILITY OF SUCH DAMAGE.
     30  1.43.2.2  jdolecek  */
     31  1.43.2.2  jdolecek 
     32  1.43.2.2  jdolecek /*
     33  1.43.2.2  jdolecek  * This driver supports the Synopsis Designware GMAC core, as found
     34  1.43.2.2  jdolecek  * on Allwinner A20 cores and others.
     35  1.43.2.2  jdolecek  *
     36  1.43.2.2  jdolecek  * Real documentation seems to not be available, the marketing product
     37  1.43.2.2  jdolecek  * documents could be found here:
     38  1.43.2.2  jdolecek  *
     39  1.43.2.2  jdolecek  *  http://www.synopsys.com/dw/ipdir.php?ds=dwc_ether_mac10_100_1000_unive
     40  1.43.2.2  jdolecek  */
     41  1.43.2.2  jdolecek 
     42  1.43.2.2  jdolecek #include <sys/cdefs.h>
     43  1.43.2.2  jdolecek 
     44  1.43.2.2  jdolecek __KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.43.2.2 2017/12/03 11:37:03 jdolecek Exp $");
     45  1.43.2.2  jdolecek 
     46  1.43.2.2  jdolecek /* #define	DWC_GMAC_DEBUG	1 */
     47  1.43.2.2  jdolecek 
     48  1.43.2.2  jdolecek #ifdef _KERNEL_OPT
     49  1.43.2.2  jdolecek #include "opt_inet.h"
     50  1.43.2.2  jdolecek #include "opt_net_mpsafe.h"
     51  1.43.2.2  jdolecek #endif
     52  1.43.2.2  jdolecek 
     53  1.43.2.2  jdolecek #include <sys/param.h>
     54  1.43.2.2  jdolecek #include <sys/bus.h>
     55  1.43.2.2  jdolecek #include <sys/device.h>
     56  1.43.2.2  jdolecek #include <sys/intr.h>
     57  1.43.2.2  jdolecek #include <sys/systm.h>
     58  1.43.2.2  jdolecek #include <sys/sockio.h>
     59  1.43.2.2  jdolecek #include <sys/cprng.h>
     60  1.43.2.2  jdolecek 
     61  1.43.2.2  jdolecek #include <net/if.h>
     62  1.43.2.2  jdolecek #include <net/if_ether.h>
     63  1.43.2.2  jdolecek #include <net/if_media.h>
     64  1.43.2.2  jdolecek #include <net/bpf.h>
     65  1.43.2.2  jdolecek #ifdef INET
     66  1.43.2.2  jdolecek #include <netinet/if_inarp.h>
     67  1.43.2.2  jdolecek #endif
     68  1.43.2.2  jdolecek 
     69  1.43.2.2  jdolecek #include <dev/mii/miivar.h>
     70  1.43.2.2  jdolecek 
     71  1.43.2.2  jdolecek #include <dev/ic/dwc_gmac_reg.h>
     72  1.43.2.2  jdolecek #include <dev/ic/dwc_gmac_var.h>
     73  1.43.2.2  jdolecek 
     74  1.43.2.2  jdolecek static int dwc_gmac_miibus_read_reg(device_t, int, int);
     75  1.43.2.2  jdolecek static void dwc_gmac_miibus_write_reg(device_t, int, int, int);
     76  1.43.2.2  jdolecek static void dwc_gmac_miibus_statchg(struct ifnet *);
     77  1.43.2.2  jdolecek 
     78  1.43.2.2  jdolecek static int dwc_gmac_reset(struct dwc_gmac_softc *sc);
     79  1.43.2.2  jdolecek static void dwc_gmac_write_hwaddr(struct dwc_gmac_softc *sc,
     80  1.43.2.2  jdolecek 			 uint8_t enaddr[ETHER_ADDR_LEN]);
     81  1.43.2.2  jdolecek static int dwc_gmac_alloc_dma_rings(struct dwc_gmac_softc *sc);
     82  1.43.2.2  jdolecek static void dwc_gmac_free_dma_rings(struct dwc_gmac_softc *sc);
     83  1.43.2.2  jdolecek static int dwc_gmac_alloc_rx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_rx_ring *);
     84  1.43.2.2  jdolecek static void dwc_gmac_reset_rx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_rx_ring *);
     85  1.43.2.2  jdolecek static void dwc_gmac_free_rx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_rx_ring *);
     86  1.43.2.2  jdolecek static int dwc_gmac_alloc_tx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_tx_ring *);
     87  1.43.2.2  jdolecek static void dwc_gmac_reset_tx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_tx_ring *);
     88  1.43.2.2  jdolecek static void dwc_gmac_free_tx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_tx_ring *);
     89  1.43.2.2  jdolecek static void dwc_gmac_txdesc_sync(struct dwc_gmac_softc *sc, int start, int end, int ops);
     90  1.43.2.2  jdolecek static int dwc_gmac_init(struct ifnet *ifp);
     91  1.43.2.2  jdolecek static int dwc_gmac_init_locked(struct ifnet *ifp);
     92  1.43.2.2  jdolecek static void dwc_gmac_stop(struct ifnet *ifp, int disable);
     93  1.43.2.2  jdolecek static void dwc_gmac_stop_locked(struct ifnet *ifp, int disable);
     94  1.43.2.2  jdolecek static void dwc_gmac_start(struct ifnet *ifp);
     95  1.43.2.2  jdolecek static void dwc_gmac_start_locked(struct ifnet *ifp);
     96  1.43.2.2  jdolecek static int dwc_gmac_queue(struct dwc_gmac_softc *sc, struct mbuf *m0);
     97  1.43.2.2  jdolecek static int dwc_gmac_ioctl(struct ifnet *, u_long, void *);
     98  1.43.2.2  jdolecek static void dwc_gmac_tx_intr(struct dwc_gmac_softc *sc);
     99  1.43.2.2  jdolecek static void dwc_gmac_rx_intr(struct dwc_gmac_softc *sc);
    100  1.43.2.2  jdolecek static void dwc_gmac_setmulti(struct dwc_gmac_softc *sc);
    101  1.43.2.2  jdolecek static int dwc_gmac_ifflags_cb(struct ethercom *);
    102  1.43.2.2  jdolecek static uint32_t	bitrev32(uint32_t x);
    103  1.43.2.2  jdolecek 
    104  1.43.2.2  jdolecek #define	TX_DESC_OFFSET(N)	((AWGE_RX_RING_COUNT+(N)) \
    105  1.43.2.2  jdolecek 				    *sizeof(struct dwc_gmac_dev_dmadesc))
    106  1.43.2.2  jdolecek #define	TX_NEXT(N)		(((N)+1) & (AWGE_TX_RING_COUNT-1))
    107  1.43.2.2  jdolecek 
    108  1.43.2.2  jdolecek #define RX_DESC_OFFSET(N)	((N)*sizeof(struct dwc_gmac_dev_dmadesc))
    109  1.43.2.2  jdolecek #define	RX_NEXT(N)		(((N)+1) & (AWGE_RX_RING_COUNT-1))
    110  1.43.2.2  jdolecek 
    111  1.43.2.2  jdolecek 
    112  1.43.2.2  jdolecek 
    113  1.43.2.2  jdolecek #define	GMAC_DEF_DMA_INT_MASK	(GMAC_DMA_INT_TIE|GMAC_DMA_INT_RIE| \
    114  1.43.2.2  jdolecek 				GMAC_DMA_INT_NIE|GMAC_DMA_INT_AIE| \
    115  1.43.2.2  jdolecek 				GMAC_DMA_INT_FBE|GMAC_DMA_INT_UNE)
    116  1.43.2.2  jdolecek 
    117  1.43.2.2  jdolecek #define	GMAC_DMA_INT_ERRORS	(GMAC_DMA_INT_AIE|GMAC_DMA_INT_ERE| \
    118  1.43.2.2  jdolecek 				GMAC_DMA_INT_FBE|	\
    119  1.43.2.2  jdolecek 				GMAC_DMA_INT_RWE|GMAC_DMA_INT_RUE| \
    120  1.43.2.2  jdolecek 				GMAC_DMA_INT_UNE|GMAC_DMA_INT_OVE| \
    121  1.43.2.2  jdolecek 				GMAC_DMA_INT_TJE)
    122  1.43.2.2  jdolecek 
    123  1.43.2.2  jdolecek #define	AWIN_DEF_MAC_INTRMASK	\
    124  1.43.2.2  jdolecek 	(AWIN_GMAC_MAC_INT_TSI | AWIN_GMAC_MAC_INT_ANEG |	\
    125  1.43.2.2  jdolecek 	AWIN_GMAC_MAC_INT_LINKCHG | AWIN_GMAC_MAC_INT_RGSMII)
    126  1.43.2.2  jdolecek 
    127  1.43.2.2  jdolecek 
    128  1.43.2.2  jdolecek #ifdef DWC_GMAC_DEBUG
    129  1.43.2.2  jdolecek static void dwc_gmac_dump_dma(struct dwc_gmac_softc *sc);
    130  1.43.2.2  jdolecek static void dwc_gmac_dump_tx_desc(struct dwc_gmac_softc *sc);
    131  1.43.2.2  jdolecek static void dwc_gmac_dump_rx_desc(struct dwc_gmac_softc *sc);
    132  1.43.2.2  jdolecek static void dwc_dump_and_abort(struct dwc_gmac_softc *sc, const char *msg);
    133  1.43.2.2  jdolecek static void dwc_dump_status(struct dwc_gmac_softc *sc);
    134  1.43.2.2  jdolecek static void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *sc, uint32_t ffilt);
    135  1.43.2.2  jdolecek #endif
    136  1.43.2.2  jdolecek 
    137  1.43.2.2  jdolecek #ifdef NET_MPSAFE
    138  1.43.2.2  jdolecek #define DWCGMAC_MPSAFE	1
    139  1.43.2.2  jdolecek #endif
    140  1.43.2.2  jdolecek 
    141  1.43.2.2  jdolecek void
    142  1.43.2.2  jdolecek dwc_gmac_attach(struct dwc_gmac_softc *sc, uint32_t mii_clk)
    143  1.43.2.2  jdolecek {
    144  1.43.2.2  jdolecek 	uint8_t enaddr[ETHER_ADDR_LEN];
    145  1.43.2.2  jdolecek 	uint32_t maclo, machi;
    146  1.43.2.2  jdolecek 	struct mii_data * const mii = &sc->sc_mii;
    147  1.43.2.2  jdolecek 	struct ifnet * const ifp = &sc->sc_ec.ec_if;
    148  1.43.2.2  jdolecek 	prop_dictionary_t dict;
    149  1.43.2.2  jdolecek 	int rv;
    150  1.43.2.2  jdolecek 
    151  1.43.2.2  jdolecek 	mutex_init(&sc->sc_mdio_lock, MUTEX_DEFAULT, IPL_NET);
    152  1.43.2.2  jdolecek 	sc->sc_mii_clk = mii_clk & 7;
    153  1.43.2.2  jdolecek 
    154  1.43.2.2  jdolecek 	dict = device_properties(sc->sc_dev);
    155  1.43.2.2  jdolecek 	prop_data_t ea = dict ? prop_dictionary_get(dict, "mac-address") : NULL;
    156  1.43.2.2  jdolecek 	if (ea != NULL) {
    157  1.43.2.2  jdolecek 		/*
    158  1.43.2.2  jdolecek 		 * If the MAC address is overriden by a device property,
    159  1.43.2.2  jdolecek 		 * use that.
    160  1.43.2.2  jdolecek 		 */
    161  1.43.2.2  jdolecek 		KASSERT(prop_object_type(ea) == PROP_TYPE_DATA);
    162  1.43.2.2  jdolecek 		KASSERT(prop_data_size(ea) == ETHER_ADDR_LEN);
    163  1.43.2.2  jdolecek 		memcpy(enaddr, prop_data_data_nocopy(ea), ETHER_ADDR_LEN);
    164  1.43.2.2  jdolecek 	} else {
    165  1.43.2.2  jdolecek 		/*
    166  1.43.2.2  jdolecek 		 * If we did not get an externaly configure address,
    167  1.43.2.2  jdolecek 		 * try to read one from the current filter setup,
    168  1.43.2.2  jdolecek 		 * before resetting the chip.
    169  1.43.2.2  jdolecek 		 */
    170  1.43.2.2  jdolecek 		maclo = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
    171  1.43.2.2  jdolecek 		    AWIN_GMAC_MAC_ADDR0LO);
    172  1.43.2.2  jdolecek 		machi = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
    173  1.43.2.2  jdolecek 		    AWIN_GMAC_MAC_ADDR0HI);
    174  1.43.2.2  jdolecek 
    175  1.43.2.2  jdolecek 		if (maclo == 0xffffffff && (machi & 0xffff) == 0xffff) {
    176  1.43.2.2  jdolecek 			/* fake MAC address */
    177  1.43.2.2  jdolecek 			maclo = 0x00f2 | (cprng_strong32() << 16);
    178  1.43.2.2  jdolecek 			machi = cprng_strong32();
    179  1.43.2.2  jdolecek 		}
    180  1.43.2.2  jdolecek 
    181  1.43.2.2  jdolecek 		enaddr[0] = maclo & 0x0ff;
    182  1.43.2.2  jdolecek 		enaddr[1] = (maclo >> 8) & 0x0ff;
    183  1.43.2.2  jdolecek 		enaddr[2] = (maclo >> 16) & 0x0ff;
    184  1.43.2.2  jdolecek 		enaddr[3] = (maclo >> 24) & 0x0ff;
    185  1.43.2.2  jdolecek 		enaddr[4] = machi & 0x0ff;
    186  1.43.2.2  jdolecek 		enaddr[5] = (machi >> 8) & 0x0ff;
    187  1.43.2.2  jdolecek 	}
    188  1.43.2.2  jdolecek 
    189  1.43.2.2  jdolecek 	/*
    190  1.43.2.2  jdolecek 	 * Init chip and do initial setup
    191  1.43.2.2  jdolecek 	 */
    192  1.43.2.2  jdolecek 	if (dwc_gmac_reset(sc) != 0)
    193  1.43.2.2  jdolecek 		return;	/* not much to cleanup, haven't attached yet */
    194  1.43.2.2  jdolecek 	dwc_gmac_write_hwaddr(sc, enaddr);
    195  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "Ethernet address: %s\n",
    196  1.43.2.2  jdolecek 	    ether_sprintf(enaddr));
    197  1.43.2.2  jdolecek 
    198  1.43.2.2  jdolecek 	/*
    199  1.43.2.2  jdolecek 	 * Allocate Tx and Rx rings
    200  1.43.2.2  jdolecek 	 */
    201  1.43.2.2  jdolecek 	if (dwc_gmac_alloc_dma_rings(sc) != 0) {
    202  1.43.2.2  jdolecek 		aprint_error_dev(sc->sc_dev, "could not allocate DMA rings\n");
    203  1.43.2.2  jdolecek 		goto fail;
    204  1.43.2.2  jdolecek 	}
    205  1.43.2.2  jdolecek 
    206  1.43.2.2  jdolecek 	if (dwc_gmac_alloc_tx_ring(sc, &sc->sc_txq) != 0) {
    207  1.43.2.2  jdolecek 		aprint_error_dev(sc->sc_dev, "could not allocate Tx ring\n");
    208  1.43.2.2  jdolecek 		goto fail;
    209  1.43.2.2  jdolecek 	}
    210  1.43.2.2  jdolecek 
    211  1.43.2.2  jdolecek 	if (dwc_gmac_alloc_rx_ring(sc, &sc->sc_rxq) != 0) {
    212  1.43.2.2  jdolecek 		aprint_error_dev(sc->sc_dev, "could not allocate Rx ring\n");
    213  1.43.2.2  jdolecek 		goto fail;
    214  1.43.2.2  jdolecek 	}
    215  1.43.2.2  jdolecek 
    216  1.43.2.2  jdolecek 	sc->sc_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET);
    217  1.43.2.2  jdolecek 	mutex_init(&sc->sc_txq.t_mtx, MUTEX_DEFAULT, IPL_NET);
    218  1.43.2.2  jdolecek 	mutex_init(&sc->sc_rxq.r_mtx, MUTEX_DEFAULT, IPL_NET);
    219  1.43.2.2  jdolecek 
    220  1.43.2.2  jdolecek 	/*
    221  1.43.2.2  jdolecek 	 * Prepare interface data
    222  1.43.2.2  jdolecek 	 */
    223  1.43.2.2  jdolecek 	ifp->if_softc = sc;
    224  1.43.2.2  jdolecek 	strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
    225  1.43.2.2  jdolecek 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
    226  1.43.2.2  jdolecek 	ifp->if_extflags = IFEF_MPSAFE;
    227  1.43.2.2  jdolecek 	ifp->if_ioctl = dwc_gmac_ioctl;
    228  1.43.2.2  jdolecek 	ifp->if_start = dwc_gmac_start;
    229  1.43.2.2  jdolecek 	ifp->if_init = dwc_gmac_init;
    230  1.43.2.2  jdolecek 	ifp->if_stop = dwc_gmac_stop;
    231  1.43.2.2  jdolecek 	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
    232  1.43.2.2  jdolecek 	IFQ_SET_READY(&ifp->if_snd);
    233  1.43.2.2  jdolecek 
    234  1.43.2.2  jdolecek 	/*
    235  1.43.2.2  jdolecek 	 * Attach MII subdevices
    236  1.43.2.2  jdolecek 	 */
    237  1.43.2.2  jdolecek 	sc->sc_ec.ec_mii = &sc->sc_mii;
    238  1.43.2.2  jdolecek 	ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus);
    239  1.43.2.2  jdolecek         mii->mii_ifp = ifp;
    240  1.43.2.2  jdolecek         mii->mii_readreg = dwc_gmac_miibus_read_reg;
    241  1.43.2.2  jdolecek         mii->mii_writereg = dwc_gmac_miibus_write_reg;
    242  1.43.2.2  jdolecek         mii->mii_statchg = dwc_gmac_miibus_statchg;
    243  1.43.2.2  jdolecek         mii_attach(sc->sc_dev, mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY,
    244  1.43.2.2  jdolecek 	    MIIF_DOPAUSE);
    245  1.43.2.2  jdolecek 
    246  1.43.2.2  jdolecek         if (LIST_EMPTY(&mii->mii_phys)) {
    247  1.43.2.2  jdolecek                 aprint_error_dev(sc->sc_dev, "no PHY found!\n");
    248  1.43.2.2  jdolecek                 ifmedia_add(&mii->mii_media, IFM_ETHER|IFM_MANUAL, 0, NULL);
    249  1.43.2.2  jdolecek                 ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_MANUAL);
    250  1.43.2.2  jdolecek         } else {
    251  1.43.2.2  jdolecek                 ifmedia_set(&mii->mii_media, IFM_ETHER|IFM_AUTO);
    252  1.43.2.2  jdolecek         }
    253  1.43.2.2  jdolecek 
    254  1.43.2.2  jdolecek 	/*
    255  1.43.2.2  jdolecek 	 * We can support 802.1Q VLAN-sized frames.
    256  1.43.2.2  jdolecek 	 */
    257  1.43.2.2  jdolecek 	sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU;
    258  1.43.2.2  jdolecek 
    259  1.43.2.2  jdolecek 	/*
    260  1.43.2.2  jdolecek 	 * Ready, attach interface
    261  1.43.2.2  jdolecek 	 */
    262  1.43.2.2  jdolecek 	/* Attach the interface. */
    263  1.43.2.2  jdolecek 	rv = if_initialize(ifp);
    264  1.43.2.2  jdolecek 	if (rv != 0)
    265  1.43.2.2  jdolecek 		goto fail_2;
    266  1.43.2.2  jdolecek 	sc->sc_ipq = if_percpuq_create(&sc->sc_ec.ec_if);
    267  1.43.2.2  jdolecek 	if_deferred_start_init(ifp, NULL);
    268  1.43.2.2  jdolecek 	ether_ifattach(ifp, enaddr);
    269  1.43.2.2  jdolecek 	ether_set_ifflags_cb(&sc->sc_ec, dwc_gmac_ifflags_cb);
    270  1.43.2.2  jdolecek 	if_register(ifp);
    271  1.43.2.2  jdolecek 
    272  1.43.2.2  jdolecek 	/*
    273  1.43.2.2  jdolecek 	 * Enable interrupts
    274  1.43.2.2  jdolecek 	 */
    275  1.43.2.2  jdolecek 	mutex_enter(sc->sc_lock);
    276  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTMASK,
    277  1.43.2.2  jdolecek 	    AWIN_DEF_MAC_INTRMASK);
    278  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE,
    279  1.43.2.2  jdolecek 	    GMAC_DEF_DMA_INT_MASK);
    280  1.43.2.2  jdolecek 	mutex_exit(sc->sc_lock);
    281  1.43.2.2  jdolecek 
    282  1.43.2.2  jdolecek 	return;
    283  1.43.2.2  jdolecek fail_2:
    284  1.43.2.2  jdolecek 	ifmedia_removeall(&mii->mii_media);
    285  1.43.2.2  jdolecek 	mii_detach(mii, MII_PHY_ANY, MII_OFFSET_ANY);
    286  1.43.2.2  jdolecek 	mutex_destroy(&sc->sc_txq.t_mtx);
    287  1.43.2.2  jdolecek 	mutex_destroy(&sc->sc_rxq.r_mtx);
    288  1.43.2.2  jdolecek 	mutex_obj_free(sc->sc_lock);
    289  1.43.2.2  jdolecek fail:
    290  1.43.2.2  jdolecek 	dwc_gmac_free_rx_ring(sc, &sc->sc_rxq);
    291  1.43.2.2  jdolecek 	dwc_gmac_free_tx_ring(sc, &sc->sc_txq);
    292  1.43.2.2  jdolecek 	dwc_gmac_free_dma_rings(sc);
    293  1.43.2.2  jdolecek 	mutex_destroy(&sc->sc_mdio_lock);
    294  1.43.2.2  jdolecek }
    295  1.43.2.2  jdolecek 
    296  1.43.2.2  jdolecek 
    297  1.43.2.2  jdolecek 
    298  1.43.2.2  jdolecek static int
    299  1.43.2.2  jdolecek dwc_gmac_reset(struct dwc_gmac_softc *sc)
    300  1.43.2.2  jdolecek {
    301  1.43.2.2  jdolecek 	size_t cnt;
    302  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE,
    303  1.43.2.2  jdolecek 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE) | GMAC_BUSMODE_RESET);
    304  1.43.2.2  jdolecek 	for (cnt = 0; cnt < 3000; cnt++) {
    305  1.43.2.2  jdolecek 		if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE)
    306  1.43.2.2  jdolecek 		    & GMAC_BUSMODE_RESET) == 0)
    307  1.43.2.2  jdolecek 			return 0;
    308  1.43.2.2  jdolecek 		delay(10);
    309  1.43.2.2  jdolecek 	}
    310  1.43.2.2  jdolecek 
    311  1.43.2.2  jdolecek 	aprint_error_dev(sc->sc_dev, "reset timed out\n");
    312  1.43.2.2  jdolecek 	return EIO;
    313  1.43.2.2  jdolecek }
    314  1.43.2.2  jdolecek 
    315  1.43.2.2  jdolecek static void
    316  1.43.2.2  jdolecek dwc_gmac_write_hwaddr(struct dwc_gmac_softc *sc,
    317  1.43.2.2  jdolecek     uint8_t enaddr[ETHER_ADDR_LEN])
    318  1.43.2.2  jdolecek {
    319  1.43.2.2  jdolecek 	uint32_t lo, hi;
    320  1.43.2.2  jdolecek 
    321  1.43.2.2  jdolecek 	lo = enaddr[0] | (enaddr[1] << 8) | (enaddr[2] << 16)
    322  1.43.2.2  jdolecek 	    | (enaddr[3] << 24);
    323  1.43.2.2  jdolecek 	hi = enaddr[4] | (enaddr[5] << 8);
    324  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0LO, lo);
    325  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0HI, hi);
    326  1.43.2.2  jdolecek }
    327  1.43.2.2  jdolecek 
    328  1.43.2.2  jdolecek static int
    329  1.43.2.2  jdolecek dwc_gmac_miibus_read_reg(device_t self, int phy, int reg)
    330  1.43.2.2  jdolecek {
    331  1.43.2.2  jdolecek 	struct dwc_gmac_softc * const sc = device_private(self);
    332  1.43.2.2  jdolecek 	uint16_t mii;
    333  1.43.2.2  jdolecek 	size_t cnt;
    334  1.43.2.2  jdolecek 	int rv = 0;
    335  1.43.2.2  jdolecek 
    336  1.43.2.2  jdolecek 	mii = __SHIFTIN(phy,GMAC_MII_PHY_MASK)
    337  1.43.2.2  jdolecek 	    | __SHIFTIN(reg,GMAC_MII_REG_MASK)
    338  1.43.2.2  jdolecek 	    | __SHIFTIN(sc->sc_mii_clk,GMAC_MII_CLKMASK)
    339  1.43.2.2  jdolecek 	    | GMAC_MII_BUSY;
    340  1.43.2.2  jdolecek 
    341  1.43.2.2  jdolecek 	mutex_enter(&sc->sc_mdio_lock);
    342  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIADDR, mii);
    343  1.43.2.2  jdolecek 
    344  1.43.2.2  jdolecek 	for (cnt = 0; cnt < 1000; cnt++) {
    345  1.43.2.2  jdolecek 		if (!(bus_space_read_4(sc->sc_bst, sc->sc_bsh,
    346  1.43.2.2  jdolecek 		    AWIN_GMAC_MAC_MIIADDR) & GMAC_MII_BUSY)) {
    347  1.43.2.2  jdolecek 			rv = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
    348  1.43.2.2  jdolecek 			    AWIN_GMAC_MAC_MIIDATA);
    349  1.43.2.2  jdolecek 			break;
    350  1.43.2.2  jdolecek 		}
    351  1.43.2.2  jdolecek 		delay(10);
    352  1.43.2.2  jdolecek 	}
    353  1.43.2.2  jdolecek 
    354  1.43.2.2  jdolecek 	mutex_exit(&sc->sc_mdio_lock);
    355  1.43.2.2  jdolecek 
    356  1.43.2.2  jdolecek 	return rv;
    357  1.43.2.2  jdolecek }
    358  1.43.2.2  jdolecek 
    359  1.43.2.2  jdolecek static void
    360  1.43.2.2  jdolecek dwc_gmac_miibus_write_reg(device_t self, int phy, int reg, int val)
    361  1.43.2.2  jdolecek {
    362  1.43.2.2  jdolecek 	struct dwc_gmac_softc * const sc = device_private(self);
    363  1.43.2.2  jdolecek 	uint16_t mii;
    364  1.43.2.2  jdolecek 	size_t cnt;
    365  1.43.2.2  jdolecek 
    366  1.43.2.2  jdolecek 	mii = __SHIFTIN(phy,GMAC_MII_PHY_MASK)
    367  1.43.2.2  jdolecek 	    | __SHIFTIN(reg,GMAC_MII_REG_MASK)
    368  1.43.2.2  jdolecek 	    | __SHIFTIN(sc->sc_mii_clk,GMAC_MII_CLKMASK)
    369  1.43.2.2  jdolecek 	    | GMAC_MII_BUSY | GMAC_MII_WRITE;
    370  1.43.2.2  jdolecek 
    371  1.43.2.2  jdolecek 	mutex_enter(&sc->sc_mdio_lock);
    372  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIDATA, val);
    373  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIADDR, mii);
    374  1.43.2.2  jdolecek 
    375  1.43.2.2  jdolecek 	for (cnt = 0; cnt < 1000; cnt++) {
    376  1.43.2.2  jdolecek 		if (!(bus_space_read_4(sc->sc_bst, sc->sc_bsh,
    377  1.43.2.2  jdolecek 		    AWIN_GMAC_MAC_MIIADDR) & GMAC_MII_BUSY))
    378  1.43.2.2  jdolecek 			break;
    379  1.43.2.2  jdolecek 		delay(10);
    380  1.43.2.2  jdolecek 	}
    381  1.43.2.2  jdolecek 
    382  1.43.2.2  jdolecek 	mutex_exit(&sc->sc_mdio_lock);
    383  1.43.2.2  jdolecek }
    384  1.43.2.2  jdolecek 
    385  1.43.2.2  jdolecek static int
    386  1.43.2.2  jdolecek dwc_gmac_alloc_rx_ring(struct dwc_gmac_softc *sc,
    387  1.43.2.2  jdolecek 	struct dwc_gmac_rx_ring *ring)
    388  1.43.2.2  jdolecek {
    389  1.43.2.2  jdolecek 	struct dwc_gmac_rx_data *data;
    390  1.43.2.2  jdolecek 	bus_addr_t physaddr;
    391  1.43.2.2  jdolecek 	const size_t descsize = AWGE_RX_RING_COUNT * sizeof(*ring->r_desc);
    392  1.43.2.2  jdolecek 	int error, i, next;
    393  1.43.2.2  jdolecek 
    394  1.43.2.2  jdolecek 	ring->r_cur = ring->r_next = 0;
    395  1.43.2.2  jdolecek 	memset(ring->r_desc, 0, descsize);
    396  1.43.2.2  jdolecek 
    397  1.43.2.2  jdolecek 	/*
    398  1.43.2.2  jdolecek 	 * Pre-allocate Rx buffers and populate Rx ring.
    399  1.43.2.2  jdolecek 	 */
    400  1.43.2.2  jdolecek 	for (i = 0; i < AWGE_RX_RING_COUNT; i++) {
    401  1.43.2.2  jdolecek 		struct dwc_gmac_dev_dmadesc *desc;
    402  1.43.2.2  jdolecek 
    403  1.43.2.2  jdolecek 		data = &sc->sc_rxq.r_data[i];
    404  1.43.2.2  jdolecek 
    405  1.43.2.2  jdolecek 		MGETHDR(data->rd_m, M_DONTWAIT, MT_DATA);
    406  1.43.2.2  jdolecek 		if (data->rd_m == NULL) {
    407  1.43.2.2  jdolecek 			aprint_error_dev(sc->sc_dev,
    408  1.43.2.2  jdolecek 			    "could not allocate rx mbuf #%d\n", i);
    409  1.43.2.2  jdolecek 			error = ENOMEM;
    410  1.43.2.2  jdolecek 			goto fail;
    411  1.43.2.2  jdolecek 		}
    412  1.43.2.2  jdolecek 		error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
    413  1.43.2.2  jdolecek 		    MCLBYTES, 0, BUS_DMA_NOWAIT, &data->rd_map);
    414  1.43.2.2  jdolecek 		if (error != 0) {
    415  1.43.2.2  jdolecek 			aprint_error_dev(sc->sc_dev,
    416  1.43.2.2  jdolecek 			    "could not create DMA map\n");
    417  1.43.2.2  jdolecek 			data->rd_map = NULL;
    418  1.43.2.2  jdolecek 			goto fail;
    419  1.43.2.2  jdolecek 		}
    420  1.43.2.2  jdolecek 		MCLGET(data->rd_m, M_DONTWAIT);
    421  1.43.2.2  jdolecek 		if (!(data->rd_m->m_flags & M_EXT)) {
    422  1.43.2.2  jdolecek 			aprint_error_dev(sc->sc_dev,
    423  1.43.2.2  jdolecek 			    "could not allocate mbuf cluster #%d\n", i);
    424  1.43.2.2  jdolecek 			error = ENOMEM;
    425  1.43.2.2  jdolecek 			goto fail;
    426  1.43.2.2  jdolecek 		}
    427  1.43.2.2  jdolecek 
    428  1.43.2.2  jdolecek 		error = bus_dmamap_load(sc->sc_dmat, data->rd_map,
    429  1.43.2.2  jdolecek 		    mtod(data->rd_m, void *), MCLBYTES, NULL,
    430  1.43.2.2  jdolecek 		    BUS_DMA_READ | BUS_DMA_NOWAIT);
    431  1.43.2.2  jdolecek 		if (error != 0) {
    432  1.43.2.2  jdolecek 			aprint_error_dev(sc->sc_dev,
    433  1.43.2.2  jdolecek 			    "could not load rx buf DMA map #%d", i);
    434  1.43.2.2  jdolecek 			goto fail;
    435  1.43.2.2  jdolecek 		}
    436  1.43.2.2  jdolecek 		physaddr = data->rd_map->dm_segs[0].ds_addr;
    437  1.43.2.2  jdolecek 
    438  1.43.2.2  jdolecek 		desc = &sc->sc_rxq.r_desc[i];
    439  1.43.2.2  jdolecek 		desc->ddesc_data = htole32(physaddr);
    440  1.43.2.2  jdolecek 		next = RX_NEXT(i);
    441  1.43.2.2  jdolecek 		desc->ddesc_next = htole32(ring->r_physaddr
    442  1.43.2.2  jdolecek 		    + next * sizeof(*desc));
    443  1.43.2.2  jdolecek 		desc->ddesc_cntl = htole32(
    444  1.43.2.2  jdolecek 		    __SHIFTIN(AWGE_MAX_PACKET,DDESC_CNTL_SIZE1MASK) |
    445  1.43.2.2  jdolecek 		    DDESC_CNTL_RXCHAIN);
    446  1.43.2.2  jdolecek 		desc->ddesc_status = htole32(DDESC_STATUS_OWNEDBYDEV);
    447  1.43.2.2  jdolecek 	}
    448  1.43.2.2  jdolecek 
    449  1.43.2.2  jdolecek 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0,
    450  1.43.2.2  jdolecek 	    AWGE_RX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc),
    451  1.43.2.2  jdolecek 	    BUS_DMASYNC_PREWRITE|BUS_DMASYNC_PREREAD);
    452  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR,
    453  1.43.2.2  jdolecek 	    ring->r_physaddr);
    454  1.43.2.2  jdolecek 
    455  1.43.2.2  jdolecek 	return 0;
    456  1.43.2.2  jdolecek 
    457  1.43.2.2  jdolecek fail:
    458  1.43.2.2  jdolecek 	dwc_gmac_free_rx_ring(sc, ring);
    459  1.43.2.2  jdolecek 	return error;
    460  1.43.2.2  jdolecek }
    461  1.43.2.2  jdolecek 
    462  1.43.2.2  jdolecek static void
    463  1.43.2.2  jdolecek dwc_gmac_reset_rx_ring(struct dwc_gmac_softc *sc,
    464  1.43.2.2  jdolecek 	struct dwc_gmac_rx_ring *ring)
    465  1.43.2.2  jdolecek {
    466  1.43.2.2  jdolecek 	struct dwc_gmac_dev_dmadesc *desc;
    467  1.43.2.2  jdolecek 	int i;
    468  1.43.2.2  jdolecek 
    469  1.43.2.2  jdolecek 	mutex_enter(&ring->r_mtx);
    470  1.43.2.2  jdolecek 	for (i = 0; i < AWGE_RX_RING_COUNT; i++) {
    471  1.43.2.2  jdolecek 		desc = &sc->sc_rxq.r_desc[i];
    472  1.43.2.2  jdolecek 		desc->ddesc_cntl = htole32(
    473  1.43.2.2  jdolecek 		    __SHIFTIN(AWGE_MAX_PACKET,DDESC_CNTL_SIZE1MASK) |
    474  1.43.2.2  jdolecek 		    DDESC_CNTL_RXCHAIN);
    475  1.43.2.2  jdolecek 		desc->ddesc_status = htole32(DDESC_STATUS_OWNEDBYDEV);
    476  1.43.2.2  jdolecek 	}
    477  1.43.2.2  jdolecek 
    478  1.43.2.2  jdolecek 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0,
    479  1.43.2.2  jdolecek 	    AWGE_RX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc),
    480  1.43.2.2  jdolecek 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
    481  1.43.2.2  jdolecek 
    482  1.43.2.2  jdolecek 	ring->r_cur = ring->r_next = 0;
    483  1.43.2.2  jdolecek 	/* reset DMA address to start of ring */
    484  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR,
    485  1.43.2.2  jdolecek 	    sc->sc_rxq.r_physaddr);
    486  1.43.2.2  jdolecek 	mutex_exit(&ring->r_mtx);
    487  1.43.2.2  jdolecek }
    488  1.43.2.2  jdolecek 
    489  1.43.2.2  jdolecek static int
    490  1.43.2.2  jdolecek dwc_gmac_alloc_dma_rings(struct dwc_gmac_softc *sc)
    491  1.43.2.2  jdolecek {
    492  1.43.2.2  jdolecek 	const size_t descsize = AWGE_TOTAL_RING_COUNT *
    493  1.43.2.2  jdolecek 		sizeof(struct dwc_gmac_dev_dmadesc);
    494  1.43.2.2  jdolecek 	int error, nsegs;
    495  1.43.2.2  jdolecek 	void *rings;
    496  1.43.2.2  jdolecek 
    497  1.43.2.2  jdolecek 	error = bus_dmamap_create(sc->sc_dmat, descsize, 1, descsize, 0,
    498  1.43.2.2  jdolecek 	    BUS_DMA_NOWAIT, &sc->sc_dma_ring_map);
    499  1.43.2.2  jdolecek 	if (error != 0) {
    500  1.43.2.2  jdolecek 		aprint_error_dev(sc->sc_dev,
    501  1.43.2.2  jdolecek 		    "could not create desc DMA map\n");
    502  1.43.2.2  jdolecek 		sc->sc_dma_ring_map = NULL;
    503  1.43.2.2  jdolecek 		goto fail;
    504  1.43.2.2  jdolecek 	}
    505  1.43.2.2  jdolecek 
    506  1.43.2.2  jdolecek 	error = bus_dmamem_alloc(sc->sc_dmat, descsize, PAGE_SIZE, 0,
    507  1.43.2.2  jdolecek 	    &sc->sc_dma_ring_seg, 1, &nsegs, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
    508  1.43.2.2  jdolecek 	if (error != 0) {
    509  1.43.2.2  jdolecek 		aprint_error_dev(sc->sc_dev,
    510  1.43.2.2  jdolecek 		    "could not map DMA memory\n");
    511  1.43.2.2  jdolecek 		goto fail;
    512  1.43.2.2  jdolecek 	}
    513  1.43.2.2  jdolecek 
    514  1.43.2.2  jdolecek 	error = bus_dmamem_map(sc->sc_dmat, &sc->sc_dma_ring_seg, nsegs,
    515  1.43.2.2  jdolecek 	    descsize, &rings, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
    516  1.43.2.2  jdolecek 	if (error != 0) {
    517  1.43.2.2  jdolecek 		aprint_error_dev(sc->sc_dev,
    518  1.43.2.2  jdolecek 		    "could not allocate DMA memory\n");
    519  1.43.2.2  jdolecek 		goto fail;
    520  1.43.2.2  jdolecek 	}
    521  1.43.2.2  jdolecek 
    522  1.43.2.2  jdolecek 	error = bus_dmamap_load(sc->sc_dmat, sc->sc_dma_ring_map, rings,
    523  1.43.2.2  jdolecek 	    descsize, NULL, BUS_DMA_NOWAIT|BUS_DMA_COHERENT);
    524  1.43.2.2  jdolecek 	if (error != 0) {
    525  1.43.2.2  jdolecek 		aprint_error_dev(sc->sc_dev,
    526  1.43.2.2  jdolecek 		    "could not load desc DMA map\n");
    527  1.43.2.2  jdolecek 		goto fail;
    528  1.43.2.2  jdolecek 	}
    529  1.43.2.2  jdolecek 
    530  1.43.2.2  jdolecek 	/* give first AWGE_RX_RING_COUNT to the RX side */
    531  1.43.2.2  jdolecek 	sc->sc_rxq.r_desc = rings;
    532  1.43.2.2  jdolecek 	sc->sc_rxq.r_physaddr = sc->sc_dma_ring_map->dm_segs[0].ds_addr;
    533  1.43.2.2  jdolecek 
    534  1.43.2.2  jdolecek 	/* and next rings to the TX side */
    535  1.43.2.2  jdolecek 	sc->sc_txq.t_desc = sc->sc_rxq.r_desc + AWGE_RX_RING_COUNT;
    536  1.43.2.2  jdolecek 	sc->sc_txq.t_physaddr = sc->sc_rxq.r_physaddr +
    537  1.43.2.2  jdolecek 	    AWGE_RX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc);
    538  1.43.2.2  jdolecek 
    539  1.43.2.2  jdolecek 	return 0;
    540  1.43.2.2  jdolecek 
    541  1.43.2.2  jdolecek fail:
    542  1.43.2.2  jdolecek 	dwc_gmac_free_dma_rings(sc);
    543  1.43.2.2  jdolecek 	return error;
    544  1.43.2.2  jdolecek }
    545  1.43.2.2  jdolecek 
    546  1.43.2.2  jdolecek static void
    547  1.43.2.2  jdolecek dwc_gmac_free_dma_rings(struct dwc_gmac_softc *sc)
    548  1.43.2.2  jdolecek {
    549  1.43.2.2  jdolecek 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0,
    550  1.43.2.2  jdolecek 	    sc->sc_dma_ring_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
    551  1.43.2.2  jdolecek 	bus_dmamap_unload(sc->sc_dmat, sc->sc_dma_ring_map);
    552  1.43.2.2  jdolecek 	bus_dmamem_unmap(sc->sc_dmat, sc->sc_rxq.r_desc,
    553  1.43.2.2  jdolecek 	    AWGE_TOTAL_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc));
    554  1.43.2.2  jdolecek 	bus_dmamem_free(sc->sc_dmat, &sc->sc_dma_ring_seg, 1);
    555  1.43.2.2  jdolecek }
    556  1.43.2.2  jdolecek 
    557  1.43.2.2  jdolecek static void
    558  1.43.2.2  jdolecek dwc_gmac_free_rx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_rx_ring *ring)
    559  1.43.2.2  jdolecek {
    560  1.43.2.2  jdolecek 	struct dwc_gmac_rx_data *data;
    561  1.43.2.2  jdolecek 	int i;
    562  1.43.2.2  jdolecek 
    563  1.43.2.2  jdolecek 	if (ring->r_desc == NULL)
    564  1.43.2.2  jdolecek 		return;
    565  1.43.2.2  jdolecek 
    566  1.43.2.2  jdolecek 
    567  1.43.2.2  jdolecek 	for (i = 0; i < AWGE_RX_RING_COUNT; i++) {
    568  1.43.2.2  jdolecek 		data = &ring->r_data[i];
    569  1.43.2.2  jdolecek 
    570  1.43.2.2  jdolecek 		if (data->rd_map != NULL) {
    571  1.43.2.2  jdolecek 			bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0,
    572  1.43.2.2  jdolecek 			    AWGE_RX_RING_COUNT
    573  1.43.2.2  jdolecek 				*sizeof(struct dwc_gmac_dev_dmadesc),
    574  1.43.2.2  jdolecek 			    BUS_DMASYNC_POSTREAD);
    575  1.43.2.2  jdolecek 			bus_dmamap_unload(sc->sc_dmat, data->rd_map);
    576  1.43.2.2  jdolecek 			bus_dmamap_destroy(sc->sc_dmat, data->rd_map);
    577  1.43.2.2  jdolecek 		}
    578  1.43.2.2  jdolecek 		if (data->rd_m != NULL)
    579  1.43.2.2  jdolecek 			m_freem(data->rd_m);
    580  1.43.2.2  jdolecek 	}
    581  1.43.2.2  jdolecek }
    582  1.43.2.2  jdolecek 
    583  1.43.2.2  jdolecek static int
    584  1.43.2.2  jdolecek dwc_gmac_alloc_tx_ring(struct dwc_gmac_softc *sc,
    585  1.43.2.2  jdolecek 	struct dwc_gmac_tx_ring *ring)
    586  1.43.2.2  jdolecek {
    587  1.43.2.2  jdolecek 	int i, error = 0;
    588  1.43.2.2  jdolecek 
    589  1.43.2.2  jdolecek 	ring->t_queued = 0;
    590  1.43.2.2  jdolecek 	ring->t_cur = ring->t_next = 0;
    591  1.43.2.2  jdolecek 
    592  1.43.2.2  jdolecek 	memset(ring->t_desc, 0, AWGE_TX_RING_COUNT*sizeof(*ring->t_desc));
    593  1.43.2.2  jdolecek 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
    594  1.43.2.2  jdolecek 	    TX_DESC_OFFSET(0),
    595  1.43.2.2  jdolecek 	    AWGE_TX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc),
    596  1.43.2.2  jdolecek 	    BUS_DMASYNC_POSTWRITE);
    597  1.43.2.2  jdolecek 
    598  1.43.2.2  jdolecek 	for (i = 0; i < AWGE_TX_RING_COUNT; i++) {
    599  1.43.2.2  jdolecek 		error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
    600  1.43.2.2  jdolecek 		    AWGE_TX_RING_COUNT, MCLBYTES, 0,
    601  1.43.2.2  jdolecek 		    BUS_DMA_NOWAIT|BUS_DMA_COHERENT,
    602  1.43.2.2  jdolecek 		    &ring->t_data[i].td_map);
    603  1.43.2.2  jdolecek 		if (error != 0) {
    604  1.43.2.2  jdolecek 			aprint_error_dev(sc->sc_dev,
    605  1.43.2.2  jdolecek 			    "could not create TX DMA map #%d\n", i);
    606  1.43.2.2  jdolecek 			ring->t_data[i].td_map = NULL;
    607  1.43.2.2  jdolecek 			goto fail;
    608  1.43.2.2  jdolecek 		}
    609  1.43.2.2  jdolecek 		ring->t_desc[i].ddesc_next = htole32(
    610  1.43.2.2  jdolecek 		    ring->t_physaddr + sizeof(struct dwc_gmac_dev_dmadesc)
    611  1.43.2.2  jdolecek 		    *TX_NEXT(i));
    612  1.43.2.2  jdolecek 	}
    613  1.43.2.2  jdolecek 
    614  1.43.2.2  jdolecek 	return 0;
    615  1.43.2.2  jdolecek 
    616  1.43.2.2  jdolecek fail:
    617  1.43.2.2  jdolecek 	dwc_gmac_free_tx_ring(sc, ring);
    618  1.43.2.2  jdolecek 	return error;
    619  1.43.2.2  jdolecek }
    620  1.43.2.2  jdolecek 
    621  1.43.2.2  jdolecek static void
    622  1.43.2.2  jdolecek dwc_gmac_txdesc_sync(struct dwc_gmac_softc *sc, int start, int end, int ops)
    623  1.43.2.2  jdolecek {
    624  1.43.2.2  jdolecek 	/* 'end' is pointing one descriptor beyound the last we want to sync */
    625  1.43.2.2  jdolecek 	if (end > start) {
    626  1.43.2.2  jdolecek 		bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
    627  1.43.2.2  jdolecek 		    TX_DESC_OFFSET(start),
    628  1.43.2.2  jdolecek 		    TX_DESC_OFFSET(end)-TX_DESC_OFFSET(start),
    629  1.43.2.2  jdolecek 		    ops);
    630  1.43.2.2  jdolecek 		return;
    631  1.43.2.2  jdolecek 	}
    632  1.43.2.2  jdolecek 	/* sync from 'start' to end of ring */
    633  1.43.2.2  jdolecek 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
    634  1.43.2.2  jdolecek 	    TX_DESC_OFFSET(start),
    635  1.43.2.2  jdolecek 	    TX_DESC_OFFSET(AWGE_TX_RING_COUNT)-TX_DESC_OFFSET(start),
    636  1.43.2.2  jdolecek 	    ops);
    637  1.43.2.2  jdolecek 	/* sync from start of ring to 'end' */
    638  1.43.2.2  jdolecek 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
    639  1.43.2.2  jdolecek 	    TX_DESC_OFFSET(0),
    640  1.43.2.2  jdolecek 	    TX_DESC_OFFSET(end)-TX_DESC_OFFSET(0),
    641  1.43.2.2  jdolecek 	    ops);
    642  1.43.2.2  jdolecek }
    643  1.43.2.2  jdolecek 
    644  1.43.2.2  jdolecek static void
    645  1.43.2.2  jdolecek dwc_gmac_reset_tx_ring(struct dwc_gmac_softc *sc,
    646  1.43.2.2  jdolecek 	struct dwc_gmac_tx_ring *ring)
    647  1.43.2.2  jdolecek {
    648  1.43.2.2  jdolecek 	int i;
    649  1.43.2.2  jdolecek 
    650  1.43.2.2  jdolecek 	mutex_enter(&ring->t_mtx);
    651  1.43.2.2  jdolecek 	for (i = 0; i < AWGE_TX_RING_COUNT; i++) {
    652  1.43.2.2  jdolecek 		struct dwc_gmac_tx_data *data = &ring->t_data[i];
    653  1.43.2.2  jdolecek 
    654  1.43.2.2  jdolecek 		if (data->td_m != NULL) {
    655  1.43.2.2  jdolecek 			bus_dmamap_sync(sc->sc_dmat, data->td_active,
    656  1.43.2.2  jdolecek 			    0, data->td_active->dm_mapsize,
    657  1.43.2.2  jdolecek 			    BUS_DMASYNC_POSTWRITE);
    658  1.43.2.2  jdolecek 			bus_dmamap_unload(sc->sc_dmat, data->td_active);
    659  1.43.2.2  jdolecek 			m_freem(data->td_m);
    660  1.43.2.2  jdolecek 			data->td_m = NULL;
    661  1.43.2.2  jdolecek 		}
    662  1.43.2.2  jdolecek 	}
    663  1.43.2.2  jdolecek 
    664  1.43.2.2  jdolecek 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
    665  1.43.2.2  jdolecek 	    TX_DESC_OFFSET(0),
    666  1.43.2.2  jdolecek 	    AWGE_TX_RING_COUNT*sizeof(struct dwc_gmac_dev_dmadesc),
    667  1.43.2.2  jdolecek 	    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
    668  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR,
    669  1.43.2.2  jdolecek 	    sc->sc_txq.t_physaddr);
    670  1.43.2.2  jdolecek 
    671  1.43.2.2  jdolecek 	ring->t_queued = 0;
    672  1.43.2.2  jdolecek 	ring->t_cur = ring->t_next = 0;
    673  1.43.2.2  jdolecek 	mutex_exit(&ring->t_mtx);
    674  1.43.2.2  jdolecek }
    675  1.43.2.2  jdolecek 
    676  1.43.2.2  jdolecek static void
    677  1.43.2.2  jdolecek dwc_gmac_free_tx_ring(struct dwc_gmac_softc *sc,
    678  1.43.2.2  jdolecek 	struct dwc_gmac_tx_ring *ring)
    679  1.43.2.2  jdolecek {
    680  1.43.2.2  jdolecek 	int i;
    681  1.43.2.2  jdolecek 
    682  1.43.2.2  jdolecek 	/* unload the maps */
    683  1.43.2.2  jdolecek 	for (i = 0; i < AWGE_TX_RING_COUNT; i++) {
    684  1.43.2.2  jdolecek 		struct dwc_gmac_tx_data *data = &ring->t_data[i];
    685  1.43.2.2  jdolecek 
    686  1.43.2.2  jdolecek 		if (data->td_m != NULL) {
    687  1.43.2.2  jdolecek 			bus_dmamap_sync(sc->sc_dmat, data->td_active,
    688  1.43.2.2  jdolecek 			    0, data->td_map->dm_mapsize,
    689  1.43.2.2  jdolecek 			    BUS_DMASYNC_POSTWRITE);
    690  1.43.2.2  jdolecek 			bus_dmamap_unload(sc->sc_dmat, data->td_active);
    691  1.43.2.2  jdolecek 			m_freem(data->td_m);
    692  1.43.2.2  jdolecek 			data->td_m = NULL;
    693  1.43.2.2  jdolecek 		}
    694  1.43.2.2  jdolecek 	}
    695  1.43.2.2  jdolecek 
    696  1.43.2.2  jdolecek 	/* and actually free them */
    697  1.43.2.2  jdolecek 	for (i = 0; i < AWGE_TX_RING_COUNT; i++) {
    698  1.43.2.2  jdolecek 		struct dwc_gmac_tx_data *data = &ring->t_data[i];
    699  1.43.2.2  jdolecek 
    700  1.43.2.2  jdolecek 		bus_dmamap_destroy(sc->sc_dmat, data->td_map);
    701  1.43.2.2  jdolecek 	}
    702  1.43.2.2  jdolecek }
    703  1.43.2.2  jdolecek 
    704  1.43.2.2  jdolecek static void
    705  1.43.2.2  jdolecek dwc_gmac_miibus_statchg(struct ifnet *ifp)
    706  1.43.2.2  jdolecek {
    707  1.43.2.2  jdolecek 	struct dwc_gmac_softc * const sc = ifp->if_softc;
    708  1.43.2.2  jdolecek 	struct mii_data * const mii = &sc->sc_mii;
    709  1.43.2.2  jdolecek 	uint32_t conf, flow;
    710  1.43.2.2  jdolecek 
    711  1.43.2.2  jdolecek 	/*
    712  1.43.2.2  jdolecek 	 * Set MII or GMII interface based on the speed
    713  1.43.2.2  jdolecek 	 * negotiated by the PHY.
    714  1.43.2.2  jdolecek 	 */
    715  1.43.2.2  jdolecek 	conf = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_CONF);
    716  1.43.2.2  jdolecek 	conf &= ~(AWIN_GMAC_MAC_CONF_FES100|AWIN_GMAC_MAC_CONF_MIISEL
    717  1.43.2.2  jdolecek 	    |AWIN_GMAC_MAC_CONF_FULLDPLX);
    718  1.43.2.2  jdolecek 	conf |= AWIN_GMAC_MAC_CONF_FRAMEBURST
    719  1.43.2.2  jdolecek 	    | AWIN_GMAC_MAC_CONF_DISABLERXOWN
    720  1.43.2.2  jdolecek 	    | AWIN_GMAC_MAC_CONF_DISABLEJABBER
    721  1.43.2.2  jdolecek 	    | AWIN_GMAC_MAC_CONF_ACS
    722  1.43.2.2  jdolecek 	    | AWIN_GMAC_MAC_CONF_RXENABLE
    723  1.43.2.2  jdolecek 	    | AWIN_GMAC_MAC_CONF_TXENABLE;
    724  1.43.2.2  jdolecek 	switch (IFM_SUBTYPE(mii->mii_media_active)) {
    725  1.43.2.2  jdolecek 	case IFM_10_T:
    726  1.43.2.2  jdolecek 		conf |= AWIN_GMAC_MAC_CONF_MIISEL;
    727  1.43.2.2  jdolecek 		break;
    728  1.43.2.2  jdolecek 	case IFM_100_TX:
    729  1.43.2.2  jdolecek 		conf |= AWIN_GMAC_MAC_CONF_FES100 |
    730  1.43.2.2  jdolecek 			AWIN_GMAC_MAC_CONF_MIISEL;
    731  1.43.2.2  jdolecek 		break;
    732  1.43.2.2  jdolecek 	case IFM_1000_T:
    733  1.43.2.2  jdolecek 		break;
    734  1.43.2.2  jdolecek 	}
    735  1.43.2.2  jdolecek 
    736  1.43.2.2  jdolecek 	flow = 0;
    737  1.43.2.2  jdolecek 	if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) {
    738  1.43.2.2  jdolecek 		conf |= AWIN_GMAC_MAC_CONF_FULLDPLX;
    739  1.43.2.2  jdolecek 		flow |= __SHIFTIN(0x200, AWIN_GMAC_MAC_FLOWCTRL_PAUSE);
    740  1.43.2.2  jdolecek 	}
    741  1.43.2.2  jdolecek 	if (mii->mii_media_active & IFM_ETH_TXPAUSE) {
    742  1.43.2.2  jdolecek 		flow |= AWIN_GMAC_MAC_FLOWCTRL_TFE;
    743  1.43.2.2  jdolecek 	}
    744  1.43.2.2  jdolecek 	if (mii->mii_media_active & IFM_ETH_RXPAUSE) {
    745  1.43.2.2  jdolecek 		flow |= AWIN_GMAC_MAC_FLOWCTRL_RFE;
    746  1.43.2.2  jdolecek 	}
    747  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh,
    748  1.43.2.2  jdolecek 	    AWIN_GMAC_MAC_FLOWCTRL, flow);
    749  1.43.2.2  jdolecek 
    750  1.43.2.2  jdolecek #ifdef DWC_GMAC_DEBUG
    751  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev,
    752  1.43.2.2  jdolecek 	    "setting MAC conf register: %08x\n", conf);
    753  1.43.2.2  jdolecek #endif
    754  1.43.2.2  jdolecek 
    755  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh,
    756  1.43.2.2  jdolecek 	    AWIN_GMAC_MAC_CONF, conf);
    757  1.43.2.2  jdolecek }
    758  1.43.2.2  jdolecek 
    759  1.43.2.2  jdolecek static int
    760  1.43.2.2  jdolecek dwc_gmac_init(struct ifnet *ifp)
    761  1.43.2.2  jdolecek {
    762  1.43.2.2  jdolecek 	struct dwc_gmac_softc *sc = ifp->if_softc;
    763  1.43.2.2  jdolecek 
    764  1.43.2.2  jdolecek 	mutex_enter(sc->sc_lock);
    765  1.43.2.2  jdolecek 	int ret = dwc_gmac_init_locked(ifp);
    766  1.43.2.2  jdolecek 	mutex_exit(sc->sc_lock);
    767  1.43.2.2  jdolecek 
    768  1.43.2.2  jdolecek 	return ret;
    769  1.43.2.2  jdolecek }
    770  1.43.2.2  jdolecek 
    771  1.43.2.2  jdolecek static int
    772  1.43.2.2  jdolecek dwc_gmac_init_locked(struct ifnet *ifp)
    773  1.43.2.2  jdolecek {
    774  1.43.2.2  jdolecek 	struct dwc_gmac_softc *sc = ifp->if_softc;
    775  1.43.2.2  jdolecek 	uint32_t ffilt;
    776  1.43.2.2  jdolecek 
    777  1.43.2.2  jdolecek 	if (ifp->if_flags & IFF_RUNNING)
    778  1.43.2.2  jdolecek 		return 0;
    779  1.43.2.2  jdolecek 
    780  1.43.2.2  jdolecek 	dwc_gmac_stop_locked(ifp, 0);
    781  1.43.2.2  jdolecek 
    782  1.43.2.2  jdolecek 	/*
    783  1.43.2.2  jdolecek 	 * Configure DMA burst/transfer mode and RX/TX priorities.
    784  1.43.2.2  jdolecek 	 * XXX - the GMAC_BUSMODE_PRIORXTX bits are undocumented.
    785  1.43.2.2  jdolecek 	 */
    786  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE,
    787  1.43.2.2  jdolecek 	    GMAC_BUSMODE_FIXEDBURST | GMAC_BUSMODE_4PBL |
    788  1.43.2.2  jdolecek 	    __SHIFTIN(2, GMAC_BUSMODE_RPBL) |
    789  1.43.2.2  jdolecek 	    __SHIFTIN(2, GMAC_BUSMODE_PBL));
    790  1.43.2.2  jdolecek 
    791  1.43.2.2  jdolecek 	/*
    792  1.43.2.2  jdolecek 	 * Set up address filter
    793  1.43.2.2  jdolecek 	 */
    794  1.43.2.2  jdolecek 	ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT);
    795  1.43.2.2  jdolecek 	if (ifp->if_flags & IFF_PROMISC) {
    796  1.43.2.2  jdolecek 		ffilt |= AWIN_GMAC_MAC_FFILT_PR;
    797  1.43.2.2  jdolecek 	} else {
    798  1.43.2.2  jdolecek 		ffilt &= ~AWIN_GMAC_MAC_FFILT_PR;
    799  1.43.2.2  jdolecek 	}
    800  1.43.2.2  jdolecek 	if (ifp->if_flags & IFF_BROADCAST) {
    801  1.43.2.2  jdolecek 		ffilt &= ~AWIN_GMAC_MAC_FFILT_DBF;
    802  1.43.2.2  jdolecek 	} else {
    803  1.43.2.2  jdolecek 		ffilt |= AWIN_GMAC_MAC_FFILT_DBF;
    804  1.43.2.2  jdolecek 	}
    805  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, ffilt);
    806  1.43.2.2  jdolecek 
    807  1.43.2.2  jdolecek 	/*
    808  1.43.2.2  jdolecek 	 * Set up multicast filter
    809  1.43.2.2  jdolecek 	 */
    810  1.43.2.2  jdolecek 	dwc_gmac_setmulti(sc);
    811  1.43.2.2  jdolecek 
    812  1.43.2.2  jdolecek 	/*
    813  1.43.2.2  jdolecek 	 * Set up dma pointer for RX and TX ring
    814  1.43.2.2  jdolecek 	 */
    815  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR,
    816  1.43.2.2  jdolecek 	    sc->sc_rxq.r_physaddr);
    817  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR,
    818  1.43.2.2  jdolecek 	    sc->sc_txq.t_physaddr);
    819  1.43.2.2  jdolecek 
    820  1.43.2.2  jdolecek 	/*
    821  1.43.2.2  jdolecek 	 * Start RX/TX part
    822  1.43.2.2  jdolecek 	 */
    823  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh,
    824  1.43.2.2  jdolecek 	    AWIN_GMAC_DMA_OPMODE, GMAC_DMA_OP_RXSTART | GMAC_DMA_OP_TXSTART |
    825  1.43.2.2  jdolecek 	    GMAC_DMA_OP_RXSTOREFORWARD | GMAC_DMA_OP_TXSTOREFORWARD);
    826  1.43.2.2  jdolecek 
    827  1.43.2.2  jdolecek 	sc->sc_stopping = false;
    828  1.43.2.2  jdolecek 
    829  1.43.2.2  jdolecek 	ifp->if_flags |= IFF_RUNNING;
    830  1.43.2.2  jdolecek 	ifp->if_flags &= ~IFF_OACTIVE;
    831  1.43.2.2  jdolecek 
    832  1.43.2.2  jdolecek 	return 0;
    833  1.43.2.2  jdolecek }
    834  1.43.2.2  jdolecek 
    835  1.43.2.2  jdolecek static void
    836  1.43.2.2  jdolecek dwc_gmac_start(struct ifnet *ifp)
    837  1.43.2.2  jdolecek {
    838  1.43.2.2  jdolecek 	struct dwc_gmac_softc *sc = ifp->if_softc;
    839  1.43.2.2  jdolecek 	KASSERT(if_is_mpsafe(ifp));
    840  1.43.2.2  jdolecek 
    841  1.43.2.2  jdolecek 	mutex_enter(sc->sc_lock);
    842  1.43.2.2  jdolecek 	if (!sc->sc_stopping) {
    843  1.43.2.2  jdolecek 		mutex_enter(&sc->sc_txq.t_mtx);
    844  1.43.2.2  jdolecek 		dwc_gmac_start_locked(ifp);
    845  1.43.2.2  jdolecek 		mutex_exit(&sc->sc_txq.t_mtx);
    846  1.43.2.2  jdolecek 	}
    847  1.43.2.2  jdolecek 	mutex_exit(sc->sc_lock);
    848  1.43.2.2  jdolecek }
    849  1.43.2.2  jdolecek 
    850  1.43.2.2  jdolecek static void
    851  1.43.2.2  jdolecek dwc_gmac_start_locked(struct ifnet *ifp)
    852  1.43.2.2  jdolecek {
    853  1.43.2.2  jdolecek 	struct dwc_gmac_softc *sc = ifp->if_softc;
    854  1.43.2.2  jdolecek 	int old = sc->sc_txq.t_queued;
    855  1.43.2.2  jdolecek 	int start = sc->sc_txq.t_cur;
    856  1.43.2.2  jdolecek 	struct mbuf *m0;
    857  1.43.2.2  jdolecek 
    858  1.43.2.2  jdolecek 	if ((ifp->if_flags & (IFF_RUNNING | IFF_OACTIVE)) != IFF_RUNNING)
    859  1.43.2.2  jdolecek 		return;
    860  1.43.2.2  jdolecek 
    861  1.43.2.2  jdolecek 	for (;;) {
    862  1.43.2.2  jdolecek 		IFQ_POLL(&ifp->if_snd, m0);
    863  1.43.2.2  jdolecek 		if (m0 == NULL)
    864  1.43.2.2  jdolecek 			break;
    865  1.43.2.2  jdolecek 		if (dwc_gmac_queue(sc, m0) != 0) {
    866  1.43.2.2  jdolecek 			ifp->if_flags |= IFF_OACTIVE;
    867  1.43.2.2  jdolecek 			break;
    868  1.43.2.2  jdolecek 		}
    869  1.43.2.2  jdolecek 		IFQ_DEQUEUE(&ifp->if_snd, m0);
    870  1.43.2.2  jdolecek 		bpf_mtap(ifp, m0);
    871  1.43.2.2  jdolecek 		if (sc->sc_txq.t_queued == AWGE_TX_RING_COUNT) {
    872  1.43.2.2  jdolecek 			ifp->if_flags |= IFF_OACTIVE;
    873  1.43.2.2  jdolecek 			break;
    874  1.43.2.2  jdolecek 		}
    875  1.43.2.2  jdolecek 	}
    876  1.43.2.2  jdolecek 
    877  1.43.2.2  jdolecek 	if (sc->sc_txq.t_queued != old) {
    878  1.43.2.2  jdolecek 		/* packets have been queued, kick it off */
    879  1.43.2.2  jdolecek 		dwc_gmac_txdesc_sync(sc, start, sc->sc_txq.t_cur,
    880  1.43.2.2  jdolecek 		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
    881  1.43.2.2  jdolecek 
    882  1.43.2.2  jdolecek 		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
    883  1.43.2.2  jdolecek 		    AWIN_GMAC_DMA_TXPOLL, ~0U);
    884  1.43.2.2  jdolecek #ifdef DWC_GMAC_DEBUG
    885  1.43.2.2  jdolecek 		dwc_dump_status(sc);
    886  1.43.2.2  jdolecek #endif
    887  1.43.2.2  jdolecek 	}
    888  1.43.2.2  jdolecek }
    889  1.43.2.2  jdolecek 
    890  1.43.2.2  jdolecek static void
    891  1.43.2.2  jdolecek dwc_gmac_stop(struct ifnet *ifp, int disable)
    892  1.43.2.2  jdolecek {
    893  1.43.2.2  jdolecek 	struct dwc_gmac_softc *sc = ifp->if_softc;
    894  1.43.2.2  jdolecek 
    895  1.43.2.2  jdolecek 	mutex_enter(sc->sc_lock);
    896  1.43.2.2  jdolecek 	dwc_gmac_stop_locked(ifp, disable);
    897  1.43.2.2  jdolecek 	mutex_exit(sc->sc_lock);
    898  1.43.2.2  jdolecek }
    899  1.43.2.2  jdolecek 
    900  1.43.2.2  jdolecek static void
    901  1.43.2.2  jdolecek dwc_gmac_stop_locked(struct ifnet *ifp, int disable)
    902  1.43.2.2  jdolecek {
    903  1.43.2.2  jdolecek 	struct dwc_gmac_softc *sc = ifp->if_softc;
    904  1.43.2.2  jdolecek 
    905  1.43.2.2  jdolecek 	sc->sc_stopping = true;
    906  1.43.2.2  jdolecek 
    907  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh,
    908  1.43.2.2  jdolecek 	    AWIN_GMAC_DMA_OPMODE,
    909  1.43.2.2  jdolecek 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh,
    910  1.43.2.2  jdolecek 	        AWIN_GMAC_DMA_OPMODE)
    911  1.43.2.2  jdolecek 		& ~(GMAC_DMA_OP_TXSTART|GMAC_DMA_OP_RXSTART));
    912  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh,
    913  1.43.2.2  jdolecek 	    AWIN_GMAC_DMA_OPMODE,
    914  1.43.2.2  jdolecek 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh,
    915  1.43.2.2  jdolecek 	        AWIN_GMAC_DMA_OPMODE) | GMAC_DMA_OP_FLUSHTX);
    916  1.43.2.2  jdolecek 
    917  1.43.2.2  jdolecek 	mii_down(&sc->sc_mii);
    918  1.43.2.2  jdolecek 	dwc_gmac_reset_tx_ring(sc, &sc->sc_txq);
    919  1.43.2.2  jdolecek 	dwc_gmac_reset_rx_ring(sc, &sc->sc_rxq);
    920  1.43.2.2  jdolecek }
    921  1.43.2.2  jdolecek 
    922  1.43.2.2  jdolecek /*
    923  1.43.2.2  jdolecek  * Add m0 to the TX ring
    924  1.43.2.2  jdolecek  */
    925  1.43.2.2  jdolecek static int
    926  1.43.2.2  jdolecek dwc_gmac_queue(struct dwc_gmac_softc *sc, struct mbuf *m0)
    927  1.43.2.2  jdolecek {
    928  1.43.2.2  jdolecek 	struct dwc_gmac_dev_dmadesc *desc = NULL;
    929  1.43.2.2  jdolecek 	struct dwc_gmac_tx_data *data = NULL;
    930  1.43.2.2  jdolecek 	bus_dmamap_t map;
    931  1.43.2.2  jdolecek 	uint32_t flags, len, status;
    932  1.43.2.2  jdolecek 	int error, i, first;
    933  1.43.2.2  jdolecek 
    934  1.43.2.2  jdolecek #ifdef DWC_GMAC_DEBUG
    935  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev,
    936  1.43.2.2  jdolecek 	    "dwc_gmac_queue: adding mbuf chain %p\n", m0);
    937  1.43.2.2  jdolecek #endif
    938  1.43.2.2  jdolecek 
    939  1.43.2.2  jdolecek 	first = sc->sc_txq.t_cur;
    940  1.43.2.2  jdolecek 	map = sc->sc_txq.t_data[first].td_map;
    941  1.43.2.2  jdolecek 
    942  1.43.2.2  jdolecek 	error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m0,
    943  1.43.2.2  jdolecek 	    BUS_DMA_WRITE|BUS_DMA_NOWAIT);
    944  1.43.2.2  jdolecek 	if (error != 0) {
    945  1.43.2.2  jdolecek 		aprint_error_dev(sc->sc_dev, "could not map mbuf "
    946  1.43.2.2  jdolecek 		    "(len: %d, error %d)\n", m0->m_pkthdr.len, error);
    947  1.43.2.2  jdolecek 		return error;
    948  1.43.2.2  jdolecek 	}
    949  1.43.2.2  jdolecek 
    950  1.43.2.2  jdolecek 	if (sc->sc_txq.t_queued + map->dm_nsegs > AWGE_TX_RING_COUNT) {
    951  1.43.2.2  jdolecek 		bus_dmamap_unload(sc->sc_dmat, map);
    952  1.43.2.2  jdolecek 		return ENOBUFS;
    953  1.43.2.2  jdolecek 	}
    954  1.43.2.2  jdolecek 
    955  1.43.2.2  jdolecek 	flags = DDESC_CNTL_TXFIRST|DDESC_CNTL_TXCHAIN;
    956  1.43.2.2  jdolecek 	status = 0;
    957  1.43.2.2  jdolecek 	for (i = 0; i < map->dm_nsegs; i++) {
    958  1.43.2.2  jdolecek 		data = &sc->sc_txq.t_data[sc->sc_txq.t_cur];
    959  1.43.2.2  jdolecek 		desc = &sc->sc_txq.t_desc[sc->sc_txq.t_cur];
    960  1.43.2.2  jdolecek 
    961  1.43.2.2  jdolecek 		desc->ddesc_data = htole32(map->dm_segs[i].ds_addr);
    962  1.43.2.2  jdolecek 		len = __SHIFTIN(map->dm_segs[i].ds_len, DDESC_CNTL_SIZE1MASK);
    963  1.43.2.2  jdolecek 
    964  1.43.2.2  jdolecek #ifdef DWC_GMAC_DEBUG
    965  1.43.2.2  jdolecek 		aprint_normal_dev(sc->sc_dev, "enqueing desc #%d data %08lx "
    966  1.43.2.2  jdolecek 		    "len %lu (flags: %08x, len: %08x)\n", sc->sc_txq.t_cur,
    967  1.43.2.2  jdolecek 		    (unsigned long)map->dm_segs[i].ds_addr,
    968  1.43.2.2  jdolecek 		    (unsigned long)map->dm_segs[i].ds_len,
    969  1.43.2.2  jdolecek 		    flags, len);
    970  1.43.2.2  jdolecek #endif
    971  1.43.2.2  jdolecek 
    972  1.43.2.2  jdolecek 		desc->ddesc_cntl = htole32(len|flags);
    973  1.43.2.2  jdolecek 		flags &= ~DDESC_CNTL_TXFIRST;
    974  1.43.2.2  jdolecek 
    975  1.43.2.2  jdolecek 		/*
    976  1.43.2.2  jdolecek 		 * Defer passing ownership of the first descriptor
    977  1.43.2.2  jdolecek 		 * until we are done.
    978  1.43.2.2  jdolecek 		 */
    979  1.43.2.2  jdolecek 		desc->ddesc_status = htole32(status);
    980  1.43.2.2  jdolecek 		status |= DDESC_STATUS_OWNEDBYDEV;
    981  1.43.2.2  jdolecek 
    982  1.43.2.2  jdolecek 		sc->sc_txq.t_queued++;
    983  1.43.2.2  jdolecek 		sc->sc_txq.t_cur = TX_NEXT(sc->sc_txq.t_cur);
    984  1.43.2.2  jdolecek 	}
    985  1.43.2.2  jdolecek 
    986  1.43.2.2  jdolecek 	desc->ddesc_cntl |= htole32(DDESC_CNTL_TXLAST|DDESC_CNTL_TXINT);
    987  1.43.2.2  jdolecek 
    988  1.43.2.2  jdolecek 	data->td_m = m0;
    989  1.43.2.2  jdolecek 	data->td_active = map;
    990  1.43.2.2  jdolecek 
    991  1.43.2.2  jdolecek 	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
    992  1.43.2.2  jdolecek 	    BUS_DMASYNC_PREWRITE);
    993  1.43.2.2  jdolecek 
    994  1.43.2.2  jdolecek 	/* Pass first to device */
    995  1.43.2.2  jdolecek 	sc->sc_txq.t_desc[first].ddesc_status =
    996  1.43.2.2  jdolecek 	    htole32(DDESC_STATUS_OWNEDBYDEV);
    997  1.43.2.2  jdolecek 
    998  1.43.2.2  jdolecek 	return 0;
    999  1.43.2.2  jdolecek }
   1000  1.43.2.2  jdolecek 
   1001  1.43.2.2  jdolecek /*
   1002  1.43.2.2  jdolecek  * If the interface is up and running, only modify the receive
   1003  1.43.2.2  jdolecek  * filter when setting promiscuous or debug mode.  Otherwise fall
   1004  1.43.2.2  jdolecek  * through to ether_ioctl, which will reset the chip.
   1005  1.43.2.2  jdolecek  */
   1006  1.43.2.2  jdolecek static int
   1007  1.43.2.2  jdolecek dwc_gmac_ifflags_cb(struct ethercom *ec)
   1008  1.43.2.2  jdolecek {
   1009  1.43.2.2  jdolecek 	struct ifnet *ifp = &ec->ec_if;
   1010  1.43.2.2  jdolecek 	struct dwc_gmac_softc *sc = ifp->if_softc;
   1011  1.43.2.2  jdolecek 	int ret = 0;
   1012  1.43.2.2  jdolecek 
   1013  1.43.2.2  jdolecek 	mutex_enter(sc->sc_lock);
   1014  1.43.2.2  jdolecek 	int change = ifp->if_flags ^ sc->sc_if_flags;
   1015  1.43.2.2  jdolecek 	sc->sc_if_flags = ifp->if_flags;
   1016  1.43.2.2  jdolecek 
   1017  1.43.2.2  jdolecek 	if ((change & ~(IFF_CANTCHANGE|IFF_DEBUG)) != 0) {
   1018  1.43.2.2  jdolecek 		ret = ENETRESET;
   1019  1.43.2.2  jdolecek 		goto out;
   1020  1.43.2.2  jdolecek 	}
   1021  1.43.2.2  jdolecek 	if ((change & IFF_PROMISC) != 0) {
   1022  1.43.2.2  jdolecek 		dwc_gmac_setmulti(sc);
   1023  1.43.2.2  jdolecek 	}
   1024  1.43.2.2  jdolecek out:
   1025  1.43.2.2  jdolecek 	mutex_exit(sc->sc_lock);
   1026  1.43.2.2  jdolecek 
   1027  1.43.2.2  jdolecek 	return ret;
   1028  1.43.2.2  jdolecek }
   1029  1.43.2.2  jdolecek 
   1030  1.43.2.2  jdolecek static int
   1031  1.43.2.2  jdolecek dwc_gmac_ioctl(struct ifnet *ifp, u_long cmd, void *data)
   1032  1.43.2.2  jdolecek {
   1033  1.43.2.2  jdolecek 	struct dwc_gmac_softc *sc = ifp->if_softc;
   1034  1.43.2.2  jdolecek 	int error = 0;
   1035  1.43.2.2  jdolecek 
   1036  1.43.2.2  jdolecek 	int s = splnet();
   1037  1.43.2.2  jdolecek 	error = ether_ioctl(ifp, cmd, data);
   1038  1.43.2.2  jdolecek 
   1039  1.43.2.2  jdolecek #ifdef DWCGMAC_MPSAFE
   1040  1.43.2.2  jdolecek 	splx(s);
   1041  1.43.2.2  jdolecek #endif
   1042  1.43.2.2  jdolecek 
   1043  1.43.2.2  jdolecek 	if (error == ENETRESET) {
   1044  1.43.2.2  jdolecek 		error = 0;
   1045  1.43.2.2  jdolecek 		if (cmd != SIOCADDMULTI && cmd != SIOCDELMULTI)
   1046  1.43.2.2  jdolecek 			;
   1047  1.43.2.2  jdolecek 		else if (ifp->if_flags & IFF_RUNNING) {
   1048  1.43.2.2  jdolecek 			/*
   1049  1.43.2.2  jdolecek 			 * Multicast list has changed; set the hardware filter
   1050  1.43.2.2  jdolecek 			 * accordingly.
   1051  1.43.2.2  jdolecek 			 */
   1052  1.43.2.2  jdolecek 			mutex_enter(sc->sc_lock);
   1053  1.43.2.2  jdolecek 			dwc_gmac_setmulti(sc);
   1054  1.43.2.2  jdolecek 			mutex_exit(sc->sc_lock);
   1055  1.43.2.2  jdolecek 		}
   1056  1.43.2.2  jdolecek 	}
   1057  1.43.2.2  jdolecek 
   1058  1.43.2.2  jdolecek 	/* Try to get things going again */
   1059  1.43.2.2  jdolecek 	if (ifp->if_flags & IFF_UP)
   1060  1.43.2.2  jdolecek 		dwc_gmac_start(ifp);
   1061  1.43.2.2  jdolecek 	sc->sc_if_flags = sc->sc_ec.ec_if.if_flags;
   1062  1.43.2.2  jdolecek 
   1063  1.43.2.2  jdolecek #ifndef DWCGMAC_MPSAFE
   1064  1.43.2.2  jdolecek 	splx(s);
   1065  1.43.2.2  jdolecek #endif
   1066  1.43.2.2  jdolecek 
   1067  1.43.2.2  jdolecek 	return error;
   1068  1.43.2.2  jdolecek }
   1069  1.43.2.2  jdolecek 
   1070  1.43.2.2  jdolecek static void
   1071  1.43.2.2  jdolecek dwc_gmac_tx_intr(struct dwc_gmac_softc *sc)
   1072  1.43.2.2  jdolecek {
   1073  1.43.2.2  jdolecek 	struct ifnet *ifp = &sc->sc_ec.ec_if;
   1074  1.43.2.2  jdolecek 	struct dwc_gmac_tx_data *data;
   1075  1.43.2.2  jdolecek 	struct dwc_gmac_dev_dmadesc *desc;
   1076  1.43.2.2  jdolecek 	uint32_t status;
   1077  1.43.2.2  jdolecek 	int i, nsegs;
   1078  1.43.2.2  jdolecek 
   1079  1.43.2.2  jdolecek 	mutex_enter(&sc->sc_txq.t_mtx);
   1080  1.43.2.2  jdolecek 
   1081  1.43.2.2  jdolecek 	for (i = sc->sc_txq.t_next; sc->sc_txq.t_queued > 0; i = TX_NEXT(i)) {
   1082  1.43.2.2  jdolecek #ifdef DWC_GMAC_DEBUG
   1083  1.43.2.2  jdolecek 		aprint_normal_dev(sc->sc_dev,
   1084  1.43.2.2  jdolecek 		    "dwc_gmac_tx_intr: checking desc #%d (t_queued: %d)\n",
   1085  1.43.2.2  jdolecek 		    i, sc->sc_txq.t_queued);
   1086  1.43.2.2  jdolecek #endif
   1087  1.43.2.2  jdolecek 
   1088  1.43.2.2  jdolecek 		/*
   1089  1.43.2.2  jdolecek 		 * i+1 does not need to be a valid descriptor,
   1090  1.43.2.2  jdolecek 		 * this is just a special notion to just sync
   1091  1.43.2.2  jdolecek 		 * a single tx descriptor (i)
   1092  1.43.2.2  jdolecek 		 */
   1093  1.43.2.2  jdolecek 		dwc_gmac_txdesc_sync(sc, i, i+1,
   1094  1.43.2.2  jdolecek 		    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
   1095  1.43.2.2  jdolecek 
   1096  1.43.2.2  jdolecek 		desc = &sc->sc_txq.t_desc[i];
   1097  1.43.2.2  jdolecek 		status = le32toh(desc->ddesc_status);
   1098  1.43.2.2  jdolecek 		if (status & DDESC_STATUS_OWNEDBYDEV)
   1099  1.43.2.2  jdolecek 			break;
   1100  1.43.2.2  jdolecek 
   1101  1.43.2.2  jdolecek 		data = &sc->sc_txq.t_data[i];
   1102  1.43.2.2  jdolecek 		if (data->td_m == NULL)
   1103  1.43.2.2  jdolecek 			continue;
   1104  1.43.2.2  jdolecek 
   1105  1.43.2.2  jdolecek 		ifp->if_opackets++;
   1106  1.43.2.2  jdolecek 		nsegs = data->td_active->dm_nsegs;
   1107  1.43.2.2  jdolecek 		bus_dmamap_sync(sc->sc_dmat, data->td_active, 0,
   1108  1.43.2.2  jdolecek 		    data->td_active->dm_mapsize, BUS_DMASYNC_POSTWRITE);
   1109  1.43.2.2  jdolecek 		bus_dmamap_unload(sc->sc_dmat, data->td_active);
   1110  1.43.2.2  jdolecek 
   1111  1.43.2.2  jdolecek #ifdef DWC_GMAC_DEBUG
   1112  1.43.2.2  jdolecek 		aprint_normal_dev(sc->sc_dev,
   1113  1.43.2.2  jdolecek 		    "dwc_gmac_tx_intr: done with packet at desc #%d, "
   1114  1.43.2.2  jdolecek 		    "freeing mbuf %p\n", i, data->td_m);
   1115  1.43.2.2  jdolecek #endif
   1116  1.43.2.2  jdolecek 
   1117  1.43.2.2  jdolecek 		m_freem(data->td_m);
   1118  1.43.2.2  jdolecek 		data->td_m = NULL;
   1119  1.43.2.2  jdolecek 
   1120  1.43.2.2  jdolecek 		sc->sc_txq.t_queued -= nsegs;
   1121  1.43.2.2  jdolecek 	}
   1122  1.43.2.2  jdolecek 
   1123  1.43.2.2  jdolecek 	sc->sc_txq.t_next = i;
   1124  1.43.2.2  jdolecek 
   1125  1.43.2.2  jdolecek 	if (sc->sc_txq.t_queued < AWGE_TX_RING_COUNT) {
   1126  1.43.2.2  jdolecek 		ifp->if_flags &= ~IFF_OACTIVE;
   1127  1.43.2.2  jdolecek 	}
   1128  1.43.2.2  jdolecek 	mutex_exit(&sc->sc_txq.t_mtx);
   1129  1.43.2.2  jdolecek }
   1130  1.43.2.2  jdolecek 
   1131  1.43.2.2  jdolecek static void
   1132  1.43.2.2  jdolecek dwc_gmac_rx_intr(struct dwc_gmac_softc *sc)
   1133  1.43.2.2  jdolecek {
   1134  1.43.2.2  jdolecek 	struct ifnet *ifp = &sc->sc_ec.ec_if;
   1135  1.43.2.2  jdolecek 	struct dwc_gmac_dev_dmadesc *desc;
   1136  1.43.2.2  jdolecek 	struct dwc_gmac_rx_data *data;
   1137  1.43.2.2  jdolecek 	bus_addr_t physaddr;
   1138  1.43.2.2  jdolecek 	uint32_t status;
   1139  1.43.2.2  jdolecek 	struct mbuf *m, *mnew;
   1140  1.43.2.2  jdolecek 	int i, len, error;
   1141  1.43.2.2  jdolecek 
   1142  1.43.2.2  jdolecek 	mutex_enter(&sc->sc_rxq.r_mtx);
   1143  1.43.2.2  jdolecek 	for (i = sc->sc_rxq.r_cur; ; i = RX_NEXT(i)) {
   1144  1.43.2.2  jdolecek 		bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
   1145  1.43.2.2  jdolecek 		    RX_DESC_OFFSET(i), sizeof(*desc),
   1146  1.43.2.2  jdolecek 		    BUS_DMASYNC_POSTREAD|BUS_DMASYNC_POSTWRITE);
   1147  1.43.2.2  jdolecek 		desc = &sc->sc_rxq.r_desc[i];
   1148  1.43.2.2  jdolecek 		data = &sc->sc_rxq.r_data[i];
   1149  1.43.2.2  jdolecek 
   1150  1.43.2.2  jdolecek 		status = le32toh(desc->ddesc_status);
   1151  1.43.2.2  jdolecek 		if (status & DDESC_STATUS_OWNEDBYDEV)
   1152  1.43.2.2  jdolecek 			break;
   1153  1.43.2.2  jdolecek 
   1154  1.43.2.2  jdolecek 		if (status & (DDESC_STATUS_RXERROR|DDESC_STATUS_RXTRUNCATED)) {
   1155  1.43.2.2  jdolecek #ifdef DWC_GMAC_DEBUG
   1156  1.43.2.2  jdolecek 			aprint_normal_dev(sc->sc_dev,
   1157  1.43.2.2  jdolecek 			    "RX error: descriptor status %08x, skipping\n",
   1158  1.43.2.2  jdolecek 			    status);
   1159  1.43.2.2  jdolecek #endif
   1160  1.43.2.2  jdolecek 			ifp->if_ierrors++;
   1161  1.43.2.2  jdolecek 			goto skip;
   1162  1.43.2.2  jdolecek 		}
   1163  1.43.2.2  jdolecek 
   1164  1.43.2.2  jdolecek 		len = __SHIFTOUT(status, DDESC_STATUS_FRMLENMSK);
   1165  1.43.2.2  jdolecek 
   1166  1.43.2.2  jdolecek #ifdef DWC_GMAC_DEBUG
   1167  1.43.2.2  jdolecek 		aprint_normal_dev(sc->sc_dev,
   1168  1.43.2.2  jdolecek 		    "rx int: device is done with descriptor #%d, len: %d\n",
   1169  1.43.2.2  jdolecek 		    i, len);
   1170  1.43.2.2  jdolecek #endif
   1171  1.43.2.2  jdolecek 
   1172  1.43.2.2  jdolecek 		/*
   1173  1.43.2.2  jdolecek 		 * Try to get a new mbuf before passing this one
   1174  1.43.2.2  jdolecek 		 * up, if that fails, drop the packet and reuse
   1175  1.43.2.2  jdolecek 		 * the existing one.
   1176  1.43.2.2  jdolecek 		 */
   1177  1.43.2.2  jdolecek 		MGETHDR(mnew, M_DONTWAIT, MT_DATA);
   1178  1.43.2.2  jdolecek 		if (mnew == NULL) {
   1179  1.43.2.2  jdolecek 			ifp->if_ierrors++;
   1180  1.43.2.2  jdolecek 			goto skip;
   1181  1.43.2.2  jdolecek 		}
   1182  1.43.2.2  jdolecek 		MCLGET(mnew, M_DONTWAIT);
   1183  1.43.2.2  jdolecek 		if ((mnew->m_flags & M_EXT) == 0) {
   1184  1.43.2.2  jdolecek 			m_freem(mnew);
   1185  1.43.2.2  jdolecek 			ifp->if_ierrors++;
   1186  1.43.2.2  jdolecek 			goto skip;
   1187  1.43.2.2  jdolecek 		}
   1188  1.43.2.2  jdolecek 
   1189  1.43.2.2  jdolecek 		/* unload old DMA map */
   1190  1.43.2.2  jdolecek 		bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0,
   1191  1.43.2.2  jdolecek 		    data->rd_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
   1192  1.43.2.2  jdolecek 		bus_dmamap_unload(sc->sc_dmat, data->rd_map);
   1193  1.43.2.2  jdolecek 
   1194  1.43.2.2  jdolecek 		/* and reload with new mbuf */
   1195  1.43.2.2  jdolecek 		error = bus_dmamap_load(sc->sc_dmat, data->rd_map,
   1196  1.43.2.2  jdolecek 		    mtod(mnew, void*), MCLBYTES, NULL,
   1197  1.43.2.2  jdolecek 		    BUS_DMA_READ | BUS_DMA_NOWAIT);
   1198  1.43.2.2  jdolecek 		if (error != 0) {
   1199  1.43.2.2  jdolecek 			m_freem(mnew);
   1200  1.43.2.2  jdolecek 			/* try to reload old mbuf */
   1201  1.43.2.2  jdolecek 			error = bus_dmamap_load(sc->sc_dmat, data->rd_map,
   1202  1.43.2.2  jdolecek 			    mtod(data->rd_m, void*), MCLBYTES, NULL,
   1203  1.43.2.2  jdolecek 			    BUS_DMA_READ | BUS_DMA_NOWAIT);
   1204  1.43.2.2  jdolecek 			if (error != 0) {
   1205  1.43.2.2  jdolecek 				panic("%s: could not load old rx mbuf",
   1206  1.43.2.2  jdolecek 				    device_xname(sc->sc_dev));
   1207  1.43.2.2  jdolecek 			}
   1208  1.43.2.2  jdolecek 			ifp->if_ierrors++;
   1209  1.43.2.2  jdolecek 			goto skip;
   1210  1.43.2.2  jdolecek 		}
   1211  1.43.2.2  jdolecek 		physaddr = data->rd_map->dm_segs[0].ds_addr;
   1212  1.43.2.2  jdolecek 
   1213  1.43.2.2  jdolecek 		/*
   1214  1.43.2.2  jdolecek 		 * New mbuf loaded, update RX ring and continue
   1215  1.43.2.2  jdolecek 		 */
   1216  1.43.2.2  jdolecek 		m = data->rd_m;
   1217  1.43.2.2  jdolecek 		data->rd_m = mnew;
   1218  1.43.2.2  jdolecek 		desc->ddesc_data = htole32(physaddr);
   1219  1.43.2.2  jdolecek 
   1220  1.43.2.2  jdolecek 		/* finalize mbuf */
   1221  1.43.2.2  jdolecek 		m->m_pkthdr.len = m->m_len = len;
   1222  1.43.2.2  jdolecek 		m_set_rcvif(m, ifp);
   1223  1.43.2.2  jdolecek 		m->m_flags |= M_HASFCS;
   1224  1.43.2.2  jdolecek 
   1225  1.43.2.2  jdolecek 		if_percpuq_enqueue(sc->sc_ipq, m);
   1226  1.43.2.2  jdolecek 
   1227  1.43.2.2  jdolecek skip:
   1228  1.43.2.2  jdolecek 		bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0,
   1229  1.43.2.2  jdolecek 		    data->rd_map->dm_mapsize, BUS_DMASYNC_PREREAD);
   1230  1.43.2.2  jdolecek 		desc->ddesc_cntl = htole32(
   1231  1.43.2.2  jdolecek 		    __SHIFTIN(AWGE_MAX_PACKET,DDESC_CNTL_SIZE1MASK) |
   1232  1.43.2.2  jdolecek 		    DDESC_CNTL_RXCHAIN);
   1233  1.43.2.2  jdolecek 		desc->ddesc_status = htole32(DDESC_STATUS_OWNEDBYDEV);
   1234  1.43.2.2  jdolecek 		bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
   1235  1.43.2.2  jdolecek 		    RX_DESC_OFFSET(i), sizeof(*desc),
   1236  1.43.2.2  jdolecek 		    BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE);
   1237  1.43.2.2  jdolecek 	}
   1238  1.43.2.2  jdolecek 
   1239  1.43.2.2  jdolecek 	/* update RX pointer */
   1240  1.43.2.2  jdolecek 	sc->sc_rxq.r_cur = i;
   1241  1.43.2.2  jdolecek 
   1242  1.43.2.2  jdolecek 	mutex_exit(&sc->sc_rxq.r_mtx);
   1243  1.43.2.2  jdolecek }
   1244  1.43.2.2  jdolecek 
   1245  1.43.2.2  jdolecek /*
   1246  1.43.2.2  jdolecek  * Reverse order of bits - http://aggregate.org/MAGIC/#Bit%20Reversal
   1247  1.43.2.2  jdolecek  */
   1248  1.43.2.2  jdolecek static uint32_t
   1249  1.43.2.2  jdolecek bitrev32(uint32_t x)
   1250  1.43.2.2  jdolecek {
   1251  1.43.2.2  jdolecek 	x = (((x & 0xaaaaaaaa) >> 1) | ((x & 0x55555555) << 1));
   1252  1.43.2.2  jdolecek 	x = (((x & 0xcccccccc) >> 2) | ((x & 0x33333333) << 2));
   1253  1.43.2.2  jdolecek 	x = (((x & 0xf0f0f0f0) >> 4) | ((x & 0x0f0f0f0f) << 4));
   1254  1.43.2.2  jdolecek 	x = (((x & 0xff00ff00) >> 8) | ((x & 0x00ff00ff) << 8));
   1255  1.43.2.2  jdolecek 
   1256  1.43.2.2  jdolecek 	return (x >> 16) | (x << 16);
   1257  1.43.2.2  jdolecek }
   1258  1.43.2.2  jdolecek 
   1259  1.43.2.2  jdolecek static void
   1260  1.43.2.2  jdolecek dwc_gmac_setmulti(struct dwc_gmac_softc *sc)
   1261  1.43.2.2  jdolecek {
   1262  1.43.2.2  jdolecek 	struct ifnet * const ifp = &sc->sc_ec.ec_if;
   1263  1.43.2.2  jdolecek 	struct ether_multi *enm;
   1264  1.43.2.2  jdolecek 	struct ether_multistep step;
   1265  1.43.2.2  jdolecek 	uint32_t hashes[2] = { 0, 0 };
   1266  1.43.2.2  jdolecek 	uint32_t ffilt, h;
   1267  1.43.2.2  jdolecek 	int mcnt;
   1268  1.43.2.2  jdolecek 
   1269  1.43.2.2  jdolecek 	KASSERT(mutex_owned(sc->sc_lock));
   1270  1.43.2.2  jdolecek 
   1271  1.43.2.2  jdolecek 	ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT);
   1272  1.43.2.2  jdolecek 
   1273  1.43.2.2  jdolecek 	if (ifp->if_flags & IFF_PROMISC) {
   1274  1.43.2.2  jdolecek 		ffilt |= AWIN_GMAC_MAC_FFILT_PR;
   1275  1.43.2.2  jdolecek 		goto special_filter;
   1276  1.43.2.2  jdolecek 	}
   1277  1.43.2.2  jdolecek 
   1278  1.43.2.2  jdolecek 	ifp->if_flags &= ~IFF_ALLMULTI;
   1279  1.43.2.2  jdolecek 	ffilt &= ~(AWIN_GMAC_MAC_FFILT_PM|AWIN_GMAC_MAC_FFILT_PR);
   1280  1.43.2.2  jdolecek 
   1281  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, 0);
   1282  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, 0);
   1283  1.43.2.2  jdolecek 
   1284  1.43.2.2  jdolecek 	ETHER_FIRST_MULTI(step, &sc->sc_ec, enm);
   1285  1.43.2.2  jdolecek 	mcnt = 0;
   1286  1.43.2.2  jdolecek 	while (enm != NULL) {
   1287  1.43.2.2  jdolecek 		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
   1288  1.43.2.2  jdolecek 		    ETHER_ADDR_LEN) != 0) {
   1289  1.43.2.2  jdolecek 			ffilt |= AWIN_GMAC_MAC_FFILT_PM;
   1290  1.43.2.2  jdolecek 			ifp->if_flags |= IFF_ALLMULTI;
   1291  1.43.2.2  jdolecek 			goto special_filter;
   1292  1.43.2.2  jdolecek 		}
   1293  1.43.2.2  jdolecek 
   1294  1.43.2.2  jdolecek 		h = bitrev32(
   1295  1.43.2.2  jdolecek 			~ether_crc32_le(enm->enm_addrlo, ETHER_ADDR_LEN)
   1296  1.43.2.2  jdolecek 		    ) >> 26;
   1297  1.43.2.2  jdolecek 		hashes[h >> 5] |= (1 << (h & 0x1f));
   1298  1.43.2.2  jdolecek 
   1299  1.43.2.2  jdolecek 		mcnt++;
   1300  1.43.2.2  jdolecek 		ETHER_NEXT_MULTI(step, enm);
   1301  1.43.2.2  jdolecek 	}
   1302  1.43.2.2  jdolecek 
   1303  1.43.2.2  jdolecek 	if (mcnt)
   1304  1.43.2.2  jdolecek 		ffilt |= AWIN_GMAC_MAC_FFILT_HMC;
   1305  1.43.2.2  jdolecek 	else
   1306  1.43.2.2  jdolecek 		ffilt &= ~AWIN_GMAC_MAC_FFILT_HMC;
   1307  1.43.2.2  jdolecek 
   1308  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, ffilt);
   1309  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW,
   1310  1.43.2.2  jdolecek 	    hashes[0]);
   1311  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH,
   1312  1.43.2.2  jdolecek 	    hashes[1]);
   1313  1.43.2.2  jdolecek 	sc->sc_if_flags = sc->sc_ec.ec_if.if_flags;
   1314  1.43.2.2  jdolecek 
   1315  1.43.2.2  jdolecek #ifdef DWC_GMAC_DEBUG
   1316  1.43.2.2  jdolecek 	dwc_gmac_dump_ffilt(sc, ffilt);
   1317  1.43.2.2  jdolecek #endif
   1318  1.43.2.2  jdolecek 	return;
   1319  1.43.2.2  jdolecek 
   1320  1.43.2.2  jdolecek special_filter:
   1321  1.43.2.2  jdolecek #ifdef DWC_GMAC_DEBUG
   1322  1.43.2.2  jdolecek 	dwc_gmac_dump_ffilt(sc, ffilt);
   1323  1.43.2.2  jdolecek #endif
   1324  1.43.2.2  jdolecek 	/* no MAC hashes, ALLMULTI or PROMISC */
   1325  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT,
   1326  1.43.2.2  jdolecek 	    ffilt);
   1327  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW,
   1328  1.43.2.2  jdolecek 	    0xffffffff);
   1329  1.43.2.2  jdolecek 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH,
   1330  1.43.2.2  jdolecek 	    0xffffffff);
   1331  1.43.2.2  jdolecek 	sc->sc_if_flags = sc->sc_ec.ec_if.if_flags;
   1332  1.43.2.2  jdolecek }
   1333  1.43.2.2  jdolecek 
   1334  1.43.2.2  jdolecek int
   1335  1.43.2.2  jdolecek dwc_gmac_intr(struct dwc_gmac_softc *sc)
   1336  1.43.2.2  jdolecek {
   1337  1.43.2.2  jdolecek 	uint32_t status, dma_status;
   1338  1.43.2.2  jdolecek 	int rv = 0;
   1339  1.43.2.2  jdolecek 
   1340  1.43.2.2  jdolecek 	if (sc->sc_stopping)
   1341  1.43.2.2  jdolecek 		return 0;
   1342  1.43.2.2  jdolecek 
   1343  1.43.2.2  jdolecek 	status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTR);
   1344  1.43.2.2  jdolecek 	if (status & AWIN_GMAC_MII_IRQ) {
   1345  1.43.2.2  jdolecek 		(void)bus_space_read_4(sc->sc_bst, sc->sc_bsh,
   1346  1.43.2.2  jdolecek 		    AWIN_GMAC_MII_STATUS);
   1347  1.43.2.2  jdolecek 		rv = 1;
   1348  1.43.2.2  jdolecek 		mii_pollstat(&sc->sc_mii);
   1349  1.43.2.2  jdolecek 	}
   1350  1.43.2.2  jdolecek 
   1351  1.43.2.2  jdolecek 	dma_status = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
   1352  1.43.2.2  jdolecek 	    AWIN_GMAC_DMA_STATUS);
   1353  1.43.2.2  jdolecek 
   1354  1.43.2.2  jdolecek 	if (dma_status & (GMAC_DMA_INT_NIE|GMAC_DMA_INT_AIE))
   1355  1.43.2.2  jdolecek 		rv = 1;
   1356  1.43.2.2  jdolecek 
   1357  1.43.2.2  jdolecek 	if (dma_status & GMAC_DMA_INT_TIE)
   1358  1.43.2.2  jdolecek 		dwc_gmac_tx_intr(sc);
   1359  1.43.2.2  jdolecek 
   1360  1.43.2.2  jdolecek 	if (dma_status & GMAC_DMA_INT_RIE)
   1361  1.43.2.2  jdolecek 		dwc_gmac_rx_intr(sc);
   1362  1.43.2.2  jdolecek 
   1363  1.43.2.2  jdolecek 	/*
   1364  1.43.2.2  jdolecek 	 * Check error conditions
   1365  1.43.2.2  jdolecek 	 */
   1366  1.43.2.2  jdolecek 	if (dma_status & GMAC_DMA_INT_ERRORS) {
   1367  1.43.2.2  jdolecek 		sc->sc_ec.ec_if.if_oerrors++;
   1368  1.43.2.2  jdolecek #ifdef DWC_GMAC_DEBUG
   1369  1.43.2.2  jdolecek 		dwc_dump_and_abort(sc, "interrupt error condition");
   1370  1.43.2.2  jdolecek #endif
   1371  1.43.2.2  jdolecek 	}
   1372  1.43.2.2  jdolecek 
   1373  1.43.2.2  jdolecek 	/* ack interrupt */
   1374  1.43.2.2  jdolecek 	if (dma_status)
   1375  1.43.2.2  jdolecek 		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
   1376  1.43.2.2  jdolecek 		    AWIN_GMAC_DMA_STATUS, dma_status & GMAC_DMA_INT_MASK);
   1377  1.43.2.2  jdolecek 
   1378  1.43.2.2  jdolecek 	/*
   1379  1.43.2.2  jdolecek 	 * Get more packets
   1380  1.43.2.2  jdolecek 	 */
   1381  1.43.2.2  jdolecek 	if (rv)
   1382  1.43.2.2  jdolecek 		if_schedule_deferred_start(&sc->sc_ec.ec_if);
   1383  1.43.2.2  jdolecek 
   1384  1.43.2.2  jdolecek 	return rv;
   1385  1.43.2.2  jdolecek }
   1386  1.43.2.2  jdolecek 
   1387  1.43.2.2  jdolecek #ifdef DWC_GMAC_DEBUG
   1388  1.43.2.2  jdolecek static void
   1389  1.43.2.2  jdolecek dwc_gmac_dump_dma(struct dwc_gmac_softc *sc)
   1390  1.43.2.2  jdolecek {
   1391  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "busmode: %08x\n",
   1392  1.43.2.2  jdolecek 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE));
   1393  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "tx poll: %08x\n",
   1394  1.43.2.2  jdolecek 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TXPOLL));
   1395  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "rx poll: %08x\n",
   1396  1.43.2.2  jdolecek 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RXPOLL));
   1397  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "rx descriptors: %08x\n",
   1398  1.43.2.2  jdolecek 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR));
   1399  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "tx descriptors: %08x\n",
   1400  1.43.2.2  jdolecek 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR));
   1401  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "status: %08x\n",
   1402  1.43.2.2  jdolecek 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_STATUS));
   1403  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "op mode: %08x\n",
   1404  1.43.2.2  jdolecek 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_OPMODE));
   1405  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "int enable: %08x\n",
   1406  1.43.2.2  jdolecek 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE));
   1407  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "cur tx: %08x\n",
   1408  1.43.2.2  jdolecek 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_TX_DESC));
   1409  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "cur rx: %08x\n",
   1410  1.43.2.2  jdolecek 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_RX_DESC));
   1411  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "cur tx buffer: %08x\n",
   1412  1.43.2.2  jdolecek 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_TX_BUFADDR));
   1413  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "cur rx buffer: %08x\n",
   1414  1.43.2.2  jdolecek 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_RX_BUFADDR));
   1415  1.43.2.2  jdolecek }
   1416  1.43.2.2  jdolecek 
   1417  1.43.2.2  jdolecek static void
   1418  1.43.2.2  jdolecek dwc_gmac_dump_tx_desc(struct dwc_gmac_softc *sc)
   1419  1.43.2.2  jdolecek {
   1420  1.43.2.2  jdolecek 	int i;
   1421  1.43.2.2  jdolecek 
   1422  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "TX queue: cur=%d, next=%d, queued=%d\n",
   1423  1.43.2.2  jdolecek 	    sc->sc_txq.t_cur, sc->sc_txq.t_next, sc->sc_txq.t_queued);
   1424  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "TX DMA descriptors:\n");
   1425  1.43.2.2  jdolecek 	for (i = 0; i < AWGE_TX_RING_COUNT; i++) {
   1426  1.43.2.2  jdolecek 		struct dwc_gmac_dev_dmadesc *desc = &sc->sc_txq.t_desc[i];
   1427  1.43.2.2  jdolecek 		aprint_normal("#%d (%08lx): status: %08x cntl: %08x "
   1428  1.43.2.2  jdolecek 		    "data: %08x next: %08x\n",
   1429  1.43.2.2  jdolecek 		    i, sc->sc_txq.t_physaddr +
   1430  1.43.2.2  jdolecek 			i*sizeof(struct dwc_gmac_dev_dmadesc),
   1431  1.43.2.2  jdolecek 		    le32toh(desc->ddesc_status), le32toh(desc->ddesc_cntl),
   1432  1.43.2.2  jdolecek 		    le32toh(desc->ddesc_data), le32toh(desc->ddesc_next));
   1433  1.43.2.2  jdolecek 	}
   1434  1.43.2.2  jdolecek }
   1435  1.43.2.2  jdolecek 
   1436  1.43.2.2  jdolecek static void
   1437  1.43.2.2  jdolecek dwc_gmac_dump_rx_desc(struct dwc_gmac_softc *sc)
   1438  1.43.2.2  jdolecek {
   1439  1.43.2.2  jdolecek 	int i;
   1440  1.43.2.2  jdolecek 
   1441  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "RX queue: cur=%d, next=%d\n",
   1442  1.43.2.2  jdolecek 	    sc->sc_rxq.r_cur, sc->sc_rxq.r_next);
   1443  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "RX DMA descriptors:\n");
   1444  1.43.2.2  jdolecek 	for (i = 0; i < AWGE_RX_RING_COUNT; i++) {
   1445  1.43.2.2  jdolecek 		struct dwc_gmac_dev_dmadesc *desc = &sc->sc_rxq.r_desc[i];
   1446  1.43.2.2  jdolecek 		aprint_normal("#%d (%08lx): status: %08x cntl: %08x "
   1447  1.43.2.2  jdolecek 		    "data: %08x next: %08x\n",
   1448  1.43.2.2  jdolecek 		    i, sc->sc_rxq.r_physaddr +
   1449  1.43.2.2  jdolecek 			i*sizeof(struct dwc_gmac_dev_dmadesc),
   1450  1.43.2.2  jdolecek 		    le32toh(desc->ddesc_status), le32toh(desc->ddesc_cntl),
   1451  1.43.2.2  jdolecek 		    le32toh(desc->ddesc_data), le32toh(desc->ddesc_next));
   1452  1.43.2.2  jdolecek 	}
   1453  1.43.2.2  jdolecek }
   1454  1.43.2.2  jdolecek 
   1455  1.43.2.2  jdolecek static void
   1456  1.43.2.2  jdolecek dwc_dump_status(struct dwc_gmac_softc *sc)
   1457  1.43.2.2  jdolecek {
   1458  1.43.2.2  jdolecek 	uint32_t status = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
   1459  1.43.2.2  jdolecek 	     AWIN_GMAC_MAC_INTR);
   1460  1.43.2.2  jdolecek 	uint32_t dma_status = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
   1461  1.43.2.2  jdolecek 	     AWIN_GMAC_DMA_STATUS);
   1462  1.43.2.2  jdolecek 	char buf[200];
   1463  1.43.2.2  jdolecek 
   1464  1.43.2.2  jdolecek 	/* print interrupt state */
   1465  1.43.2.2  jdolecek 	snprintb(buf, sizeof(buf), "\177\20"
   1466  1.43.2.2  jdolecek 	    "b\x10""NI\0"
   1467  1.43.2.2  jdolecek 	    "b\x0f""AI\0"
   1468  1.43.2.2  jdolecek 	    "b\x0e""ER\0"
   1469  1.43.2.2  jdolecek 	    "b\x0d""FB\0"
   1470  1.43.2.2  jdolecek 	    "b\x0a""ET\0"
   1471  1.43.2.2  jdolecek 	    "b\x09""RW\0"
   1472  1.43.2.2  jdolecek 	    "b\x08""RS\0"
   1473  1.43.2.2  jdolecek 	    "b\x07""RU\0"
   1474  1.43.2.2  jdolecek 	    "b\x06""RI\0"
   1475  1.43.2.2  jdolecek 	    "b\x05""UN\0"
   1476  1.43.2.2  jdolecek 	    "b\x04""OV\0"
   1477  1.43.2.2  jdolecek 	    "b\x03""TJ\0"
   1478  1.43.2.2  jdolecek 	    "b\x02""TU\0"
   1479  1.43.2.2  jdolecek 	    "b\x01""TS\0"
   1480  1.43.2.2  jdolecek 	    "b\x00""TI\0"
   1481  1.43.2.2  jdolecek 	    "\0", dma_status);
   1482  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "INTR status: %08x, DMA status: %s\n",
   1483  1.43.2.2  jdolecek 	    status, buf);
   1484  1.43.2.2  jdolecek }
   1485  1.43.2.2  jdolecek 
   1486  1.43.2.2  jdolecek static void
   1487  1.43.2.2  jdolecek dwc_dump_and_abort(struct dwc_gmac_softc *sc, const char *msg)
   1488  1.43.2.2  jdolecek {
   1489  1.43.2.2  jdolecek 	dwc_dump_status(sc);
   1490  1.43.2.2  jdolecek 	dwc_gmac_dump_ffilt(sc,
   1491  1.43.2.2  jdolecek 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT));
   1492  1.43.2.2  jdolecek 	dwc_gmac_dump_dma(sc);
   1493  1.43.2.2  jdolecek 	dwc_gmac_dump_tx_desc(sc);
   1494  1.43.2.2  jdolecek 	dwc_gmac_dump_rx_desc(sc);
   1495  1.43.2.2  jdolecek 
   1496  1.43.2.2  jdolecek 	panic("%s", msg);
   1497  1.43.2.2  jdolecek }
   1498  1.43.2.2  jdolecek 
   1499  1.43.2.2  jdolecek static void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *sc, uint32_t ffilt)
   1500  1.43.2.2  jdolecek {
   1501  1.43.2.2  jdolecek 	char buf[200];
   1502  1.43.2.2  jdolecek 
   1503  1.43.2.2  jdolecek 	/* print filter setup */
   1504  1.43.2.2  jdolecek 	snprintb(buf, sizeof(buf), "\177\20"
   1505  1.43.2.2  jdolecek 	    "b\x1f""RA\0"
   1506  1.43.2.2  jdolecek 	    "b\x0a""HPF\0"
   1507  1.43.2.2  jdolecek 	    "b\x09""SAF\0"
   1508  1.43.2.2  jdolecek 	    "b\x08""SAIF\0"
   1509  1.43.2.2  jdolecek 	    "b\x05""DBF\0"
   1510  1.43.2.2  jdolecek 	    "b\x04""PM\0"
   1511  1.43.2.2  jdolecek 	    "b\x03""DAIF\0"
   1512  1.43.2.2  jdolecek 	    "b\x02""HMC\0"
   1513  1.43.2.2  jdolecek 	    "b\x01""HUC\0"
   1514  1.43.2.2  jdolecek 	    "b\x00""PR\0"
   1515  1.43.2.2  jdolecek 	    "\0", ffilt);
   1516  1.43.2.2  jdolecek 	aprint_normal_dev(sc->sc_dev, "FFILT: %s\n", buf);
   1517  1.43.2.2  jdolecek }
   1518  1.43.2.2  jdolecek #endif
   1519