xref: /netbsd-src/sys/dev/ic/dwc_gmac.c (revision 8469df929f4af7108beb12d564f7f89318e711ff)
1*8469df92Sandvar /* $NetBSD: dwc_gmac.c,v 1.95 2024/09/07 06:17:37 andvar Exp $ */
2231538d1Sjmcneill 
3971dc1a0Smartin /*-
4971dc1a0Smartin  * Copyright (c) 2013, 2014 The NetBSD Foundation, Inc.
5971dc1a0Smartin  * All rights reserved.
6971dc1a0Smartin  *
7971dc1a0Smartin  * This code is derived from software contributed to The NetBSD Foundation
8971dc1a0Smartin  * by Matt Thomas of 3am Software Foundry and Martin Husemann.
9971dc1a0Smartin  *
10971dc1a0Smartin  * Redistribution and use in source and binary forms, with or without
11971dc1a0Smartin  * modification, are permitted provided that the following conditions
12971dc1a0Smartin  * are met:
13971dc1a0Smartin  * 1. Redistributions of source code must retain the above copyright
14971dc1a0Smartin  *    notice, this list of conditions and the following disclaimer.
15971dc1a0Smartin  * 2. Redistributions in binary form must reproduce the above copyright
16971dc1a0Smartin  *    notice, this list of conditions and the following disclaimer in the
17971dc1a0Smartin  *    documentation and/or other materials provided with the distribution.
18971dc1a0Smartin  *
19971dc1a0Smartin  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20971dc1a0Smartin  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21971dc1a0Smartin  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22971dc1a0Smartin  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23971dc1a0Smartin  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24971dc1a0Smartin  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25971dc1a0Smartin  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26971dc1a0Smartin  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27971dc1a0Smartin  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28971dc1a0Smartin  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29971dc1a0Smartin  * POSSIBILITY OF SUCH DAMAGE.
30971dc1a0Smartin  */
31971dc1a0Smartin 
32971dc1a0Smartin /*
33971dc1a0Smartin  * This driver supports the Synopsis Designware GMAC core, as found
34971dc1a0Smartin  * on Allwinner A20 cores and others.
35971dc1a0Smartin  *
36971dc1a0Smartin  * Real documentation seems to not be available, the marketing product
37971dc1a0Smartin  * documents could be found here:
38971dc1a0Smartin  *
39971dc1a0Smartin  *  http://www.synopsys.com/dw/ipdir.php?ds=dwc_ether_mac10_100_1000_unive
40971dc1a0Smartin  */
41971dc1a0Smartin 
4296373f68Sriastradh /*
4396373f68Sriastradh  * Lock order:
4496373f68Sriastradh  *
4596373f68Sriastradh  *	IFNET_LOCK -> sc_mcast_lock
4696373f68Sriastradh  *	IFNET_LOCK -> sc_intr_lock -> {sc_txq.t_mtx, sc_rxq.r_mtx}
4796373f68Sriastradh  */
4896373f68Sriastradh 
49971dc1a0Smartin #include <sys/cdefs.h>
50971dc1a0Smartin 
51*8469df92Sandvar __KERNEL_RCSID(1, "$NetBSD: dwc_gmac.c,v 1.95 2024/09/07 06:17:37 andvar Exp $");
5237ad3d63Smartin 
5337ad3d63Smartin /* #define	DWC_GMAC_DEBUG	1 */
54971dc1a0Smartin 
55fc18ade0Sskrll #ifdef _KERNEL_OPT
56971dc1a0Smartin #include "opt_inet.h"
57fc18ade0Sskrll #endif
58971dc1a0Smartin 
59971dc1a0Smartin #include <sys/param.h>
60971dc1a0Smartin #include <sys/bus.h>
61971dc1a0Smartin #include <sys/device.h>
62971dc1a0Smartin #include <sys/intr.h>
63971dc1a0Smartin #include <sys/systm.h>
64971dc1a0Smartin #include <sys/sockio.h>
654f90260eSjmcneill #include <sys/cprng.h>
66f872a062Smsaitoh #include <sys/rndsource.h>
67971dc1a0Smartin 
68971dc1a0Smartin #include <net/if.h>
69971dc1a0Smartin #include <net/if_ether.h>
70971dc1a0Smartin #include <net/if_media.h>
71971dc1a0Smartin #include <net/bpf.h>
72971dc1a0Smartin #ifdef INET
73971dc1a0Smartin #include <netinet/if_inarp.h>
74971dc1a0Smartin #endif
75971dc1a0Smartin 
76971dc1a0Smartin #include <dev/mii/miivar.h>
77971dc1a0Smartin 
78971dc1a0Smartin #include <dev/ic/dwc_gmac_reg.h>
79971dc1a0Smartin #include <dev/ic/dwc_gmac_var.h>
80971dc1a0Smartin 
81a5cdd4b4Smsaitoh static int dwc_gmac_miibus_read_reg(device_t, int, int, uint16_t *);
82a5cdd4b4Smsaitoh static int dwc_gmac_miibus_write_reg(device_t, int, int, uint16_t);
83971dc1a0Smartin static void dwc_gmac_miibus_statchg(struct ifnet *);
84971dc1a0Smartin 
85c34bdbc5Smsaitoh static int dwc_gmac_reset(struct dwc_gmac_softc *);
86f8570f8aSmrg static void dwc_gmac_write_hwaddr(struct dwc_gmac_softc *, uint8_t[ETHER_ADDR_LEN]);
87c34bdbc5Smsaitoh static int dwc_gmac_alloc_dma_rings(struct dwc_gmac_softc *);
88c34bdbc5Smsaitoh static void dwc_gmac_free_dma_rings(struct dwc_gmac_softc *);
89c34bdbc5Smsaitoh static int dwc_gmac_alloc_rx_ring(struct dwc_gmac_softc *, struct dwc_gmac_rx_ring *);
90c34bdbc5Smsaitoh static void dwc_gmac_reset_rx_ring(struct dwc_gmac_softc *, struct dwc_gmac_rx_ring *);
91c34bdbc5Smsaitoh static void dwc_gmac_free_rx_ring(struct dwc_gmac_softc *, struct dwc_gmac_rx_ring *);
92c34bdbc5Smsaitoh static int dwc_gmac_alloc_tx_ring(struct dwc_gmac_softc *, struct dwc_gmac_tx_ring *);
93c34bdbc5Smsaitoh static void dwc_gmac_reset_tx_ring(struct dwc_gmac_softc *, struct dwc_gmac_tx_ring *);
94c34bdbc5Smsaitoh static void dwc_gmac_free_tx_ring(struct dwc_gmac_softc *, struct dwc_gmac_tx_ring *);
95c34bdbc5Smsaitoh static void dwc_gmac_txdesc_sync(struct dwc_gmac_softc *, int, int, int);
96c34bdbc5Smsaitoh static int dwc_gmac_init(struct ifnet *);
97c34bdbc5Smsaitoh static void dwc_gmac_stop(struct ifnet *, int);
98c34bdbc5Smsaitoh static void dwc_gmac_start(struct ifnet *);
99c34bdbc5Smsaitoh static void dwc_gmac_start_locked(struct ifnet *);
100c34bdbc5Smsaitoh static int dwc_gmac_queue(struct dwc_gmac_softc *, struct mbuf *);
101971dc1a0Smartin static int dwc_gmac_ioctl(struct ifnet *, u_long, void *);
102c34bdbc5Smsaitoh static void dwc_gmac_tx_intr(struct dwc_gmac_softc *);
103c34bdbc5Smsaitoh static void dwc_gmac_rx_intr(struct dwc_gmac_softc *);
104c34bdbc5Smsaitoh static void dwc_gmac_setmulti(struct dwc_gmac_softc *);
105d1bd22e8Smartin static int dwc_gmac_ifflags_cb(struct ethercom *);
10672645925Smartin static void dwc_gmac_desc_set_owned_by_dev(struct dwc_gmac_dev_dmadesc *);
10772645925Smartin static int  dwc_gmac_desc_is_owned_by_dev(struct dwc_gmac_dev_dmadesc *);
10872645925Smartin static void dwc_gmac_desc_std_set_len(struct dwc_gmac_dev_dmadesc *, int);
10972645925Smartin static uint32_t dwc_gmac_desc_std_get_len(struct dwc_gmac_dev_dmadesc *);
11072645925Smartin static void dwc_gmac_desc_std_tx_init_flags(struct dwc_gmac_dev_dmadesc *);
11172645925Smartin static void dwc_gmac_desc_std_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *);
11272645925Smartin static void dwc_gmac_desc_std_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *);
11372645925Smartin static void dwc_gmac_desc_std_rx_init_flags(struct dwc_gmac_dev_dmadesc *);
11472645925Smartin static int  dwc_gmac_desc_std_rx_has_error(struct dwc_gmac_dev_dmadesc *);
11572645925Smartin static void dwc_gmac_desc_enh_set_len(struct dwc_gmac_dev_dmadesc *, int);
11672645925Smartin static uint32_t dwc_gmac_desc_enh_get_len(struct dwc_gmac_dev_dmadesc *);
11772645925Smartin static void dwc_gmac_desc_enh_tx_init_flags(struct dwc_gmac_dev_dmadesc *);
11872645925Smartin static void dwc_gmac_desc_enh_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *);
11972645925Smartin static void dwc_gmac_desc_enh_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *);
12072645925Smartin static void dwc_gmac_desc_enh_rx_init_flags(struct dwc_gmac_dev_dmadesc *);
12172645925Smartin static int  dwc_gmac_desc_enh_rx_has_error(struct dwc_gmac_dev_dmadesc *);
12272645925Smartin 
12372645925Smartin static const struct dwc_gmac_desc_methods desc_methods_standard = {
12472645925Smartin 	.tx_init_flags = dwc_gmac_desc_std_tx_init_flags,
12572645925Smartin 	.tx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev,
12672645925Smartin 	.tx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev,
12772645925Smartin 	.tx_set_len = dwc_gmac_desc_std_set_len,
12872645925Smartin 	.tx_set_first_frag = dwc_gmac_desc_std_tx_set_first_frag,
12972645925Smartin 	.tx_set_last_frag = dwc_gmac_desc_std_tx_set_last_frag,
13072645925Smartin 	.rx_init_flags = dwc_gmac_desc_std_rx_init_flags,
13172645925Smartin 	.rx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev,
13272645925Smartin 	.rx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev,
13372645925Smartin 	.rx_set_len = dwc_gmac_desc_std_set_len,
13472645925Smartin 	.rx_get_len = dwc_gmac_desc_std_get_len,
13572645925Smartin 	.rx_has_error = dwc_gmac_desc_std_rx_has_error
13672645925Smartin };
13772645925Smartin 
13872645925Smartin static const struct dwc_gmac_desc_methods desc_methods_enhanced = {
13972645925Smartin 	.tx_init_flags = dwc_gmac_desc_enh_tx_init_flags,
14072645925Smartin 	.tx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev,
14172645925Smartin 	.tx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev,
14272645925Smartin 	.tx_set_len = dwc_gmac_desc_enh_set_len,
14372645925Smartin 	.tx_set_first_frag = dwc_gmac_desc_enh_tx_set_first_frag,
14472645925Smartin 	.tx_set_last_frag = dwc_gmac_desc_enh_tx_set_last_frag,
14572645925Smartin 	.rx_init_flags = dwc_gmac_desc_enh_rx_init_flags,
14672645925Smartin 	.rx_set_owned_by_dev = dwc_gmac_desc_set_owned_by_dev,
14772645925Smartin 	.rx_is_owned_by_dev = dwc_gmac_desc_is_owned_by_dev,
14872645925Smartin 	.rx_set_len = dwc_gmac_desc_enh_set_len,
14972645925Smartin 	.rx_get_len = dwc_gmac_desc_enh_get_len,
15072645925Smartin 	.rx_has_error = dwc_gmac_desc_enh_rx_has_error
15172645925Smartin };
15272645925Smartin 
153971dc1a0Smartin 
154971dc1a0Smartin #define	TX_DESC_OFFSET(N)	((AWGE_RX_RING_COUNT + (N)) \
155971dc1a0Smartin 				    * sizeof(struct dwc_gmac_dev_dmadesc))
156bdbd5db8Smartin #define	TX_NEXT(N)		(((N) + 1) & (AWGE_TX_RING_COUNT - 1))
157971dc1a0Smartin 
158971dc1a0Smartin #define RX_DESC_OFFSET(N)	((N) * sizeof(struct dwc_gmac_dev_dmadesc))
159bdbd5db8Smartin #define	RX_NEXT(N)		(((N) + 1) & (AWGE_RX_RING_COUNT - 1))
160bdbd5db8Smartin 
161bdbd5db8Smartin 
162bdbd5db8Smartin 
163426c40ceSmartin #define	GMAC_DEF_DMA_INT_MASK	(GMAC_DMA_INT_TIE | GMAC_DMA_INT_RIE | \
164bdbd5db8Smartin 				GMAC_DMA_INT_NIE | GMAC_DMA_INT_AIE | \
165bdbd5db8Smartin 				GMAC_DMA_INT_FBE | GMAC_DMA_INT_UNE)
166bdbd5db8Smartin 
167bdbd5db8Smartin #define	GMAC_DMA_INT_ERRORS	(GMAC_DMA_INT_AIE | GMAC_DMA_INT_ERE | \
1685158fc24Smartin 				GMAC_DMA_INT_FBE |	\
169bdbd5db8Smartin 				GMAC_DMA_INT_RWE | GMAC_DMA_INT_RUE | \
170bdbd5db8Smartin 				GMAC_DMA_INT_UNE | GMAC_DMA_INT_OVE | \
1715158fc24Smartin 				GMAC_DMA_INT_TJE)
172bdbd5db8Smartin 
173bdbd5db8Smartin #define	AWIN_DEF_MAC_INTRMASK	\
174bdbd5db8Smartin 	(AWIN_GMAC_MAC_INT_TSI | AWIN_GMAC_MAC_INT_ANEG |	\
17572645925Smartin 	AWIN_GMAC_MAC_INT_LINKCHG)
176971dc1a0Smartin 
17737ad3d63Smartin #ifdef DWC_GMAC_DEBUG
178c34bdbc5Smsaitoh static void dwc_gmac_dump_dma(struct dwc_gmac_softc *);
179c34bdbc5Smsaitoh static void dwc_gmac_dump_tx_desc(struct dwc_gmac_softc *);
180c34bdbc5Smsaitoh static void dwc_gmac_dump_rx_desc(struct dwc_gmac_softc *);
181c34bdbc5Smsaitoh static void dwc_dump_and_abort(struct dwc_gmac_softc *, const char *);
182c34bdbc5Smsaitoh static void dwc_dump_status(struct dwc_gmac_softc *);
183c34bdbc5Smsaitoh static void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *, uint32_t);
18437ad3d63Smartin #endif
18537ad3d63Smartin 
18689fbd498Sjmcneill int
18735026302Smartin dwc_gmac_attach(struct dwc_gmac_softc *sc, int phy_id, uint32_t mii_clk)
188971dc1a0Smartin {
189971dc1a0Smartin 	uint8_t enaddr[ETHER_ADDR_LEN];
19077147dd2Sskrll 	uint32_t maclo, machi, hwft;
191971dc1a0Smartin 	struct mii_data * const mii = &sc->sc_mii;
192971dc1a0Smartin 	struct ifnet * const ifp = &sc->sc_ec.ec_if;
1936224bda1Smartin 	prop_dictionary_t dict;
194971dc1a0Smartin 
195971dc1a0Smartin 	mutex_init(&sc->sc_mdio_lock, MUTEX_DEFAULT, IPL_NET);
196612a2a40Smartin 	sc->sc_mii_clk = mii_clk & 7;
197971dc1a0Smartin 
1986224bda1Smartin 	dict = device_properties(sc->sc_dev);
1996224bda1Smartin 	prop_data_t ea = dict ? prop_dictionary_get(dict, "mac-address") : NULL;
2006224bda1Smartin 	if (ea != NULL) {
201971dc1a0Smartin 		/*
202207defd0Sandvar 		 * If the MAC address is overridden by a device property,
2036224bda1Smartin 		 * use that.
2046224bda1Smartin 		 */
2056224bda1Smartin 		KASSERT(prop_object_type(ea) == PROP_TYPE_DATA);
2066224bda1Smartin 		KASSERT(prop_data_size(ea) == ETHER_ADDR_LEN);
207423f1f50Sjmcneill 		memcpy(enaddr, prop_data_value(ea), ETHER_ADDR_LEN);
2086224bda1Smartin 	} else {
2096224bda1Smartin 		/*
210*8469df92Sandvar 		 * If we did not get an externally configure address,
2116224bda1Smartin 		 * try to read one from the current filter setup,
212971dc1a0Smartin 		 * before resetting the chip.
213971dc1a0Smartin 		 */
214bdbd5db8Smartin 		maclo = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
215bdbd5db8Smartin 		    AWIN_GMAC_MAC_ADDR0LO);
216bdbd5db8Smartin 		machi = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
217bdbd5db8Smartin 		    AWIN_GMAC_MAC_ADDR0HI);
218d4b3eb15Sjmcneill 
219d4b3eb15Sjmcneill 		if (maclo == 0xffffffff && (machi & 0xffff) == 0xffff) {
2204f90260eSjmcneill 			/* fake MAC address */
2214f90260eSjmcneill 			maclo = 0x00f2 | (cprng_strong32() << 16);
2224f90260eSjmcneill 			machi = cprng_strong32();
223d4b3eb15Sjmcneill 		}
224d4b3eb15Sjmcneill 
225971dc1a0Smartin 		enaddr[0] = maclo & 0x0ff;
226971dc1a0Smartin 		enaddr[1] = (maclo >> 8) & 0x0ff;
227971dc1a0Smartin 		enaddr[2] = (maclo >> 16) & 0x0ff;
228971dc1a0Smartin 		enaddr[3] = (maclo >> 24) & 0x0ff;
229971dc1a0Smartin 		enaddr[4] = machi & 0x0ff;
230971dc1a0Smartin 		enaddr[5] = (machi >> 8) & 0x0ff;
231971dc1a0Smartin 	}
232971dc1a0Smartin 
23377147dd2Sskrll 	const uint32_t ver =
23477147dd2Sskrll 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_VERSION);
23577147dd2Sskrll 	const uint32_t snpsver =
23677147dd2Sskrll 	    __SHIFTOUT(ver, AWIN_GMAC_MAC_VERSION_SNPSVER_MASK);
23777147dd2Sskrll 	aprint_normal_dev(sc->sc_dev, "Core version: %08x\n", snpsver);
23872645925Smartin 
239971dc1a0Smartin 	/*
240a1f0cbdaSjoerg 	 * Init chip and do initial setup
241971dc1a0Smartin 	 */
242971dc1a0Smartin 	if (dwc_gmac_reset(sc) != 0)
24389fbd498Sjmcneill 		return ENXIO;	/* not much to cleanup, haven't attached yet */
2446224bda1Smartin 	dwc_gmac_write_hwaddr(sc, enaddr);
2457ffbd423Ssevan 	aprint_normal_dev(sc->sc_dev, "Ethernet address %s\n",
246971dc1a0Smartin 	    ether_sprintf(enaddr));
247971dc1a0Smartin 
24872645925Smartin 	hwft = 0;
24977147dd2Sskrll 	if (snpsver >= 0x35) {
25072645925Smartin 		hwft = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
25172645925Smartin 		    AWIN_GMAC_DMA_HWFEATURES);
25272645925Smartin 		aprint_normal_dev(sc->sc_dev,
25372645925Smartin 		    "HW feature mask: %x\n", hwft);
25472645925Smartin 	}
255921379d2Sskrll 
256921379d2Sskrll 	if (sizeof(bus_addr_t) > 4) {
257921379d2Sskrll 		int error = bus_dmatag_subregion(sc->sc_dmat, 0, __MASK(32),
258921379d2Sskrll 		    &sc->sc_dmat, BUS_DMA_WAITOK);
259921379d2Sskrll 		if (error != 0) {
260921379d2Sskrll 			aprint_error_dev(sc->sc_dev,
261921379d2Sskrll 			    "failed to create DMA subregion\n");
262921379d2Sskrll 			return ENOMEM;
263921379d2Sskrll 		}
264921379d2Sskrll 	}
265921379d2Sskrll 
26672645925Smartin 	if (hwft & GMAC_DMA_FEAT_ENHANCED_DESC) {
26772645925Smartin 		aprint_normal_dev(sc->sc_dev,
26872645925Smartin 		    "Using enhanced descriptor format\n");
26972645925Smartin 		sc->sc_descm = &desc_methods_enhanced;
27072645925Smartin 	} else {
27172645925Smartin 		sc->sc_descm = &desc_methods_standard;
27272645925Smartin 	}
27317e5d3c8Schs 	if (hwft & GMAC_DMA_FEAT_RMON) {
27417e5d3c8Schs 		uint32_t val;
27517e5d3c8Schs 
27617e5d3c8Schs 		/* Mask all MMC interrupts */
27717e5d3c8Schs 		val = 0xffffffff;
27817e5d3c8Schs 		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
27917e5d3c8Schs 		    GMAC_MMC_RX_INT_MSK, val);
28017e5d3c8Schs 		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
28117e5d3c8Schs 		    GMAC_MMC_TX_INT_MSK, val);
28217e5d3c8Schs 	}
28372645925Smartin 
284971dc1a0Smartin 	/*
285971dc1a0Smartin 	 * Allocate Tx and Rx rings
286971dc1a0Smartin 	 */
287971dc1a0Smartin 	if (dwc_gmac_alloc_dma_rings(sc) != 0) {
288971dc1a0Smartin 		aprint_error_dev(sc->sc_dev, "could not allocate DMA rings\n");
289971dc1a0Smartin 		goto fail;
290971dc1a0Smartin 	}
291971dc1a0Smartin 
292971dc1a0Smartin 	if (dwc_gmac_alloc_tx_ring(sc, &sc->sc_txq) != 0) {
293971dc1a0Smartin 		aprint_error_dev(sc->sc_dev, "could not allocate Tx ring\n");
294971dc1a0Smartin 		goto fail;
295971dc1a0Smartin 	}
296971dc1a0Smartin 
297971dc1a0Smartin 	if (dwc_gmac_alloc_rx_ring(sc, &sc->sc_rxq) != 0) {
298971dc1a0Smartin 		aprint_error_dev(sc->sc_dev, "could not allocate Rx ring\n");
299971dc1a0Smartin 		goto fail;
300971dc1a0Smartin 	}
301971dc1a0Smartin 
302c9ba1e93Sskrll 	sc->sc_stopping = false;
303c9ba1e93Sskrll 	sc->sc_txbusy = false;
304c9ba1e93Sskrll 
30596373f68Sriastradh 	sc->sc_mcast_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_SOFTNET);
306c9ba1e93Sskrll 	sc->sc_intr_lock = mutex_obj_alloc(MUTEX_DEFAULT, IPL_NET);
307fc18ade0Sskrll 	mutex_init(&sc->sc_txq.t_mtx, MUTEX_DEFAULT, IPL_NET);
308fc18ade0Sskrll 	mutex_init(&sc->sc_rxq.r_mtx, MUTEX_DEFAULT, IPL_NET);
309fc18ade0Sskrll 
310971dc1a0Smartin 	/*
311971dc1a0Smartin 	 * Prepare interface data
312971dc1a0Smartin 	 */
313971dc1a0Smartin 	ifp->if_softc = sc;
314971dc1a0Smartin 	strlcpy(ifp->if_xname, device_xname(sc->sc_dev), IFNAMSIZ);
315971dc1a0Smartin 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
316ab3cd725Sozaki-r 	ifp->if_extflags = IFEF_MPSAFE;
317971dc1a0Smartin 	ifp->if_ioctl = dwc_gmac_ioctl;
318971dc1a0Smartin 	ifp->if_start = dwc_gmac_start;
319971dc1a0Smartin 	ifp->if_init = dwc_gmac_init;
320971dc1a0Smartin 	ifp->if_stop = dwc_gmac_stop;
321971dc1a0Smartin 	IFQ_SET_MAXLEN(&ifp->if_snd, IFQ_MAXLEN);
322971dc1a0Smartin 	IFQ_SET_READY(&ifp->if_snd);
323971dc1a0Smartin 
324971dc1a0Smartin 	/*
325971dc1a0Smartin 	 * Attach MII subdevices
326971dc1a0Smartin 	 */
32783658911Smartin 	sc->sc_ec.ec_mii = &sc->sc_mii;
328971dc1a0Smartin 	ifmedia_init(&mii->mii_media, 0, ether_mediachange, ether_mediastatus);
329971dc1a0Smartin 	mii->mii_ifp = ifp;
330971dc1a0Smartin 	mii->mii_readreg = dwc_gmac_miibus_read_reg;
331971dc1a0Smartin 	mii->mii_writereg = dwc_gmac_miibus_write_reg;
332971dc1a0Smartin 	mii->mii_statchg = dwc_gmac_miibus_statchg;
33348fb522fSmsaitoh 	mii_attach(sc->sc_dev, mii, 0xffffffff, phy_id, MII_OFFSET_ANY,
33424d51e99Sjmcneill 	    MIIF_DOPAUSE);
335971dc1a0Smartin 
336971dc1a0Smartin 	if (LIST_EMPTY(&mii->mii_phys)) {
337971dc1a0Smartin 		aprint_error_dev(sc->sc_dev, "no PHY found!\n");
338971dc1a0Smartin 		ifmedia_add(&mii->mii_media, IFM_ETHER | IFM_MANUAL, 0, NULL);
339971dc1a0Smartin 		ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_MANUAL);
340971dc1a0Smartin 	} else {
341971dc1a0Smartin 		ifmedia_set(&mii->mii_media, IFM_ETHER | IFM_AUTO);
342971dc1a0Smartin 	}
343971dc1a0Smartin 
344971dc1a0Smartin 	/*
345845d2aa5Stnn 	 * We can support 802.1Q VLAN-sized frames.
346845d2aa5Stnn 	 */
347845d2aa5Stnn 	sc->sc_ec.ec_capabilities |= ETHERCAP_VLAN_MTU;
348845d2aa5Stnn 
349845d2aa5Stnn 	/*
350971dc1a0Smartin 	 * Ready, attach interface
351971dc1a0Smartin 	 */
352fc18ade0Sskrll 	/* Attach the interface. */
353076e3579Sriastradh 	if_initialize(ifp);
354fc18ade0Sskrll 	sc->sc_ipq = if_percpuq_create(&sc->sc_ec.ec_if);
3551c82c572Sozaki-r 	if_deferred_start_init(ifp, NULL);
356971dc1a0Smartin 	ether_ifattach(ifp, enaddr);
357d1bd22e8Smartin 	ether_set_ifflags_cb(&sc->sc_ec, dwc_gmac_ifflags_cb);
358fc18ade0Sskrll 	if_register(ifp);
359f872a062Smsaitoh 	rnd_attach_source(&sc->rnd_source, device_xname(sc->sc_dev),
360f872a062Smsaitoh 	    RND_TYPE_NET, RND_FLAG_DEFAULT);
361971dc1a0Smartin 
362971dc1a0Smartin 	/*
363971dc1a0Smartin 	 * Enable interrupts
364971dc1a0Smartin 	 */
365c9ba1e93Sskrll 	mutex_enter(sc->sc_intr_lock);
36624d51e99Sjmcneill 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTMASK,
367bdbd5db8Smartin 	    AWIN_DEF_MAC_INTRMASK);
368bdbd5db8Smartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE,
369bdbd5db8Smartin 	    GMAC_DEF_DMA_INT_MASK);
370c9ba1e93Sskrll 	mutex_exit(sc->sc_intr_lock);
371971dc1a0Smartin 
37289fbd498Sjmcneill 	return 0;
37389fbd498Sjmcneill 
374971dc1a0Smartin fail:
375971dc1a0Smartin 	dwc_gmac_free_rx_ring(sc, &sc->sc_rxq);
376971dc1a0Smartin 	dwc_gmac_free_tx_ring(sc, &sc->sc_txq);
377a80b2b73Smsaitoh 	dwc_gmac_free_dma_rings(sc);
378a80b2b73Smsaitoh 	mutex_destroy(&sc->sc_mdio_lock);
37989fbd498Sjmcneill 
38089fbd498Sjmcneill 	return ENXIO;
381971dc1a0Smartin }
382971dc1a0Smartin 
383971dc1a0Smartin 
384971dc1a0Smartin 
385971dc1a0Smartin static int
386971dc1a0Smartin dwc_gmac_reset(struct dwc_gmac_softc *sc)
387971dc1a0Smartin {
388971dc1a0Smartin 	size_t cnt;
389971dc1a0Smartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE,
390c34bdbc5Smsaitoh 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE)
391c34bdbc5Smsaitoh 	    | GMAC_BUSMODE_RESET);
392b3feca02Sryo 	for (cnt = 0; cnt < 30000; cnt++) {
393971dc1a0Smartin 		if ((bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE)
394971dc1a0Smartin 		    & GMAC_BUSMODE_RESET) == 0)
395971dc1a0Smartin 			return 0;
396971dc1a0Smartin 		delay(10);
397971dc1a0Smartin 	}
398971dc1a0Smartin 
399971dc1a0Smartin 	aprint_error_dev(sc->sc_dev, "reset timed out\n");
400971dc1a0Smartin 	return EIO;
401971dc1a0Smartin }
402971dc1a0Smartin 
403971dc1a0Smartin static void
404971dc1a0Smartin dwc_gmac_write_hwaddr(struct dwc_gmac_softc *sc,
405971dc1a0Smartin     uint8_t enaddr[ETHER_ADDR_LEN])
406971dc1a0Smartin {
40773ce4049Sjmcneill 	uint32_t hi, lo;
408971dc1a0Smartin 
40973ce4049Sjmcneill 	hi = enaddr[4] | (enaddr[5] << 8);
410971dc1a0Smartin 	lo = enaddr[0] | (enaddr[1] << 8) | (enaddr[2] << 16)
4112f8b3c43Smsaitoh 	    | ((uint32_t)enaddr[3] << 24);
412971dc1a0Smartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0HI, hi);
41373ce4049Sjmcneill 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_ADDR0LO, lo);
414971dc1a0Smartin }
415971dc1a0Smartin 
416971dc1a0Smartin static int
417a5cdd4b4Smsaitoh dwc_gmac_miibus_read_reg(device_t self, int phy, int reg, uint16_t *val)
418971dc1a0Smartin {
419971dc1a0Smartin 	struct dwc_gmac_softc * const sc = device_private(self);
420518bac49Smartin 	uint16_t mii;
421971dc1a0Smartin 	size_t cnt;
422971dc1a0Smartin 
423518bac49Smartin 	mii = __SHIFTIN(phy, GMAC_MII_PHY_MASK)
424518bac49Smartin 	    | __SHIFTIN(reg, GMAC_MII_REG_MASK)
425518bac49Smartin 	    | __SHIFTIN(sc->sc_mii_clk, GMAC_MII_CLKMASK)
426518bac49Smartin 	    | GMAC_MII_BUSY;
427971dc1a0Smartin 
428971dc1a0Smartin 	mutex_enter(&sc->sc_mdio_lock);
429518bac49Smartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIADDR, mii);
430971dc1a0Smartin 
431971dc1a0Smartin 	for (cnt = 0; cnt < 1000; cnt++) {
432612a2a40Smartin 		if (!(bus_space_read_4(sc->sc_bst, sc->sc_bsh,
433612a2a40Smartin 		    AWIN_GMAC_MAC_MIIADDR) & GMAC_MII_BUSY)) {
434a5cdd4b4Smsaitoh 			*val = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
435612a2a40Smartin 			    AWIN_GMAC_MAC_MIIDATA);
436971dc1a0Smartin 			break;
437971dc1a0Smartin 		}
438971dc1a0Smartin 		delay(10);
439971dc1a0Smartin 	}
440971dc1a0Smartin 
441971dc1a0Smartin 	mutex_exit(&sc->sc_mdio_lock);
442971dc1a0Smartin 
443a5cdd4b4Smsaitoh 	if (cnt >= 1000)
444a5cdd4b4Smsaitoh 		return ETIMEDOUT;
445a5cdd4b4Smsaitoh 
446a5cdd4b4Smsaitoh 	return 0;
447971dc1a0Smartin }
448971dc1a0Smartin 
449a5cdd4b4Smsaitoh static int
450a5cdd4b4Smsaitoh dwc_gmac_miibus_write_reg(device_t self, int phy, int reg, uint16_t val)
451971dc1a0Smartin {
452971dc1a0Smartin 	struct dwc_gmac_softc * const sc = device_private(self);
453518bac49Smartin 	uint16_t mii;
454971dc1a0Smartin 	size_t cnt;
455971dc1a0Smartin 
456518bac49Smartin 	mii = __SHIFTIN(phy, GMAC_MII_PHY_MASK)
457518bac49Smartin 	    | __SHIFTIN(reg, GMAC_MII_REG_MASK)
458518bac49Smartin 	    | __SHIFTIN(sc->sc_mii_clk, GMAC_MII_CLKMASK)
459518bac49Smartin 	    | GMAC_MII_BUSY | GMAC_MII_WRITE;
460971dc1a0Smartin 
461971dc1a0Smartin 	mutex_enter(&sc->sc_mdio_lock);
462971dc1a0Smartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIDATA, val);
463518bac49Smartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_MIIADDR, mii);
464971dc1a0Smartin 
465971dc1a0Smartin 	for (cnt = 0; cnt < 1000; cnt++) {
466612a2a40Smartin 		if (!(bus_space_read_4(sc->sc_bst, sc->sc_bsh,
467612a2a40Smartin 		    AWIN_GMAC_MAC_MIIADDR) & GMAC_MII_BUSY))
468971dc1a0Smartin 			break;
469971dc1a0Smartin 		delay(10);
470971dc1a0Smartin 	}
471971dc1a0Smartin 
472971dc1a0Smartin 	mutex_exit(&sc->sc_mdio_lock);
473a5cdd4b4Smsaitoh 
474a5cdd4b4Smsaitoh 	if (cnt >= 1000)
475a5cdd4b4Smsaitoh 		return ETIMEDOUT;
476a5cdd4b4Smsaitoh 
477a5cdd4b4Smsaitoh 	return 0;
478971dc1a0Smartin }
479971dc1a0Smartin 
480971dc1a0Smartin static int
481971dc1a0Smartin dwc_gmac_alloc_rx_ring(struct dwc_gmac_softc *sc,
482971dc1a0Smartin 	struct dwc_gmac_rx_ring *ring)
483971dc1a0Smartin {
484971dc1a0Smartin 	struct dwc_gmac_rx_data *data;
485971dc1a0Smartin 	bus_addr_t physaddr;
48640044749Sskrll 	const size_t rxringsz = AWGE_RX_RING_COUNT * sizeof(*ring->r_desc);
487971dc1a0Smartin 	int error, i, next;
488971dc1a0Smartin 
489971dc1a0Smartin 	ring->r_cur = ring->r_next = 0;
49040044749Sskrll 	memset(ring->r_desc, 0, rxringsz);
491971dc1a0Smartin 
492971dc1a0Smartin 	/*
493971dc1a0Smartin 	 * Pre-allocate Rx buffers and populate Rx ring.
494971dc1a0Smartin 	 */
495971dc1a0Smartin 	for (i = 0; i < AWGE_RX_RING_COUNT; i++) {
496971dc1a0Smartin 		struct dwc_gmac_dev_dmadesc *desc;
497971dc1a0Smartin 
498971dc1a0Smartin 		data = &sc->sc_rxq.r_data[i];
499971dc1a0Smartin 
500971dc1a0Smartin 		MGETHDR(data->rd_m, M_DONTWAIT, MT_DATA);
501971dc1a0Smartin 		if (data->rd_m == NULL) {
502971dc1a0Smartin 			aprint_error_dev(sc->sc_dev,
503971dc1a0Smartin 			    "could not allocate rx mbuf #%d\n", i);
504971dc1a0Smartin 			error = ENOMEM;
505971dc1a0Smartin 			goto fail;
506971dc1a0Smartin 		}
507971dc1a0Smartin 		error = bus_dmamap_create(sc->sc_dmat, MCLBYTES, 1,
508971dc1a0Smartin 		    MCLBYTES, 0, BUS_DMA_NOWAIT, &data->rd_map);
509971dc1a0Smartin 		if (error != 0) {
510971dc1a0Smartin 			aprint_error_dev(sc->sc_dev,
511971dc1a0Smartin 			    "could not create DMA map\n");
512971dc1a0Smartin 			data->rd_map = NULL;
513971dc1a0Smartin 			goto fail;
514971dc1a0Smartin 		}
515971dc1a0Smartin 		MCLGET(data->rd_m, M_DONTWAIT);
516971dc1a0Smartin 		if (!(data->rd_m->m_flags & M_EXT)) {
517971dc1a0Smartin 			aprint_error_dev(sc->sc_dev,
518971dc1a0Smartin 			    "could not allocate mbuf cluster #%d\n", i);
519971dc1a0Smartin 			error = ENOMEM;
520971dc1a0Smartin 			goto fail;
521971dc1a0Smartin 		}
5223c96a2beStnn 		data->rd_m->m_len = data->rd_m->m_pkthdr.len
5233c96a2beStnn 		    = data->rd_m->m_ext.ext_size;
5243c96a2beStnn 		if (data->rd_m->m_len > AWGE_MAX_PACKET) {
5253c96a2beStnn 			data->rd_m->m_len = data->rd_m->m_pkthdr.len
5263c96a2beStnn 			    = AWGE_MAX_PACKET;
5273c96a2beStnn 		}
528971dc1a0Smartin 
5293c96a2beStnn 		error = bus_dmamap_load_mbuf(sc->sc_dmat, data->rd_map,
5303c96a2beStnn 		    data->rd_m, BUS_DMA_READ | BUS_DMA_NOWAIT);
531971dc1a0Smartin 		if (error != 0) {
532971dc1a0Smartin 			aprint_error_dev(sc->sc_dev,
533971dc1a0Smartin 			    "could not load rx buf DMA map #%d", i);
534971dc1a0Smartin 			goto fail;
535971dc1a0Smartin 		}
5363c96a2beStnn 		bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0,
5373c96a2beStnn 		    data->rd_map->dm_mapsize, BUS_DMASYNC_PREREAD);
538971dc1a0Smartin 		physaddr = data->rd_map->dm_segs[0].ds_addr;
539971dc1a0Smartin 
540971dc1a0Smartin 		desc = &sc->sc_rxq.r_desc[i];
541971dc1a0Smartin 		desc->ddesc_data = htole32(physaddr);
542bdbd5db8Smartin 		next = RX_NEXT(i);
543971dc1a0Smartin 		desc->ddesc_next = htole32(ring->r_physaddr
544971dc1a0Smartin 		    + next * sizeof(*desc));
54572645925Smartin 		sc->sc_descm->rx_init_flags(desc);
5463c96a2beStnn 		sc->sc_descm->rx_set_len(desc, data->rd_m->m_len);
54772645925Smartin 		sc->sc_descm->rx_set_owned_by_dev(desc);
548971dc1a0Smartin 	}
549971dc1a0Smartin 
55040044749Sskrll 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
55140044749Sskrll 	    RX_DESC_OFFSET(0),
552971dc1a0Smartin 	    AWGE_RX_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc),
5539893fe95Sskrll 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
554971dc1a0Smartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR,
555518bac49Smartin 	    ring->r_physaddr);
556971dc1a0Smartin 
557971dc1a0Smartin 	return 0;
558971dc1a0Smartin 
559971dc1a0Smartin fail:
560971dc1a0Smartin 	dwc_gmac_free_rx_ring(sc, ring);
561971dc1a0Smartin 	return error;
562971dc1a0Smartin }
563971dc1a0Smartin 
564971dc1a0Smartin static void
565971dc1a0Smartin dwc_gmac_reset_rx_ring(struct dwc_gmac_softc *sc,
566971dc1a0Smartin 	struct dwc_gmac_rx_ring *ring)
567971dc1a0Smartin {
568971dc1a0Smartin 	struct dwc_gmac_dev_dmadesc *desc;
5693c96a2beStnn 	struct dwc_gmac_rx_data *data;
570971dc1a0Smartin 	int i;
571971dc1a0Smartin 
572fc18ade0Sskrll 	mutex_enter(&ring->r_mtx);
573971dc1a0Smartin 	for (i = 0; i < AWGE_RX_RING_COUNT; i++) {
574971dc1a0Smartin 		desc = &sc->sc_rxq.r_desc[i];
5753c96a2beStnn 		data = &sc->sc_rxq.r_data[i];
57672645925Smartin 		sc->sc_descm->rx_init_flags(desc);
5773c96a2beStnn 		sc->sc_descm->rx_set_len(desc, data->rd_m->m_len);
57872645925Smartin 		sc->sc_descm->rx_set_owned_by_dev(desc);
579971dc1a0Smartin 	}
580971dc1a0Smartin 
581971dc1a0Smartin 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0,
582971dc1a0Smartin 	    AWGE_RX_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc),
5830c8fe4ccSmatt 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
584971dc1a0Smartin 
585971dc1a0Smartin 	ring->r_cur = ring->r_next = 0;
586426c40ceSmartin 	/* reset DMA address to start of ring */
587426c40ceSmartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR,
588426c40ceSmartin 	    sc->sc_rxq.r_physaddr);
589fc18ade0Sskrll 	mutex_exit(&ring->r_mtx);
590971dc1a0Smartin }
591971dc1a0Smartin 
592971dc1a0Smartin static int
593971dc1a0Smartin dwc_gmac_alloc_dma_rings(struct dwc_gmac_softc *sc)
594971dc1a0Smartin {
59540044749Sskrll 	const size_t ringsize = AWGE_TOTAL_RING_COUNT *
596971dc1a0Smartin 		sizeof(struct dwc_gmac_dev_dmadesc);
597971dc1a0Smartin 	int error, nsegs;
598971dc1a0Smartin 	void *rings;
599971dc1a0Smartin 
60040044749Sskrll 	error = bus_dmamap_create(sc->sc_dmat, ringsize, 1, ringsize, 0,
601971dc1a0Smartin 	    BUS_DMA_NOWAIT, &sc->sc_dma_ring_map);
602971dc1a0Smartin 	if (error != 0) {
603971dc1a0Smartin 		aprint_error_dev(sc->sc_dev,
604971dc1a0Smartin 		    "could not create desc DMA map\n");
605971dc1a0Smartin 		sc->sc_dma_ring_map = NULL;
606971dc1a0Smartin 		goto fail;
607971dc1a0Smartin 	}
608971dc1a0Smartin 
60940044749Sskrll 	error = bus_dmamem_alloc(sc->sc_dmat, ringsize, PAGE_SIZE, 0,
610971dc1a0Smartin 	    &sc->sc_dma_ring_seg, 1, &nsegs, BUS_DMA_NOWAIT |BUS_DMA_COHERENT);
611971dc1a0Smartin 	if (error != 0) {
612971dc1a0Smartin 		aprint_error_dev(sc->sc_dev,
613971dc1a0Smartin 		    "could not map DMA memory\n");
614971dc1a0Smartin 		goto fail;
615971dc1a0Smartin 	}
616971dc1a0Smartin 
617971dc1a0Smartin 	error = bus_dmamem_map(sc->sc_dmat, &sc->sc_dma_ring_seg, nsegs,
61840044749Sskrll 	    ringsize, &rings, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
619971dc1a0Smartin 	if (error != 0) {
620971dc1a0Smartin 		aprint_error_dev(sc->sc_dev,
621971dc1a0Smartin 		    "could not allocate DMA memory\n");
622971dc1a0Smartin 		goto fail;
623971dc1a0Smartin 	}
624971dc1a0Smartin 
625971dc1a0Smartin 	error = bus_dmamap_load(sc->sc_dmat, sc->sc_dma_ring_map, rings,
62640044749Sskrll 	    ringsize, NULL, BUS_DMA_NOWAIT | BUS_DMA_COHERENT);
627971dc1a0Smartin 	if (error != 0) {
628971dc1a0Smartin 		aprint_error_dev(sc->sc_dev,
629971dc1a0Smartin 		    "could not load desc DMA map\n");
630971dc1a0Smartin 		goto fail;
631971dc1a0Smartin 	}
632971dc1a0Smartin 
633971dc1a0Smartin 	/* give first AWGE_RX_RING_COUNT to the RX side */
634971dc1a0Smartin 	sc->sc_rxq.r_desc = rings;
635971dc1a0Smartin 	sc->sc_rxq.r_physaddr = sc->sc_dma_ring_map->dm_segs[0].ds_addr;
636971dc1a0Smartin 
637971dc1a0Smartin 	/* and next rings to the TX side */
638971dc1a0Smartin 	sc->sc_txq.t_desc = sc->sc_rxq.r_desc + AWGE_RX_RING_COUNT;
639971dc1a0Smartin 	sc->sc_txq.t_physaddr = sc->sc_rxq.r_physaddr +
640971dc1a0Smartin 	    AWGE_RX_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc);
641971dc1a0Smartin 
642971dc1a0Smartin 	return 0;
643971dc1a0Smartin 
644971dc1a0Smartin fail:
645971dc1a0Smartin 	dwc_gmac_free_dma_rings(sc);
646971dc1a0Smartin 	return error;
647971dc1a0Smartin }
648971dc1a0Smartin 
649971dc1a0Smartin static void
650971dc1a0Smartin dwc_gmac_free_dma_rings(struct dwc_gmac_softc *sc)
651971dc1a0Smartin {
652971dc1a0Smartin 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map, 0,
653971dc1a0Smartin 	    sc->sc_dma_ring_map->dm_mapsize, BUS_DMASYNC_POSTWRITE);
654971dc1a0Smartin 	bus_dmamap_unload(sc->sc_dmat, sc->sc_dma_ring_map);
655971dc1a0Smartin 	bus_dmamem_unmap(sc->sc_dmat, sc->sc_rxq.r_desc,
656971dc1a0Smartin 	    AWGE_TOTAL_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc));
657971dc1a0Smartin 	bus_dmamem_free(sc->sc_dmat, &sc->sc_dma_ring_seg, 1);
658971dc1a0Smartin }
659971dc1a0Smartin 
660971dc1a0Smartin static void
661971dc1a0Smartin dwc_gmac_free_rx_ring(struct dwc_gmac_softc *sc, struct dwc_gmac_rx_ring *ring)
662971dc1a0Smartin {
663971dc1a0Smartin 	struct dwc_gmac_rx_data *data;
664971dc1a0Smartin 	int i;
665971dc1a0Smartin 
666971dc1a0Smartin 	if (ring->r_desc == NULL)
667971dc1a0Smartin 		return;
668971dc1a0Smartin 
669971dc1a0Smartin 	for (i = 0; i < AWGE_RX_RING_COUNT; i++) {
670971dc1a0Smartin 		data = &ring->r_data[i];
671971dc1a0Smartin 
672971dc1a0Smartin 		if (data->rd_map != NULL) {
673971dc1a0Smartin 			bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0,
674971dc1a0Smartin 			    AWGE_RX_RING_COUNT
675971dc1a0Smartin 				* sizeof(struct dwc_gmac_dev_dmadesc),
676971dc1a0Smartin 			    BUS_DMASYNC_POSTREAD);
677971dc1a0Smartin 			bus_dmamap_unload(sc->sc_dmat, data->rd_map);
678971dc1a0Smartin 			bus_dmamap_destroy(sc->sc_dmat, data->rd_map);
679971dc1a0Smartin 		}
680971dc1a0Smartin 		m_freem(data->rd_m);
681971dc1a0Smartin 	}
682971dc1a0Smartin }
683971dc1a0Smartin 
684971dc1a0Smartin static int
685971dc1a0Smartin dwc_gmac_alloc_tx_ring(struct dwc_gmac_softc *sc,
686971dc1a0Smartin 	struct dwc_gmac_tx_ring *ring)
687971dc1a0Smartin {
688971dc1a0Smartin 	int i, error = 0;
689971dc1a0Smartin 
690971dc1a0Smartin 	ring->t_queued = 0;
691971dc1a0Smartin 	ring->t_cur = ring->t_next = 0;
692971dc1a0Smartin 
693971dc1a0Smartin 	memset(ring->t_desc, 0, AWGE_TX_RING_COUNT * sizeof(*ring->t_desc));
694971dc1a0Smartin 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
695971dc1a0Smartin 	    TX_DESC_OFFSET(0),
696971dc1a0Smartin 	    AWGE_TX_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc),
69740044749Sskrll 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
698971dc1a0Smartin 
699971dc1a0Smartin 	for (i = 0; i < AWGE_TX_RING_COUNT; i++) {
700971dc1a0Smartin 		error = bus_dmamap_create(sc->sc_dmat, MCLBYTES,
701971dc1a0Smartin 		    AWGE_TX_RING_COUNT, MCLBYTES, 0,
702971dc1a0Smartin 		    BUS_DMA_NOWAIT | BUS_DMA_COHERENT,
703971dc1a0Smartin 		    &ring->t_data[i].td_map);
704971dc1a0Smartin 		if (error != 0) {
705971dc1a0Smartin 			aprint_error_dev(sc->sc_dev,
706971dc1a0Smartin 			    "could not create TX DMA map #%d\n", i);
707971dc1a0Smartin 			ring->t_data[i].td_map = NULL;
708971dc1a0Smartin 			goto fail;
709971dc1a0Smartin 		}
710971dc1a0Smartin 		ring->t_desc[i].ddesc_next = htole32(
711971dc1a0Smartin 		    ring->t_physaddr + sizeof(struct dwc_gmac_dev_dmadesc)
712bdbd5db8Smartin 		    * TX_NEXT(i));
713971dc1a0Smartin 	}
71440044749Sskrll 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
71540044749Sskrll 	    TX_DESC_OFFSET(0),
71640044749Sskrll 	    AWGE_TX_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc),
71740044749Sskrll 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
718971dc1a0Smartin 
719971dc1a0Smartin 	return 0;
720971dc1a0Smartin 
721971dc1a0Smartin fail:
722971dc1a0Smartin 	dwc_gmac_free_tx_ring(sc, ring);
723971dc1a0Smartin 	return error;
724971dc1a0Smartin }
725971dc1a0Smartin 
726971dc1a0Smartin static void
727971dc1a0Smartin dwc_gmac_txdesc_sync(struct dwc_gmac_softc *sc, int start, int end, int ops)
728971dc1a0Smartin {
729ba5b08dfSmrg 	/* 'end' is pointing one descriptor beyond the last we want to sync */
730971dc1a0Smartin 	if (end > start) {
731971dc1a0Smartin 		bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
732971dc1a0Smartin 		    TX_DESC_OFFSET(start),
733971dc1a0Smartin 		    TX_DESC_OFFSET(end) - TX_DESC_OFFSET(start),
734971dc1a0Smartin 		    ops);
735971dc1a0Smartin 		return;
736971dc1a0Smartin 	}
737971dc1a0Smartin 	/* sync from 'start' to end of ring */
738971dc1a0Smartin 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
739971dc1a0Smartin 	    TX_DESC_OFFSET(start),
7408bddfabdSjmcneill 	    TX_DESC_OFFSET(AWGE_TX_RING_COUNT) - TX_DESC_OFFSET(start),
741971dc1a0Smartin 	    ops);
74269e07b1eSjmcneill 	if (TX_DESC_OFFSET(end) - TX_DESC_OFFSET(0) > 0) {
743971dc1a0Smartin 		/* sync from start of ring to 'end' */
744971dc1a0Smartin 		bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
745971dc1a0Smartin 		    TX_DESC_OFFSET(0),
746971dc1a0Smartin 		    TX_DESC_OFFSET(end) - TX_DESC_OFFSET(0),
747971dc1a0Smartin 		    ops);
748971dc1a0Smartin 	}
74969e07b1eSjmcneill }
750971dc1a0Smartin 
751971dc1a0Smartin static void
752971dc1a0Smartin dwc_gmac_reset_tx_ring(struct dwc_gmac_softc *sc,
753971dc1a0Smartin 	struct dwc_gmac_tx_ring *ring)
754971dc1a0Smartin {
755971dc1a0Smartin 	int i;
756971dc1a0Smartin 
757fc18ade0Sskrll 	mutex_enter(&ring->t_mtx);
758971dc1a0Smartin 	for (i = 0; i < AWGE_TX_RING_COUNT; i++) {
759971dc1a0Smartin 		struct dwc_gmac_tx_data *data = &ring->t_data[i];
760971dc1a0Smartin 
761971dc1a0Smartin 		if (data->td_m != NULL) {
762971dc1a0Smartin 			bus_dmamap_sync(sc->sc_dmat, data->td_active,
763971dc1a0Smartin 			    0, data->td_active->dm_mapsize,
764971dc1a0Smartin 			    BUS_DMASYNC_POSTWRITE);
765971dc1a0Smartin 			bus_dmamap_unload(sc->sc_dmat, data->td_active);
766971dc1a0Smartin 			m_freem(data->td_m);
767971dc1a0Smartin 			data->td_m = NULL;
768971dc1a0Smartin 		}
769971dc1a0Smartin 	}
770971dc1a0Smartin 
771971dc1a0Smartin 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
772971dc1a0Smartin 	    TX_DESC_OFFSET(0),
773971dc1a0Smartin 	    AWGE_TX_RING_COUNT * sizeof(struct dwc_gmac_dev_dmadesc),
7740c8fe4ccSmatt 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
775518bac49Smartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR,
776518bac49Smartin 	    sc->sc_txq.t_physaddr);
777971dc1a0Smartin 
778971dc1a0Smartin 	ring->t_queued = 0;
779971dc1a0Smartin 	ring->t_cur = ring->t_next = 0;
780fc18ade0Sskrll 	mutex_exit(&ring->t_mtx);
781971dc1a0Smartin }
782971dc1a0Smartin 
783971dc1a0Smartin static void
784971dc1a0Smartin dwc_gmac_free_tx_ring(struct dwc_gmac_softc *sc,
785971dc1a0Smartin 	struct dwc_gmac_tx_ring *ring)
786971dc1a0Smartin {
787971dc1a0Smartin 	int i;
788971dc1a0Smartin 
789971dc1a0Smartin 	/* unload the maps */
790971dc1a0Smartin 	for (i = 0; i < AWGE_TX_RING_COUNT; i++) {
791971dc1a0Smartin 		struct dwc_gmac_tx_data *data = &ring->t_data[i];
792971dc1a0Smartin 
793971dc1a0Smartin 		if (data->td_m != NULL) {
794971dc1a0Smartin 			bus_dmamap_sync(sc->sc_dmat, data->td_active,
795971dc1a0Smartin 			    0, data->td_map->dm_mapsize,
796971dc1a0Smartin 			    BUS_DMASYNC_POSTWRITE);
797971dc1a0Smartin 			bus_dmamap_unload(sc->sc_dmat, data->td_active);
798971dc1a0Smartin 			m_freem(data->td_m);
799971dc1a0Smartin 			data->td_m = NULL;
800971dc1a0Smartin 		}
801971dc1a0Smartin 	}
802971dc1a0Smartin 
803971dc1a0Smartin 	/* and actually free them */
804971dc1a0Smartin 	for (i = 0; i < AWGE_TX_RING_COUNT; i++) {
805971dc1a0Smartin 		struct dwc_gmac_tx_data *data = &ring->t_data[i];
806971dc1a0Smartin 
807971dc1a0Smartin 		bus_dmamap_destroy(sc->sc_dmat, data->td_map);
808971dc1a0Smartin 	}
809971dc1a0Smartin }
810971dc1a0Smartin 
811971dc1a0Smartin static void
812971dc1a0Smartin dwc_gmac_miibus_statchg(struct ifnet *ifp)
813971dc1a0Smartin {
814971dc1a0Smartin 	struct dwc_gmac_softc * const sc = ifp->if_softc;
815971dc1a0Smartin 	struct mii_data * const mii = &sc->sc_mii;
81624d51e99Sjmcneill 	uint32_t conf, flow;
817971dc1a0Smartin 
818971dc1a0Smartin 	/*
819971dc1a0Smartin 	 * Set MII or GMII interface based on the speed
820971dc1a0Smartin 	 * negotiated by the PHY.
821971dc1a0Smartin 	 */
8228277fba8Smartin 	conf = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_CONF);
8238277fba8Smartin 	conf &= ~(AWIN_GMAC_MAC_CONF_FES100 | AWIN_GMAC_MAC_CONF_MIISEL
8248277fba8Smartin 	    | AWIN_GMAC_MAC_CONF_FULLDPLX);
825426c40ceSmartin 	conf |= AWIN_GMAC_MAC_CONF_FRAMEBURST
826426c40ceSmartin 	    | AWIN_GMAC_MAC_CONF_DISABLERXOWN
82724d51e99Sjmcneill 	    | AWIN_GMAC_MAC_CONF_DISABLEJABBER
828426c40ceSmartin 	    | AWIN_GMAC_MAC_CONF_RXENABLE
829426c40ceSmartin 	    | AWIN_GMAC_MAC_CONF_TXENABLE;
830971dc1a0Smartin 	switch (IFM_SUBTYPE(mii->mii_media_active)) {
831971dc1a0Smartin 	case IFM_10_T:
83272e2d70fSjmcneill 		conf |= AWIN_GMAC_MAC_CONF_MIISEL;
8338277fba8Smartin 		break;
834971dc1a0Smartin 	case IFM_100_TX:
83572e2d70fSjmcneill 		conf |= AWIN_GMAC_MAC_CONF_FES100 |
83672e2d70fSjmcneill 			AWIN_GMAC_MAC_CONF_MIISEL;
837971dc1a0Smartin 		break;
838971dc1a0Smartin 	case IFM_1000_T:
839971dc1a0Smartin 		break;
840971dc1a0Smartin 	}
841041c183aSjmcneill 	if (sc->sc_set_speed)
842041c183aSjmcneill 		sc->sc_set_speed(sc, IFM_SUBTYPE(mii->mii_media_active));
84324d51e99Sjmcneill 
84424d51e99Sjmcneill 	flow = 0;
84524d51e99Sjmcneill 	if (IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) {
8468277fba8Smartin 		conf |= AWIN_GMAC_MAC_CONF_FULLDPLX;
84724d51e99Sjmcneill 		flow |= __SHIFTIN(0x200, AWIN_GMAC_MAC_FLOWCTRL_PAUSE);
84824d51e99Sjmcneill 	}
84924d51e99Sjmcneill 	if (mii->mii_media_active & IFM_ETH_TXPAUSE) {
85024d51e99Sjmcneill 		flow |= AWIN_GMAC_MAC_FLOWCTRL_TFE;
85124d51e99Sjmcneill 	}
85224d51e99Sjmcneill 	if (mii->mii_media_active & IFM_ETH_RXPAUSE) {
85324d51e99Sjmcneill 		flow |= AWIN_GMAC_MAC_FLOWCTRL_RFE;
85424d51e99Sjmcneill 	}
85524d51e99Sjmcneill 	bus_space_write_4(sc->sc_bst, sc->sc_bsh,
85624d51e99Sjmcneill 	    AWIN_GMAC_MAC_FLOWCTRL, flow);
8578277fba8Smartin 
8588277fba8Smartin #ifdef DWC_GMAC_DEBUG
8598277fba8Smartin 	aprint_normal_dev(sc->sc_dev,
8608277fba8Smartin 	    "setting MAC conf register: %08x\n", conf);
8618277fba8Smartin #endif
8628277fba8Smartin 
8638277fba8Smartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh,
8648277fba8Smartin 	    AWIN_GMAC_MAC_CONF, conf);
865971dc1a0Smartin }
866971dc1a0Smartin 
867971dc1a0Smartin static int
868971dc1a0Smartin dwc_gmac_init(struct ifnet *ifp)
869971dc1a0Smartin {
870eb43ba5fSskrll 	struct dwc_gmac_softc * const sc = ifp->if_softc;
871a0ef5e67Sjmcneill 	uint32_t ffilt;
872971dc1a0Smartin 
873c9ba1e93Sskrll 	ASSERT_SLEEPABLE();
874c9ba1e93Sskrll 	KASSERT(IFNET_LOCKED(ifp));
875c9ba1e93Sskrll 	KASSERT(ifp == &sc->sc_ec.ec_if);
876971dc1a0Smartin 
87796373f68Sriastradh 	dwc_gmac_stop(ifp, 0);
878971dc1a0Smartin 
879971dc1a0Smartin 	/*
880426c40ceSmartin 	 * Configure DMA burst/transfer mode and RX/TX priorities.
881426c40ceSmartin 	 * XXX - the GMAC_BUSMODE_PRIORXTX bits are undocumented.
882426c40ceSmartin 	 */
883426c40ceSmartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE,
88424d51e99Sjmcneill 	    GMAC_BUSMODE_FIXEDBURST | GMAC_BUSMODE_4PBL |
88524d51e99Sjmcneill 	    __SHIFTIN(2, GMAC_BUSMODE_RPBL) |
88624d51e99Sjmcneill 	    __SHIFTIN(2, GMAC_BUSMODE_PBL));
887426c40ceSmartin 
888426c40ceSmartin 	/*
889a0ef5e67Sjmcneill 	 * Set up address filter
890426c40ceSmartin 	 */
891f8c640e7Sjmcneill 	ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT);
892f8c640e7Sjmcneill 	if (ifp->if_flags & IFF_PROMISC) {
893a0ef5e67Sjmcneill 		ffilt |= AWIN_GMAC_MAC_FFILT_PR;
894f8c640e7Sjmcneill 	} else {
895f8c640e7Sjmcneill 		ffilt &= ~AWIN_GMAC_MAC_FFILT_PR;
896f8c640e7Sjmcneill 	}
897f8c640e7Sjmcneill 	if (ifp->if_flags & IFF_BROADCAST) {
898f8c640e7Sjmcneill 		ffilt &= ~AWIN_GMAC_MAC_FFILT_DBF;
899f8c640e7Sjmcneill 	} else {
900f8c640e7Sjmcneill 		ffilt |= AWIN_GMAC_MAC_FFILT_DBF;
901f8c640e7Sjmcneill 	}
902a0ef5e67Sjmcneill 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, ffilt);
903426c40ceSmartin 
904426c40ceSmartin 	/*
905f8c640e7Sjmcneill 	 * Set up multicast filter
906f8c640e7Sjmcneill 	 */
90796373f68Sriastradh 	mutex_enter(sc->sc_mcast_lock);
908f8c640e7Sjmcneill 	dwc_gmac_setmulti(sc);
90996373f68Sriastradh 	mutex_exit(sc->sc_mcast_lock);
910f8c640e7Sjmcneill 
911f8c640e7Sjmcneill 	/*
912518bac49Smartin 	 * Set up dma pointer for RX and TX ring
913971dc1a0Smartin 	 */
914518bac49Smartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR,
915518bac49Smartin 	    sc->sc_rxq.r_physaddr);
916518bac49Smartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR,
917518bac49Smartin 	    sc->sc_txq.t_physaddr);
918518bac49Smartin 
919518bac49Smartin 	/*
9205158fc24Smartin 	 * Start RX/TX part
921518bac49Smartin 	 */
922041c183aSjmcneill 	uint32_t opmode = GMAC_DMA_OP_RXSTART | GMAC_DMA_OP_TXSTART;
923041c183aSjmcneill 	if ((sc->sc_flags & DWC_GMAC_FORCE_THRESH_DMA_MODE) == 0) {
924041c183aSjmcneill 		opmode |= GMAC_DMA_OP_RXSTOREFORWARD | GMAC_DMA_OP_TXSTOREFORWARD;
925041c183aSjmcneill 	}
926041c183aSjmcneill 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_OPMODE, opmode);
92704b7b2c1Sskrll #ifdef DWC_GMAC_DEBUG
92804b7b2c1Sskrll 	aprint_normal_dev(sc->sc_dev,
92904b7b2c1Sskrll 	    "setting DMA opmode register: %08x\n", opmode);
93004b7b2c1Sskrll #endif
931971dc1a0Smartin 
932c9ba1e93Sskrll 	ifp->if_flags |= IFF_RUNNING;
933c9ba1e93Sskrll 	sc->sc_if_flags = ifp->if_flags;
934c9ba1e93Sskrll 
935c9ba1e93Sskrll 	mutex_enter(sc->sc_intr_lock);
936fc18ade0Sskrll 	sc->sc_stopping = false;
93796373f68Sriastradh 	mutex_exit(sc->sc_intr_lock);
938fc18ade0Sskrll 
939c9ba1e93Sskrll 	mutex_enter(&sc->sc_txq.t_mtx);
940bdb3207bSthorpej 	sc->sc_txbusy = false;
941c9ba1e93Sskrll 	mutex_exit(&sc->sc_txq.t_mtx);
942971dc1a0Smartin 
943971dc1a0Smartin 	return 0;
944971dc1a0Smartin }
945971dc1a0Smartin 
946971dc1a0Smartin static void
947971dc1a0Smartin dwc_gmac_start(struct ifnet *ifp)
948971dc1a0Smartin {
949eb43ba5fSskrll 	struct dwc_gmac_softc * const sc = ifp->if_softc;
950ab3cd725Sozaki-r 	KASSERT(if_is_mpsafe(ifp));
951fc18ade0Sskrll 
952c9ba1e93Sskrll 	mutex_enter(sc->sc_intr_lock);
953fc18ade0Sskrll 	if (!sc->sc_stopping) {
954fc18ade0Sskrll 		dwc_gmac_start_locked(ifp);
955fc18ade0Sskrll 	}
956c9ba1e93Sskrll 	mutex_exit(sc->sc_intr_lock);
957fc18ade0Sskrll }
958fc18ade0Sskrll 
959fc18ade0Sskrll static void
960fc18ade0Sskrll dwc_gmac_start_locked(struct ifnet *ifp)
961fc18ade0Sskrll {
962eb43ba5fSskrll 	struct dwc_gmac_softc * const sc = ifp->if_softc;
963971dc1a0Smartin 	int old = sc->sc_txq.t_queued;
964ef110221Smartin 	int start = sc->sc_txq.t_cur;
965971dc1a0Smartin 	struct mbuf *m0;
966971dc1a0Smartin 
967c9ba1e93Sskrll 	KASSERT(mutex_owned(sc->sc_intr_lock));
968c9ba1e93Sskrll 
969c9ba1e93Sskrll 	mutex_enter(&sc->sc_txq.t_mtx);
970c9ba1e93Sskrll 	if (sc->sc_txbusy) {
971c9ba1e93Sskrll 		mutex_exit(&sc->sc_txq.t_mtx);
972bdb3207bSthorpej 		return;
973c9ba1e93Sskrll 	}
974971dc1a0Smartin 
975971dc1a0Smartin 	for (;;) {
976971dc1a0Smartin 		IFQ_POLL(&ifp->if_snd, m0);
977971dc1a0Smartin 		if (m0 == NULL)
978971dc1a0Smartin 			break;
979971dc1a0Smartin 		if (dwc_gmac_queue(sc, m0) != 0) {
980bdb3207bSthorpej 			sc->sc_txbusy = true;
981971dc1a0Smartin 			break;
982971dc1a0Smartin 		}
983971dc1a0Smartin 		IFQ_DEQUEUE(&ifp->if_snd, m0);
9843cd62456Smsaitoh 		bpf_mtap(ifp, m0, BPF_D_OUT);
9858132f7b2Smartin 		if (sc->sc_txq.t_queued == AWGE_TX_RING_COUNT) {
986bdb3207bSthorpej 			sc->sc_txbusy = true;
9878132f7b2Smartin 			break;
9888132f7b2Smartin 		}
989971dc1a0Smartin 	}
990971dc1a0Smartin 
991971dc1a0Smartin 	if (sc->sc_txq.t_queued != old) {
992971dc1a0Smartin 		/* packets have been queued, kick it off */
993ef110221Smartin 		dwc_gmac_txdesc_sync(sc, start, sc->sc_txq.t_cur,
994971dc1a0Smartin 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
995518bac49Smartin 
9965158fc24Smartin #ifdef DWC_GMAC_DEBUG
9975158fc24Smartin 		dwc_dump_status(sc);
9985158fc24Smartin #endif
99972645925Smartin 		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
100072645925Smartin 		    AWIN_GMAC_DMA_TXPOLL, ~0U);
1001971dc1a0Smartin 	}
1002c9ba1e93Sskrll 	mutex_exit(&sc->sc_txq.t_mtx);
1003971dc1a0Smartin }
1004971dc1a0Smartin 
1005971dc1a0Smartin static void
1006971dc1a0Smartin dwc_gmac_stop(struct ifnet *ifp, int disable)
1007971dc1a0Smartin {
1008eb43ba5fSskrll 	struct dwc_gmac_softc * const sc = ifp->if_softc;
1009971dc1a0Smartin 
1010c9ba1e93Sskrll 	ASSERT_SLEEPABLE();
1011c9ba1e93Sskrll 	KASSERT(IFNET_LOCKED(ifp));
101296373f68Sriastradh 
101396373f68Sriastradh 	ifp->if_flags &= ~IFF_RUNNING;
101496373f68Sriastradh 
101596373f68Sriastradh 	mutex_enter(sc->sc_mcast_lock);
101696373f68Sriastradh 	sc->sc_if_flags = ifp->if_flags;
101796373f68Sriastradh 	mutex_exit(sc->sc_mcast_lock);
1018c9ba1e93Sskrll 
1019c9ba1e93Sskrll 	mutex_enter(sc->sc_intr_lock);
1020fc18ade0Sskrll 	sc->sc_stopping = true;
102196373f68Sriastradh 	mutex_exit(sc->sc_intr_lock);
1022fc18ade0Sskrll 
1023c9ba1e93Sskrll 	mutex_enter(&sc->sc_txq.t_mtx);
1024c9ba1e93Sskrll 	sc->sc_txbusy = false;
1025c9ba1e93Sskrll 	mutex_exit(&sc->sc_txq.t_mtx);
1026c9ba1e93Sskrll 
1027518bac49Smartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh,
1028518bac49Smartin 	    AWIN_GMAC_DMA_OPMODE,
1029518bac49Smartin 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh,
1030518bac49Smartin 		AWIN_GMAC_DMA_OPMODE)
1031518bac49Smartin 		& ~(GMAC_DMA_OP_TXSTART | GMAC_DMA_OP_RXSTART));
1032518bac49Smartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh,
1033518bac49Smartin 	    AWIN_GMAC_DMA_OPMODE,
1034518bac49Smartin 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh,
1035518bac49Smartin 		AWIN_GMAC_DMA_OPMODE) | GMAC_DMA_OP_FLUSHTX);
1036518bac49Smartin 
1037971dc1a0Smartin 	mii_down(&sc->sc_mii);
1038971dc1a0Smartin 	dwc_gmac_reset_tx_ring(sc, &sc->sc_txq);
1039971dc1a0Smartin 	dwc_gmac_reset_rx_ring(sc, &sc->sc_rxq);
1040971dc1a0Smartin }
1041971dc1a0Smartin 
1042971dc1a0Smartin /*
1043971dc1a0Smartin  * Add m0 to the TX ring
1044971dc1a0Smartin  */
1045971dc1a0Smartin static int
1046971dc1a0Smartin dwc_gmac_queue(struct dwc_gmac_softc *sc, struct mbuf *m0)
1047971dc1a0Smartin {
1048971dc1a0Smartin 	struct dwc_gmac_dev_dmadesc *desc = NULL;
1049971dc1a0Smartin 	struct dwc_gmac_tx_data *data = NULL;
1050971dc1a0Smartin 	bus_dmamap_t map;
1051971dc1a0Smartin 	int error, i, first;
1052971dc1a0Smartin 
1053bdbd5db8Smartin #ifdef DWC_GMAC_DEBUG
1054bdbd5db8Smartin 	aprint_normal_dev(sc->sc_dev,
1055bdbd5db8Smartin 	    "dwc_gmac_queue: adding mbuf chain %p\n", m0);
1056bdbd5db8Smartin #endif
1057bdbd5db8Smartin 
1058971dc1a0Smartin 	first = sc->sc_txq.t_cur;
1059971dc1a0Smartin 	map = sc->sc_txq.t_data[first].td_map;
1060971dc1a0Smartin 
1061971dc1a0Smartin 	error = bus_dmamap_load_mbuf(sc->sc_dmat, map, m0,
1062971dc1a0Smartin 	    BUS_DMA_WRITE | BUS_DMA_NOWAIT);
1063971dc1a0Smartin 	if (error != 0) {
1064971dc1a0Smartin 		aprint_error_dev(sc->sc_dev, "could not map mbuf "
1065971dc1a0Smartin 		    "(len: %d, error %d)\n", m0->m_pkthdr.len, error);
1066971dc1a0Smartin 		return error;
1067971dc1a0Smartin 	}
1068971dc1a0Smartin 
10698132f7b2Smartin 	if (sc->sc_txq.t_queued + map->dm_nsegs > AWGE_TX_RING_COUNT) {
1070971dc1a0Smartin 		bus_dmamap_unload(sc->sc_dmat, map);
1071971dc1a0Smartin 		return ENOBUFS;
1072971dc1a0Smartin 	}
1073971dc1a0Smartin 
1074971dc1a0Smartin 	for (i = 0; i < map->dm_nsegs; i++) {
1075971dc1a0Smartin 		data = &sc->sc_txq.t_data[sc->sc_txq.t_cur];
1076971dc1a0Smartin 		desc = &sc->sc_txq.t_desc[sc->sc_txq.t_cur];
1077971dc1a0Smartin 
1078971dc1a0Smartin 		desc->ddesc_data = htole32(map->dm_segs[i].ds_addr);
1079bdbd5db8Smartin 
1080bdbd5db8Smartin #ifdef DWC_GMAC_DEBUG
1081b29c5071Sskrll 		aprint_normal_dev(sc->sc_dev, "enqueuing desc #%d data %08lx "
108272645925Smartin 		    "len %lu\n", sc->sc_txq.t_cur,
1083bdbd5db8Smartin 		    (unsigned long)map->dm_segs[i].ds_addr,
108472645925Smartin 		    (unsigned long)map->dm_segs[i].ds_len);
1085bdbd5db8Smartin #endif
1086bdbd5db8Smartin 
108772645925Smartin 		sc->sc_descm->tx_init_flags(desc);
108872645925Smartin 		sc->sc_descm->tx_set_len(desc, map->dm_segs[i].ds_len);
108972645925Smartin 
109072645925Smartin 		if (i == 0)
109172645925Smartin 			sc->sc_descm->tx_set_first_frag(desc);
1092971dc1a0Smartin 
1093971dc1a0Smartin 		/*
1094971dc1a0Smartin 		 * Defer passing ownership of the first descriptor
1095480d5fceSjoerg 		 * until we are done.
1096971dc1a0Smartin 		 */
109772645925Smartin 		if (i != 0)
109872645925Smartin 			sc->sc_descm->tx_set_owned_by_dev(desc);
1099971dc1a0Smartin 
1100bdbd5db8Smartin 		sc->sc_txq.t_queued++;
1101bdbd5db8Smartin 		sc->sc_txq.t_cur = TX_NEXT(sc->sc_txq.t_cur);
1102971dc1a0Smartin 	}
1103971dc1a0Smartin 
110472645925Smartin 	sc->sc_descm->tx_set_last_frag(desc);
1105971dc1a0Smartin 
1106971dc1a0Smartin 	data->td_m = m0;
1107971dc1a0Smartin 	data->td_active = map;
1108971dc1a0Smartin 
110940044749Sskrll 	/* sync the packet buffer */
1110971dc1a0Smartin 	bus_dmamap_sync(sc->sc_dmat, map, 0, map->dm_mapsize,
11114a5c3abbSjmcneill 	    BUS_DMASYNC_PREWRITE);
1112971dc1a0Smartin 
111340044749Sskrll 	/* sync the new descriptors - ownership not transferred yet */
111440044749Sskrll 	dwc_gmac_txdesc_sync(sc, first, sc->sc_txq.t_cur,
111540044749Sskrll 	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
111640044749Sskrll 
11178132f7b2Smartin 	/* Pass first to device */
111872645925Smartin 	sc->sc_descm->tx_set_owned_by_dev(&sc->sc_txq.t_desc[first]);
111972645925Smartin 
1120971dc1a0Smartin 	return 0;
1121971dc1a0Smartin }
1122971dc1a0Smartin 
1123d1bd22e8Smartin /*
1124d1bd22e8Smartin  * If the interface is up and running, only modify the receive
1125d1bd22e8Smartin  * filter when setting promiscuous or debug mode.  Otherwise fall
1126d1bd22e8Smartin  * through to ether_ioctl, which will reset the chip.
1127d1bd22e8Smartin  */
1128d1bd22e8Smartin static int
1129d1bd22e8Smartin dwc_gmac_ifflags_cb(struct ethercom *ec)
1130d1bd22e8Smartin {
1131eb43ba5fSskrll 	struct ifnet * const ifp = &ec->ec_if;
1132eb43ba5fSskrll 	struct dwc_gmac_softc * const sc = ifp->if_softc;
1133fc18ade0Sskrll 	int ret = 0;
1134d1bd22e8Smartin 
1135c9ba1e93Sskrll 	KASSERT(IFNET_LOCKED(ifp));
113696373f68Sriastradh 	mutex_enter(sc->sc_mcast_lock);
1137c9ba1e93Sskrll 
113870b25bc9Smsaitoh 	u_short change = ifp->if_flags ^ sc->sc_if_flags;
1139fc18ade0Sskrll 	sc->sc_if_flags = ifp->if_flags;
1140fc18ade0Sskrll 
1141fc18ade0Sskrll 	if ((change & ~(IFF_CANTCHANGE | IFF_DEBUG)) != 0) {
1142fc18ade0Sskrll 		ret = ENETRESET;
1143c9ba1e93Sskrll 	} else  if ((change & IFF_PROMISC) != 0) {
1144d1bd22e8Smartin 		dwc_gmac_setmulti(sc);
1145fc18ade0Sskrll 	}
1146c9ba1e93Sskrll 
114796373f68Sriastradh 	mutex_exit(sc->sc_mcast_lock);
1148fc18ade0Sskrll 
1149fc18ade0Sskrll 	return ret;
1150d1bd22e8Smartin }
1151d1bd22e8Smartin 
1152971dc1a0Smartin static int
1153971dc1a0Smartin dwc_gmac_ioctl(struct ifnet *ifp, u_long cmd, void *data)
1154971dc1a0Smartin {
1155eb43ba5fSskrll 	struct dwc_gmac_softc * const sc = ifp->if_softc;
1156fc18ade0Sskrll 	int error = 0;
1157971dc1a0Smartin 
1158c9ba1e93Sskrll 	switch (cmd) {
1159c9ba1e93Sskrll 	case SIOCADDMULTI:
1160c9ba1e93Sskrll 	case SIOCDELMULTI:
1161c9ba1e93Sskrll 		break;
1162c9ba1e93Sskrll 	default:
1163c9ba1e93Sskrll 		KASSERT(IFNET_LOCKED(ifp));
1164c9ba1e93Sskrll 	}
1165971dc1a0Smartin 
1166c9ba1e93Sskrll 	const int s = splnet();
1167c9ba1e93Sskrll 	error = ether_ioctl(ifp, cmd, data);
1168fc18ade0Sskrll 	splx(s);
1169fc18ade0Sskrll 
1170fc18ade0Sskrll 	if (error == ENETRESET) {
1171971dc1a0Smartin 		error = 0;
1172c9ba1e93Sskrll 		if (cmd == SIOCADDMULTI || cmd == SIOCDELMULTI) {
117396373f68Sriastradh 			mutex_enter(sc->sc_mcast_lock);
1174c9ba1e93Sskrll 			if (sc->sc_if_flags & IFF_RUNNING) {
1175d1bd22e8Smartin 				/*
1176c9ba1e93Sskrll 				 * Multicast list has changed; set the hardware
1177c9ba1e93Sskrll 				 * filter accordingly.
1178d1bd22e8Smartin 				 */
1179f8c640e7Sjmcneill 				dwc_gmac_setmulti(sc);
1180c9ba1e93Sskrll 			}
118196373f68Sriastradh 			mutex_exit(sc->sc_mcast_lock);
1182d1bd22e8Smartin 		}
1183971dc1a0Smartin 	}
1184971dc1a0Smartin 
1185971dc1a0Smartin 	return error;
1186971dc1a0Smartin }
1187971dc1a0Smartin 
1188bdbd5db8Smartin static void
1189bdbd5db8Smartin dwc_gmac_tx_intr(struct dwc_gmac_softc *sc)
1190bdbd5db8Smartin {
1191eb43ba5fSskrll 	struct ifnet * const ifp = &sc->sc_ec.ec_if;
1192bdbd5db8Smartin 	struct dwc_gmac_tx_data *data;
1193bdbd5db8Smartin 	struct dwc_gmac_dev_dmadesc *desc;
11948132f7b2Smartin 	int i, nsegs;
1195bdbd5db8Smartin 
1196fc18ade0Sskrll 	mutex_enter(&sc->sc_txq.t_mtx);
1197fc18ade0Sskrll 
11988132f7b2Smartin 	for (i = sc->sc_txq.t_next; sc->sc_txq.t_queued > 0; i = TX_NEXT(i)) {
1199bdbd5db8Smartin #ifdef DWC_GMAC_DEBUG
1200bdbd5db8Smartin 		aprint_normal_dev(sc->sc_dev,
120104b7b2c1Sskrll 		    "%s: checking desc #%d (t_queued: %d)\n", __func__,
1202bdbd5db8Smartin 		    i, sc->sc_txq.t_queued);
1203bdbd5db8Smartin #endif
1204bdbd5db8Smartin 
12052d00f56cSmartin 		/*
12062d00f56cSmartin 		 * i + 1 does not need to be a valid descriptor,
12072d00f56cSmartin 		 * this is just a special notion to just sync
12082d00f56cSmartin 		 * a single tx descriptor (i)
12092d00f56cSmartin 		 */
12102d00f56cSmartin 		dwc_gmac_txdesc_sync(sc, i, i + 1,
1211bdbd5db8Smartin 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1212426c40ceSmartin 
12138132f7b2Smartin 		desc = &sc->sc_txq.t_desc[i];
121472645925Smartin 		if (sc->sc_descm->tx_is_owned_by_dev(desc))
1215bdbd5db8Smartin 			break;
1216426c40ceSmartin 
1217bdbd5db8Smartin 		data = &sc->sc_txq.t_data[i];
1218bdbd5db8Smartin 		if (data->td_m == NULL)
1219bdbd5db8Smartin 			continue;
12208132f7b2Smartin 
12212d501ecfSthorpej 		if_statinc(ifp, if_opackets);
12228132f7b2Smartin 		nsegs = data->td_active->dm_nsegs;
1223bdbd5db8Smartin 		bus_dmamap_sync(sc->sc_dmat, data->td_active, 0,
1224bdbd5db8Smartin 		    data->td_active->dm_mapsize, BUS_DMASYNC_POSTWRITE);
1225bdbd5db8Smartin 		bus_dmamap_unload(sc->sc_dmat, data->td_active);
1226bdbd5db8Smartin 
1227bdbd5db8Smartin #ifdef DWC_GMAC_DEBUG
1228bdbd5db8Smartin 		aprint_normal_dev(sc->sc_dev,
122904b7b2c1Sskrll 		    "%s: done with packet at desc #%d, freeing mbuf %p\n",
123004b7b2c1Sskrll 		    __func__, i, data->td_m);
1231bdbd5db8Smartin #endif
1232bdbd5db8Smartin 
1233bdbd5db8Smartin 		m_freem(data->td_m);
1234bdbd5db8Smartin 		data->td_m = NULL;
12358132f7b2Smartin 
12368132f7b2Smartin 		sc->sc_txq.t_queued -= nsegs;
1237bdbd5db8Smartin 	}
1238bdbd5db8Smartin 
1239bdbd5db8Smartin 	sc->sc_txq.t_next = i;
1240bdbd5db8Smartin 
1241bdbd5db8Smartin 	if (sc->sc_txq.t_queued < AWGE_TX_RING_COUNT) {
1242bdb3207bSthorpej 		sc->sc_txbusy = false;
1243bdbd5db8Smartin 	}
1244fc18ade0Sskrll 	mutex_exit(&sc->sc_txq.t_mtx);
1245bdbd5db8Smartin }
1246bdbd5db8Smartin 
1247bdbd5db8Smartin static void
1248bdbd5db8Smartin dwc_gmac_rx_intr(struct dwc_gmac_softc *sc)
1249bdbd5db8Smartin {
1250eb43ba5fSskrll 	struct ifnet * const ifp = &sc->sc_ec.ec_if;
1251426c40ceSmartin 	struct dwc_gmac_dev_dmadesc *desc;
1252426c40ceSmartin 	struct dwc_gmac_rx_data *data;
1253426c40ceSmartin 	bus_addr_t physaddr;
1254426c40ceSmartin 	struct mbuf *m, *mnew;
1255426c40ceSmartin 	int i, len, error;
1256426c40ceSmartin 
1257fc18ade0Sskrll 	mutex_enter(&sc->sc_rxq.r_mtx);
1258426c40ceSmartin 	for (i = sc->sc_rxq.r_cur; ; i = RX_NEXT(i)) {
125904b7b2c1Sskrll #ifdef DWC_GMAC_DEBUG
126004b7b2c1Sskrll 		aprint_normal_dev(sc->sc_dev, "%s: checking desc #%d\n",
126104b7b2c1Sskrll 		    __func__, i);
126204b7b2c1Sskrll #endif
1263426c40ceSmartin 		bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
1264426c40ceSmartin 		    RX_DESC_OFFSET(i), sizeof(*desc),
1265426c40ceSmartin 		    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1266426c40ceSmartin 		desc = &sc->sc_rxq.r_desc[i];
1267426c40ceSmartin 		data = &sc->sc_rxq.r_data[i];
1268426c40ceSmartin 
126972645925Smartin 		if (sc->sc_descm->rx_is_owned_by_dev(desc))
1270426c40ceSmartin 			break;
1271426c40ceSmartin 
127272645925Smartin 		if (sc->sc_descm->rx_has_error(desc)) {
1273426c40ceSmartin #ifdef DWC_GMAC_DEBUG
12743131c860Smartin 			aprint_normal_dev(sc->sc_dev,
127504b7b2c1Sskrll 			    "%s: RX error: status %08x, skipping\n",
127604b7b2c1Sskrll 			    __func__, le32toh(desc->ddesc_status0));
1277426c40ceSmartin #endif
12782d501ecfSthorpej 			if_statinc(ifp, if_ierrors);
1279426c40ceSmartin 			goto skip;
1280426c40ceSmartin 		}
1281426c40ceSmartin 
128272645925Smartin 		len = sc->sc_descm->rx_get_len(desc);
1283426c40ceSmartin 
1284426c40ceSmartin #ifdef DWC_GMAC_DEBUG
12853131c860Smartin 		aprint_normal_dev(sc->sc_dev,
128604b7b2c1Sskrll 		    "%s: device is done with descriptor #%d, len: %d\n",
128704b7b2c1Sskrll 		    __func__, i, len);
1288426c40ceSmartin #endif
1289426c40ceSmartin 
1290426c40ceSmartin 		/*
1291426c40ceSmartin 		 * Try to get a new mbuf before passing this one
1292426c40ceSmartin 		 * up, if that fails, drop the packet and reuse
1293426c40ceSmartin 		 * the existing one.
1294426c40ceSmartin 		 */
1295426c40ceSmartin 		MGETHDR(mnew, M_DONTWAIT, MT_DATA);
1296426c40ceSmartin 		if (mnew == NULL) {
12972d501ecfSthorpej 			if_statinc(ifp, if_ierrors);
1298426c40ceSmartin 			goto skip;
1299426c40ceSmartin 		}
1300426c40ceSmartin 		MCLGET(mnew, M_DONTWAIT);
1301426c40ceSmartin 		if ((mnew->m_flags & M_EXT) == 0) {
1302426c40ceSmartin 			m_freem(mnew);
13032d501ecfSthorpej 			if_statinc(ifp, if_ierrors);
1304426c40ceSmartin 			goto skip;
1305426c40ceSmartin 		}
13063c96a2beStnn 		mnew->m_len = mnew->m_pkthdr.len = mnew->m_ext.ext_size;
13073c96a2beStnn 		if (mnew->m_len > AWGE_MAX_PACKET) {
13083c96a2beStnn 			mnew->m_len = mnew->m_pkthdr.len = AWGE_MAX_PACKET;
13093c96a2beStnn 		}
1310426c40ceSmartin 
1311426c40ceSmartin 		/* unload old DMA map */
1312426c40ceSmartin 		bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0,
1313426c40ceSmartin 		    data->rd_map->dm_mapsize, BUS_DMASYNC_POSTREAD);
1314426c40ceSmartin 		bus_dmamap_unload(sc->sc_dmat, data->rd_map);
1315426c40ceSmartin 
1316426c40ceSmartin 		/* and reload with new mbuf */
13173c96a2beStnn 		error = bus_dmamap_load_mbuf(sc->sc_dmat, data->rd_map,
13183c96a2beStnn 		    mnew, BUS_DMA_READ | BUS_DMA_NOWAIT);
1319426c40ceSmartin 		if (error != 0) {
1320426c40ceSmartin 			m_freem(mnew);
1321426c40ceSmartin 			/* try to reload old mbuf */
13223c96a2beStnn 			error = bus_dmamap_load_mbuf(sc->sc_dmat, data->rd_map,
13233c96a2beStnn 			    data->rd_m, BUS_DMA_READ | BUS_DMA_NOWAIT);
1324426c40ceSmartin 			if (error != 0) {
1325426c40ceSmartin 				panic("%s: could not load old rx mbuf",
1326426c40ceSmartin 				    device_xname(sc->sc_dev));
1327426c40ceSmartin 			}
13282d501ecfSthorpej 			if_statinc(ifp, if_ierrors);
1329426c40ceSmartin 			goto skip;
1330426c40ceSmartin 		}
1331426c40ceSmartin 		physaddr = data->rd_map->dm_segs[0].ds_addr;
1332426c40ceSmartin 
133304b7b2c1Sskrll #ifdef DWC_GMAC_DEBUG
133404b7b2c1Sskrll 		aprint_normal_dev(sc->sc_dev,
133504b7b2c1Sskrll 		    "%s: receiving packet at desc #%d,   using mbuf %p\n",
133604b7b2c1Sskrll 		    __func__, i, data->rd_m);
133704b7b2c1Sskrll #endif
1338426c40ceSmartin 		/*
1339426c40ceSmartin 		 * New mbuf loaded, update RX ring and continue
1340426c40ceSmartin 		 */
1341426c40ceSmartin 		m = data->rd_m;
1342426c40ceSmartin 		data->rd_m = mnew;
1343426c40ceSmartin 		desc->ddesc_data = htole32(physaddr);
1344426c40ceSmartin 
1345426c40ceSmartin 		/* finalize mbuf */
1346426c40ceSmartin 		m->m_pkthdr.len = m->m_len = len;
1347d938d837Sozaki-r 		m_set_rcvif(m, ifp);
1348e40fc052Ssekiya 		m->m_flags |= M_HASFCS;
1349426c40ceSmartin 
1350a70a0336Sskrll 		if_percpuq_enqueue(sc->sc_ipq, m);
1351426c40ceSmartin 
1352426c40ceSmartin skip:
13530c8fe4ccSmatt 		bus_dmamap_sync(sc->sc_dmat, data->rd_map, 0,
13540c8fe4ccSmatt 		    data->rd_map->dm_mapsize, BUS_DMASYNC_PREREAD);
135572645925Smartin 
135672645925Smartin 		sc->sc_descm->rx_init_flags(desc);
13573c96a2beStnn 		sc->sc_descm->rx_set_len(desc, data->rd_m->m_len);
135840044749Sskrll 
135940044749Sskrll 		bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
136040044749Sskrll 		    RX_DESC_OFFSET(i), sizeof(*desc),
136140044749Sskrll 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
136240044749Sskrll 
136372645925Smartin 		sc->sc_descm->rx_set_owned_by_dev(desc);
136472645925Smartin 
1365426c40ceSmartin 		bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
1366426c40ceSmartin 		    RX_DESC_OFFSET(i), sizeof(*desc),
1367426c40ceSmartin 		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1368426c40ceSmartin 	}
1369426c40ceSmartin 
1370426c40ceSmartin 	/* update RX pointer */
1371426c40ceSmartin 	sc->sc_rxq.r_cur = i;
1372426c40ceSmartin 
1373fc18ade0Sskrll 	mutex_exit(&sc->sc_rxq.r_mtx);
1374bdbd5db8Smartin }
1375bdbd5db8Smartin 
1376f8c640e7Sjmcneill static void
1377f8c640e7Sjmcneill dwc_gmac_setmulti(struct dwc_gmac_softc *sc)
1378f8c640e7Sjmcneill {
1379f8c640e7Sjmcneill 	struct ether_multi *enm;
1380f8c640e7Sjmcneill 	struct ether_multistep step;
1381390d6c3dSozaki-r 	struct ethercom *ec = &sc->sc_ec;
1382f8c640e7Sjmcneill 	uint32_t hashes[2] = { 0, 0 };
1383d1bd22e8Smartin 	uint32_t ffilt, h;
1384fc18ade0Sskrll 	int mcnt;
1385d1bd22e8Smartin 
138696373f68Sriastradh 	KASSERT(mutex_owned(sc->sc_mcast_lock));
1387f8c640e7Sjmcneill 
1388f8c640e7Sjmcneill 	ffilt = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT);
1389f8c640e7Sjmcneill 
1390c9ba1e93Sskrll 	if (sc->sc_if_flags & IFF_PROMISC) {
1391d1bd22e8Smartin 		ffilt |= AWIN_GMAC_MAC_FFILT_PR;
1392d1bd22e8Smartin 		goto special_filter;
1393f8c640e7Sjmcneill 	}
1394f8c640e7Sjmcneill 
1395d1bd22e8Smartin 	ffilt &= ~(AWIN_GMAC_MAC_FFILT_PM | AWIN_GMAC_MAC_FFILT_PR);
1396f8c640e7Sjmcneill 
1397f8c640e7Sjmcneill 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW, 0);
1398f8c640e7Sjmcneill 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH, 0);
1399f8c640e7Sjmcneill 
1400390d6c3dSozaki-r 	ETHER_LOCK(ec);
140199ec0af5Sozaki-r 	ec->ec_flags &= ~ETHER_F_ALLMULTI;
1402390d6c3dSozaki-r 	ETHER_FIRST_MULTI(step, ec, enm);
1403f8c640e7Sjmcneill 	mcnt = 0;
1404f8c640e7Sjmcneill 	while (enm != NULL) {
1405f8c640e7Sjmcneill 		if (memcmp(enm->enm_addrlo, enm->enm_addrhi,
1406d1bd22e8Smartin 		    ETHER_ADDR_LEN) != 0) {
1407d1bd22e8Smartin 			ffilt |= AWIN_GMAC_MAC_FFILT_PM;
140899ec0af5Sozaki-r 			ec->ec_flags |= ETHER_F_ALLMULTI;
140999ec0af5Sozaki-r 			ETHER_UNLOCK(ec);
1410d1bd22e8Smartin 			goto special_filter;
1411d1bd22e8Smartin 		}
1412f8c640e7Sjmcneill 
1413fb93b87aSjakllsch 		h = ~ether_crc32_be(enm->enm_addrlo, ETHER_ADDR_LEN) >> 26;
1414f8c640e7Sjmcneill 		hashes[h >> 5] |= (1 << (h & 0x1f));
1415f8c640e7Sjmcneill 
1416f8c640e7Sjmcneill 		mcnt++;
1417f8c640e7Sjmcneill 		ETHER_NEXT_MULTI(step, enm);
1418f8c640e7Sjmcneill 	}
1419390d6c3dSozaki-r 	ETHER_UNLOCK(ec);
1420f8c640e7Sjmcneill 
1421f8c640e7Sjmcneill 	if (mcnt)
1422f8c640e7Sjmcneill 		ffilt |= AWIN_GMAC_MAC_FFILT_HMC;
1423f8c640e7Sjmcneill 	else
1424f8c640e7Sjmcneill 		ffilt &= ~AWIN_GMAC_MAC_FFILT_HMC;
1425f8c640e7Sjmcneill 
1426f8c640e7Sjmcneill 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT, ffilt);
1427f8c640e7Sjmcneill 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW,
1428f8c640e7Sjmcneill 	    hashes[0]);
1429f8c640e7Sjmcneill 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH,
1430f8c640e7Sjmcneill 	    hashes[1]);
1431d1bd22e8Smartin 
1432d1bd22e8Smartin #ifdef DWC_GMAC_DEBUG
1433d1bd22e8Smartin 	dwc_gmac_dump_ffilt(sc, ffilt);
1434d1bd22e8Smartin #endif
1435d1bd22e8Smartin 	return;
1436d1bd22e8Smartin 
1437d1bd22e8Smartin special_filter:
1438d1bd22e8Smartin #ifdef DWC_GMAC_DEBUG
1439d1bd22e8Smartin 	dwc_gmac_dump_ffilt(sc, ffilt);
1440d1bd22e8Smartin #endif
1441d1bd22e8Smartin 	/* no MAC hashes, ALLMULTI or PROMISC */
1442d1bd22e8Smartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT,
1443d1bd22e8Smartin 	    ffilt);
1444d1bd22e8Smartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTLOW,
1445d1bd22e8Smartin 	    0xffffffff);
1446d1bd22e8Smartin 	bus_space_write_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_HTHIGH,
1447d1bd22e8Smartin 	    0xffffffff);
1448f8c640e7Sjmcneill }
1449f8c640e7Sjmcneill 
1450971dc1a0Smartin int
1451971dc1a0Smartin dwc_gmac_intr(struct dwc_gmac_softc *sc)
1452971dc1a0Smartin {
1453971dc1a0Smartin 	uint32_t status, dma_status;
1454bdbd5db8Smartin 	int rv = 0;
1455971dc1a0Smartin 
1456c9ba1e93Sskrll 	mutex_enter(sc->sc_intr_lock);
1457c9ba1e93Sskrll 	if (sc->sc_stopping) {
1458c9ba1e93Sskrll 		mutex_exit(sc->sc_intr_lock);
1459fc18ade0Sskrll 		return 0;
1460c9ba1e93Sskrll 	}
1461fc18ade0Sskrll 
1462971dc1a0Smartin 	status = bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_INTR);
146383658911Smartin 	if (status & AWIN_GMAC_MII_IRQ) {
1464971dc1a0Smartin 		(void)bus_space_read_4(sc->sc_bst, sc->sc_bsh,
1465971dc1a0Smartin 		    AWIN_GMAC_MII_STATUS);
1466bdbd5db8Smartin 		rv = 1;
146783658911Smartin 		mii_pollstat(&sc->sc_mii);
146883658911Smartin 	}
1469971dc1a0Smartin 
1470971dc1a0Smartin 	dma_status = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
1471971dc1a0Smartin 	    AWIN_GMAC_DMA_STATUS);
1472971dc1a0Smartin 
1473bdbd5db8Smartin 	if (dma_status & (GMAC_DMA_INT_NIE | GMAC_DMA_INT_AIE))
1474bdbd5db8Smartin 		rv = 1;
1475971dc1a0Smartin 
1476bdbd5db8Smartin 	if (dma_status & GMAC_DMA_INT_TIE)
1477bdbd5db8Smartin 		dwc_gmac_tx_intr(sc);
1478971dc1a0Smartin 
1479bdbd5db8Smartin 	if (dma_status & GMAC_DMA_INT_RIE)
1480bdbd5db8Smartin 		dwc_gmac_rx_intr(sc);
1481bdbd5db8Smartin 
1482bdbd5db8Smartin 	/*
1483bdbd5db8Smartin 	 * Check error conditions
1484bdbd5db8Smartin 	 */
1485bdbd5db8Smartin 	if (dma_status & GMAC_DMA_INT_ERRORS) {
14862d501ecfSthorpej 		if_statinc(&sc->sc_ec.ec_if, if_oerrors);
1487bdbd5db8Smartin #ifdef DWC_GMAC_DEBUG
1488bdbd5db8Smartin 		dwc_dump_and_abort(sc, "interrupt error condition");
1489bdbd5db8Smartin #endif
1490bdbd5db8Smartin 	}
1491bdbd5db8Smartin 
1492f872a062Smsaitoh 	rnd_add_uint32(&sc->rnd_source, dma_status);
1493f872a062Smsaitoh 
1494bdbd5db8Smartin 	/* ack interrupt */
1495bdbd5db8Smartin 	if (dma_status)
1496bdbd5db8Smartin 		bus_space_write_4(sc->sc_bst, sc->sc_bsh,
1497bdbd5db8Smartin 		    AWIN_GMAC_DMA_STATUS, dma_status & GMAC_DMA_INT_MASK);
1498bdbd5db8Smartin 
1499ce7dba4dSmartin 	/*
1500ce7dba4dSmartin 	 * Get more packets
1501ce7dba4dSmartin 	 */
1502ce7dba4dSmartin 	if (rv)
15031c82c572Sozaki-r 		if_schedule_deferred_start(&sc->sc_ec.ec_if);
1504ce7dba4dSmartin 
1505c9ba1e93Sskrll 	mutex_exit(sc->sc_intr_lock);
1506c9ba1e93Sskrll 
1507bdbd5db8Smartin 	return rv;
1508971dc1a0Smartin }
150937ad3d63Smartin 
151072645925Smartin static void
151172645925Smartin dwc_gmac_desc_set_owned_by_dev(struct dwc_gmac_dev_dmadesc *desc)
151272645925Smartin {
151372645925Smartin 
151472645925Smartin 	desc->ddesc_status0 |= htole32(DDESC_STATUS_OWNEDBYDEV);
151572645925Smartin }
151672645925Smartin 
151772645925Smartin static int
151872645925Smartin dwc_gmac_desc_is_owned_by_dev(struct dwc_gmac_dev_dmadesc *desc)
151972645925Smartin {
152072645925Smartin 
152172645925Smartin 	return !!(le32toh(desc->ddesc_status0) & DDESC_STATUS_OWNEDBYDEV);
152272645925Smartin }
152372645925Smartin 
152472645925Smartin static void
152572645925Smartin dwc_gmac_desc_std_set_len(struct dwc_gmac_dev_dmadesc *desc, int len)
152672645925Smartin {
152772645925Smartin 	uint32_t cntl = le32toh(desc->ddesc_cntl1);
152872645925Smartin 
152972645925Smartin 	desc->ddesc_cntl1 = htole32((cntl & ~DDESC_CNTL_SIZE1MASK) |
153072645925Smartin 		__SHIFTIN(len, DDESC_CNTL_SIZE1MASK));
153172645925Smartin }
153272645925Smartin 
153372645925Smartin static uint32_t
153472645925Smartin dwc_gmac_desc_std_get_len(struct dwc_gmac_dev_dmadesc *desc)
153572645925Smartin {
153672645925Smartin 
153772645925Smartin 	return __SHIFTOUT(le32toh(desc->ddesc_status0), DDESC_STATUS_FRMLENMSK);
153872645925Smartin }
153972645925Smartin 
154072645925Smartin static void
154172645925Smartin dwc_gmac_desc_std_tx_init_flags(struct dwc_gmac_dev_dmadesc *desc)
154272645925Smartin {
154372645925Smartin 
154472645925Smartin 	desc->ddesc_status0 = 0;
154572645925Smartin 	desc->ddesc_cntl1 = htole32(DDESC_CNTL_TXCHAIN);
154672645925Smartin }
154772645925Smartin 
154872645925Smartin static void
154972645925Smartin dwc_gmac_desc_std_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *desc)
155072645925Smartin {
155172645925Smartin 	uint32_t cntl = le32toh(desc->ddesc_cntl1);
155272645925Smartin 
155372645925Smartin 	desc->ddesc_cntl1 = htole32(cntl | DDESC_CNTL_TXFIRST);
155472645925Smartin }
155572645925Smartin 
155672645925Smartin static void
155772645925Smartin dwc_gmac_desc_std_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *desc)
155872645925Smartin {
155972645925Smartin 	uint32_t cntl = le32toh(desc->ddesc_cntl1);
156072645925Smartin 
156172645925Smartin 	desc->ddesc_cntl1 = htole32(cntl |
156272645925Smartin 		DDESC_CNTL_TXLAST | DDESC_CNTL_TXINT);
156372645925Smartin }
156472645925Smartin 
156572645925Smartin static void
156672645925Smartin dwc_gmac_desc_std_rx_init_flags(struct dwc_gmac_dev_dmadesc *desc)
156772645925Smartin {
156872645925Smartin 
156972645925Smartin 	desc->ddesc_status0 = 0;
157072645925Smartin 	desc->ddesc_cntl1 = htole32(DDESC_CNTL_TXCHAIN);
157172645925Smartin }
157272645925Smartin 
157372645925Smartin static int
157472645925Smartin dwc_gmac_desc_std_rx_has_error(struct dwc_gmac_dev_dmadesc *desc) {
157572645925Smartin 	return !!(le32toh(desc->ddesc_status0) &
157672645925Smartin 		(DDESC_STATUS_RXERROR | DDESC_STATUS_RXTRUNCATED));
157772645925Smartin }
157872645925Smartin 
157972645925Smartin static void
158072645925Smartin dwc_gmac_desc_enh_set_len(struct dwc_gmac_dev_dmadesc *desc, int len)
158172645925Smartin {
158272645925Smartin 	uint32_t tdes1 = le32toh(desc->ddesc_cntl1);
158372645925Smartin 
158472645925Smartin 	desc->ddesc_cntl1 = htole32((tdes1 & ~DDESC_DES1_SIZE1MASK) |
158572645925Smartin 		__SHIFTIN(len, DDESC_DES1_SIZE1MASK));
158672645925Smartin }
158772645925Smartin 
158872645925Smartin static uint32_t
158972645925Smartin dwc_gmac_desc_enh_get_len(struct dwc_gmac_dev_dmadesc *desc)
159072645925Smartin {
159172645925Smartin 
159272645925Smartin 	return __SHIFTOUT(le32toh(desc->ddesc_status0), DDESC_RDES0_FL);
159372645925Smartin }
159472645925Smartin 
159572645925Smartin static void
159672645925Smartin dwc_gmac_desc_enh_tx_init_flags(struct dwc_gmac_dev_dmadesc *desc)
159772645925Smartin {
159872645925Smartin 
159972645925Smartin 	desc->ddesc_status0 = htole32(DDESC_TDES0_TCH);
160072645925Smartin 	desc->ddesc_cntl1 = 0;
160172645925Smartin }
160272645925Smartin 
160372645925Smartin static void
160472645925Smartin dwc_gmac_desc_enh_tx_set_first_frag(struct dwc_gmac_dev_dmadesc *desc)
160572645925Smartin {
160672645925Smartin 	uint32_t tdes0 = le32toh(desc->ddesc_status0);
160772645925Smartin 
160872645925Smartin 	desc->ddesc_status0 = htole32(tdes0 | DDESC_TDES0_FS);
160972645925Smartin }
161072645925Smartin 
161172645925Smartin static void
161272645925Smartin dwc_gmac_desc_enh_tx_set_last_frag(struct dwc_gmac_dev_dmadesc *desc)
161372645925Smartin {
161472645925Smartin 	uint32_t tdes0 = le32toh(desc->ddesc_status0);
161572645925Smartin 
161672645925Smartin 	desc->ddesc_status0 = htole32(tdes0 | DDESC_TDES0_LS | DDESC_TDES0_IC);
161772645925Smartin }
161872645925Smartin 
161972645925Smartin static void
162072645925Smartin dwc_gmac_desc_enh_rx_init_flags(struct dwc_gmac_dev_dmadesc *desc)
162172645925Smartin {
162272645925Smartin 
162372645925Smartin 	desc->ddesc_status0 = 0;
162472645925Smartin 	desc->ddesc_cntl1 = htole32(DDESC_RDES1_RCH);
162572645925Smartin }
162672645925Smartin 
162772645925Smartin static int
162872645925Smartin dwc_gmac_desc_enh_rx_has_error(struct dwc_gmac_dev_dmadesc *desc)
162972645925Smartin {
163072645925Smartin 
163172645925Smartin 	return !!(le32toh(desc->ddesc_status0) &
163272645925Smartin 		(DDESC_RDES0_ES | DDESC_RDES0_LE));
163372645925Smartin }
163472645925Smartin 
163537ad3d63Smartin #ifdef DWC_GMAC_DEBUG
163637ad3d63Smartin static void
163737ad3d63Smartin dwc_gmac_dump_dma(struct dwc_gmac_softc *sc)
163837ad3d63Smartin {
163937ad3d63Smartin 	aprint_normal_dev(sc->sc_dev, "busmode: %08x\n",
164037ad3d63Smartin 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_BUSMODE));
164137ad3d63Smartin 	aprint_normal_dev(sc->sc_dev, "tx poll: %08x\n",
164237ad3d63Smartin 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TXPOLL));
164337ad3d63Smartin 	aprint_normal_dev(sc->sc_dev, "rx poll: %08x\n",
164437ad3d63Smartin 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RXPOLL));
164537ad3d63Smartin 	aprint_normal_dev(sc->sc_dev, "rx descriptors: %08x\n",
164637ad3d63Smartin 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_RX_ADDR));
164737ad3d63Smartin 	aprint_normal_dev(sc->sc_dev, "tx descriptors: %08x\n",
164837ad3d63Smartin 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_TX_ADDR));
164937ad3d63Smartin 	aprint_normal_dev(sc->sc_dev, " status: %08x\n",
165037ad3d63Smartin 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_STATUS));
165137ad3d63Smartin 	aprint_normal_dev(sc->sc_dev, "op mode: %08x\n",
165237ad3d63Smartin 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_OPMODE));
165304b7b2c1Sskrll 	aprint_normal_dev(sc->sc_dev, "int en.: %08x\n",
165437ad3d63Smartin 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_INTENABLE));
165537ad3d63Smartin 	aprint_normal_dev(sc->sc_dev, " cur tx: %08x\n",
165637ad3d63Smartin 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_TX_DESC));
165737ad3d63Smartin 	aprint_normal_dev(sc->sc_dev, " cur rx: %08x\n",
165837ad3d63Smartin 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_RX_DESC));
165904b7b2c1Sskrll 	aprint_normal_dev(sc->sc_dev, "cur txb: %08x\n",
166037ad3d63Smartin 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_TX_BUFADDR));
166104b7b2c1Sskrll 	aprint_normal_dev(sc->sc_dev, "cur rxb: %08x\n",
166237ad3d63Smartin 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_DMA_CUR_RX_BUFADDR));
166337ad3d63Smartin }
166437ad3d63Smartin 
166537ad3d63Smartin static void
166637ad3d63Smartin dwc_gmac_dump_tx_desc(struct dwc_gmac_softc *sc)
166737ad3d63Smartin {
166840044749Sskrll 	const size_t descsz = sizeof(struct dwc_gmac_dev_dmadesc);
166937ad3d63Smartin 
1670bdbd5db8Smartin 	aprint_normal_dev(sc->sc_dev, "TX queue: cur=%d, next=%d, queued=%d\n",
1671bdbd5db8Smartin 	    sc->sc_txq.t_cur, sc->sc_txq.t_next, sc->sc_txq.t_queued);
167237ad3d63Smartin 	aprint_normal_dev(sc->sc_dev, "TX DMA descriptors:\n");
167340044749Sskrll 
167440044749Sskrll 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
167540044749Sskrll 	    TX_DESC_OFFSET(0), AWGE_TX_RING_COUNT * descsz,
167640044749Sskrll 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
167740044749Sskrll 
167804b7b2c1Sskrll 	for (size_t i = 0; i < AWGE_TX_RING_COUNT; i++) {
167937ad3d63Smartin 		struct dwc_gmac_dev_dmadesc *desc = &sc->sc_txq.t_desc[i];
168004b7b2c1Sskrll 		aprint_normal("#%3zu (%08lx): status: %08x cntl: %08x "
16813131c860Smartin 		    "data: %08x next: %08x\n",
168204b7b2c1Sskrll 		    i, sc->sc_txq.t_physaddr + i * descsz,
168372645925Smartin 		    le32toh(desc->ddesc_status0), le32toh(desc->ddesc_cntl1),
168437ad3d63Smartin 		    le32toh(desc->ddesc_data), le32toh(desc->ddesc_next));
168537ad3d63Smartin 	}
168637ad3d63Smartin }
1687bdbd5db8Smartin 
1688bdbd5db8Smartin static void
1689426c40ceSmartin dwc_gmac_dump_rx_desc(struct dwc_gmac_softc *sc)
1690426c40ceSmartin {
169140044749Sskrll 	const size_t descsz = sizeof(struct dwc_gmac_dev_dmadesc);
1692426c40ceSmartin 
1693426c40ceSmartin 	aprint_normal_dev(sc->sc_dev, "RX queue: cur=%d, next=%d\n",
1694426c40ceSmartin 	    sc->sc_rxq.r_cur, sc->sc_rxq.r_next);
1695426c40ceSmartin 	aprint_normal_dev(sc->sc_dev, "RX DMA descriptors:\n");
169640044749Sskrll 
169740044749Sskrll 	bus_dmamap_sync(sc->sc_dmat, sc->sc_dma_ring_map,
169840044749Sskrll 	    RX_DESC_OFFSET(0), AWGE_RX_RING_COUNT * descsz,
169940044749Sskrll 	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
170040044749Sskrll 
170104b7b2c1Sskrll 	for (size_t i = 0; i < AWGE_RX_RING_COUNT; i++) {
1702426c40ceSmartin 		struct dwc_gmac_dev_dmadesc *desc = &sc->sc_rxq.r_desc[i];
170304b7b2c1Sskrll 		char buf[200];
170404b7b2c1Sskrll 
170504b7b2c1Sskrll 		if (!sc->sc_descm->rx_is_owned_by_dev(desc)) {
170604b7b2c1Sskrll 			/* print interrupt state */
170704b7b2c1Sskrll 			snprintb(buf, sizeof(buf),
170804b7b2c1Sskrll 			    "\177\20"
170904b7b2c1Sskrll 			    "b\x1e"	"daff\0"
171004b7b2c1Sskrll 			    "f\x10\xe"	"frlen\0"
171104b7b2c1Sskrll 			    "b\x0f"	"error\0"
171204b7b2c1Sskrll 			    "b\x0e"	"rxtrunc\0"	/* descriptor error? */
171304b7b2c1Sskrll 			    "b\x0d"	"saff\0"
171404b7b2c1Sskrll 			    "b\x0c"	"giantframe\0"	/* length error? */
171504b7b2c1Sskrll 			    "b\x0b"	"damaged\0"
171604b7b2c1Sskrll 			    "b\x0a"	"vlan\0"
171704b7b2c1Sskrll 			    "b\x09"	"first\0"
171804b7b2c1Sskrll 			    "b\x08"	"last\0"
171904b7b2c1Sskrll 			    "b\x07"	"giant\0"
172004b7b2c1Sskrll 			    "b\x06"	"collison\0"
172104b7b2c1Sskrll 			    "b\x05"	"ether\0"
172204b7b2c1Sskrll 			    "b\x04"	"watchdog\0"
172304b7b2c1Sskrll 			    "b\x03"	"miierror\0"
172404b7b2c1Sskrll 			    "b\x02"	"dribbling\0"
172504b7b2c1Sskrll 			    "b\x01"	"crc\0"
172604b7b2c1Sskrll 			    "\0", le32toh(desc->ddesc_status0));
172704b7b2c1Sskrll 		}
172804b7b2c1Sskrll 
172904b7b2c1Sskrll 		aprint_normal("#%3zu (%08lx): status: %08x cntl: %08x "
173004b7b2c1Sskrll 		    "data: %08x next: %08x %s\n",
173104b7b2c1Sskrll 		    i, sc->sc_rxq.r_physaddr + i * descsz,
173272645925Smartin 		    le32toh(desc->ddesc_status0), le32toh(desc->ddesc_cntl1),
173304b7b2c1Sskrll 		    le32toh(desc->ddesc_data), le32toh(desc->ddesc_next),
173404b7b2c1Sskrll 		    sc->sc_descm->rx_is_owned_by_dev(desc) ? "" : buf);
1735426c40ceSmartin 	}
1736426c40ceSmartin }
1737426c40ceSmartin 
1738426c40ceSmartin static void
17395158fc24Smartin dwc_dump_status(struct dwc_gmac_softc *sc)
1740bdbd5db8Smartin {
1741bdbd5db8Smartin 	uint32_t status = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
1742bdbd5db8Smartin 	    AWIN_GMAC_MAC_INTR);
1743bdbd5db8Smartin 	uint32_t dma_status = bus_space_read_4(sc->sc_bst, sc->sc_bsh,
1744bdbd5db8Smartin 	    AWIN_GMAC_DMA_STATUS);
1745bdbd5db8Smartin 	char buf[200];
1746bdbd5db8Smartin 
1747bdbd5db8Smartin 	/* print interrupt state */
174804b7b2c1Sskrll 	snprintb(buf, sizeof(buf),
174904b7b2c1Sskrll 	    "\177\20"
175004b7b2c1Sskrll 	    "b\x1c"	"GPI\0"
175104b7b2c1Sskrll 	    "b\x1b"	"GMC\0"
175204b7b2c1Sskrll 	    "b\x1a"	"GLI\0"
175304b7b2c1Sskrll 	    "f\x17\x3"	"EB\0"
175404b7b2c1Sskrll 	    "f\x14\x3"	"TPS\0"
175504b7b2c1Sskrll 	    "f\x11\x3"	"RPS\0"
17565158fc24Smartin 	    "b\x10"	"NI\0"
17575158fc24Smartin 	    "b\x0f"	"AI\0"
17585158fc24Smartin 	    "b\x0e"	"ER\0"
17595158fc24Smartin 	    "b\x0d"	"FB\0"
17605158fc24Smartin 	    "b\x0a"	"ET\0"
17615158fc24Smartin 	    "b\x09"	"RW\0"
17625158fc24Smartin 	    "b\x08"	"RS\0"
17635158fc24Smartin 	    "b\x07"	"RU\0"
17645158fc24Smartin 	    "b\x06"	"RI\0"
17655158fc24Smartin 	    "b\x05"	"UN\0"
17665158fc24Smartin 	    "b\x04"	"OV\0"
17675158fc24Smartin 	    "b\x03"	"TJ\0"
17685158fc24Smartin 	    "b\x02"	"TU\0"
17695158fc24Smartin 	    "b\x01"	"TS\0"
17705158fc24Smartin 	    "b\x00"	"TI\0"
1771bdbd5db8Smartin 	    "\0", dma_status);
17725158fc24Smartin 	aprint_normal_dev(sc->sc_dev, "INTR status: %08x, DMA status: %s\n",
1773bdbd5db8Smartin 	    status, buf);
17745158fc24Smartin }
1775bdbd5db8Smartin 
17765158fc24Smartin static void
17775158fc24Smartin dwc_dump_and_abort(struct dwc_gmac_softc *sc, const char *msg)
17785158fc24Smartin {
17795158fc24Smartin 	dwc_dump_status(sc);
1780d1bd22e8Smartin 	dwc_gmac_dump_ffilt(sc,
1781d1bd22e8Smartin 	    bus_space_read_4(sc->sc_bst, sc->sc_bsh, AWIN_GMAC_MAC_FFILT));
1782bdbd5db8Smartin 	dwc_gmac_dump_dma(sc);
1783bdbd5db8Smartin 	dwc_gmac_dump_tx_desc(sc);
1784426c40ceSmartin 	dwc_gmac_dump_rx_desc(sc);
1785bdbd5db8Smartin 
1786a1f0cbdaSjoerg 	panic("%s", msg);
1787bdbd5db8Smartin }
1788d1bd22e8Smartin 
1789d1bd22e8Smartin static void dwc_gmac_dump_ffilt(struct dwc_gmac_softc *sc, uint32_t ffilt)
1790d1bd22e8Smartin {
1791d1bd22e8Smartin 	char buf[200];
1792d1bd22e8Smartin 
1793d1bd22e8Smartin 	/* print filter setup */
1794d1bd22e8Smartin 	snprintb(buf, sizeof(buf), "\177\20"
1795d1bd22e8Smartin 	    "b\x1f""RA\0"
1796d1bd22e8Smartin 	    "b\x0a""HPF\0"
1797d1bd22e8Smartin 	    "b\x09""SAF\0"
1798d1bd22e8Smartin 	    "b\x08""SAIF\0"
1799d1bd22e8Smartin 	    "b\x05""DBF\0"
1800d1bd22e8Smartin 	    "b\x04""PM\0"
1801d1bd22e8Smartin 	    "b\x03""DAIF\0"
1802d1bd22e8Smartin 	    "b\x02""HMC\0"
1803d1bd22e8Smartin 	    "b\x01""HUC\0"
1804d1bd22e8Smartin 	    "b\x00""PR\0"
1805d1bd22e8Smartin 	    "\0", ffilt);
1806d1bd22e8Smartin 	aprint_normal_dev(sc->sc_dev, "FFILT: %s\n", buf);
1807d1bd22e8Smartin }
180837ad3d63Smartin #endif
1809