xref: /freebsd/sys/dev/dwc/if_dwc.c (revision 5d43fd685b4005709bde4b72d59d4534a79c4832)
1*5d43fd68SRuslan Bukin /*-
2*5d43fd68SRuslan Bukin  * Copyright (c) 2014 Ruslan Bukin <br@bsdpad.com>
3*5d43fd68SRuslan Bukin  * All rights reserved.
4*5d43fd68SRuslan Bukin  *
5*5d43fd68SRuslan Bukin  * This software was developed by SRI International and the University of
6*5d43fd68SRuslan Bukin  * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-10-C-0237)
7*5d43fd68SRuslan Bukin  * ("CTSRD"), as part of the DARPA CRASH research programme.
8*5d43fd68SRuslan Bukin  *
9*5d43fd68SRuslan Bukin  * Redistribution and use in source and binary forms, with or without
10*5d43fd68SRuslan Bukin  * modification, are permitted provided that the following conditions
11*5d43fd68SRuslan Bukin  * are met:
12*5d43fd68SRuslan Bukin  * 1. Redistributions of source code must retain the above copyright
13*5d43fd68SRuslan Bukin  *    notice, this list of conditions and the following disclaimer.
14*5d43fd68SRuslan Bukin  * 2. Redistributions in binary form must reproduce the above copyright
15*5d43fd68SRuslan Bukin  *    notice, this list of conditions and the following disclaimer in the
16*5d43fd68SRuslan Bukin  *    documentation and/or other materials provided with the distribution.
17*5d43fd68SRuslan Bukin  *
18*5d43fd68SRuslan Bukin  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
19*5d43fd68SRuslan Bukin  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
20*5d43fd68SRuslan Bukin  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
21*5d43fd68SRuslan Bukin  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
22*5d43fd68SRuslan Bukin  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
23*5d43fd68SRuslan Bukin  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
24*5d43fd68SRuslan Bukin  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
25*5d43fd68SRuslan Bukin  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
26*5d43fd68SRuslan Bukin  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
27*5d43fd68SRuslan Bukin  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
28*5d43fd68SRuslan Bukin  * SUCH DAMAGE.
29*5d43fd68SRuslan Bukin  */
30*5d43fd68SRuslan Bukin 
31*5d43fd68SRuslan Bukin /*
32*5d43fd68SRuslan Bukin  * Ethernet media access controller (EMAC)
33*5d43fd68SRuslan Bukin  * Chapter 17, Altera Cyclone V Device Handbook (CV-5V2 2014.07.22)
34*5d43fd68SRuslan Bukin  *
35*5d43fd68SRuslan Bukin  * EMAC is an instance of the Synopsys DesignWare 3504-0
36*5d43fd68SRuslan Bukin  * Universal 10/100/1000 Ethernet MAC (DWC_gmac).
37*5d43fd68SRuslan Bukin  */
38*5d43fd68SRuslan Bukin 
39*5d43fd68SRuslan Bukin #include <sys/cdefs.h>
40*5d43fd68SRuslan Bukin __FBSDID("$FreeBSD$");
41*5d43fd68SRuslan Bukin 
42*5d43fd68SRuslan Bukin #include <sys/param.h>
43*5d43fd68SRuslan Bukin #include <sys/systm.h>
44*5d43fd68SRuslan Bukin #include <sys/bus.h>
45*5d43fd68SRuslan Bukin #include <sys/kernel.h>
46*5d43fd68SRuslan Bukin #include <sys/module.h>
47*5d43fd68SRuslan Bukin #include <sys/malloc.h>
48*5d43fd68SRuslan Bukin #include <sys/rman.h>
49*5d43fd68SRuslan Bukin #include <sys/timeet.h>
50*5d43fd68SRuslan Bukin #include <sys/timetc.h>
51*5d43fd68SRuslan Bukin #include <sys/endian.h>
52*5d43fd68SRuslan Bukin #include <sys/lock.h>
53*5d43fd68SRuslan Bukin #include <sys/mbuf.h>
54*5d43fd68SRuslan Bukin #include <sys/mutex.h>
55*5d43fd68SRuslan Bukin #include <sys/socket.h>
56*5d43fd68SRuslan Bukin #include <sys/sockio.h>
57*5d43fd68SRuslan Bukin #include <sys/sysctl.h>
58*5d43fd68SRuslan Bukin 
59*5d43fd68SRuslan Bukin #include <dev/fdt/fdt_common.h>
60*5d43fd68SRuslan Bukin #include <dev/ofw/openfirm.h>
61*5d43fd68SRuslan Bukin #include <dev/ofw/ofw_bus.h>
62*5d43fd68SRuslan Bukin #include <dev/ofw/ofw_bus_subr.h>
63*5d43fd68SRuslan Bukin 
64*5d43fd68SRuslan Bukin #include <net/bpf.h>
65*5d43fd68SRuslan Bukin #include <net/if.h>
66*5d43fd68SRuslan Bukin #include <net/ethernet.h>
67*5d43fd68SRuslan Bukin #include <net/if_dl.h>
68*5d43fd68SRuslan Bukin #include <net/if_media.h>
69*5d43fd68SRuslan Bukin #include <net/if_types.h>
70*5d43fd68SRuslan Bukin #include <net/if_var.h>
71*5d43fd68SRuslan Bukin #include <net/if_vlan_var.h>
72*5d43fd68SRuslan Bukin 
73*5d43fd68SRuslan Bukin #include <machine/bus.h>
74*5d43fd68SRuslan Bukin #include <machine/fdt.h>
75*5d43fd68SRuslan Bukin #include <machine/cpu.h>
76*5d43fd68SRuslan Bukin #include <machine/intr.h>
77*5d43fd68SRuslan Bukin 
78*5d43fd68SRuslan Bukin #include <dev/mii/mii.h>
79*5d43fd68SRuslan Bukin #include <dev/mii/miivar.h>
80*5d43fd68SRuslan Bukin #include "miibus_if.h"
81*5d43fd68SRuslan Bukin 
82*5d43fd68SRuslan Bukin #define	READ4(_sc, _reg) \
83*5d43fd68SRuslan Bukin 	bus_read_4((_sc)->res[0], _reg)
84*5d43fd68SRuslan Bukin #define	WRITE4(_sc, _reg, _val) \
85*5d43fd68SRuslan Bukin 	bus_write_4((_sc)->res[0], _reg, _val)
86*5d43fd68SRuslan Bukin 
87*5d43fd68SRuslan Bukin #define	WATCHDOG_TIMEOUT_SECS	5
88*5d43fd68SRuslan Bukin #define	STATS_HARVEST_INTERVAL	2
89*5d43fd68SRuslan Bukin #define	MII_CLK_VAL		2
90*5d43fd68SRuslan Bukin 
91*5d43fd68SRuslan Bukin #include <dev/dwc/if_dwc.h>
92*5d43fd68SRuslan Bukin 
93*5d43fd68SRuslan Bukin #define	DWC_LOCK(sc)			mtx_lock(&(sc)->mtx)
94*5d43fd68SRuslan Bukin #define	DWC_UNLOCK(sc)			mtx_unlock(&(sc)->mtx)
95*5d43fd68SRuslan Bukin #define	DWC_ASSERT_LOCKED(sc)		mtx_assert(&(sc)->mtx, MA_OWNED);
96*5d43fd68SRuslan Bukin #define	DWC_ASSERT_UNLOCKED(sc)		mtx_assert(&(sc)->mtx, MA_NOTOWNED);
97*5d43fd68SRuslan Bukin 
98*5d43fd68SRuslan Bukin #define	DDESC_TDES0_OWN			(1 << 31)
99*5d43fd68SRuslan Bukin #define	DDESC_TDES0_TXINT		(1 << 30)
100*5d43fd68SRuslan Bukin #define	DDESC_TDES0_TXLAST		(1 << 29)
101*5d43fd68SRuslan Bukin #define	DDESC_TDES0_TXFIRST		(1 << 28)
102*5d43fd68SRuslan Bukin #define	DDESC_TDES0_TXCRCDIS		(1 << 27)
103*5d43fd68SRuslan Bukin #define	DDESC_TDES0_TXRINGEND		(1 << 21)
104*5d43fd68SRuslan Bukin #define	DDESC_TDES0_TXCHAIN		(1 << 20)
105*5d43fd68SRuslan Bukin 
106*5d43fd68SRuslan Bukin #define	DDESC_RDES0_OWN			(1 << 31)
107*5d43fd68SRuslan Bukin #define	DDESC_RDES0_FL_MASK		0x3fff
108*5d43fd68SRuslan Bukin #define	DDESC_RDES0_FL_SHIFT		16	/* Frame Length */
109*5d43fd68SRuslan Bukin #define	DDESC_RDES1_CHAINED		(1 << 14)
110*5d43fd68SRuslan Bukin 
111*5d43fd68SRuslan Bukin struct dwc_bufmap {
112*5d43fd68SRuslan Bukin 	bus_dmamap_t	map;
113*5d43fd68SRuslan Bukin 	struct mbuf	*mbuf;
114*5d43fd68SRuslan Bukin };
115*5d43fd68SRuslan Bukin 
116*5d43fd68SRuslan Bukin /*
117*5d43fd68SRuslan Bukin  * A hardware buffer descriptor.  Rx and Tx buffers have the same descriptor
118*5d43fd68SRuslan Bukin  * layout, but the bits in the flags field have different meanings.
119*5d43fd68SRuslan Bukin  */
120*5d43fd68SRuslan Bukin struct dwc_hwdesc
121*5d43fd68SRuslan Bukin {
122*5d43fd68SRuslan Bukin 	uint32_t tdes0;
123*5d43fd68SRuslan Bukin 	uint32_t tdes1;
124*5d43fd68SRuslan Bukin 	uint32_t addr;		/* pointer to buffer data */
125*5d43fd68SRuslan Bukin 	uint32_t addr_next;	/* link to next descriptor */
126*5d43fd68SRuslan Bukin };
127*5d43fd68SRuslan Bukin 
128*5d43fd68SRuslan Bukin /*
129*5d43fd68SRuslan Bukin  * Driver data and defines.
130*5d43fd68SRuslan Bukin  */
131*5d43fd68SRuslan Bukin #define	RX_DESC_COUNT	1024
132*5d43fd68SRuslan Bukin #define	RX_DESC_SIZE	(sizeof(struct dwc_hwdesc) * RX_DESC_COUNT)
133*5d43fd68SRuslan Bukin #define	TX_DESC_COUNT	1024
134*5d43fd68SRuslan Bukin #define	TX_DESC_SIZE	(sizeof(struct dwc_hwdesc) * TX_DESC_COUNT)
135*5d43fd68SRuslan Bukin 
136*5d43fd68SRuslan Bukin /*
137*5d43fd68SRuslan Bukin  * The hardware imposes alignment restrictions on various objects involved in
138*5d43fd68SRuslan Bukin  * DMA transfers.  These values are expressed in bytes (not bits).
139*5d43fd68SRuslan Bukin  */
140*5d43fd68SRuslan Bukin #define	DWC_DESC_RING_ALIGN		2048
141*5d43fd68SRuslan Bukin 
142*5d43fd68SRuslan Bukin struct dwc_softc {
143*5d43fd68SRuslan Bukin 	struct resource		*res[2];
144*5d43fd68SRuslan Bukin 	bus_space_tag_t		bst;
145*5d43fd68SRuslan Bukin 	bus_space_handle_t	bsh;
146*5d43fd68SRuslan Bukin 	device_t		dev;
147*5d43fd68SRuslan Bukin 	int			mii_clk;
148*5d43fd68SRuslan Bukin 	device_t		miibus;
149*5d43fd68SRuslan Bukin 	struct mii_data *	mii_softc;
150*5d43fd68SRuslan Bukin 	struct ifnet		*ifp;
151*5d43fd68SRuslan Bukin 	int			if_flags;
152*5d43fd68SRuslan Bukin 	struct mtx		mtx;
153*5d43fd68SRuslan Bukin 	void *			intr_cookie;
154*5d43fd68SRuslan Bukin 	struct callout		dwc_callout;
155*5d43fd68SRuslan Bukin 	uint8_t			phy_conn_type;
156*5d43fd68SRuslan Bukin 	uint8_t			mactype;
157*5d43fd68SRuslan Bukin 	boolean_t		link_is_up;
158*5d43fd68SRuslan Bukin 	boolean_t		is_attached;
159*5d43fd68SRuslan Bukin 	boolean_t		is_detaching;
160*5d43fd68SRuslan Bukin 	int			tx_watchdog_count;
161*5d43fd68SRuslan Bukin 	int			stats_harvest_count;
162*5d43fd68SRuslan Bukin 
163*5d43fd68SRuslan Bukin 	/* RX */
164*5d43fd68SRuslan Bukin 	bus_dma_tag_t		rxdesc_tag;
165*5d43fd68SRuslan Bukin 	bus_dmamap_t		rxdesc_map;
166*5d43fd68SRuslan Bukin 	struct dwc_hwdesc	*rxdesc_ring;
167*5d43fd68SRuslan Bukin 	bus_addr_t		rxdesc_ring_paddr;
168*5d43fd68SRuslan Bukin 	bus_dma_tag_t		rxbuf_tag;
169*5d43fd68SRuslan Bukin 	struct dwc_bufmap	rxbuf_map[RX_DESC_COUNT];
170*5d43fd68SRuslan Bukin 	uint32_t		rx_idx;
171*5d43fd68SRuslan Bukin 
172*5d43fd68SRuslan Bukin 	/* TX */
173*5d43fd68SRuslan Bukin 	bus_dma_tag_t		txdesc_tag;
174*5d43fd68SRuslan Bukin 	bus_dmamap_t		txdesc_map;
175*5d43fd68SRuslan Bukin 	struct dwc_hwdesc	*txdesc_ring;
176*5d43fd68SRuslan Bukin 	bus_addr_t		txdesc_ring_paddr;
177*5d43fd68SRuslan Bukin 	bus_dma_tag_t		txbuf_tag;
178*5d43fd68SRuslan Bukin 	struct dwc_bufmap	txbuf_map[RX_DESC_COUNT];
179*5d43fd68SRuslan Bukin 	uint32_t		tx_idx_head;
180*5d43fd68SRuslan Bukin 	uint32_t		tx_idx_tail;
181*5d43fd68SRuslan Bukin 	int			txcount;
182*5d43fd68SRuslan Bukin };
183*5d43fd68SRuslan Bukin 
184*5d43fd68SRuslan Bukin static struct resource_spec dwc_spec[] = {
185*5d43fd68SRuslan Bukin 	{ SYS_RES_MEMORY,	0,	RF_ACTIVE },
186*5d43fd68SRuslan Bukin 	{ SYS_RES_IRQ,		0,	RF_ACTIVE },
187*5d43fd68SRuslan Bukin 	{ -1, 0 }
188*5d43fd68SRuslan Bukin };
189*5d43fd68SRuslan Bukin 
190*5d43fd68SRuslan Bukin static void dwc_txfinish_locked(struct dwc_softc *sc);
191*5d43fd68SRuslan Bukin static void dwc_rxfinish_locked(struct dwc_softc *sc);
192*5d43fd68SRuslan Bukin static void dwc_stop_locked(struct dwc_softc *sc);
193*5d43fd68SRuslan Bukin static void dwc_setup_rxfilter(struct dwc_softc *sc);
194*5d43fd68SRuslan Bukin 
195*5d43fd68SRuslan Bukin static inline uint32_t
196*5d43fd68SRuslan Bukin next_rxidx(struct dwc_softc *sc, uint32_t curidx)
197*5d43fd68SRuslan Bukin {
198*5d43fd68SRuslan Bukin 
199*5d43fd68SRuslan Bukin 	return ((curidx + 1) % RX_DESC_COUNT);
200*5d43fd68SRuslan Bukin }
201*5d43fd68SRuslan Bukin 
202*5d43fd68SRuslan Bukin static inline uint32_t
203*5d43fd68SRuslan Bukin next_txidx(struct dwc_softc *sc, uint32_t curidx)
204*5d43fd68SRuslan Bukin {
205*5d43fd68SRuslan Bukin 
206*5d43fd68SRuslan Bukin 	return ((curidx + 1) % TX_DESC_COUNT);
207*5d43fd68SRuslan Bukin }
208*5d43fd68SRuslan Bukin 
209*5d43fd68SRuslan Bukin static void
210*5d43fd68SRuslan Bukin dwc_get1paddr(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
211*5d43fd68SRuslan Bukin {
212*5d43fd68SRuslan Bukin 
213*5d43fd68SRuslan Bukin 	if (error != 0)
214*5d43fd68SRuslan Bukin 		return;
215*5d43fd68SRuslan Bukin 	*(bus_addr_t *)arg = segs[0].ds_addr;
216*5d43fd68SRuslan Bukin }
217*5d43fd68SRuslan Bukin 
218*5d43fd68SRuslan Bukin inline static uint32_t
219*5d43fd68SRuslan Bukin dwc_setup_txdesc(struct dwc_softc *sc, int idx, bus_addr_t paddr,
220*5d43fd68SRuslan Bukin     uint32_t len)
221*5d43fd68SRuslan Bukin {
222*5d43fd68SRuslan Bukin 	uint32_t flags;
223*5d43fd68SRuslan Bukin 	uint32_t nidx;
224*5d43fd68SRuslan Bukin 
225*5d43fd68SRuslan Bukin 	nidx = next_txidx(sc, idx);
226*5d43fd68SRuslan Bukin 
227*5d43fd68SRuslan Bukin 	/* Addr/len 0 means we're clearing the descriptor after xmit done. */
228*5d43fd68SRuslan Bukin 	if (paddr == 0 || len == 0) {
229*5d43fd68SRuslan Bukin 		flags = 0;
230*5d43fd68SRuslan Bukin 		--sc->txcount;
231*5d43fd68SRuslan Bukin 	} else {
232*5d43fd68SRuslan Bukin 		flags = DDESC_TDES0_TXCHAIN | DDESC_TDES0_TXFIRST
233*5d43fd68SRuslan Bukin 		    | DDESC_TDES0_TXLAST | DDESC_TDES0_TXINT;
234*5d43fd68SRuslan Bukin 		++sc->txcount;
235*5d43fd68SRuslan Bukin 	}
236*5d43fd68SRuslan Bukin 
237*5d43fd68SRuslan Bukin 	sc->txdesc_ring[idx].addr = (uint32_t)(paddr);
238*5d43fd68SRuslan Bukin 	sc->txdesc_ring[idx].tdes0 = flags;
239*5d43fd68SRuslan Bukin 	sc->txdesc_ring[idx].tdes1 = len;
240*5d43fd68SRuslan Bukin 
241*5d43fd68SRuslan Bukin 	if (paddr && len) {
242*5d43fd68SRuslan Bukin 		wmb();
243*5d43fd68SRuslan Bukin 		sc->txdesc_ring[idx].tdes0 |= DDESC_TDES0_OWN;
244*5d43fd68SRuslan Bukin 		wmb();
245*5d43fd68SRuslan Bukin 	}
246*5d43fd68SRuslan Bukin 
247*5d43fd68SRuslan Bukin 	return (nidx);
248*5d43fd68SRuslan Bukin }
249*5d43fd68SRuslan Bukin 
250*5d43fd68SRuslan Bukin static int
251*5d43fd68SRuslan Bukin dwc_setup_txbuf(struct dwc_softc *sc, int idx, struct mbuf **mp)
252*5d43fd68SRuslan Bukin {
253*5d43fd68SRuslan Bukin 	struct bus_dma_segment seg;
254*5d43fd68SRuslan Bukin 	int error, nsegs;
255*5d43fd68SRuslan Bukin 	struct mbuf * m;
256*5d43fd68SRuslan Bukin 
257*5d43fd68SRuslan Bukin 	if ((m = m_defrag(*mp, M_NOWAIT)) == NULL)
258*5d43fd68SRuslan Bukin 		return (ENOMEM);
259*5d43fd68SRuslan Bukin 	*mp = m;
260*5d43fd68SRuslan Bukin 
261*5d43fd68SRuslan Bukin 	error = bus_dmamap_load_mbuf_sg(sc->txbuf_tag, sc->txbuf_map[idx].map,
262*5d43fd68SRuslan Bukin 	    m, &seg, &nsegs, 0);
263*5d43fd68SRuslan Bukin 	if (error != 0) {
264*5d43fd68SRuslan Bukin 		return (ENOMEM);
265*5d43fd68SRuslan Bukin 	}
266*5d43fd68SRuslan Bukin 
267*5d43fd68SRuslan Bukin 	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
268*5d43fd68SRuslan Bukin 
269*5d43fd68SRuslan Bukin 	bus_dmamap_sync(sc->txbuf_tag, sc->txbuf_map[idx].map,
270*5d43fd68SRuslan Bukin 	    BUS_DMASYNC_PREWRITE);
271*5d43fd68SRuslan Bukin 
272*5d43fd68SRuslan Bukin 	sc->txbuf_map[idx].mbuf = m;
273*5d43fd68SRuslan Bukin 
274*5d43fd68SRuslan Bukin 	dwc_setup_txdesc(sc, idx, seg.ds_addr, seg.ds_len);
275*5d43fd68SRuslan Bukin 
276*5d43fd68SRuslan Bukin 	return (0);
277*5d43fd68SRuslan Bukin }
278*5d43fd68SRuslan Bukin 
279*5d43fd68SRuslan Bukin static void
280*5d43fd68SRuslan Bukin dwc_txstart_locked(struct dwc_softc *sc)
281*5d43fd68SRuslan Bukin {
282*5d43fd68SRuslan Bukin 	struct ifnet *ifp;
283*5d43fd68SRuslan Bukin 	struct mbuf *m;
284*5d43fd68SRuslan Bukin 	int enqueued;
285*5d43fd68SRuslan Bukin 
286*5d43fd68SRuslan Bukin 	DWC_ASSERT_LOCKED(sc);
287*5d43fd68SRuslan Bukin 
288*5d43fd68SRuslan Bukin 	if (!sc->link_is_up)
289*5d43fd68SRuslan Bukin 		return;
290*5d43fd68SRuslan Bukin 
291*5d43fd68SRuslan Bukin 	ifp = sc->ifp;
292*5d43fd68SRuslan Bukin 
293*5d43fd68SRuslan Bukin 	if (ifp->if_drv_flags & IFF_DRV_OACTIVE) {
294*5d43fd68SRuslan Bukin 		return;
295*5d43fd68SRuslan Bukin 	}
296*5d43fd68SRuslan Bukin 
297*5d43fd68SRuslan Bukin 	enqueued = 0;
298*5d43fd68SRuslan Bukin 
299*5d43fd68SRuslan Bukin 	for (;;) {
300*5d43fd68SRuslan Bukin 		if (sc->txcount == (TX_DESC_COUNT-1)) {
301*5d43fd68SRuslan Bukin 			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
302*5d43fd68SRuslan Bukin 			break;
303*5d43fd68SRuslan Bukin 		}
304*5d43fd68SRuslan Bukin 
305*5d43fd68SRuslan Bukin 		IFQ_DRV_DEQUEUE(&ifp->if_snd, m);
306*5d43fd68SRuslan Bukin 		if (m == NULL)
307*5d43fd68SRuslan Bukin 			break;
308*5d43fd68SRuslan Bukin 		if (dwc_setup_txbuf(sc, sc->tx_idx_head, &m) != 0) {
309*5d43fd68SRuslan Bukin 			IFQ_DRV_PREPEND(&ifp->if_snd, m);
310*5d43fd68SRuslan Bukin 			break;
311*5d43fd68SRuslan Bukin 		}
312*5d43fd68SRuslan Bukin 		BPF_MTAP(ifp, m);
313*5d43fd68SRuslan Bukin 		sc->tx_idx_head = next_txidx(sc, sc->tx_idx_head);
314*5d43fd68SRuslan Bukin 		++enqueued;
315*5d43fd68SRuslan Bukin 	}
316*5d43fd68SRuslan Bukin 
317*5d43fd68SRuslan Bukin 	if (enqueued != 0) {
318*5d43fd68SRuslan Bukin 		WRITE4(sc, TRANSMIT_POLL_DEMAND, 0x1);
319*5d43fd68SRuslan Bukin 		sc->tx_watchdog_count = WATCHDOG_TIMEOUT_SECS;
320*5d43fd68SRuslan Bukin 	}
321*5d43fd68SRuslan Bukin }
322*5d43fd68SRuslan Bukin 
323*5d43fd68SRuslan Bukin static void
324*5d43fd68SRuslan Bukin dwc_txstart(struct ifnet *ifp)
325*5d43fd68SRuslan Bukin {
326*5d43fd68SRuslan Bukin 	struct dwc_softc *sc = ifp->if_softc;
327*5d43fd68SRuslan Bukin 
328*5d43fd68SRuslan Bukin 	DWC_LOCK(sc);
329*5d43fd68SRuslan Bukin 	dwc_txstart_locked(sc);
330*5d43fd68SRuslan Bukin 	DWC_UNLOCK(sc);
331*5d43fd68SRuslan Bukin }
332*5d43fd68SRuslan Bukin 
333*5d43fd68SRuslan Bukin static void
334*5d43fd68SRuslan Bukin dwc_stop_locked(struct dwc_softc *sc)
335*5d43fd68SRuslan Bukin {
336*5d43fd68SRuslan Bukin 	struct ifnet *ifp;
337*5d43fd68SRuslan Bukin 	int reg;
338*5d43fd68SRuslan Bukin 
339*5d43fd68SRuslan Bukin 	DWC_ASSERT_LOCKED(sc);
340*5d43fd68SRuslan Bukin 
341*5d43fd68SRuslan Bukin 	ifp = sc->ifp;
342*5d43fd68SRuslan Bukin 	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
343*5d43fd68SRuslan Bukin 	sc->tx_watchdog_count = 0;
344*5d43fd68SRuslan Bukin 	sc->stats_harvest_count = 0;
345*5d43fd68SRuslan Bukin 
346*5d43fd68SRuslan Bukin 	callout_stop(&sc->dwc_callout);
347*5d43fd68SRuslan Bukin 
348*5d43fd68SRuslan Bukin 	/* Stop DMA TX */
349*5d43fd68SRuslan Bukin 	reg = READ4(sc, OPERATION_MODE);
350*5d43fd68SRuslan Bukin 	reg &= ~(MODE_ST);
351*5d43fd68SRuslan Bukin 	WRITE4(sc, OPERATION_MODE, reg);
352*5d43fd68SRuslan Bukin 
353*5d43fd68SRuslan Bukin 	/* Flush TX */
354*5d43fd68SRuslan Bukin 	reg = READ4(sc, OPERATION_MODE);
355*5d43fd68SRuslan Bukin 	reg |= (MODE_FTF);
356*5d43fd68SRuslan Bukin 	WRITE4(sc, OPERATION_MODE, reg);
357*5d43fd68SRuslan Bukin 
358*5d43fd68SRuslan Bukin 	/* Stop transmitters */
359*5d43fd68SRuslan Bukin 	reg = READ4(sc, MAC_CONFIGURATION);
360*5d43fd68SRuslan Bukin 	reg &= ~(CONF_TE | CONF_RE);
361*5d43fd68SRuslan Bukin 	WRITE4(sc, MAC_CONFIGURATION, reg);
362*5d43fd68SRuslan Bukin 
363*5d43fd68SRuslan Bukin 	/* Stop DMA RX */
364*5d43fd68SRuslan Bukin 	reg = READ4(sc, OPERATION_MODE);
365*5d43fd68SRuslan Bukin 	reg &= ~(MODE_SR);
366*5d43fd68SRuslan Bukin 	WRITE4(sc, OPERATION_MODE, reg);
367*5d43fd68SRuslan Bukin }
368*5d43fd68SRuslan Bukin 
369*5d43fd68SRuslan Bukin static void dwc_clear_stats(struct dwc_softc *sc)
370*5d43fd68SRuslan Bukin {
371*5d43fd68SRuslan Bukin 	int reg;
372*5d43fd68SRuslan Bukin 
373*5d43fd68SRuslan Bukin 	reg = READ4(sc, MMC_CONTROL);
374*5d43fd68SRuslan Bukin 	reg |= (MMC_CONTROL_CNTRST);
375*5d43fd68SRuslan Bukin 	WRITE4(sc, MMC_CONTROL, reg);
376*5d43fd68SRuslan Bukin }
377*5d43fd68SRuslan Bukin 
378*5d43fd68SRuslan Bukin static void
379*5d43fd68SRuslan Bukin dwc_harvest_stats(struct dwc_softc *sc)
380*5d43fd68SRuslan Bukin {
381*5d43fd68SRuslan Bukin 	struct ifnet *ifp;
382*5d43fd68SRuslan Bukin 
383*5d43fd68SRuslan Bukin 	/* We don't need to harvest too often. */
384*5d43fd68SRuslan Bukin 	if (++sc->stats_harvest_count < STATS_HARVEST_INTERVAL)
385*5d43fd68SRuslan Bukin 		return;
386*5d43fd68SRuslan Bukin 
387*5d43fd68SRuslan Bukin 	sc->stats_harvest_count = 0;
388*5d43fd68SRuslan Bukin 	ifp = sc->ifp;
389*5d43fd68SRuslan Bukin 
390*5d43fd68SRuslan Bukin 	if_inc_counter(ifp, IFCOUNTER_IPACKETS, READ4(sc, RXFRAMECOUNT_GB));
391*5d43fd68SRuslan Bukin 	if_inc_counter(ifp, IFCOUNTER_IMCASTS, READ4(sc, RXMULTICASTFRAMES_G));
392*5d43fd68SRuslan Bukin 	if_inc_counter(ifp, IFCOUNTER_IERRORS,
393*5d43fd68SRuslan Bukin 	    READ4(sc, RXOVERSIZE_G) + READ4(sc, RXUNDERSIZE_G) +
394*5d43fd68SRuslan Bukin 	    READ4(sc, RXCRCERROR) + READ4(sc, RXALIGNMENTERROR) +
395*5d43fd68SRuslan Bukin 	    READ4(sc, RXRUNTERROR) + READ4(sc, RXJABBERERROR) +
396*5d43fd68SRuslan Bukin 	    READ4(sc, RXLENGTHERROR));
397*5d43fd68SRuslan Bukin 
398*5d43fd68SRuslan Bukin 	if_inc_counter(ifp, IFCOUNTER_OPACKETS, READ4(sc, TXFRAMECOUNT_G));
399*5d43fd68SRuslan Bukin 	if_inc_counter(ifp, IFCOUNTER_OMCASTS, READ4(sc, TXMULTICASTFRAMES_G));
400*5d43fd68SRuslan Bukin 	if_inc_counter(ifp, IFCOUNTER_OERRORS,
401*5d43fd68SRuslan Bukin 	    READ4(sc, TXOVERSIZE_G) + READ4(sc, TXEXCESSDEF) +
402*5d43fd68SRuslan Bukin 	    READ4(sc, TXCARRIERERR) + READ4(sc, TXUNDERFLOWERROR));
403*5d43fd68SRuslan Bukin 
404*5d43fd68SRuslan Bukin 	if_inc_counter(ifp, IFCOUNTER_COLLISIONS,
405*5d43fd68SRuslan Bukin 	    READ4(sc, TXEXESSCOL) + READ4(sc, TXLATECOL));
406*5d43fd68SRuslan Bukin 
407*5d43fd68SRuslan Bukin 	dwc_clear_stats(sc);
408*5d43fd68SRuslan Bukin }
409*5d43fd68SRuslan Bukin 
410*5d43fd68SRuslan Bukin static void
411*5d43fd68SRuslan Bukin dwc_tick(void *arg)
412*5d43fd68SRuslan Bukin {
413*5d43fd68SRuslan Bukin 	struct dwc_softc *sc;
414*5d43fd68SRuslan Bukin 	struct ifnet *ifp;
415*5d43fd68SRuslan Bukin 	int link_was_up;
416*5d43fd68SRuslan Bukin 
417*5d43fd68SRuslan Bukin 	sc = arg;
418*5d43fd68SRuslan Bukin 
419*5d43fd68SRuslan Bukin 	DWC_ASSERT_LOCKED(sc);
420*5d43fd68SRuslan Bukin 
421*5d43fd68SRuslan Bukin 	ifp = sc->ifp;
422*5d43fd68SRuslan Bukin 
423*5d43fd68SRuslan Bukin 	if (!(ifp->if_drv_flags & IFF_DRV_RUNNING))
424*5d43fd68SRuslan Bukin 	    return;
425*5d43fd68SRuslan Bukin 
426*5d43fd68SRuslan Bukin 	/*
427*5d43fd68SRuslan Bukin 	 * Typical tx watchdog.  If this fires it indicates that we enqueued
428*5d43fd68SRuslan Bukin 	 * packets for output and never got a txdone interrupt for them.  Maybe
429*5d43fd68SRuslan Bukin 	 * it's a missed interrupt somehow, just pretend we got one.
430*5d43fd68SRuslan Bukin 	 */
431*5d43fd68SRuslan Bukin 	if (sc->tx_watchdog_count > 0) {
432*5d43fd68SRuslan Bukin 		if (--sc->tx_watchdog_count == 0) {
433*5d43fd68SRuslan Bukin 			dwc_txfinish_locked(sc);
434*5d43fd68SRuslan Bukin 		}
435*5d43fd68SRuslan Bukin 	}
436*5d43fd68SRuslan Bukin 
437*5d43fd68SRuslan Bukin 	/* Gather stats from hardware counters. */
438*5d43fd68SRuslan Bukin 	dwc_harvest_stats(sc);
439*5d43fd68SRuslan Bukin 
440*5d43fd68SRuslan Bukin 	/* Check the media status. */
441*5d43fd68SRuslan Bukin 	link_was_up = sc->link_is_up;
442*5d43fd68SRuslan Bukin 	mii_tick(sc->mii_softc);
443*5d43fd68SRuslan Bukin 	if (sc->link_is_up && !link_was_up)
444*5d43fd68SRuslan Bukin 		dwc_txstart_locked(sc);
445*5d43fd68SRuslan Bukin 
446*5d43fd68SRuslan Bukin 	/* Schedule another check one second from now. */
447*5d43fd68SRuslan Bukin 	callout_reset(&sc->dwc_callout, hz, dwc_tick, sc);
448*5d43fd68SRuslan Bukin }
449*5d43fd68SRuslan Bukin 
450*5d43fd68SRuslan Bukin static void
451*5d43fd68SRuslan Bukin dwc_init_locked(struct dwc_softc *sc)
452*5d43fd68SRuslan Bukin {
453*5d43fd68SRuslan Bukin 	struct ifnet *ifp = sc->ifp;
454*5d43fd68SRuslan Bukin 	int reg;
455*5d43fd68SRuslan Bukin 
456*5d43fd68SRuslan Bukin 	DWC_ASSERT_LOCKED(sc);
457*5d43fd68SRuslan Bukin 
458*5d43fd68SRuslan Bukin 	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
459*5d43fd68SRuslan Bukin 		return;
460*5d43fd68SRuslan Bukin 
461*5d43fd68SRuslan Bukin 	ifp->if_drv_flags |= IFF_DRV_RUNNING;
462*5d43fd68SRuslan Bukin 
463*5d43fd68SRuslan Bukin 	dwc_setup_rxfilter(sc);
464*5d43fd68SRuslan Bukin 
465*5d43fd68SRuslan Bukin 	/* Initializa DMA and enable transmitters */
466*5d43fd68SRuslan Bukin 	reg = READ4(sc, OPERATION_MODE);
467*5d43fd68SRuslan Bukin 	reg |= (MODE_TSF | MODE_OSF | MODE_FUF);
468*5d43fd68SRuslan Bukin 	reg &= ~(MODE_RSF);
469*5d43fd68SRuslan Bukin 	reg |= (MODE_RTC_LEV32 << MODE_RTC_SHIFT);
470*5d43fd68SRuslan Bukin 	WRITE4(sc, OPERATION_MODE, reg);
471*5d43fd68SRuslan Bukin 
472*5d43fd68SRuslan Bukin 	WRITE4(sc, INTERRUPT_ENABLE, INT_EN_DEFAULT);
473*5d43fd68SRuslan Bukin 
474*5d43fd68SRuslan Bukin 	/* Start DMA */
475*5d43fd68SRuslan Bukin 	reg = READ4(sc, OPERATION_MODE);
476*5d43fd68SRuslan Bukin 	reg |= (MODE_ST | MODE_SR);
477*5d43fd68SRuslan Bukin 	WRITE4(sc, OPERATION_MODE, reg);
478*5d43fd68SRuslan Bukin 
479*5d43fd68SRuslan Bukin 	/* Enable transmitters */
480*5d43fd68SRuslan Bukin 	reg = READ4(sc, MAC_CONFIGURATION);
481*5d43fd68SRuslan Bukin 	reg |= (CONF_JD | CONF_ACS | CONF_BE);
482*5d43fd68SRuslan Bukin 	reg |= (CONF_TE | CONF_RE);
483*5d43fd68SRuslan Bukin 	WRITE4(sc, MAC_CONFIGURATION, reg);
484*5d43fd68SRuslan Bukin 
485*5d43fd68SRuslan Bukin 	/*
486*5d43fd68SRuslan Bukin 	 * Call mii_mediachg() which will call back into dwc_miibus_statchg()
487*5d43fd68SRuslan Bukin 	 * to set up the remaining config registers based on current media.
488*5d43fd68SRuslan Bukin 	 */
489*5d43fd68SRuslan Bukin 	mii_mediachg(sc->mii_softc);
490*5d43fd68SRuslan Bukin 	callout_reset(&sc->dwc_callout, hz, dwc_tick, sc);
491*5d43fd68SRuslan Bukin }
492*5d43fd68SRuslan Bukin 
493*5d43fd68SRuslan Bukin static void
494*5d43fd68SRuslan Bukin dwc_init(void *if_softc)
495*5d43fd68SRuslan Bukin {
496*5d43fd68SRuslan Bukin 	struct dwc_softc *sc = if_softc;
497*5d43fd68SRuslan Bukin 
498*5d43fd68SRuslan Bukin 	DWC_LOCK(sc);
499*5d43fd68SRuslan Bukin 	dwc_init_locked(sc);
500*5d43fd68SRuslan Bukin 	DWC_UNLOCK(sc);
501*5d43fd68SRuslan Bukin }
502*5d43fd68SRuslan Bukin 
503*5d43fd68SRuslan Bukin inline static uint32_t
504*5d43fd68SRuslan Bukin dwc_setup_rxdesc(struct dwc_softc *sc, int idx, bus_addr_t paddr)
505*5d43fd68SRuslan Bukin {
506*5d43fd68SRuslan Bukin 	uint32_t nidx;
507*5d43fd68SRuslan Bukin 
508*5d43fd68SRuslan Bukin 	sc->rxdesc_ring[idx].addr = (uint32_t)paddr;
509*5d43fd68SRuslan Bukin 	nidx = next_rxidx(sc, idx);
510*5d43fd68SRuslan Bukin 	sc->rxdesc_ring[idx].addr_next = sc->rxdesc_ring_paddr +	\
511*5d43fd68SRuslan Bukin 	    (nidx * sizeof(struct dwc_hwdesc));
512*5d43fd68SRuslan Bukin 	sc->rxdesc_ring[idx].tdes1 = DDESC_RDES1_CHAINED | MCLBYTES;
513*5d43fd68SRuslan Bukin 
514*5d43fd68SRuslan Bukin 	wmb();
515*5d43fd68SRuslan Bukin 	sc->rxdesc_ring[idx].tdes0 = DDESC_RDES0_OWN;
516*5d43fd68SRuslan Bukin 	wmb();
517*5d43fd68SRuslan Bukin 
518*5d43fd68SRuslan Bukin 	return (nidx);
519*5d43fd68SRuslan Bukin }
520*5d43fd68SRuslan Bukin 
521*5d43fd68SRuslan Bukin static int
522*5d43fd68SRuslan Bukin dwc_setup_rxbuf(struct dwc_softc *sc, int idx, struct mbuf *m)
523*5d43fd68SRuslan Bukin {
524*5d43fd68SRuslan Bukin 	struct bus_dma_segment seg;
525*5d43fd68SRuslan Bukin 	int error, nsegs;
526*5d43fd68SRuslan Bukin 
527*5d43fd68SRuslan Bukin 	m_adj(m, ETHER_ALIGN);
528*5d43fd68SRuslan Bukin 
529*5d43fd68SRuslan Bukin 	error = bus_dmamap_load_mbuf_sg(sc->rxbuf_tag, sc->rxbuf_map[idx].map,
530*5d43fd68SRuslan Bukin 	    m, &seg, &nsegs, 0);
531*5d43fd68SRuslan Bukin 	if (error != 0) {
532*5d43fd68SRuslan Bukin 		return (error);
533*5d43fd68SRuslan Bukin 	}
534*5d43fd68SRuslan Bukin 
535*5d43fd68SRuslan Bukin 	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
536*5d43fd68SRuslan Bukin 
537*5d43fd68SRuslan Bukin 	bus_dmamap_sync(sc->rxbuf_tag, sc->rxbuf_map[idx].map,
538*5d43fd68SRuslan Bukin 	    BUS_DMASYNC_PREREAD);
539*5d43fd68SRuslan Bukin 
540*5d43fd68SRuslan Bukin 	sc->rxbuf_map[idx].mbuf = m;
541*5d43fd68SRuslan Bukin 	dwc_setup_rxdesc(sc, idx, seg.ds_addr);
542*5d43fd68SRuslan Bukin 
543*5d43fd68SRuslan Bukin 	return (0);
544*5d43fd68SRuslan Bukin }
545*5d43fd68SRuslan Bukin 
546*5d43fd68SRuslan Bukin static struct mbuf *
547*5d43fd68SRuslan Bukin dwc_alloc_mbufcl(struct dwc_softc *sc)
548*5d43fd68SRuslan Bukin {
549*5d43fd68SRuslan Bukin 	struct mbuf *m;
550*5d43fd68SRuslan Bukin 
551*5d43fd68SRuslan Bukin 	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
552*5d43fd68SRuslan Bukin 	m->m_pkthdr.len = m->m_len = m->m_ext.ext_size;
553*5d43fd68SRuslan Bukin 
554*5d43fd68SRuslan Bukin 	return (m);
555*5d43fd68SRuslan Bukin }
556*5d43fd68SRuslan Bukin 
557*5d43fd68SRuslan Bukin static void
558*5d43fd68SRuslan Bukin dwc_media_status(struct ifnet * ifp, struct ifmediareq *ifmr)
559*5d43fd68SRuslan Bukin {
560*5d43fd68SRuslan Bukin 	struct dwc_softc *sc;
561*5d43fd68SRuslan Bukin 	struct mii_data *mii;
562*5d43fd68SRuslan Bukin 
563*5d43fd68SRuslan Bukin 	sc = ifp->if_softc;
564*5d43fd68SRuslan Bukin 	mii = sc->mii_softc;
565*5d43fd68SRuslan Bukin 	DWC_LOCK(sc);
566*5d43fd68SRuslan Bukin 	mii_pollstat(mii);
567*5d43fd68SRuslan Bukin 	ifmr->ifm_active = mii->mii_media_active;
568*5d43fd68SRuslan Bukin 	ifmr->ifm_status = mii->mii_media_status;
569*5d43fd68SRuslan Bukin 	DWC_UNLOCK(sc);
570*5d43fd68SRuslan Bukin }
571*5d43fd68SRuslan Bukin 
572*5d43fd68SRuslan Bukin static int
573*5d43fd68SRuslan Bukin dwc_media_change_locked(struct dwc_softc *sc)
574*5d43fd68SRuslan Bukin {
575*5d43fd68SRuslan Bukin 
576*5d43fd68SRuslan Bukin 	return (mii_mediachg(sc->mii_softc));
577*5d43fd68SRuslan Bukin }
578*5d43fd68SRuslan Bukin 
579*5d43fd68SRuslan Bukin static int
580*5d43fd68SRuslan Bukin dwc_media_change(struct ifnet * ifp)
581*5d43fd68SRuslan Bukin {
582*5d43fd68SRuslan Bukin 	struct dwc_softc *sc;
583*5d43fd68SRuslan Bukin 	int error;
584*5d43fd68SRuslan Bukin 
585*5d43fd68SRuslan Bukin 	sc = ifp->if_softc;
586*5d43fd68SRuslan Bukin 
587*5d43fd68SRuslan Bukin 	DWC_LOCK(sc);
588*5d43fd68SRuslan Bukin 	error = dwc_media_change_locked(sc);
589*5d43fd68SRuslan Bukin 	DWC_UNLOCK(sc);
590*5d43fd68SRuslan Bukin 	return (error);
591*5d43fd68SRuslan Bukin }
592*5d43fd68SRuslan Bukin 
593*5d43fd68SRuslan Bukin static const uint8_t nibbletab[] = {
594*5d43fd68SRuslan Bukin 	/* 0x0 0000 -> 0000 */  0x0,
595*5d43fd68SRuslan Bukin 	/* 0x1 0001 -> 1000 */  0x8,
596*5d43fd68SRuslan Bukin 	/* 0x2 0010 -> 0100 */  0x4,
597*5d43fd68SRuslan Bukin 	/* 0x3 0011 -> 1100 */  0xc,
598*5d43fd68SRuslan Bukin 	/* 0x4 0100 -> 0010 */  0x2,
599*5d43fd68SRuslan Bukin 	/* 0x5 0101 -> 1010 */  0xa,
600*5d43fd68SRuslan Bukin 	/* 0x6 0110 -> 0110 */  0x6,
601*5d43fd68SRuslan Bukin 	/* 0x7 0111 -> 1110 */  0xe,
602*5d43fd68SRuslan Bukin 	/* 0x8 1000 -> 0001 */  0x1,
603*5d43fd68SRuslan Bukin 	/* 0x9 1001 -> 1001 */  0x9,
604*5d43fd68SRuslan Bukin 	/* 0xa 1010 -> 0101 */  0x5,
605*5d43fd68SRuslan Bukin 	/* 0xb 1011 -> 1101 */  0xd,
606*5d43fd68SRuslan Bukin 	/* 0xc 1100 -> 0011 */  0x3,
607*5d43fd68SRuslan Bukin 	/* 0xd 1101 -> 1011 */  0xb,
608*5d43fd68SRuslan Bukin 	/* 0xe 1110 -> 0111 */  0x7,
609*5d43fd68SRuslan Bukin 	/* 0xf 1111 -> 1111 */  0xf, };
610*5d43fd68SRuslan Bukin 
611*5d43fd68SRuslan Bukin static uint8_t
612*5d43fd68SRuslan Bukin bitreverse(uint8_t x)
613*5d43fd68SRuslan Bukin {
614*5d43fd68SRuslan Bukin 
615*5d43fd68SRuslan Bukin 	return (nibbletab[x & 0xf] << 4) | nibbletab[x >> 4];
616*5d43fd68SRuslan Bukin }
617*5d43fd68SRuslan Bukin 
618*5d43fd68SRuslan Bukin static void
619*5d43fd68SRuslan Bukin dwc_setup_rxfilter(struct dwc_softc *sc)
620*5d43fd68SRuslan Bukin {
621*5d43fd68SRuslan Bukin 	struct ifmultiaddr *ifma;
622*5d43fd68SRuslan Bukin 	struct ifnet *ifp;
623*5d43fd68SRuslan Bukin 	uint8_t *eaddr;
624*5d43fd68SRuslan Bukin 	uint32_t crc;
625*5d43fd68SRuslan Bukin 	uint8_t val;
626*5d43fd68SRuslan Bukin 	int hashbit;
627*5d43fd68SRuslan Bukin 	int hashreg;
628*5d43fd68SRuslan Bukin 	int ffval;
629*5d43fd68SRuslan Bukin 	int reg;
630*5d43fd68SRuslan Bukin 	int lo;
631*5d43fd68SRuslan Bukin 	int hi;
632*5d43fd68SRuslan Bukin 
633*5d43fd68SRuslan Bukin 	DWC_ASSERT_LOCKED(sc);
634*5d43fd68SRuslan Bukin 
635*5d43fd68SRuslan Bukin 	ifp = sc->ifp;
636*5d43fd68SRuslan Bukin 
637*5d43fd68SRuslan Bukin 	/*
638*5d43fd68SRuslan Bukin 	 * Set the multicast (group) filter hash.
639*5d43fd68SRuslan Bukin 	 */
640*5d43fd68SRuslan Bukin 	if ((ifp->if_flags & IFF_ALLMULTI))
641*5d43fd68SRuslan Bukin 		ffval = (FRAME_FILTER_PM);
642*5d43fd68SRuslan Bukin 	else {
643*5d43fd68SRuslan Bukin 		ffval = (FRAME_FILTER_HMC);
644*5d43fd68SRuslan Bukin 		if_maddr_rlock(ifp);
645*5d43fd68SRuslan Bukin 		TAILQ_FOREACH(ifma, &sc->ifp->if_multiaddrs, ifma_link) {
646*5d43fd68SRuslan Bukin 			if (ifma->ifma_addr->sa_family != AF_LINK)
647*5d43fd68SRuslan Bukin 				continue;
648*5d43fd68SRuslan Bukin 			crc = ether_crc32_le(LLADDR((struct sockaddr_dl *)
649*5d43fd68SRuslan Bukin 				ifma->ifma_addr), ETHER_ADDR_LEN);
650*5d43fd68SRuslan Bukin 
651*5d43fd68SRuslan Bukin 			/* Take lower 8 bits and reverse it */
652*5d43fd68SRuslan Bukin 			val = bitreverse(~crc & 0xff);
653*5d43fd68SRuslan Bukin 			hashreg = (val >> 5);
654*5d43fd68SRuslan Bukin 			hashbit = (val & 31);
655*5d43fd68SRuslan Bukin 
656*5d43fd68SRuslan Bukin 			reg = READ4(sc, HASH_TABLE_REG(hashreg));
657*5d43fd68SRuslan Bukin 			reg |= (1 << hashbit);
658*5d43fd68SRuslan Bukin 			WRITE4(sc, HASH_TABLE_REG(hashreg), reg);
659*5d43fd68SRuslan Bukin 		}
660*5d43fd68SRuslan Bukin 		if_maddr_runlock(ifp);
661*5d43fd68SRuslan Bukin 	}
662*5d43fd68SRuslan Bukin 
663*5d43fd68SRuslan Bukin 	/*
664*5d43fd68SRuslan Bukin 	 * Set the individual address filter hash.
665*5d43fd68SRuslan Bukin 	 */
666*5d43fd68SRuslan Bukin 	if (ifp->if_flags & IFF_PROMISC)
667*5d43fd68SRuslan Bukin 		ffval |= (FRAME_FILTER_PR);
668*5d43fd68SRuslan Bukin 
669*5d43fd68SRuslan Bukin 	/*
670*5d43fd68SRuslan Bukin 	 * Set the primary address.
671*5d43fd68SRuslan Bukin 	 */
672*5d43fd68SRuslan Bukin 	eaddr = IF_LLADDR(ifp);
673*5d43fd68SRuslan Bukin 	lo = eaddr[0] | (eaddr[1] << 8) | (eaddr[2] << 16) |
674*5d43fd68SRuslan Bukin 	    (eaddr[3] << 24);
675*5d43fd68SRuslan Bukin 	hi = eaddr[4] | (eaddr[5] << 8);
676*5d43fd68SRuslan Bukin 	WRITE4(sc, MAC_ADDRESS_LOW(0), lo);
677*5d43fd68SRuslan Bukin 	WRITE4(sc, MAC_ADDRESS_HIGH(0), hi);
678*5d43fd68SRuslan Bukin 	WRITE4(sc, MAC_FRAME_FILTER, ffval);
679*5d43fd68SRuslan Bukin }
680*5d43fd68SRuslan Bukin 
681*5d43fd68SRuslan Bukin static int
682*5d43fd68SRuslan Bukin dwc_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
683*5d43fd68SRuslan Bukin {
684*5d43fd68SRuslan Bukin 	struct dwc_softc *sc;
685*5d43fd68SRuslan Bukin 	struct mii_data *mii;
686*5d43fd68SRuslan Bukin 	struct ifreq *ifr;
687*5d43fd68SRuslan Bukin 	int mask, error;
688*5d43fd68SRuslan Bukin 
689*5d43fd68SRuslan Bukin 	sc = ifp->if_softc;
690*5d43fd68SRuslan Bukin 	ifr = (struct ifreq *)data;
691*5d43fd68SRuslan Bukin 
692*5d43fd68SRuslan Bukin 	error = 0;
693*5d43fd68SRuslan Bukin 	switch (cmd) {
694*5d43fd68SRuslan Bukin 	case SIOCSIFFLAGS:
695*5d43fd68SRuslan Bukin 		DWC_LOCK(sc);
696*5d43fd68SRuslan Bukin 		if (ifp->if_flags & IFF_UP) {
697*5d43fd68SRuslan Bukin 			if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
698*5d43fd68SRuslan Bukin 				if ((ifp->if_flags ^ sc->if_flags) &
699*5d43fd68SRuslan Bukin 				    (IFF_PROMISC | IFF_ALLMULTI))
700*5d43fd68SRuslan Bukin 					dwc_setup_rxfilter(sc);
701*5d43fd68SRuslan Bukin 			} else {
702*5d43fd68SRuslan Bukin 				if (!sc->is_detaching)
703*5d43fd68SRuslan Bukin 					dwc_init_locked(sc);
704*5d43fd68SRuslan Bukin 			}
705*5d43fd68SRuslan Bukin 		} else {
706*5d43fd68SRuslan Bukin 			if (ifp->if_drv_flags & IFF_DRV_RUNNING)
707*5d43fd68SRuslan Bukin 				dwc_stop_locked(sc);
708*5d43fd68SRuslan Bukin 		}
709*5d43fd68SRuslan Bukin 		sc->if_flags = ifp->if_flags;
710*5d43fd68SRuslan Bukin 		DWC_UNLOCK(sc);
711*5d43fd68SRuslan Bukin 		break;
712*5d43fd68SRuslan Bukin 	case SIOCADDMULTI:
713*5d43fd68SRuslan Bukin 	case SIOCDELMULTI:
714*5d43fd68SRuslan Bukin 		if (ifp->if_drv_flags & IFF_DRV_RUNNING) {
715*5d43fd68SRuslan Bukin 			DWC_LOCK(sc);
716*5d43fd68SRuslan Bukin 			dwc_setup_rxfilter(sc);
717*5d43fd68SRuslan Bukin 			DWC_UNLOCK(sc);
718*5d43fd68SRuslan Bukin 		}
719*5d43fd68SRuslan Bukin 		break;
720*5d43fd68SRuslan Bukin 	case SIOCSIFMEDIA:
721*5d43fd68SRuslan Bukin 	case SIOCGIFMEDIA:
722*5d43fd68SRuslan Bukin 		mii = sc->mii_softc;
723*5d43fd68SRuslan Bukin 		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
724*5d43fd68SRuslan Bukin 		break;
725*5d43fd68SRuslan Bukin 	case SIOCSIFCAP:
726*5d43fd68SRuslan Bukin 		mask = ifp->if_capenable ^ ifr->ifr_reqcap;
727*5d43fd68SRuslan Bukin 		if (mask & IFCAP_VLAN_MTU) {
728*5d43fd68SRuslan Bukin 			/* No work to do except acknowledge the change took */
729*5d43fd68SRuslan Bukin 			ifp->if_capenable ^= IFCAP_VLAN_MTU;
730*5d43fd68SRuslan Bukin 		}
731*5d43fd68SRuslan Bukin 		break;
732*5d43fd68SRuslan Bukin 
733*5d43fd68SRuslan Bukin 	default:
734*5d43fd68SRuslan Bukin 		error = ether_ioctl(ifp, cmd, data);
735*5d43fd68SRuslan Bukin 		break;
736*5d43fd68SRuslan Bukin 	}
737*5d43fd68SRuslan Bukin 
738*5d43fd68SRuslan Bukin 	return (error);
739*5d43fd68SRuslan Bukin }
740*5d43fd68SRuslan Bukin 
741*5d43fd68SRuslan Bukin static void
742*5d43fd68SRuslan Bukin dwc_txfinish_locked(struct dwc_softc *sc)
743*5d43fd68SRuslan Bukin {
744*5d43fd68SRuslan Bukin 	struct dwc_bufmap *bmap;
745*5d43fd68SRuslan Bukin 	struct dwc_hwdesc *desc;
746*5d43fd68SRuslan Bukin 	struct ifnet *ifp;
747*5d43fd68SRuslan Bukin 
748*5d43fd68SRuslan Bukin 	DWC_ASSERT_LOCKED(sc);
749*5d43fd68SRuslan Bukin 
750*5d43fd68SRuslan Bukin 	ifp = sc->ifp;
751*5d43fd68SRuslan Bukin 
752*5d43fd68SRuslan Bukin 	while (sc->tx_idx_tail != sc->tx_idx_head) {
753*5d43fd68SRuslan Bukin 		desc = &sc->txdesc_ring[sc->tx_idx_tail];
754*5d43fd68SRuslan Bukin 		if ((desc->tdes0 & DDESC_TDES0_OWN) != 0)
755*5d43fd68SRuslan Bukin 			break;
756*5d43fd68SRuslan Bukin 		bmap = &sc->txbuf_map[sc->tx_idx_tail];
757*5d43fd68SRuslan Bukin 		bus_dmamap_sync(sc->txbuf_tag, bmap->map,
758*5d43fd68SRuslan Bukin 		    BUS_DMASYNC_POSTWRITE);
759*5d43fd68SRuslan Bukin 		bus_dmamap_unload(sc->txbuf_tag, bmap->map);
760*5d43fd68SRuslan Bukin 		m_freem(bmap->mbuf);
761*5d43fd68SRuslan Bukin 		bmap->mbuf = NULL;
762*5d43fd68SRuslan Bukin 		dwc_setup_txdesc(sc, sc->tx_idx_tail, 0, 0);
763*5d43fd68SRuslan Bukin 		sc->tx_idx_tail = next_txidx(sc, sc->tx_idx_tail);
764*5d43fd68SRuslan Bukin 	}
765*5d43fd68SRuslan Bukin 
766*5d43fd68SRuslan Bukin 	/* If there are no buffers outstanding, muzzle the watchdog. */
767*5d43fd68SRuslan Bukin 	if (sc->tx_idx_tail == sc->tx_idx_head) {
768*5d43fd68SRuslan Bukin 		sc->tx_watchdog_count = 0;
769*5d43fd68SRuslan Bukin 	}
770*5d43fd68SRuslan Bukin }
771*5d43fd68SRuslan Bukin 
772*5d43fd68SRuslan Bukin static void
773*5d43fd68SRuslan Bukin dwc_rxfinish_locked(struct dwc_softc *sc)
774*5d43fd68SRuslan Bukin {
775*5d43fd68SRuslan Bukin 	struct ifnet *ifp;
776*5d43fd68SRuslan Bukin 	struct mbuf *m0;
777*5d43fd68SRuslan Bukin 	struct mbuf *m;
778*5d43fd68SRuslan Bukin 	int error;
779*5d43fd68SRuslan Bukin 	int rdes0;
780*5d43fd68SRuslan Bukin 	int idx;
781*5d43fd68SRuslan Bukin 	int len;
782*5d43fd68SRuslan Bukin 
783*5d43fd68SRuslan Bukin 	ifp = sc->ifp;
784*5d43fd68SRuslan Bukin 
785*5d43fd68SRuslan Bukin 	for (;;) {
786*5d43fd68SRuslan Bukin 		idx = sc->rx_idx;
787*5d43fd68SRuslan Bukin 
788*5d43fd68SRuslan Bukin 		rdes0 = sc->rxdesc_ring[idx].tdes0;
789*5d43fd68SRuslan Bukin 		if ((rdes0 & DDESC_RDES0_OWN) != 0)
790*5d43fd68SRuslan Bukin 			break;
791*5d43fd68SRuslan Bukin 
792*5d43fd68SRuslan Bukin 		bus_dmamap_sync(sc->rxbuf_tag, sc->rxbuf_map[idx].map,
793*5d43fd68SRuslan Bukin 		    BUS_DMASYNC_POSTREAD);
794*5d43fd68SRuslan Bukin 		bus_dmamap_unload(sc->rxbuf_tag, sc->rxbuf_map[idx].map);
795*5d43fd68SRuslan Bukin 
796*5d43fd68SRuslan Bukin 		len = (rdes0 >> DDESC_RDES0_FL_SHIFT) & DDESC_RDES0_FL_MASK;
797*5d43fd68SRuslan Bukin 		if (len != 0) {
798*5d43fd68SRuslan Bukin 			m = sc->rxbuf_map[idx].mbuf;
799*5d43fd68SRuslan Bukin 			m->m_pkthdr.rcvif = ifp;
800*5d43fd68SRuslan Bukin 			m->m_pkthdr.len = len;
801*5d43fd68SRuslan Bukin 			m->m_len = len;
802*5d43fd68SRuslan Bukin 			ifp->if_ipackets++;
803*5d43fd68SRuslan Bukin 
804*5d43fd68SRuslan Bukin 			DWC_UNLOCK(sc);
805*5d43fd68SRuslan Bukin 			(*ifp->if_input)(ifp, m);
806*5d43fd68SRuslan Bukin 			DWC_LOCK(sc);
807*5d43fd68SRuslan Bukin 		} else {
808*5d43fd68SRuslan Bukin 			/* XXX Zero-length packet ? */
809*5d43fd68SRuslan Bukin 		}
810*5d43fd68SRuslan Bukin 
811*5d43fd68SRuslan Bukin 		if ((m0 = dwc_alloc_mbufcl(sc)) != NULL) {
812*5d43fd68SRuslan Bukin 			if ((error = dwc_setup_rxbuf(sc, idx, m0)) != 0) {
813*5d43fd68SRuslan Bukin 				/*
814*5d43fd68SRuslan Bukin 				 * XXX Now what?
815*5d43fd68SRuslan Bukin 				 * We've got a hole in the rx ring.
816*5d43fd68SRuslan Bukin 				 */
817*5d43fd68SRuslan Bukin 			}
818*5d43fd68SRuslan Bukin 		} else
819*5d43fd68SRuslan Bukin 			if_inc_counter(sc->ifp, IFCOUNTER_IQDROPS, 1);
820*5d43fd68SRuslan Bukin 
821*5d43fd68SRuslan Bukin 		sc->rx_idx = next_rxidx(sc, sc->rx_idx);
822*5d43fd68SRuslan Bukin 	}
823*5d43fd68SRuslan Bukin }
824*5d43fd68SRuslan Bukin 
825*5d43fd68SRuslan Bukin static void
826*5d43fd68SRuslan Bukin dwc_intr(void *arg)
827*5d43fd68SRuslan Bukin {
828*5d43fd68SRuslan Bukin 	struct dwc_softc *sc;
829*5d43fd68SRuslan Bukin 	uint32_t reg;
830*5d43fd68SRuslan Bukin 
831*5d43fd68SRuslan Bukin 	sc = arg;
832*5d43fd68SRuslan Bukin 
833*5d43fd68SRuslan Bukin 	DWC_LOCK(sc);
834*5d43fd68SRuslan Bukin 
835*5d43fd68SRuslan Bukin 	reg = READ4(sc, INTERRUPT_STATUS);
836*5d43fd68SRuslan Bukin 	if (reg) {
837*5d43fd68SRuslan Bukin 		mii_mediachg(sc->mii_softc);
838*5d43fd68SRuslan Bukin 		READ4(sc, SGMII_RGMII_SMII_CTRL_STATUS);
839*5d43fd68SRuslan Bukin 	}
840*5d43fd68SRuslan Bukin 
841*5d43fd68SRuslan Bukin 	reg = READ4(sc, DMA_STATUS);
842*5d43fd68SRuslan Bukin 	if (reg & DMA_STATUS_NIS) {
843*5d43fd68SRuslan Bukin 		if (reg & DMA_STATUS_RI)
844*5d43fd68SRuslan Bukin 			dwc_rxfinish_locked(sc);
845*5d43fd68SRuslan Bukin 
846*5d43fd68SRuslan Bukin 		if (reg & DMA_STATUS_TI)
847*5d43fd68SRuslan Bukin 			dwc_txfinish_locked(sc);
848*5d43fd68SRuslan Bukin 	}
849*5d43fd68SRuslan Bukin 
850*5d43fd68SRuslan Bukin 	if (reg & DMA_STATUS_AIS) {
851*5d43fd68SRuslan Bukin 		if (reg & DMA_STATUS_FBI) {
852*5d43fd68SRuslan Bukin 			/* Fatal bus error */
853*5d43fd68SRuslan Bukin 			device_printf(sc->dev,
854*5d43fd68SRuslan Bukin 			    "Ethernet DMA error, restarting controller.\n");
855*5d43fd68SRuslan Bukin 			dwc_stop_locked(sc);
856*5d43fd68SRuslan Bukin 			dwc_init_locked(sc);
857*5d43fd68SRuslan Bukin 		}
858*5d43fd68SRuslan Bukin 	}
859*5d43fd68SRuslan Bukin 
860*5d43fd68SRuslan Bukin 	WRITE4(sc, DMA_STATUS, reg & DMA_STATUS_INTR_MASK);
861*5d43fd68SRuslan Bukin 	DWC_UNLOCK(sc);
862*5d43fd68SRuslan Bukin }
863*5d43fd68SRuslan Bukin 
864*5d43fd68SRuslan Bukin static int
865*5d43fd68SRuslan Bukin setup_dma(struct dwc_softc *sc)
866*5d43fd68SRuslan Bukin {
867*5d43fd68SRuslan Bukin 	struct mbuf *m;
868*5d43fd68SRuslan Bukin 	int error;
869*5d43fd68SRuslan Bukin 	int nidx;
870*5d43fd68SRuslan Bukin 	int idx;
871*5d43fd68SRuslan Bukin 
872*5d43fd68SRuslan Bukin 	/*
873*5d43fd68SRuslan Bukin 	 * Set up TX descriptor ring, descriptors, and dma maps.
874*5d43fd68SRuslan Bukin 	 */
875*5d43fd68SRuslan Bukin 	error = bus_dma_tag_create(
876*5d43fd68SRuslan Bukin 	    bus_get_dma_tag(sc->dev),	/* Parent tag. */
877*5d43fd68SRuslan Bukin 	    DWC_DESC_RING_ALIGN, 0,	/* alignment, boundary */
878*5d43fd68SRuslan Bukin 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
879*5d43fd68SRuslan Bukin 	    BUS_SPACE_MAXADDR,		/* highaddr */
880*5d43fd68SRuslan Bukin 	    NULL, NULL,			/* filter, filterarg */
881*5d43fd68SRuslan Bukin 	    TX_DESC_SIZE, 1, 		/* maxsize, nsegments */
882*5d43fd68SRuslan Bukin 	    TX_DESC_SIZE,		/* maxsegsize */
883*5d43fd68SRuslan Bukin 	    0,				/* flags */
884*5d43fd68SRuslan Bukin 	    NULL, NULL,			/* lockfunc, lockarg */
885*5d43fd68SRuslan Bukin 	    &sc->txdesc_tag);
886*5d43fd68SRuslan Bukin 	if (error != 0) {
887*5d43fd68SRuslan Bukin 		device_printf(sc->dev,
888*5d43fd68SRuslan Bukin 		    "could not create TX ring DMA tag.\n");
889*5d43fd68SRuslan Bukin 		goto out;
890*5d43fd68SRuslan Bukin 	}
891*5d43fd68SRuslan Bukin 
892*5d43fd68SRuslan Bukin 	error = bus_dmamem_alloc(sc->txdesc_tag, (void**)&sc->txdesc_ring,
893*5d43fd68SRuslan Bukin 	    BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO,
894*5d43fd68SRuslan Bukin 	    &sc->txdesc_map);
895*5d43fd68SRuslan Bukin 	if (error != 0) {
896*5d43fd68SRuslan Bukin 		device_printf(sc->dev,
897*5d43fd68SRuslan Bukin 		    "could not allocate TX descriptor ring.\n");
898*5d43fd68SRuslan Bukin 		goto out;
899*5d43fd68SRuslan Bukin 	}
900*5d43fd68SRuslan Bukin 
901*5d43fd68SRuslan Bukin 	error = bus_dmamap_load(sc->txdesc_tag, sc->txdesc_map,
902*5d43fd68SRuslan Bukin 	    sc->txdesc_ring, TX_DESC_SIZE, dwc_get1paddr,
903*5d43fd68SRuslan Bukin 	    &sc->txdesc_ring_paddr, 0);
904*5d43fd68SRuslan Bukin 	if (error != 0) {
905*5d43fd68SRuslan Bukin 		device_printf(sc->dev,
906*5d43fd68SRuslan Bukin 		    "could not load TX descriptor ring map.\n");
907*5d43fd68SRuslan Bukin 		goto out;
908*5d43fd68SRuslan Bukin 	}
909*5d43fd68SRuslan Bukin 
910*5d43fd68SRuslan Bukin 	for (idx = 0; idx < TX_DESC_COUNT; idx++) {
911*5d43fd68SRuslan Bukin 		sc->txdesc_ring[idx].tdes0 = DDESC_TDES0_TXCHAIN;
912*5d43fd68SRuslan Bukin 		sc->txdesc_ring[idx].tdes1 = 0;
913*5d43fd68SRuslan Bukin 		nidx = next_txidx(sc, idx);
914*5d43fd68SRuslan Bukin 		sc->txdesc_ring[idx].addr_next = sc->txdesc_ring_paddr + \
915*5d43fd68SRuslan Bukin 		    (nidx * sizeof(struct dwc_hwdesc));
916*5d43fd68SRuslan Bukin 	}
917*5d43fd68SRuslan Bukin 
918*5d43fd68SRuslan Bukin 	error = bus_dma_tag_create(
919*5d43fd68SRuslan Bukin 	    bus_get_dma_tag(sc->dev),	/* Parent tag. */
920*5d43fd68SRuslan Bukin 	    1, 0,			/* alignment, boundary */
921*5d43fd68SRuslan Bukin 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
922*5d43fd68SRuslan Bukin 	    BUS_SPACE_MAXADDR,		/* highaddr */
923*5d43fd68SRuslan Bukin 	    NULL, NULL,			/* filter, filterarg */
924*5d43fd68SRuslan Bukin 	    MCLBYTES, 1, 		/* maxsize, nsegments */
925*5d43fd68SRuslan Bukin 	    MCLBYTES,			/* maxsegsize */
926*5d43fd68SRuslan Bukin 	    0,				/* flags */
927*5d43fd68SRuslan Bukin 	    NULL, NULL,			/* lockfunc, lockarg */
928*5d43fd68SRuslan Bukin 	    &sc->txbuf_tag);
929*5d43fd68SRuslan Bukin 	if (error != 0) {
930*5d43fd68SRuslan Bukin 		device_printf(sc->dev,
931*5d43fd68SRuslan Bukin 		    "could not create TX ring DMA tag.\n");
932*5d43fd68SRuslan Bukin 		goto out;
933*5d43fd68SRuslan Bukin 	}
934*5d43fd68SRuslan Bukin 
935*5d43fd68SRuslan Bukin 	for (idx = 0; idx < TX_DESC_COUNT; idx++) {
936*5d43fd68SRuslan Bukin 		error = bus_dmamap_create(sc->txbuf_tag, BUS_DMA_COHERENT,
937*5d43fd68SRuslan Bukin 		    &sc->txbuf_map[idx].map);
938*5d43fd68SRuslan Bukin 		if (error != 0) {
939*5d43fd68SRuslan Bukin 			device_printf(sc->dev,
940*5d43fd68SRuslan Bukin 			    "could not create TX buffer DMA map.\n");
941*5d43fd68SRuslan Bukin 			goto out;
942*5d43fd68SRuslan Bukin 		}
943*5d43fd68SRuslan Bukin 		dwc_setup_txdesc(sc, idx, 0, 0);
944*5d43fd68SRuslan Bukin 	}
945*5d43fd68SRuslan Bukin 
946*5d43fd68SRuslan Bukin 	/*
947*5d43fd68SRuslan Bukin 	 * Set up RX descriptor ring, descriptors, dma maps, and mbufs.
948*5d43fd68SRuslan Bukin 	 */
949*5d43fd68SRuslan Bukin 	error = bus_dma_tag_create(
950*5d43fd68SRuslan Bukin 	    bus_get_dma_tag(sc->dev),	/* Parent tag. */
951*5d43fd68SRuslan Bukin 	    DWC_DESC_RING_ALIGN, 0,	/* alignment, boundary */
952*5d43fd68SRuslan Bukin 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
953*5d43fd68SRuslan Bukin 	    BUS_SPACE_MAXADDR,		/* highaddr */
954*5d43fd68SRuslan Bukin 	    NULL, NULL,			/* filter, filterarg */
955*5d43fd68SRuslan Bukin 	    RX_DESC_SIZE, 1, 		/* maxsize, nsegments */
956*5d43fd68SRuslan Bukin 	    RX_DESC_SIZE,		/* maxsegsize */
957*5d43fd68SRuslan Bukin 	    0,				/* flags */
958*5d43fd68SRuslan Bukin 	    NULL, NULL,			/* lockfunc, lockarg */
959*5d43fd68SRuslan Bukin 	    &sc->rxdesc_tag);
960*5d43fd68SRuslan Bukin 	if (error != 0) {
961*5d43fd68SRuslan Bukin 		device_printf(sc->dev,
962*5d43fd68SRuslan Bukin 		    "could not create RX ring DMA tag.\n");
963*5d43fd68SRuslan Bukin 		goto out;
964*5d43fd68SRuslan Bukin 	}
965*5d43fd68SRuslan Bukin 
966*5d43fd68SRuslan Bukin 	error = bus_dmamem_alloc(sc->rxdesc_tag, (void **)&sc->rxdesc_ring,
967*5d43fd68SRuslan Bukin 	    BUS_DMA_COHERENT | BUS_DMA_WAITOK | BUS_DMA_ZERO,
968*5d43fd68SRuslan Bukin 	    &sc->rxdesc_map);
969*5d43fd68SRuslan Bukin 	if (error != 0) {
970*5d43fd68SRuslan Bukin 		device_printf(sc->dev,
971*5d43fd68SRuslan Bukin 		    "could not allocate RX descriptor ring.\n");
972*5d43fd68SRuslan Bukin 		goto out;
973*5d43fd68SRuslan Bukin 	}
974*5d43fd68SRuslan Bukin 
975*5d43fd68SRuslan Bukin 	error = bus_dmamap_load(sc->rxdesc_tag, sc->rxdesc_map,
976*5d43fd68SRuslan Bukin 	    sc->rxdesc_ring, RX_DESC_SIZE, dwc_get1paddr,
977*5d43fd68SRuslan Bukin 	    &sc->rxdesc_ring_paddr, 0);
978*5d43fd68SRuslan Bukin 	if (error != 0) {
979*5d43fd68SRuslan Bukin 		device_printf(sc->dev,
980*5d43fd68SRuslan Bukin 		    "could not load RX descriptor ring map.\n");
981*5d43fd68SRuslan Bukin 		goto out;
982*5d43fd68SRuslan Bukin 	}
983*5d43fd68SRuslan Bukin 
984*5d43fd68SRuslan Bukin 	error = bus_dma_tag_create(
985*5d43fd68SRuslan Bukin 	    bus_get_dma_tag(sc->dev),	/* Parent tag. */
986*5d43fd68SRuslan Bukin 	    1, 0,			/* alignment, boundary */
987*5d43fd68SRuslan Bukin 	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
988*5d43fd68SRuslan Bukin 	    BUS_SPACE_MAXADDR,		/* highaddr */
989*5d43fd68SRuslan Bukin 	    NULL, NULL,			/* filter, filterarg */
990*5d43fd68SRuslan Bukin 	    MCLBYTES, 1, 		/* maxsize, nsegments */
991*5d43fd68SRuslan Bukin 	    MCLBYTES,			/* maxsegsize */
992*5d43fd68SRuslan Bukin 	    0,				/* flags */
993*5d43fd68SRuslan Bukin 	    NULL, NULL,			/* lockfunc, lockarg */
994*5d43fd68SRuslan Bukin 	    &sc->rxbuf_tag);
995*5d43fd68SRuslan Bukin 	if (error != 0) {
996*5d43fd68SRuslan Bukin 		device_printf(sc->dev,
997*5d43fd68SRuslan Bukin 		    "could not create RX buf DMA tag.\n");
998*5d43fd68SRuslan Bukin 		goto out;
999*5d43fd68SRuslan Bukin 	}
1000*5d43fd68SRuslan Bukin 
1001*5d43fd68SRuslan Bukin 	for (idx = 0; idx < RX_DESC_COUNT; idx++) {
1002*5d43fd68SRuslan Bukin 		error = bus_dmamap_create(sc->rxbuf_tag, BUS_DMA_COHERENT,
1003*5d43fd68SRuslan Bukin 		    &sc->rxbuf_map[idx].map);
1004*5d43fd68SRuslan Bukin 		if (error != 0) {
1005*5d43fd68SRuslan Bukin 			device_printf(sc->dev,
1006*5d43fd68SRuslan Bukin 			    "could not create RX buffer DMA map.\n");
1007*5d43fd68SRuslan Bukin 			goto out;
1008*5d43fd68SRuslan Bukin 		}
1009*5d43fd68SRuslan Bukin 		if ((m = dwc_alloc_mbufcl(sc)) == NULL) {
1010*5d43fd68SRuslan Bukin 			device_printf(sc->dev, "Could not alloc mbuf\n");
1011*5d43fd68SRuslan Bukin 			error = ENOMEM;
1012*5d43fd68SRuslan Bukin 			goto out;
1013*5d43fd68SRuslan Bukin 		}
1014*5d43fd68SRuslan Bukin 		if ((error = dwc_setup_rxbuf(sc, idx, m)) != 0) {
1015*5d43fd68SRuslan Bukin 			device_printf(sc->dev,
1016*5d43fd68SRuslan Bukin 			    "could not create new RX buffer.\n");
1017*5d43fd68SRuslan Bukin 			goto out;
1018*5d43fd68SRuslan Bukin 		}
1019*5d43fd68SRuslan Bukin 	}
1020*5d43fd68SRuslan Bukin 
1021*5d43fd68SRuslan Bukin out:
1022*5d43fd68SRuslan Bukin 	if (error != 0)
1023*5d43fd68SRuslan Bukin 		return (ENXIO);
1024*5d43fd68SRuslan Bukin 
1025*5d43fd68SRuslan Bukin 	return (0);
1026*5d43fd68SRuslan Bukin }
1027*5d43fd68SRuslan Bukin 
1028*5d43fd68SRuslan Bukin static int
1029*5d43fd68SRuslan Bukin dwc_get_hwaddr(struct dwc_softc *sc, uint8_t *hwaddr)
1030*5d43fd68SRuslan Bukin {
1031*5d43fd68SRuslan Bukin 	int rnd;
1032*5d43fd68SRuslan Bukin 	int lo;
1033*5d43fd68SRuslan Bukin 	int hi;
1034*5d43fd68SRuslan Bukin 
1035*5d43fd68SRuslan Bukin 	/*
1036*5d43fd68SRuslan Bukin 	 * Try to recover a MAC address from the running hardware. If there's
1037*5d43fd68SRuslan Bukin 	 * something non-zero there, assume the bootloader did the right thing
1038*5d43fd68SRuslan Bukin 	 * and just use it.
1039*5d43fd68SRuslan Bukin 	 *
1040*5d43fd68SRuslan Bukin 	 * Otherwise, set the address to a convenient locally assigned address,
1041*5d43fd68SRuslan Bukin 	 * 'bsd' + random 24 low-order bits.  'b' is 0x62, which has the locally
1042*5d43fd68SRuslan Bukin 	 * assigned bit set, and the broadcast/multicast bit clear.
1043*5d43fd68SRuslan Bukin 	 */
1044*5d43fd68SRuslan Bukin 	lo = READ4(sc, MAC_ADDRESS_LOW(0));
1045*5d43fd68SRuslan Bukin 	hi = READ4(sc, MAC_ADDRESS_HIGH(0)) & 0xffff;
1046*5d43fd68SRuslan Bukin 	if ((lo != 0xffffffff) || (hi != 0xffff)) {
1047*5d43fd68SRuslan Bukin 		hwaddr[0] = (lo >>  0) & 0xff;
1048*5d43fd68SRuslan Bukin 		hwaddr[1] = (lo >>  8) & 0xff;
1049*5d43fd68SRuslan Bukin 		hwaddr[2] = (lo >> 16) & 0xff;
1050*5d43fd68SRuslan Bukin 		hwaddr[3] = (lo >> 24) & 0xff;
1051*5d43fd68SRuslan Bukin 		hwaddr[4] = (hi >>  0) & 0xff;
1052*5d43fd68SRuslan Bukin 		hwaddr[5] = (hi >>  8) & 0xff;
1053*5d43fd68SRuslan Bukin 	} else {
1054*5d43fd68SRuslan Bukin 		rnd = arc4random() & 0x00ffffff;
1055*5d43fd68SRuslan Bukin 		hwaddr[0] = 'b';
1056*5d43fd68SRuslan Bukin 		hwaddr[1] = 's';
1057*5d43fd68SRuslan Bukin 		hwaddr[2] = 'd';
1058*5d43fd68SRuslan Bukin 		hwaddr[3] = rnd >> 16;
1059*5d43fd68SRuslan Bukin 		hwaddr[4] = rnd >>  8;
1060*5d43fd68SRuslan Bukin 		hwaddr[5] = rnd >>  0;
1061*5d43fd68SRuslan Bukin 	}
1062*5d43fd68SRuslan Bukin 
1063*5d43fd68SRuslan Bukin 	return (0);
1064*5d43fd68SRuslan Bukin }
1065*5d43fd68SRuslan Bukin 
1066*5d43fd68SRuslan Bukin static int
1067*5d43fd68SRuslan Bukin dwc_probe(device_t dev)
1068*5d43fd68SRuslan Bukin {
1069*5d43fd68SRuslan Bukin 
1070*5d43fd68SRuslan Bukin 	if (!ofw_bus_status_okay(dev))
1071*5d43fd68SRuslan Bukin 		return (ENXIO);
1072*5d43fd68SRuslan Bukin 
1073*5d43fd68SRuslan Bukin 	if (!ofw_bus_is_compatible(dev, "snps,dwmac"))
1074*5d43fd68SRuslan Bukin 		return (ENXIO);
1075*5d43fd68SRuslan Bukin 
1076*5d43fd68SRuslan Bukin 	device_set_desc(dev, "Gigabit Ethernet Controller");
1077*5d43fd68SRuslan Bukin 	return (BUS_PROBE_DEFAULT);
1078*5d43fd68SRuslan Bukin }
1079*5d43fd68SRuslan Bukin 
1080*5d43fd68SRuslan Bukin static int
1081*5d43fd68SRuslan Bukin dwc_attach(device_t dev)
1082*5d43fd68SRuslan Bukin {
1083*5d43fd68SRuslan Bukin 	uint8_t macaddr[ETHER_ADDR_LEN];
1084*5d43fd68SRuslan Bukin 	struct dwc_softc *sc;
1085*5d43fd68SRuslan Bukin 	struct ifnet *ifp;
1086*5d43fd68SRuslan Bukin 	int error;
1087*5d43fd68SRuslan Bukin 	int reg;
1088*5d43fd68SRuslan Bukin 	int i;
1089*5d43fd68SRuslan Bukin 
1090*5d43fd68SRuslan Bukin 	sc = device_get_softc(dev);
1091*5d43fd68SRuslan Bukin 	sc->dev = dev;
1092*5d43fd68SRuslan Bukin 	sc->mii_clk = MII_CLK_VAL;
1093*5d43fd68SRuslan Bukin 	sc->rx_idx = 0;
1094*5d43fd68SRuslan Bukin 
1095*5d43fd68SRuslan Bukin 	sc->txcount = TX_DESC_COUNT;
1096*5d43fd68SRuslan Bukin 
1097*5d43fd68SRuslan Bukin 	if (bus_alloc_resources(dev, dwc_spec, sc->res)) {
1098*5d43fd68SRuslan Bukin 		device_printf(dev, "could not allocate resources\n");
1099*5d43fd68SRuslan Bukin 		return (ENXIO);
1100*5d43fd68SRuslan Bukin 	}
1101*5d43fd68SRuslan Bukin 
1102*5d43fd68SRuslan Bukin 	/* Memory interface */
1103*5d43fd68SRuslan Bukin 	sc->bst = rman_get_bustag(sc->res[0]);
1104*5d43fd68SRuslan Bukin 	sc->bsh = rman_get_bushandle(sc->res[0]);
1105*5d43fd68SRuslan Bukin 
1106*5d43fd68SRuslan Bukin 	mtx_init(&sc->mtx, device_get_nameunit(sc->dev),
1107*5d43fd68SRuslan Bukin 	    MTX_NETWORK_LOCK, MTX_DEF);
1108*5d43fd68SRuslan Bukin 
1109*5d43fd68SRuslan Bukin 	callout_init_mtx(&sc->dwc_callout, &sc->mtx, 0);
1110*5d43fd68SRuslan Bukin 
1111*5d43fd68SRuslan Bukin 	/* Setup interrupt handler. */
1112*5d43fd68SRuslan Bukin 	error = bus_setup_intr(dev, sc->res[1], INTR_TYPE_NET | INTR_MPSAFE,
1113*5d43fd68SRuslan Bukin 	    NULL, dwc_intr, sc, &sc->intr_cookie);
1114*5d43fd68SRuslan Bukin 	if (error != 0) {
1115*5d43fd68SRuslan Bukin 		device_printf(dev, "could not setup interrupt handler.\n");
1116*5d43fd68SRuslan Bukin 		return (ENXIO);
1117*5d43fd68SRuslan Bukin 	}
1118*5d43fd68SRuslan Bukin 
1119*5d43fd68SRuslan Bukin 	/* Read MAC before reset */
1120*5d43fd68SRuslan Bukin 	if (dwc_get_hwaddr(sc, macaddr)) {
1121*5d43fd68SRuslan Bukin 		device_printf(sc->dev, "can't get mac\n");
1122*5d43fd68SRuslan Bukin 		return (ENXIO);
1123*5d43fd68SRuslan Bukin 	}
1124*5d43fd68SRuslan Bukin 
1125*5d43fd68SRuslan Bukin 	/* Reset */
1126*5d43fd68SRuslan Bukin 	reg = READ4(sc, BUS_MODE);
1127*5d43fd68SRuslan Bukin 	reg |= (BUS_MODE_SWR);
1128*5d43fd68SRuslan Bukin 	WRITE4(sc, BUS_MODE, reg);
1129*5d43fd68SRuslan Bukin 
1130*5d43fd68SRuslan Bukin 	for (i = 0; i < 100; i++) {
1131*5d43fd68SRuslan Bukin 		if ((READ4(sc, BUS_MODE) & BUS_MODE_SWR) == 0)
1132*5d43fd68SRuslan Bukin 			break;
1133*5d43fd68SRuslan Bukin 		DELAY(10);
1134*5d43fd68SRuslan Bukin 	}
1135*5d43fd68SRuslan Bukin 	if (i == 0) {
1136*5d43fd68SRuslan Bukin 		device_printf(sc->dev, "Can't reset DWC.\n");
1137*5d43fd68SRuslan Bukin 		return (ENXIO);
1138*5d43fd68SRuslan Bukin 	}
1139*5d43fd68SRuslan Bukin 
1140*5d43fd68SRuslan Bukin 	reg = READ4(sc, BUS_MODE);
1141*5d43fd68SRuslan Bukin 	reg |= (BUS_MODE_EIGHTXPBL);
1142*5d43fd68SRuslan Bukin 	reg |= (BUS_MODE_PBL_BEATS_8 << BUS_MODE_PBL_SHIFT);
1143*5d43fd68SRuslan Bukin 	WRITE4(sc, BUS_MODE, reg);
1144*5d43fd68SRuslan Bukin 
1145*5d43fd68SRuslan Bukin 	/*
1146*5d43fd68SRuslan Bukin 	 * DMA must be stop while changing descriptor list addresses.
1147*5d43fd68SRuslan Bukin 	 */
1148*5d43fd68SRuslan Bukin 	reg = READ4(sc, OPERATION_MODE);
1149*5d43fd68SRuslan Bukin 	reg &= ~(MODE_ST | MODE_SR);
1150*5d43fd68SRuslan Bukin 	WRITE4(sc, OPERATION_MODE, reg);
1151*5d43fd68SRuslan Bukin 
1152*5d43fd68SRuslan Bukin 	if (setup_dma(sc))
1153*5d43fd68SRuslan Bukin 	        return (ENXIO);
1154*5d43fd68SRuslan Bukin 
1155*5d43fd68SRuslan Bukin 	/* Setup addresses */
1156*5d43fd68SRuslan Bukin 	WRITE4(sc, RX_DESCR_LIST_ADDR, sc->rxdesc_ring_paddr);
1157*5d43fd68SRuslan Bukin 	WRITE4(sc, TX_DESCR_LIST_ADDR, sc->txdesc_ring_paddr);
1158*5d43fd68SRuslan Bukin 
1159*5d43fd68SRuslan Bukin 	/* Set up the ethernet interface. */
1160*5d43fd68SRuslan Bukin 	sc->ifp = ifp = if_alloc(IFT_ETHER);
1161*5d43fd68SRuslan Bukin 
1162*5d43fd68SRuslan Bukin 	ifp->if_softc = sc;
1163*5d43fd68SRuslan Bukin 	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1164*5d43fd68SRuslan Bukin 	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1165*5d43fd68SRuslan Bukin 	ifp->if_capabilities = IFCAP_VLAN_MTU;
1166*5d43fd68SRuslan Bukin 	ifp->if_capenable = ifp->if_capabilities;
1167*5d43fd68SRuslan Bukin 	ifp->if_start = dwc_txstart;
1168*5d43fd68SRuslan Bukin 	ifp->if_ioctl = dwc_ioctl;
1169*5d43fd68SRuslan Bukin 	ifp->if_init = dwc_init;
1170*5d43fd68SRuslan Bukin 	IFQ_SET_MAXLEN(&ifp->if_snd, TX_DESC_COUNT - 1);
1171*5d43fd68SRuslan Bukin 	ifp->if_snd.ifq_drv_maxlen = TX_DESC_COUNT - 1;
1172*5d43fd68SRuslan Bukin 	IFQ_SET_READY(&ifp->if_snd);
1173*5d43fd68SRuslan Bukin 	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
1174*5d43fd68SRuslan Bukin 
1175*5d43fd68SRuslan Bukin 	/* Attach the mii driver. */
1176*5d43fd68SRuslan Bukin 	error = mii_attach(dev, &sc->miibus, ifp, dwc_media_change,
1177*5d43fd68SRuslan Bukin 	    dwc_media_status, BMSR_DEFCAPMASK, MII_PHY_ANY,
1178*5d43fd68SRuslan Bukin 	    MII_OFFSET_ANY, 0);
1179*5d43fd68SRuslan Bukin 
1180*5d43fd68SRuslan Bukin 	if (error != 0) {
1181*5d43fd68SRuslan Bukin 		device_printf(dev, "PHY attach failed\n");
1182*5d43fd68SRuslan Bukin 		return (ENXIO);
1183*5d43fd68SRuslan Bukin 	}
1184*5d43fd68SRuslan Bukin 	sc->mii_softc = device_get_softc(sc->miibus);
1185*5d43fd68SRuslan Bukin 
1186*5d43fd68SRuslan Bukin 	/* All ready to run, attach the ethernet interface. */
1187*5d43fd68SRuslan Bukin 	ether_ifattach(ifp, macaddr);
1188*5d43fd68SRuslan Bukin 	sc->is_attached = true;
1189*5d43fd68SRuslan Bukin 
1190*5d43fd68SRuslan Bukin 	return (0);
1191*5d43fd68SRuslan Bukin }
1192*5d43fd68SRuslan Bukin 
1193*5d43fd68SRuslan Bukin static int
1194*5d43fd68SRuslan Bukin dwc_miibus_read_reg(device_t dev, int phy, int reg)
1195*5d43fd68SRuslan Bukin {
1196*5d43fd68SRuslan Bukin 	struct dwc_softc *sc;
1197*5d43fd68SRuslan Bukin 	uint16_t mii;
1198*5d43fd68SRuslan Bukin 	size_t cnt;
1199*5d43fd68SRuslan Bukin 	int rv = 0;
1200*5d43fd68SRuslan Bukin 
1201*5d43fd68SRuslan Bukin 	sc = device_get_softc(dev);
1202*5d43fd68SRuslan Bukin 
1203*5d43fd68SRuslan Bukin 	mii = ((phy & GMII_ADDRESS_PA_MASK) << GMII_ADDRESS_PA_SHIFT)
1204*5d43fd68SRuslan Bukin 	    | ((reg & GMII_ADDRESS_GR_MASK) << GMII_ADDRESS_GR_SHIFT)
1205*5d43fd68SRuslan Bukin 	    | (sc->mii_clk << GMII_ADDRESS_CR_SHIFT)
1206*5d43fd68SRuslan Bukin 	    | GMII_ADDRESS_GB; /* Busy flag */
1207*5d43fd68SRuslan Bukin 
1208*5d43fd68SRuslan Bukin 	WRITE4(sc, GMII_ADDRESS, mii);
1209*5d43fd68SRuslan Bukin 
1210*5d43fd68SRuslan Bukin 	for (cnt = 0; cnt < 1000; cnt++) {
1211*5d43fd68SRuslan Bukin 		if (!(READ4(sc, GMII_ADDRESS) & GMII_ADDRESS_GB)) {
1212*5d43fd68SRuslan Bukin 			rv = READ4(sc, GMII_DATA);
1213*5d43fd68SRuslan Bukin 			break;
1214*5d43fd68SRuslan Bukin 		}
1215*5d43fd68SRuslan Bukin 		DELAY(10);
1216*5d43fd68SRuslan Bukin 	}
1217*5d43fd68SRuslan Bukin 
1218*5d43fd68SRuslan Bukin 	return rv;
1219*5d43fd68SRuslan Bukin }
1220*5d43fd68SRuslan Bukin 
1221*5d43fd68SRuslan Bukin static int
1222*5d43fd68SRuslan Bukin dwc_miibus_write_reg(device_t dev, int phy, int reg, int val)
1223*5d43fd68SRuslan Bukin {
1224*5d43fd68SRuslan Bukin 	struct dwc_softc *sc;
1225*5d43fd68SRuslan Bukin 	uint16_t mii;
1226*5d43fd68SRuslan Bukin 	size_t cnt;
1227*5d43fd68SRuslan Bukin 
1228*5d43fd68SRuslan Bukin 	sc = device_get_softc(dev);
1229*5d43fd68SRuslan Bukin 
1230*5d43fd68SRuslan Bukin 	mii = ((phy & GMII_ADDRESS_PA_MASK) << GMII_ADDRESS_PA_SHIFT)
1231*5d43fd68SRuslan Bukin 	    | ((reg & GMII_ADDRESS_GR_MASK) << GMII_ADDRESS_GR_SHIFT)
1232*5d43fd68SRuslan Bukin 	    | (sc->mii_clk << GMII_ADDRESS_CR_SHIFT)
1233*5d43fd68SRuslan Bukin 	    | GMII_ADDRESS_GB | GMII_ADDRESS_GW;
1234*5d43fd68SRuslan Bukin 
1235*5d43fd68SRuslan Bukin 	WRITE4(sc, GMII_DATA, val);
1236*5d43fd68SRuslan Bukin 	WRITE4(sc, GMII_ADDRESS, mii);
1237*5d43fd68SRuslan Bukin 
1238*5d43fd68SRuslan Bukin 	for (cnt = 0; cnt < 1000; cnt++) {
1239*5d43fd68SRuslan Bukin 		if (!(READ4(sc, GMII_ADDRESS) & GMII_ADDRESS_GB)) {
1240*5d43fd68SRuslan Bukin 			break;
1241*5d43fd68SRuslan Bukin                 }
1242*5d43fd68SRuslan Bukin 		DELAY(10);
1243*5d43fd68SRuslan Bukin 	}
1244*5d43fd68SRuslan Bukin 
1245*5d43fd68SRuslan Bukin 	return (0);
1246*5d43fd68SRuslan Bukin }
1247*5d43fd68SRuslan Bukin 
1248*5d43fd68SRuslan Bukin static void
1249*5d43fd68SRuslan Bukin dwc_miibus_statchg(device_t dev)
1250*5d43fd68SRuslan Bukin {
1251*5d43fd68SRuslan Bukin 	struct dwc_softc *sc;
1252*5d43fd68SRuslan Bukin 	struct mii_data *mii;
1253*5d43fd68SRuslan Bukin 	int reg;
1254*5d43fd68SRuslan Bukin 
1255*5d43fd68SRuslan Bukin 	/*
1256*5d43fd68SRuslan Bukin 	 * Called by the MII bus driver when the PHY establishes
1257*5d43fd68SRuslan Bukin 	 * link to set the MAC interface registers.
1258*5d43fd68SRuslan Bukin 	 */
1259*5d43fd68SRuslan Bukin 
1260*5d43fd68SRuslan Bukin 	sc = device_get_softc(dev);
1261*5d43fd68SRuslan Bukin 
1262*5d43fd68SRuslan Bukin 	DWC_ASSERT_LOCKED(sc);
1263*5d43fd68SRuslan Bukin 
1264*5d43fd68SRuslan Bukin 	mii = sc->mii_softc;
1265*5d43fd68SRuslan Bukin 
1266*5d43fd68SRuslan Bukin 	if (mii->mii_media_status & IFM_ACTIVE)
1267*5d43fd68SRuslan Bukin 		sc->link_is_up = true;
1268*5d43fd68SRuslan Bukin 	else
1269*5d43fd68SRuslan Bukin 		sc->link_is_up = false;
1270*5d43fd68SRuslan Bukin 
1271*5d43fd68SRuslan Bukin 	reg = READ4(sc, MAC_CONFIGURATION);
1272*5d43fd68SRuslan Bukin 	switch (IFM_SUBTYPE(mii->mii_media_active)) {
1273*5d43fd68SRuslan Bukin 	case IFM_1000_T:
1274*5d43fd68SRuslan Bukin 	case IFM_1000_SX:
1275*5d43fd68SRuslan Bukin 		reg &= ~(CONF_FES | CONF_PS);
1276*5d43fd68SRuslan Bukin 		break;
1277*5d43fd68SRuslan Bukin 	case IFM_100_TX:
1278*5d43fd68SRuslan Bukin 		reg |= (CONF_FES | CONF_PS);
1279*5d43fd68SRuslan Bukin 		break;
1280*5d43fd68SRuslan Bukin 	case IFM_10_T:
1281*5d43fd68SRuslan Bukin 		reg &= ~(CONF_FES);
1282*5d43fd68SRuslan Bukin 		reg |= (CONF_PS);
1283*5d43fd68SRuslan Bukin 		break;
1284*5d43fd68SRuslan Bukin 	case IFM_NONE:
1285*5d43fd68SRuslan Bukin 		sc->link_is_up = false;
1286*5d43fd68SRuslan Bukin 		return;
1287*5d43fd68SRuslan Bukin 	default:
1288*5d43fd68SRuslan Bukin 		sc->link_is_up = false;
1289*5d43fd68SRuslan Bukin 		device_printf(dev, "Unsupported media %u\n",
1290*5d43fd68SRuslan Bukin 		    IFM_SUBTYPE(mii->mii_media_active));
1291*5d43fd68SRuslan Bukin 		return;
1292*5d43fd68SRuslan Bukin 	}
1293*5d43fd68SRuslan Bukin 	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0)
1294*5d43fd68SRuslan Bukin 		reg |= (CONF_DM);
1295*5d43fd68SRuslan Bukin 	else
1296*5d43fd68SRuslan Bukin 		reg &= ~(CONF_DM);
1297*5d43fd68SRuslan Bukin 	WRITE4(sc, MAC_CONFIGURATION, reg);
1298*5d43fd68SRuslan Bukin }
1299*5d43fd68SRuslan Bukin 
1300*5d43fd68SRuslan Bukin static device_method_t dwc_methods[] = {
1301*5d43fd68SRuslan Bukin 	DEVMETHOD(device_probe,		dwc_probe),
1302*5d43fd68SRuslan Bukin 	DEVMETHOD(device_attach,	dwc_attach),
1303*5d43fd68SRuslan Bukin 
1304*5d43fd68SRuslan Bukin 	/* MII Interface */
1305*5d43fd68SRuslan Bukin 	DEVMETHOD(miibus_readreg,	dwc_miibus_read_reg),
1306*5d43fd68SRuslan Bukin 	DEVMETHOD(miibus_writereg,	dwc_miibus_write_reg),
1307*5d43fd68SRuslan Bukin 	DEVMETHOD(miibus_statchg,	dwc_miibus_statchg),
1308*5d43fd68SRuslan Bukin 
1309*5d43fd68SRuslan Bukin 	{ 0, 0 }
1310*5d43fd68SRuslan Bukin };
1311*5d43fd68SRuslan Bukin 
1312*5d43fd68SRuslan Bukin static driver_t dwc_driver = {
1313*5d43fd68SRuslan Bukin 	"dwc",
1314*5d43fd68SRuslan Bukin 	dwc_methods,
1315*5d43fd68SRuslan Bukin 	sizeof(struct dwc_softc),
1316*5d43fd68SRuslan Bukin };
1317*5d43fd68SRuslan Bukin 
1318*5d43fd68SRuslan Bukin static devclass_t dwc_devclass;
1319*5d43fd68SRuslan Bukin 
1320*5d43fd68SRuslan Bukin DRIVER_MODULE(dwc, simplebus, dwc_driver, dwc_devclass, 0, 0);
1321*5d43fd68SRuslan Bukin DRIVER_MODULE(miibus, dwc, miibus_driver, miibus_devclass, 0, 0);
1322*5d43fd68SRuslan Bukin 
1323*5d43fd68SRuslan Bukin MODULE_DEPEND(dwc, ether, 1, 1, 1);
1324*5d43fd68SRuslan Bukin MODULE_DEPEND(dwc, miibus, 1, 1, 1);
1325