1256752Sbrooks/*-
2256752Sbrooks * Copyright (c) 2012,2013 Bjoern A. Zeeb
3271969Sbz * Copyright (c) 2014 Robert N. M. Watson
4256752Sbrooks * All rights reserved.
5256752Sbrooks *
6256752Sbrooks * This software was developed by SRI International and the University of
7256752Sbrooks * Cambridge Computer Laboratory under DARPA/AFRL contract (FA8750-11-C-0249)
8256752Sbrooks * ("MRC2"), as part of the DARPA MRC research programme.
9256752Sbrooks *
10256752Sbrooks * Redistribution and use in source and binary forms, with or without
11256752Sbrooks * modification, are permitted provided that the following conditions
12256752Sbrooks * are met:
13256752Sbrooks * 1. Redistributions of source code must retain the above copyright
14256752Sbrooks *    notice, this list of conditions and the following disclaimer.
15256752Sbrooks * 2. Redistributions in binary form must reproduce the above copyright
16256752Sbrooks *    notice, this list of conditions and the following disclaimer in the
17256752Sbrooks *    documentation and/or other materials provided with the distribution.
18256752Sbrooks *
19256752Sbrooks * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
20256752Sbrooks * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21256752Sbrooks * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22256752Sbrooks * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
23256752Sbrooks * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24256752Sbrooks * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25256752Sbrooks * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26256752Sbrooks * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27256752Sbrooks * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28256752Sbrooks * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29256752Sbrooks * SUCH DAMAGE.
30256752Sbrooks */
31256752Sbrooks/*
32256752Sbrooks * Altera Triple-Speed Ethernet MegaCore, Function User Guide
33256752Sbrooks * UG-01008-3.0, Software Version: 12.0, June 2012.
34256752Sbrooks * Available at the time of writing at:
35256752Sbrooks * http://www.altera.com/literature/ug/ug_ethernet.pdf
36256752Sbrooks *
37256752Sbrooks * We are using an Marvell E1111 (Alaska) PHY on the DE4.  See mii/e1000phy.c.
38256752Sbrooks */
39256752Sbrooks/*
40256752Sbrooks * XXX-BZ NOTES:
41256752Sbrooks * - ifOutBroadcastPkts are only counted if both ether dst and src are all-1s;
42256752Sbrooks *   seems an IP core bug, they count ether broadcasts as multicast.  Is this
43256752Sbrooks *   still the case?
44256752Sbrooks * - figure out why the TX FIFO fill status and intr did not work as expected.
45256752Sbrooks * - test 100Mbit/s and 10Mbit/s
46256752Sbrooks * - blacklist the one special factory programmed ethernet address (for now
47256752Sbrooks *   hardcoded, later from loader?)
48256752Sbrooks * - resolve all XXX, left as reminders to shake out details later
49256752Sbrooks * - Jumbo frame support
50256752Sbrooks */
51256752Sbrooks
52256752Sbrooks#include <sys/cdefs.h>
53256752Sbrooks__FBSDID("$FreeBSD$");
54256752Sbrooks
55256752Sbrooks#include "opt_device_polling.h"
56256752Sbrooks
57256752Sbrooks#include <sys/param.h>
58256752Sbrooks#include <sys/systm.h>
59256752Sbrooks#include <sys/kernel.h>
60256752Sbrooks#include <sys/bus.h>
61256752Sbrooks#include <sys/endian.h>
62256752Sbrooks#include <sys/jail.h>
63256752Sbrooks#include <sys/lock.h>
64256752Sbrooks#include <sys/module.h>
65256752Sbrooks#include <sys/mutex.h>
66256752Sbrooks#include <sys/proc.h>
67256752Sbrooks#include <sys/socket.h>
68256752Sbrooks#include <sys/sockio.h>
69256752Sbrooks#include <sys/types.h>
70256752Sbrooks
71256752Sbrooks#include <net/ethernet.h>
72256752Sbrooks#include <net/if.h>
73256752Sbrooks#include <net/if_var.h>
74256752Sbrooks#include <net/if_dl.h>
75256752Sbrooks#include <net/if_media.h>
76256752Sbrooks#include <net/if_types.h>
77256752Sbrooks#include <net/if_vlan_var.h>
78256752Sbrooks
79256752Sbrooks#include <net/bpf.h>
80256752Sbrooks
81256752Sbrooks#include <machine/bus.h>
82256752Sbrooks#include <machine/resource.h>
83256752Sbrooks#include <sys/rman.h>
84256752Sbrooks
85256752Sbrooks#include <dev/mii/mii.h>
86256752Sbrooks#include <dev/mii/miivar.h>
87256752Sbrooks
88256752Sbrooks#include <dev/altera/atse/if_atsereg.h>
89256752Sbrooks#include <dev/altera/atse/a_api.h>
90256752Sbrooks
91256752SbrooksMODULE_DEPEND(atse, ether, 1, 1, 1);
92256752SbrooksMODULE_DEPEND(atse, miibus, 1, 1, 1);
93256752Sbrooks
94256752Sbrooks
95256752Sbrooks#define	ATSE_WATCHDOG_TIME	5
96256752Sbrooks
97256752Sbrooks#ifdef DEVICE_POLLING
98256752Sbrooksstatic poll_handler_t atse_poll;
99256752Sbrooks#endif
100256752Sbrooks
101256752Sbrooks/* XXX once we'd do parallel attach, we need a global lock for this. */
102256752Sbrooks#define	ATSE_ETHERNET_OPTION_BITS_UNDEF	0
103256752Sbrooks#define	ATSE_ETHERNET_OPTION_BITS_READ	1
104256752Sbrooksstatic int atse_ethernet_option_bits_flag = ATSE_ETHERNET_OPTION_BITS_UNDEF;
105256752Sbrooksstatic uint8_t atse_ethernet_option_bits[ALTERA_ETHERNET_OPTION_BITS_LEN];
106256752Sbrooks
107271969Sbzstatic int	atse_intr_debug_enable = 0;
108271969SbzSYSCTL_INT(_debug, OID_AUTO, atse_intr_debug_enable, CTLFLAG_RW,
109271969Sbz    &atse_intr_debug_enable, 0,
110271969Sbz   "Extra debugging output for atse interrupts");
111271969Sbz
112256752Sbrooks/*
113256752Sbrooks * Softc and critical resource locking.
114256752Sbrooks */
115256752Sbrooks#define	ATSE_LOCK(_sc)		mtx_lock(&(_sc)->atse_mtx)
116256752Sbrooks#define	ATSE_UNLOCK(_sc)	mtx_unlock(&(_sc)->atse_mtx)
117256752Sbrooks#define	ATSE_LOCK_ASSERT(_sc)	mtx_assert(&(_sc)->atse_mtx, MA_OWNED)
118256752Sbrooks
119271969Sbz#define	ATSE_TX_PENDING(sc)	(sc->atse_tx_m != NULL ||		\
120271969Sbz				    !IFQ_DRV_IS_EMPTY(&ifp->if_snd))
121271969Sbz
122256752Sbrooks#ifdef DEBUG
123256752Sbrooks#define	DPRINTF(format, ...)	printf(format, __VA_ARGS__)
124256752Sbrooks#else
125256752Sbrooks#define	DPRINTF(format, ...)
126256752Sbrooks#endif
127256752Sbrooks
128256752Sbrooks/* a_api.c functions; factor out? */
129256752Sbrooksstatic inline void
130256752Sbrooksa_onchip_fifo_mem_core_write(struct resource *res, uint32_t off,
131256752Sbrooks    uint32_t val4, const char *desc, const char *f, const int l)
132256752Sbrooks{
133256752Sbrooks
134256752Sbrooks	val4 = htole32(val4);
135256752Sbrooks	DPRINTF("[%s:%d] FIFOW %s 0x%08x = 0x%08x\n", f, l, desc, off, val4);
136256752Sbrooks	bus_write_4(res, off, val4);
137256752Sbrooks}
138256752Sbrooksstatic inline uint32_t
139256752Sbrooksa_onchip_fifo_mem_core_read(struct resource *res, uint32_t off,
140256752Sbrooks    const char *desc, const char *f, const int l)
141256752Sbrooks{
142256752Sbrooks	uint32_t val4;
143256752Sbrooks
144256752Sbrooks	val4 = le32toh(bus_read_4(res, off));
145256752Sbrooks	DPRINTF("[%s:%d] FIFOR %s 0x%08x = 0x%08x\n", f, l, desc, off, val4);
146256752Sbrooks	return (val4);
147256752Sbrooks}
148256752Sbrooks
149256752Sbrooks/* The FIFO does an endian convertion, so we must not do it as well. */
150256752Sbrooks/* XXX-BZ in fact we should do a htobe32 so le would be fine as well? */
151256752Sbrooks#define	ATSE_TX_DATA_WRITE(sc, val4)					\
152256752Sbrooks	bus_write_4((sc)->atse_tx_mem_res, A_ONCHIP_FIFO_MEM_CORE_DATA, val4)
153256752Sbrooks
154256752Sbrooks#define	ATSE_TX_META_WRITE(sc, val4)					\
155256752Sbrooks	a_onchip_fifo_mem_core_write((sc)->atse_tx_mem_res,		\
156256752Sbrooks	    A_ONCHIP_FIFO_MEM_CORE_METADATA,				\
157256752Sbrooks	    (val4), "TXM", __func__, __LINE__)
158256752Sbrooks#define	ATSE_TX_META_READ(sc)						\
159256752Sbrooks	a_onchip_fifo_mem_core_read((sc)->atse_tx_mem_res,		\
160256752Sbrooks	    A_ONCHIP_FIFO_MEM_CORE_METADATA,				\
161256752Sbrooks	    "TXM", __func__, __LINE__)
162256752Sbrooks
163256752Sbrooks#define	ATSE_TX_READ_FILL_LEVEL(sc)					\
164256752Sbrooks	a_onchip_fifo_mem_core_read((sc)->atse_txc_mem_res,		\
165256752Sbrooks	    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_FILL_LEVEL,		\
166256752Sbrooks	    "TX_FILL", __func__, __LINE__)
167256752Sbrooks#define	ATSE_RX_READ_FILL_LEVEL(sc)					\
168256752Sbrooks	a_onchip_fifo_mem_core_read((sc)->atse_rxc_mem_res,		\
169256752Sbrooks	    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_FILL_LEVEL,		\
170256752Sbrooks	    "RX_FILL", __func__, __LINE__)
171256752Sbrooks
172256752Sbrooks/* The FIFO does an endian convertion, so we must not do it as well. */
173256752Sbrooks/* XXX-BZ in fact we shoudl do a htobe32 so le would be fine as well? */
174256752Sbrooks#define	ATSE_RX_DATA_READ(sc)						\
175256752Sbrooks	bus_read_4((sc)->atse_rx_mem_res, A_ONCHIP_FIFO_MEM_CORE_DATA)
176256752Sbrooks#define	ATSE_RX_META_READ(sc)						\
177256752Sbrooks	a_onchip_fifo_mem_core_read((sc)->atse_rx_mem_res,		\
178256752Sbrooks	    A_ONCHIP_FIFO_MEM_CORE_METADATA,				\
179256752Sbrooks	    "RXM", __func__, __LINE__)
180256752Sbrooks
181271969Sbz#define	ATSE_RX_STATUS_READ(sc)						\
182271969Sbz	a_onchip_fifo_mem_core_read((sc)->atse_rxc_mem_res,		\
183271969Sbz	    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_I_STATUS,			\
184271969Sbz	    "RX_EVENT", __func__, __LINE__)
185271969Sbz
186271969Sbz#define	ATSE_TX_STATUS_READ(sc)						\
187271969Sbz	a_onchip_fifo_mem_core_read((sc)->atse_txc_mem_res,		\
188271969Sbz	    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_I_STATUS,			\
189271969Sbz	    "TX_EVENT", __func__, __LINE__)
190271969Sbz
191256752Sbrooks#define	ATSE_RX_EVENT_READ(sc)						\
192256752Sbrooks	a_onchip_fifo_mem_core_read((sc)->atse_rxc_mem_res,		\
193256752Sbrooks	    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT,			\
194256752Sbrooks	    "RX_EVENT", __func__, __LINE__)
195256752Sbrooks
196256752Sbrooks#define	ATSE_TX_EVENT_READ(sc)						\
197256752Sbrooks	a_onchip_fifo_mem_core_read((sc)->atse_txc_mem_res,		\
198256752Sbrooks	    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT,			\
199256752Sbrooks	    "TX_EVENT", __func__, __LINE__)
200256752Sbrooks
201256752Sbrooks#define	ATSE_RX_EVENT_CLEAR(sc)						\
202256752Sbrooks	do {								\
203256752Sbrooks		uint32_t val4;						\
204256752Sbrooks									\
205256752Sbrooks		val4 = a_onchip_fifo_mem_core_read(			\
206256752Sbrooks		    (sc)->atse_rxc_mem_res,				\
207256752Sbrooks		    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT,		\
208256752Sbrooks		    "RX_EVENT", __func__, __LINE__);			\
209256752Sbrooks		if (val4 != 0x00)					\
210256752Sbrooks			a_onchip_fifo_mem_core_write(			\
211256752Sbrooks			    (sc)->atse_rxc_mem_res,			\
212256752Sbrooks			    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT,	\
213256752Sbrooks			    val4, "RX_EVENT", __func__, __LINE__);	\
214256752Sbrooks	} while(0)
215256752Sbrooks#define	ATSE_TX_EVENT_CLEAR(sc)						\
216256752Sbrooks	do {								\
217256752Sbrooks		uint32_t val4;						\
218256752Sbrooks									\
219256752Sbrooks		val4 = a_onchip_fifo_mem_core_read(			\
220256752Sbrooks		    (sc)->atse_txc_mem_res,				\
221256752Sbrooks		    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT,		\
222256752Sbrooks		    "TX_EVENT", __func__, __LINE__);			\
223256752Sbrooks		if (val4 != 0x00)					\
224256752Sbrooks			a_onchip_fifo_mem_core_write(			\
225256752Sbrooks			    (sc)->atse_txc_mem_res,			\
226256752Sbrooks			    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_EVENT,	\
227256752Sbrooks			    val4, "TX_EVENT", __func__, __LINE__);	\
228256752Sbrooks	} while(0)
229256752Sbrooks
230271969Sbz#define	ATSE_RX_EVENTS	(A_ONCHIP_FIFO_MEM_CORE_INTR_FULL |	\
231271969Sbz			    A_ONCHIP_FIFO_MEM_CORE_INTR_OVERFLOW |	\
232271969Sbz			    A_ONCHIP_FIFO_MEM_CORE_INTR_UNDERFLOW)
233256752Sbrooks#define	ATSE_RX_INTR_ENABLE(sc)						\
234256752Sbrooks	a_onchip_fifo_mem_core_write((sc)->atse_rxc_mem_res,		\
235256752Sbrooks	    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE,		\
236271969Sbz	    ATSE_RX_EVENTS,						\
237256752Sbrooks	    "RX_INTR", __func__, __LINE__)	/* XXX-BZ review later. */
238256752Sbrooks#define	ATSE_RX_INTR_DISABLE(sc)					\
239256752Sbrooks	a_onchip_fifo_mem_core_write((sc)->atse_rxc_mem_res,		\
240256752Sbrooks	    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE, 0,		\
241256752Sbrooks	    "RX_INTR", __func__, __LINE__)
242271969Sbz#define	ATSE_RX_INTR_READ(sc)						\
243271969Sbz	a_onchip_fifo_mem_core_read((sc)->atse_rxc_mem_res,		\
244271969Sbz	    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE,		\
245271969Sbz	    "RX_INTR", __func__, __LINE__)
246271969Sbz
247271969Sbz#define	ATSE_TX_EVENTS	(A_ONCHIP_FIFO_MEM_CORE_INTR_EMPTY |		\
248271969Sbz			    A_ONCHIP_FIFO_MEM_CORE_INTR_OVERFLOW |	\
249271969Sbz			    A_ONCHIP_FIFO_MEM_CORE_INTR_UNDERFLOW)
250256752Sbrooks#define	ATSE_TX_INTR_ENABLE(sc)						\
251256752Sbrooks	a_onchip_fifo_mem_core_write((sc)->atse_txc_mem_res,		\
252256752Sbrooks	    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE,		\
253271969Sbz	    ATSE_TX_EVENTS,						\
254256752Sbrooks	    "TX_INTR", __func__, __LINE__)	/* XXX-BZ review later. */
255256752Sbrooks#define	ATSE_TX_INTR_DISABLE(sc)					\
256256752Sbrooks	a_onchip_fifo_mem_core_write((sc)->atse_txc_mem_res,		\
257256752Sbrooks	    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE, 0,		\
258256752Sbrooks	    "TX_INTR", __func__, __LINE__)
259271969Sbz#define	ATSE_TX_INTR_READ(sc)						\
260271969Sbz	a_onchip_fifo_mem_core_read((sc)->atse_txc_mem_res,		\
261271969Sbz	    A_ONCHIP_FIFO_MEM_CORE_STATUS_REG_INT_ENABLE,		\
262271969Sbz	    "TX_INTR", __func__, __LINE__)
263256752Sbrooks
264271969Sbzstatic int	atse_rx_locked(struct atse_softc *sc);
265271969Sbz
266256752Sbrooks/*
267256752Sbrooks * Register space access macros.
268256752Sbrooks */
269256752Sbrooksstatic inline void
270256752Sbrookscsr_write_4(struct atse_softc *sc, uint32_t reg, uint32_t val4,
271256752Sbrooks    const char *f, const int l)
272256752Sbrooks{
273256752Sbrooks
274256752Sbrooks	val4 = htole32(val4);
275256752Sbrooks	DPRINTF("[%s:%d] CSR W %s 0x%08x (0x%08x) = 0x%08x\n", f, l,
276256752Sbrooks	    "atse_mem_res", reg, reg * 4, val4);
277256752Sbrooks	bus_write_4(sc->atse_mem_res, reg * 4, val4);
278256752Sbrooks}
279256752Sbrooks
280256752Sbrooksstatic inline uint32_t
281256752Sbrookscsr_read_4(struct atse_softc *sc, uint32_t reg, const char *f, const int l)
282256752Sbrooks{
283256752Sbrooks	uint32_t val4;
284256752Sbrooks
285256752Sbrooks	val4 = le32toh(bus_read_4(sc->atse_mem_res, reg * 4));
286256752Sbrooks	DPRINTF("[%s:%d] CSR R %s 0x%08x (0x%08x) = 0x%08x\n", f, l,
287256752Sbrooks	    "atse_mem_res", reg, reg * 4, val4);
288256752Sbrooks	return (val4);
289256752Sbrooks}
290256752Sbrooks
291256752Sbrooks/*
292256752Sbrooks * See page 5-2 that it's all dword offsets and the MS 16 bits need to be zero
293256752Sbrooks * on write and ignored on read.
294256752Sbrooks */
295256752Sbrooksstatic inline void
296256752Sbrookspxx_write_2(struct atse_softc *sc, bus_addr_t bmcr, uint32_t reg, uint16_t val,
297256752Sbrooks    const char *f, const int l, const char *s)
298256752Sbrooks{
299256752Sbrooks	uint32_t val4;
300256752Sbrooks
301256752Sbrooks	val4 = htole32(val & 0x0000ffff);
302256752Sbrooks	DPRINTF("[%s:%d] %s W %s 0x%08x (0x%08jx) = 0x%08x\n", f, l, s,
303256752Sbrooks	    "atse_mem_res", reg, (bmcr + reg) * 4, val4);
304256752Sbrooks	bus_write_4(sc->atse_mem_res, (bmcr + reg) * 4, val4);
305256752Sbrooks}
306256752Sbrooks
307256752Sbrooksstatic inline uint16_t
308256752Sbrookspxx_read_2(struct atse_softc *sc, bus_addr_t bmcr, uint32_t reg, const char *f,
309256752Sbrooks    const int l, const char *s)
310256752Sbrooks{
311256752Sbrooks	uint32_t val4;
312256752Sbrooks	uint16_t val;
313256752Sbrooks
314256752Sbrooks	val4 = bus_read_4(sc->atse_mem_res, (bmcr + reg) * 4);
315256752Sbrooks	val = le32toh(val4) & 0x0000ffff;
316256752Sbrooks	DPRINTF("[%s:%d] %s R %s 0x%08x (0x%08jx) = 0x%04x\n", f, l, s,
317256752Sbrooks	    "atse_mem_res", reg, (bmcr + reg) * 4, val);
318256752Sbrooks	return (val);
319256752Sbrooks}
320256752Sbrooks
321256752Sbrooks#define	CSR_WRITE_4(sc, reg, val)	\
322256752Sbrooks	csr_write_4((sc), (reg), (val), __func__, __LINE__)
323256752Sbrooks#define	CSR_READ_4(sc, reg)		\
324256752Sbrooks	csr_read_4((sc), (reg), __func__, __LINE__)
325256752Sbrooks#define	PCS_WRITE_2(sc, reg, val)	\
326256752Sbrooks	pxx_write_2((sc), sc->atse_bmcr0, (reg), (val), __func__, __LINE__, \
327256752Sbrooks	    "PCS")
328256752Sbrooks#define	PCS_READ_2(sc, reg)		\
329256752Sbrooks	pxx_read_2((sc), sc->atse_bmcr0, (reg), __func__, __LINE__, "PCS")
330256752Sbrooks#define	PHY_WRITE_2(sc, reg, val)	\
331256752Sbrooks	pxx_write_2((sc), sc->atse_bmcr1, (reg), (val), __func__, __LINE__, \
332256752Sbrooks	    "PHY")
333256752Sbrooks#define	PHY_READ_2(sc, reg)		\
334256752Sbrooks	pxx_read_2((sc), sc->atse_bmcr1, (reg), __func__, __LINE__, "PHY")
335256752Sbrooks
336256752Sbrooksstatic void atse_tick(void *);
337256752Sbrooksstatic int atse_detach(device_t);
338256752Sbrooks
339256752Sbrooksdevclass_t atse_devclass;
340256752Sbrooks
341256752Sbrooksstatic int
342256752Sbrooksatse_tx_locked(struct atse_softc *sc, int *sent)
343256752Sbrooks{
344256752Sbrooks	struct mbuf *m;
345256752Sbrooks	uint32_t val4, fill_level;
346256752Sbrooks	int c;
347256752Sbrooks
348256752Sbrooks	ATSE_LOCK_ASSERT(sc);
349256752Sbrooks
350256752Sbrooks	m = sc->atse_tx_m;
351256752Sbrooks	KASSERT(m != NULL, ("%s: m is null: sc=%p", __func__, sc));
352256752Sbrooks	KASSERT(m->m_flags & M_PKTHDR, ("%s: not a pkthdr: m=%p", __func__, m));
353256752Sbrooks
354256752Sbrooks	/*
355256752Sbrooks	 * Copy to buffer to minimize our pain as we can only store
356256752Sbrooks	 * double words which, after the first mbuf gets out of alignment
357256752Sbrooks	 * quite quickly.
358256752Sbrooks	 */
359256752Sbrooks	if (sc->atse_tx_m_offset == 0) {
360256752Sbrooks		m_copydata(m, 0, m->m_pkthdr.len, sc->atse_tx_buf);
361256752Sbrooks		sc->atse_tx_buf_len = m->m_pkthdr.len;
362256752Sbrooks	}
363256752Sbrooks
364256752Sbrooks	fill_level = ATSE_TX_READ_FILL_LEVEL(sc);
365256752Sbrooks#if 0	/* Returns 0xdeadc0de. */
366256752Sbrooks	val4 = ATSE_TX_META_READ(sc);
367256752Sbrooks#endif
368256752Sbrooks	if (sc->atse_tx_m_offset == 0) {
369256752Sbrooks		/* Write start of packet. */
370256752Sbrooks		val4 = A_ONCHIP_FIFO_MEM_CORE_SOP;
371256752Sbrooks		val4 &= ~A_ONCHIP_FIFO_MEM_CORE_EOP;
372256752Sbrooks		ATSE_TX_META_WRITE(sc, val4);
373256752Sbrooks	}
374256752Sbrooks
375256752Sbrooks	/* TX FIFO is single clock mode, so we have the full FIFO. */
376256752Sbrooks	c = 0;
377256752Sbrooks	while ((sc->atse_tx_buf_len - sc->atse_tx_m_offset) > 4 &&
378256752Sbrooks	     fill_level < AVALON_FIFO_TX_BASIC_OPTS_DEPTH) {
379256752Sbrooks
380256752Sbrooks		bcopy(&sc->atse_tx_buf[sc->atse_tx_m_offset], &val4,
381256752Sbrooks		    sizeof(val4));
382256752Sbrooks		ATSE_TX_DATA_WRITE(sc, val4);
383256752Sbrooks		sc->atse_tx_m_offset += sizeof(val4);
384256752Sbrooks		c += sizeof(val4);
385256752Sbrooks
386256752Sbrooks		fill_level++;
387256752Sbrooks		if (fill_level == AVALON_FIFO_TX_BASIC_OPTS_DEPTH)
388256752Sbrooks			fill_level = ATSE_TX_READ_FILL_LEVEL(sc);
389256752Sbrooks	}
390256752Sbrooks	if (sent != NULL)
391256752Sbrooks		*sent += c;
392256752Sbrooks
393256752Sbrooks	/* Set EOP *before* writing the last symbol. */
394256752Sbrooks	if (sc->atse_tx_m_offset >= (sc->atse_tx_buf_len - 4) &&
395256752Sbrooks	    fill_level < AVALON_FIFO_TX_BASIC_OPTS_DEPTH) {
396256752Sbrooks		int leftm;
397256752Sbrooks		uint32_t x;
398256752Sbrooks
399256752Sbrooks		/* Set EndOfPacket. */
400256752Sbrooks		val4 = A_ONCHIP_FIFO_MEM_CORE_EOP;
401256752Sbrooks		/* Set EMPTY. */
402256752Sbrooks		leftm = sc->atse_tx_buf_len - sc->atse_tx_m_offset;
403256752Sbrooks		val4 |= ((4 - leftm) << A_ONCHIP_FIFO_MEM_CORE_EMPTY_SHIFT);
404256752Sbrooks		x = val4;
405256752Sbrooks		ATSE_TX_META_WRITE(sc, val4);
406256752Sbrooks
407256752Sbrooks		/* Write last symbol. */
408256752Sbrooks		val4 = 0;
409256752Sbrooks		bcopy(sc->atse_tx_buf + sc->atse_tx_m_offset, &val4, leftm);
410256752Sbrooks		ATSE_TX_DATA_WRITE(sc, val4);
411256752Sbrooks
412256752Sbrooks		if (sent != NULL)
413256752Sbrooks			*sent += leftm;
414256752Sbrooks
415256752Sbrooks		/* OK, the packet is gone. */
416256752Sbrooks		sc->atse_tx_m = NULL;
417256752Sbrooks		sc->atse_tx_m_offset = 0;
418256752Sbrooks
419256752Sbrooks		/* If anyone is interested give them a copy. */
420256752Sbrooks		BPF_MTAP(sc->atse_ifp, m);
421256752Sbrooks
422256752Sbrooks		m_freem(m);
423256752Sbrooks		return (0);
424256752Sbrooks	}
425256752Sbrooks
426256752Sbrooks	return (EBUSY);
427256752Sbrooks}
428256752Sbrooks
429256752Sbrooksstatic void
430256752Sbrooksatse_start_locked(struct ifnet *ifp)
431256752Sbrooks{
432256752Sbrooks	struct atse_softc *sc;
433256752Sbrooks	int error, sent;
434256752Sbrooks
435256752Sbrooks	sc = ifp->if_softc;
436256752Sbrooks	ATSE_LOCK_ASSERT(sc);
437256752Sbrooks
438256752Sbrooks	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
439256752Sbrooks	    IFF_DRV_RUNNING || (sc->atse_flags & ATSE_FLAGS_LINK) == 0)
440256752Sbrooks		return;
441256752Sbrooks
442256752Sbrooks#if 1
443256752Sbrooks	/*
444256752Sbrooks	 * Disable the watchdog while sending, we are batching packets.
445256752Sbrooks	 * Though we should never reach 5 seconds, and are holding the lock,
446256752Sbrooks	 * but who knows.
447256752Sbrooks	 */
448256752Sbrooks	sc->atse_watchdog_timer = 0;
449256752Sbrooks#endif
450256752Sbrooks
451256752Sbrooks	if (sc->atse_tx_m != NULL) {
452256752Sbrooks		error = atse_tx_locked(sc, &sent);
453256752Sbrooks		if (error != 0)
454256752Sbrooks			goto done;
455256752Sbrooks	}
456256752Sbrooks	/* We have more space to send so continue ... */
457256752Sbrooks	for (; !IFQ_DRV_IS_EMPTY(&ifp->if_snd); ) {
458256752Sbrooks
459256752Sbrooks		IFQ_DRV_DEQUEUE(&ifp->if_snd, sc->atse_tx_m);
460256752Sbrooks		sc->atse_tx_m_offset = 0;
461256752Sbrooks		if (sc->atse_tx_m == NULL)
462256752Sbrooks			break;
463256752Sbrooks		error = atse_tx_locked(sc, &sent);
464256752Sbrooks		if (error != 0)
465256752Sbrooks			goto done;
466256752Sbrooks	}
467256752Sbrooks
468256752Sbrooksdone:
469256752Sbrooks	/* If the IP core walks into Nekromanteion try to bail out. */
470256752Sbrooks	if (sent > 0)
471256752Sbrooks		sc->atse_watchdog_timer = ATSE_WATCHDOG_TIME;
472256752Sbrooks}
473256752Sbrooks
474256752Sbrooksstatic void
475256752Sbrooksatse_start(struct ifnet *ifp)
476256752Sbrooks{
477256752Sbrooks	struct atse_softc *sc;
478256752Sbrooks
479256752Sbrooks	sc = ifp->if_softc;
480256752Sbrooks	ATSE_LOCK(sc);
481256752Sbrooks	atse_start_locked(ifp);
482256752Sbrooks	ATSE_UNLOCK(sc);
483256752Sbrooks}
484256752Sbrooks
485256752Sbrooksstatic int
486256752Sbrooksatse_stop_locked(struct atse_softc *sc)
487256752Sbrooks{
488256752Sbrooks	struct ifnet *ifp;
489256752Sbrooks	uint32_t mask, val4;
490256752Sbrooks	int i;
491256752Sbrooks
492256752Sbrooks	ATSE_LOCK_ASSERT(sc);
493256752Sbrooks
494256752Sbrooks	sc->atse_watchdog_timer = 0;
495256752Sbrooks	callout_stop(&sc->atse_tick);
496256752Sbrooks
497256752Sbrooks	ifp = sc->atse_ifp;
498256752Sbrooks	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
499256752Sbrooks	ATSE_RX_INTR_DISABLE(sc);
500256752Sbrooks	ATSE_TX_INTR_DISABLE(sc);
501256752Sbrooks	ATSE_RX_EVENT_CLEAR(sc);
502256752Sbrooks	ATSE_TX_EVENT_CLEAR(sc);
503256752Sbrooks
504256752Sbrooks	/* Disable MAC transmit and receive datapath. */
505256752Sbrooks	mask = BASE_CFG_COMMAND_CONFIG_TX_ENA|BASE_CFG_COMMAND_CONFIG_RX_ENA;
506256752Sbrooks	val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG);
507256752Sbrooks	val4 &= ~mask;
508256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4);
509256752Sbrooks	/* Wait for bits to be cleared; i=100 is excessive. */
510256752Sbrooks	for (i = 0; i < 100; i++) {
511256752Sbrooks		val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG);
512256752Sbrooks		if ((val4 & mask) == 0)
513256752Sbrooks			break;
514256752Sbrooks		DELAY(10);
515256752Sbrooks	}
516256752Sbrooks	if ((val4 & mask) != 0)
517256752Sbrooks		device_printf(sc->atse_dev, "Disabling MAC TX/RX timed out.\n");
518256752Sbrooks		/* Punt. */
519256752Sbrooks
520256752Sbrooks	sc->atse_flags &= ~ATSE_FLAGS_LINK;
521256752Sbrooks
522256752Sbrooks	/* XXX-BZ free the RX/TX rings. */
523256752Sbrooks
524256752Sbrooks	return (0);
525256752Sbrooks}
526256752Sbrooks
527256752Sbrooksstatic uint8_t
528256752Sbrooksatse_mchash(struct atse_softc *sc __unused, const uint8_t *addr)
529256752Sbrooks{
530256752Sbrooks	int i, j;
531256752Sbrooks	uint8_t x, y;
532256752Sbrooks
533256752Sbrooks	x = 0;
534256752Sbrooks	for (i = 0; i < ETHER_ADDR_LEN; i++) {
535256752Sbrooks		y = addr[i] & 0x01;
536256752Sbrooks		for (j = 1; j < 8; j++)
537256752Sbrooks			y ^= (addr[i] >> j) & 0x01;
538256752Sbrooks		x |= (y << i);
539256752Sbrooks	}
540256752Sbrooks	return (x);
541256752Sbrooks}
542256752Sbrooks
543256752Sbrooksstatic int
544256752Sbrooksatse_rxfilter_locked(struct atse_softc *sc)
545256752Sbrooks{
546256752Sbrooks	struct ifnet *ifp;
547256752Sbrooks	struct ifmultiaddr *ifma;
548256752Sbrooks	uint32_t val4;
549256752Sbrooks	int i;
550256752Sbrooks
551256752Sbrooks	/* XXX-BZ can we find out if we have the MHASH synthesized? */
552256752Sbrooks	val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG);
553256752Sbrooks	/* For simplicity always hash full 48 bits of addresses. */
554256752Sbrooks	if ((val4 & BASE_CFG_COMMAND_CONFIG_MHASH_SEL) != 0)
555256752Sbrooks		val4 &= ~BASE_CFG_COMMAND_CONFIG_MHASH_SEL;
556256752Sbrooks
557256752Sbrooks	ifp = sc->atse_ifp;
558256752Sbrooks	if (ifp->if_flags & IFF_PROMISC)
559256752Sbrooks		val4 |= BASE_CFG_COMMAND_CONFIG_PROMIS_EN;
560256752Sbrooks	else
561256752Sbrooks		val4 &= ~BASE_CFG_COMMAND_CONFIG_PROMIS_EN;
562256752Sbrooks
563256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4);
564256752Sbrooks
565256752Sbrooks	if (ifp->if_flags & IFF_ALLMULTI) {
566256752Sbrooks		/* Accept all multicast addresses. */
567256752Sbrooks		for (i = 0; i <= MHASH_LEN; i++)
568256752Sbrooks			CSR_WRITE_4(sc, MHASH_START + i, 0x1);
569256752Sbrooks	} else {
570256752Sbrooks		/*
571256752Sbrooks		 * Can hold MHASH_LEN entries.
572256752Sbrooks		 * XXX-BZ bitstring.h would be more general.
573256752Sbrooks		 */
574256752Sbrooks		uint64_t h;
575256752Sbrooks
576256752Sbrooks		h = 0;
577256752Sbrooks		/*
578256752Sbrooks		 * Re-build and re-program hash table.  First build the
579256752Sbrooks		 * bit-field "yes" or "no" for each slot per address, then
580256752Sbrooks		 * do all the programming afterwards.
581256752Sbrooks		 */
582256752Sbrooks		if_maddr_rlock(ifp);
583256752Sbrooks		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
584256752Sbrooks			if (ifma->ifma_addr->sa_family != AF_LINK)
585256752Sbrooks				continue;
586256752Sbrooks
587256752Sbrooks			h |= (1 << atse_mchash(sc,
588256752Sbrooks			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr)));
589256752Sbrooks		}
590256752Sbrooks		if_maddr_runlock(ifp);
591256752Sbrooks		for (i = 0; i <= MHASH_LEN; i++)
592256752Sbrooks			CSR_WRITE_4(sc, MHASH_START + i,
593256752Sbrooks			    (h & (1 << i)) ? 0x01 : 0x00);
594256752Sbrooks	}
595256752Sbrooks
596256752Sbrooks	return (0);
597256752Sbrooks}
598256752Sbrooks
599256752Sbrooksstatic int
600256752Sbrooksatse_ethernet_option_bits_read_fdt(device_t dev)
601256752Sbrooks{
602256752Sbrooks	struct resource *res;
603256752Sbrooks	device_t fdev;
604256752Sbrooks	int i, rid;
605256752Sbrooks
606256752Sbrooks	if (atse_ethernet_option_bits_flag & ATSE_ETHERNET_OPTION_BITS_READ)
607256752Sbrooks		return (0);
608256752Sbrooks
609256752Sbrooks	fdev = device_find_child(device_get_parent(dev), "cfi", 0);
610256752Sbrooks	if (fdev == NULL)
611256752Sbrooks		return (ENOENT);
612256752Sbrooks
613256752Sbrooks	rid = 0;
614256752Sbrooks	res = bus_alloc_resource_any(fdev, SYS_RES_MEMORY, &rid,
615256752Sbrooks	    RF_ACTIVE | RF_SHAREABLE);
616256752Sbrooks	if (res == NULL)
617256752Sbrooks		return (ENXIO);
618256752Sbrooks
619256752Sbrooks	for (i = 0; i < ALTERA_ETHERNET_OPTION_BITS_LEN; i++)
620256752Sbrooks		atse_ethernet_option_bits[i] = bus_read_1(res,
621256752Sbrooks		    ALTERA_ETHERNET_OPTION_BITS_OFF + i);
622256752Sbrooks
623256752Sbrooks	bus_release_resource(fdev, SYS_RES_MEMORY, rid, res);
624256752Sbrooks	atse_ethernet_option_bits_flag |= ATSE_ETHERNET_OPTION_BITS_READ;
625256752Sbrooks
626256752Sbrooks	return (0);
627256752Sbrooks}
628256752Sbrooks
629256752Sbrooksstatic int
630256752Sbrooksatse_ethernet_option_bits_read(device_t dev)
631256752Sbrooks{
632256752Sbrooks	int error;
633256752Sbrooks
634256752Sbrooks	error = atse_ethernet_option_bits_read_fdt(dev);
635256752Sbrooks	if (error == 0)
636256752Sbrooks		return (0);
637256752Sbrooks
638256752Sbrooks	device_printf(dev, "Cannot read Ethernet addresses from flash.\n");
639256752Sbrooks	return (error);
640256752Sbrooks}
641256752Sbrooks
642256752Sbrooksstatic int
643256752Sbrooksatse_get_eth_address(struct atse_softc *sc)
644256752Sbrooks{
645256752Sbrooks	unsigned long hostid;
646256752Sbrooks	uint32_t val4;
647256752Sbrooks	int unit;
648256752Sbrooks
649256752Sbrooks	/*
650256752Sbrooks	 * Make sure to only ever do this once.  Otherwise a reset would
651256752Sbrooks	 * possibly change our ethernet address, which is not good at all.
652256752Sbrooks	 */
653256752Sbrooks	if (sc->atse_eth_addr[0] != 0x00 || sc->atse_eth_addr[1] != 0x00 ||
654256752Sbrooks	    sc->atse_eth_addr[2] != 0x00)
655256752Sbrooks		return (0);
656256752Sbrooks
657256752Sbrooks	if ((atse_ethernet_option_bits_flag &
658256752Sbrooks	    ATSE_ETHERNET_OPTION_BITS_READ) == 0)
659256752Sbrooks		goto get_random;
660256752Sbrooks
661256752Sbrooks	val4 = atse_ethernet_option_bits[0] << 24;
662256752Sbrooks	val4 |= atse_ethernet_option_bits[1] << 16;
663256752Sbrooks	val4 |= atse_ethernet_option_bits[2] << 8;
664256752Sbrooks	val4 |= atse_ethernet_option_bits[3];
665256752Sbrooks	/* They chose "safe". */
666256752Sbrooks	if (val4 != le32toh(0x00005afe)) {
667256752Sbrooks		device_printf(sc->atse_dev, "Magic '5afe' is not safe: 0x%08x. "
668256752Sbrooks		    "Falling back to random numbers for hardware address.\n",
669256752Sbrooks		     val4);
670256752Sbrooks		goto get_random;
671256752Sbrooks	}
672256752Sbrooks
673256752Sbrooks	sc->atse_eth_addr[0] = atse_ethernet_option_bits[4];
674256752Sbrooks	sc->atse_eth_addr[1] = atse_ethernet_option_bits[5];
675256752Sbrooks	sc->atse_eth_addr[2] = atse_ethernet_option_bits[6];
676256752Sbrooks	sc->atse_eth_addr[3] = atse_ethernet_option_bits[7];
677256752Sbrooks	sc->atse_eth_addr[4] = atse_ethernet_option_bits[8];
678256752Sbrooks	sc->atse_eth_addr[5] = atse_ethernet_option_bits[9];
679256752Sbrooks
680256752Sbrooks	/* Handle factory default ethernet addresss: 00:07:ed:ff:ed:15 */
681256752Sbrooks	if (sc->atse_eth_addr[0] == 0x00 && sc->atse_eth_addr[1] == 0x07 &&
682256752Sbrooks	    sc->atse_eth_addr[2] == 0xed && sc->atse_eth_addr[3] == 0xff &&
683256752Sbrooks	    sc->atse_eth_addr[4] == 0xed && sc->atse_eth_addr[5] == 0x15) {
684256752Sbrooks
685256752Sbrooks		device_printf(sc->atse_dev, "Factory programmed Ethernet "
686256752Sbrooks		    "hardware address blacklisted.  Falling back to random "
687256752Sbrooks		    "address to avoid collisions.\n");
688256752Sbrooks		device_printf(sc->atse_dev, "Please re-program your flash.\n");
689256752Sbrooks		goto get_random;
690256752Sbrooks	}
691256752Sbrooks
692256752Sbrooks	if (sc->atse_eth_addr[0] == 0x00 && sc->atse_eth_addr[1] == 0x00 &&
693256752Sbrooks	    sc->atse_eth_addr[2] == 0x00 && sc->atse_eth_addr[3] == 0x00 &&
694256752Sbrooks	    sc->atse_eth_addr[4] == 0x00 && sc->atse_eth_addr[5] == 0x00) {
695256752Sbrooks		device_printf(sc->atse_dev, "All zero's Ethernet hardware "
696256752Sbrooks		    "address blacklisted.  Falling back to random address.\n");
697256752Sbrooks		device_printf(sc->atse_dev, "Please re-program your flash.\n");
698256752Sbrooks		goto get_random;
699256752Sbrooks	}
700256752Sbrooks
701256752Sbrooks	if (ETHER_IS_MULTICAST(sc->atse_eth_addr)) {
702256752Sbrooks		device_printf(sc->atse_dev, "Multicast Ethernet hardware "
703256752Sbrooks		    "address blacklisted.  Falling back to random address.\n");
704256752Sbrooks		device_printf(sc->atse_dev, "Please re-program your flash.\n");
705256752Sbrooks		goto get_random;
706256752Sbrooks	}
707256752Sbrooks
708256752Sbrooks	/*
709256752Sbrooks	 * If we find an Altera prefixed address with a 0x0 ending
710256752Sbrooks	 * adjust by device unit.  If not and this is not the first
711256752Sbrooks	 * Ethernet, go to random.
712256752Sbrooks	 */
713256752Sbrooks	unit = device_get_unit(sc->atse_dev);
714256752Sbrooks	if (unit == 0x00)
715256752Sbrooks		return (0);
716256752Sbrooks
717256752Sbrooks	if (unit > 0x0f) {
718256752Sbrooks		device_printf(sc->atse_dev, "We do not support Ethernet "
719256752Sbrooks		    "addresses for more than 16 MACs. Falling back to "
720256752Sbrooks		    "random hadware address.\n");
721256752Sbrooks		goto get_random;
722256752Sbrooks	}
723256752Sbrooks	if ((sc->atse_eth_addr[0] & ~0x2) != 0 ||
724256752Sbrooks	    sc->atse_eth_addr[1] != 0x07 || sc->atse_eth_addr[2] != 0xed ||
725256752Sbrooks	    (sc->atse_eth_addr[5] & 0x0f) != 0x0) {
726256752Sbrooks		device_printf(sc->atse_dev, "Ethernet address not meeting our "
727256752Sbrooks		    "multi-MAC standards. Falling back to random hadware "
728256752Sbrooks		    "address.\n");
729256752Sbrooks		goto get_random;
730256752Sbrooks	}
731256752Sbrooks	sc->atse_eth_addr[5] |= (unit & 0x0f);
732256752Sbrooks
733256752Sbrooks	return (0);
734256752Sbrooks
735256752Sbrooksget_random:
736256752Sbrooks	/*
737256752Sbrooks	 * Fall back to random code we also use on bridge(4).
738256752Sbrooks	 */
739256752Sbrooks	getcredhostid(curthread->td_ucred, &hostid);
740256752Sbrooks	if (hostid == 0) {
741256752Sbrooks		arc4rand(sc->atse_eth_addr, ETHER_ADDR_LEN, 1);
742256752Sbrooks		sc->atse_eth_addr[0] &= ~1;/* clear multicast bit */
743256752Sbrooks		sc->atse_eth_addr[0] |= 2; /* set the LAA bit */
744256752Sbrooks	} else {
745256752Sbrooks		sc->atse_eth_addr[0] = 0x2;
746256752Sbrooks		sc->atse_eth_addr[1] = (hostid >> 24)	& 0xff;
747256752Sbrooks		sc->atse_eth_addr[2] = (hostid >> 16)	& 0xff;
748256752Sbrooks		sc->atse_eth_addr[3] = (hostid >> 8 )	& 0xff;
749256752Sbrooks		sc->atse_eth_addr[4] = hostid		& 0xff;
750256752Sbrooks		sc->atse_eth_addr[5] = sc->atse_unit	& 0xff;
751256752Sbrooks	}
752256752Sbrooks
753256752Sbrooks	return (0);
754256752Sbrooks}
755256752Sbrooks
756256752Sbrooksstatic int
757256752Sbrooksatse_set_eth_address(struct atse_softc *sc, int n)
758256752Sbrooks{
759256752Sbrooks	uint32_t v0, v1;
760256752Sbrooks
761256752Sbrooks	v0 = (sc->atse_eth_addr[3] << 24) | (sc->atse_eth_addr[2] << 16) |
762256752Sbrooks	    (sc->atse_eth_addr[1] << 8) | sc->atse_eth_addr[0];
763256752Sbrooks	v1 = (sc->atse_eth_addr[5] << 8) | sc->atse_eth_addr[4];
764256752Sbrooks
765256752Sbrooks	if (n & ATSE_ETH_ADDR_DEF) {
766256752Sbrooks		CSR_WRITE_4(sc, BASE_CFG_MAC_0, v0);
767256752Sbrooks		CSR_WRITE_4(sc, BASE_CFG_MAC_1, v1);
768256752Sbrooks	}
769256752Sbrooks	if (n & ATSE_ETH_ADDR_SUPP1) {
770256752Sbrooks		CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_0_0, v0);
771256752Sbrooks		CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_0_1, v1);
772256752Sbrooks	}
773256752Sbrooks	if (n & ATSE_ETH_ADDR_SUPP2) {
774256752Sbrooks		CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_1_0, v0);
775256752Sbrooks		CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_1_1, v1);
776256752Sbrooks	}
777256752Sbrooks	if (n & ATSE_ETH_ADDR_SUPP3) {
778256752Sbrooks		CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_2_0, v0);
779256752Sbrooks		CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_2_1, v1);
780256752Sbrooks	}
781256752Sbrooks	if (n & ATSE_ETH_ADDR_SUPP4) {
782256752Sbrooks		CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_3_0, v0);
783256752Sbrooks		CSR_WRITE_4(sc, SUPPL_ADDR_SMAC_3_1, v1);
784256752Sbrooks	}
785256752Sbrooks
786256752Sbrooks	return (0);
787256752Sbrooks}
788256752Sbrooks
789256752Sbrooksstatic int
790256752Sbrooksatse_reset(struct atse_softc *sc)
791256752Sbrooks{
792256752Sbrooks	int i;
793256752Sbrooks	uint32_t val4, mask;
794256752Sbrooks	uint16_t val;
795256752Sbrooks
796256752Sbrooks	/* 1. External PHY Initialization using MDIO. */
797256752Sbrooks	/*
798256752Sbrooks	 * We select the right MDIO space in atse_attach() and let MII do
799256752Sbrooks	 * anything else.
800256752Sbrooks	 */
801256752Sbrooks
802256752Sbrooks	/* 2. PCS Configuration Register Initialization. */
803256752Sbrooks	/* a. Set auto negotiation link timer to 1.6ms for SGMII. */
804256752Sbrooks	PCS_WRITE_2(sc, PCS_EXT_LINK_TIMER_0, 0x0D40);
805256752Sbrooks	PCS_WRITE_2(sc, PCS_EXT_LINK_TIMER_1, 0x0003);
806256752Sbrooks
807256752Sbrooks	/* b. Configure SGMII. */
808256752Sbrooks	val = PCS_EXT_IF_MODE_SGMII_ENA|PCS_EXT_IF_MODE_USE_SGMII_AN;
809256752Sbrooks	PCS_WRITE_2(sc, PCS_EXT_IF_MODE, val);
810256752Sbrooks
811256752Sbrooks	/* c. Enable auto negotiation. */
812256752Sbrooks	/* Ignore Bits 6,8,13; should be set,set,unset. */
813256752Sbrooks	val = PCS_READ_2(sc, PCS_CONTROL);
814256752Sbrooks	val &= ~(PCS_CONTROL_ISOLATE|PCS_CONTROL_POWERDOWN);
815256752Sbrooks	val &= ~PCS_CONTROL_LOOPBACK;		/* Make this a -link1 option? */
816256752Sbrooks	val |= PCS_CONTROL_AUTO_NEGOTIATION_ENABLE;
817256752Sbrooks	PCS_WRITE_2(sc, PCS_CONTROL, val);
818256752Sbrooks
819256752Sbrooks	/* d. PCS reset. */
820256752Sbrooks	val = PCS_READ_2(sc, PCS_CONTROL);
821256752Sbrooks	val |= PCS_CONTROL_RESET;
822256752Sbrooks	PCS_WRITE_2(sc, PCS_CONTROL, val);
823256752Sbrooks	/* Wait for reset bit to clear; i=100 is excessive. */
824256752Sbrooks	for (i = 0; i < 100; i++) {
825256752Sbrooks		val = PCS_READ_2(sc, PCS_CONTROL);
826256752Sbrooks		if ((val & PCS_CONTROL_RESET) == 0)
827256752Sbrooks			break;
828256752Sbrooks		DELAY(10);
829256752Sbrooks	}
830256752Sbrooks	if ((val & PCS_CONTROL_RESET) != 0) {
831256752Sbrooks		device_printf(sc->atse_dev, "PCS reset timed out.\n");
832256752Sbrooks		return (ENXIO);
833256752Sbrooks	}
834256752Sbrooks
835256752Sbrooks	/* 3. MAC Configuration Register Initialization. */
836256752Sbrooks	/* a. Disable MAC transmit and receive datapath. */
837256752Sbrooks	mask = BASE_CFG_COMMAND_CONFIG_TX_ENA|BASE_CFG_COMMAND_CONFIG_RX_ENA;
838256752Sbrooks	val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG);
839256752Sbrooks	val4 &= ~mask;
840256752Sbrooks	/* Samples in the manual do have the SW_RESET bit set here, why? */
841256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4);
842256752Sbrooks	/* Wait for bits to be cleared; i=100 is excessive. */
843256752Sbrooks	for (i = 0; i < 100; i++) {
844256752Sbrooks		val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG);
845256752Sbrooks		if ((val4 & mask) == 0)
846256752Sbrooks			break;
847256752Sbrooks		DELAY(10);
848256752Sbrooks	}
849256752Sbrooks	if ((val4 & mask) != 0) {
850256752Sbrooks		device_printf(sc->atse_dev, "Disabling MAC TX/RX timed out.\n");
851256752Sbrooks		return (ENXIO);
852256752Sbrooks	}
853256752Sbrooks	/* b. MAC FIFO configuration. */
854256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_TX_SECTION_EMPTY, FIFO_DEPTH_TX - 16);
855256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_TX_ALMOST_FULL, 3);
856256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_TX_ALMOST_EMPTY, 8);
857256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_RX_SECTION_EMPTY, FIFO_DEPTH_RX - 16);
858256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_RX_ALMOST_FULL, 8);
859256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_RX_ALMOST_EMPTY, 8);
860256752Sbrooks#if 0
861256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_TX_SECTION_FULL, 16);
862256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_RX_SECTION_FULL, 16);
863256752Sbrooks#else
864256752Sbrooks	/* For store-and-forward mode, set this threshold to 0. */
865256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_TX_SECTION_FULL, 0);
866256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_RX_SECTION_FULL, 0);
867256752Sbrooks#endif
868256752Sbrooks	/* c. MAC address configuration. */
869256752Sbrooks	/* Also intialize supplementary addresses to our primary one. */
870256752Sbrooks	/* XXX-BZ FreeBSD really needs to grow and API for using these. */
871256752Sbrooks	atse_get_eth_address(sc);
872256752Sbrooks	atse_set_eth_address(sc, ATSE_ETH_ADDR_ALL);
873256752Sbrooks
874256752Sbrooks	/* d. MAC function configuration. */
875256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_FRM_LENGTH, 1518);	/* Default. */
876256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_TX_IPG_LENGTH, 12);
877256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_PAUSE_QUANT, 0xFFFF);
878256752Sbrooks
879256752Sbrooks	val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG);
880256752Sbrooks	/*
881256752Sbrooks	 * If 1000BASE-X/SGMII PCS is initialized, set the ETH_SPEED (bit 3)
882256752Sbrooks	 * and ENA_10 (bit 25) in command_config register to 0.  If half duplex
883256752Sbrooks	 * is reported in the PHY/PCS status register, set the HD_ENA (bit 10)
884256752Sbrooks	 * to 1 in command_config register.
885256752Sbrooks	 * BZ: We shoot for 1000 instead.
886256752Sbrooks	 */
887256752Sbrooks#if 0
888256752Sbrooks	val4 |= BASE_CFG_COMMAND_CONFIG_ETH_SPEED;
889256752Sbrooks#else
890256752Sbrooks	val4 &= ~BASE_CFG_COMMAND_CONFIG_ETH_SPEED;
891256752Sbrooks#endif
892256752Sbrooks	val4 &= ~BASE_CFG_COMMAND_CONFIG_ENA_10;
893256752Sbrooks#if 0
894256752Sbrooks	/*
895256752Sbrooks	 * We do not want to set this, otherwise, we could not even send
896256752Sbrooks	 * random raw ethernet frames for various other research.  By default
897256752Sbrooks	 * FreeBSD will use the right ether source address.
898256752Sbrooks	 */
899256752Sbrooks	val4 |= BASE_CFG_COMMAND_CONFIG_TX_ADDR_INS;
900256752Sbrooks#endif
901256752Sbrooks	val4 |= BASE_CFG_COMMAND_CONFIG_PAD_EN;
902256752Sbrooks	val4 &= ~BASE_CFG_COMMAND_CONFIG_CRC_FWD;
903256752Sbrooks#if 0
904256752Sbrooks	val4 |= BASE_CFG_COMMAND_CONFIG_CNTL_FRM_ENA;
905256752Sbrooks#endif
906256752Sbrooks#if 1
907256752Sbrooks	val4 |= BASE_CFG_COMMAND_CONFIG_RX_ERR_DISC;
908256752Sbrooks#endif
909256752Sbrooks	val &= ~BASE_CFG_COMMAND_CONFIG_LOOP_ENA;		/* link0? */
910256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4);
911256752Sbrooks
912256752Sbrooks	/*
913256752Sbrooks	 * Make sure we do not enable 32bit alignment;  FreeBSD cannot
914256752Sbrooks	 * cope with the additional padding (though we should!?).
915256752Sbrooks	 * Also make sure we get the CRC appended.
916256752Sbrooks	 */
917256752Sbrooks	val4 = CSR_READ_4(sc, TX_CMD_STAT);
918256752Sbrooks	val4 &= ~(TX_CMD_STAT_OMIT_CRC|TX_CMD_STAT_TX_SHIFT16);
919256752Sbrooks	CSR_WRITE_4(sc, TX_CMD_STAT, val4);
920256752Sbrooks	val4 = CSR_READ_4(sc, RX_CMD_STAT);
921256752Sbrooks	val4 &= ~RX_CMD_STAT_RX_SHIFT16;
922256752Sbrooks	CSR_WRITE_4(sc, RX_CMD_STAT, val4);
923256752Sbrooks
924256752Sbrooks	/* e. Reset MAC. */
925256752Sbrooks	val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG);
926256752Sbrooks	val4 |= BASE_CFG_COMMAND_CONFIG_SW_RESET;
927256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4);
928256752Sbrooks	/* Wait for bits to be cleared; i=100 is excessive. */
929256752Sbrooks	for (i = 0; i < 100; i++) {
930256752Sbrooks		val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG);
931256752Sbrooks		if ((val4 & BASE_CFG_COMMAND_CONFIG_SW_RESET) == 0)
932256752Sbrooks			break;
933256752Sbrooks		DELAY(10);
934256752Sbrooks	}
935256752Sbrooks	if ((val4 & BASE_CFG_COMMAND_CONFIG_SW_RESET) != 0) {
936256752Sbrooks		device_printf(sc->atse_dev, "MAC reset timed out.\n");
937256752Sbrooks		return (ENXIO);
938256752Sbrooks	}
939256752Sbrooks
940256752Sbrooks	/* f. Enable MAC transmit and receive datapath. */
941256752Sbrooks	mask = BASE_CFG_COMMAND_CONFIG_TX_ENA|BASE_CFG_COMMAND_CONFIG_RX_ENA;
942256752Sbrooks	val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG);
943256752Sbrooks	val4 |= mask;
944256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4);
945256752Sbrooks	/* Wait for bits to be cleared; i=100 is excessive. */
946256752Sbrooks	for (i = 0; i < 100; i++) {
947256752Sbrooks		val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG);
948256752Sbrooks		if ((val4 & mask) == mask)
949256752Sbrooks			break;
950256752Sbrooks		DELAY(10);
951256752Sbrooks	}
952256752Sbrooks	if ((val4 & mask) != mask) {
953256752Sbrooks		device_printf(sc->atse_dev, "Enabling MAC TX/RX timed out.\n");
954256752Sbrooks		return (ENXIO);
955256752Sbrooks	}
956256752Sbrooks
957256752Sbrooks	return (0);
958256752Sbrooks}
959256752Sbrooks
960256752Sbrooksstatic void
961256752Sbrooksatse_init_locked(struct atse_softc *sc)
962256752Sbrooks{
963256752Sbrooks	struct ifnet *ifp;
964256752Sbrooks	struct mii_data *mii;
965256752Sbrooks	uint8_t *eaddr;
966256752Sbrooks
967256752Sbrooks	ATSE_LOCK_ASSERT(sc);
968256752Sbrooks	ifp = sc->atse_ifp;
969256752Sbrooks
970256752Sbrooks	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
971256752Sbrooks		return;
972256752Sbrooks
973256752Sbrooks	/*
974256752Sbrooks	 * Must update the ether address if changed.  Given we do not handle
975256752Sbrooks	 * in atse_ioctl() but it's in the general framework, just always
976256752Sbrooks	 * do it here before atse_reset().
977256752Sbrooks	 */
978256752Sbrooks	eaddr = IF_LLADDR(sc->atse_ifp);
979256752Sbrooks	bcopy(eaddr, &sc->atse_eth_addr, ETHER_ADDR_LEN);
980256752Sbrooks
981256752Sbrooks	/* Make things frind to halt, cleanup, ... */
982256752Sbrooks	atse_stop_locked(sc);
983256752Sbrooks	/* ... reset, ... */
984256752Sbrooks	atse_reset(sc);
985256752Sbrooks
986256752Sbrooks	/* ... and fire up the engine again. */
987256752Sbrooks	atse_rxfilter_locked(sc);
988256752Sbrooks
989256752Sbrooks	/* Memory rings?  DMA engine? */
990256752Sbrooks
991256752Sbrooks	sc->atse_rx_buf_len = 0;
992256752Sbrooks	sc->atse_flags &= ATSE_FLAGS_LINK;	/* Preserve. */
993256752Sbrooks
994256752Sbrooks#ifdef DEVICE_POLLING
995256752Sbrooks        /* Only enable interrupts if we are not polling. */
996256752Sbrooks	if (ifp->if_capenable & IFCAP_POLLING) {
997256752Sbrooks		ATSE_RX_INTR_DISABLE(sc);
998256752Sbrooks		ATSE_TX_INTR_DISABLE(sc);
999256752Sbrooks		ATSE_RX_EVENT_CLEAR(sc);
1000256752Sbrooks		ATSE_TX_EVENT_CLEAR(sc);
1001256752Sbrooks	} else
1002256752Sbrooks#endif
1003256752Sbrooks	{
1004256752Sbrooks		ATSE_RX_INTR_ENABLE(sc);
1005256752Sbrooks		ATSE_TX_INTR_ENABLE(sc);
1006256752Sbrooks	}
1007256752Sbrooks
1008256752Sbrooks	mii = device_get_softc(sc->atse_miibus);
1009256752Sbrooks
1010256752Sbrooks	sc->atse_flags &= ~ATSE_FLAGS_LINK;
1011256752Sbrooks	mii_mediachg(mii);
1012256752Sbrooks
1013256752Sbrooks	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1014256752Sbrooks	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1015256752Sbrooks
1016256752Sbrooks	callout_reset(&sc->atse_tick, hz, atse_tick, sc);
1017256752Sbrooks}
1018256752Sbrooks
1019256752Sbrooksstatic void
1020256752Sbrooksatse_init(void *xsc)
1021256752Sbrooks{
1022256752Sbrooks	struct atse_softc *sc;
1023256752Sbrooks
1024271969Sbz	/*
1025271969Sbz	 * XXXRW: There is some argument that we should immediately do RX
1026271969Sbz	 * processing after enabling interrupts, or one may not fire if there
1027271969Sbz	 * are buffered packets.
1028271969Sbz	 */
1029256752Sbrooks	sc = (struct atse_softc *)xsc;
1030256752Sbrooks	ATSE_LOCK(sc);
1031256752Sbrooks	atse_init_locked(sc);
1032256752Sbrooks	ATSE_UNLOCK(sc);
1033256752Sbrooks}
1034256752Sbrooks
1035256752Sbrooksstatic int
1036256752Sbrooksatse_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
1037256752Sbrooks{
1038256752Sbrooks	struct atse_softc *sc;
1039256752Sbrooks	struct ifreq *ifr;
1040256752Sbrooks	int error, mask;
1041256752Sbrooks
1042256752Sbrooks
1043256752Sbrooks	error = 0;
1044256752Sbrooks	sc = ifp->if_softc;
1045256752Sbrooks	ifr = (struct ifreq *)data;
1046256752Sbrooks
1047256752Sbrooks	switch (command) {
1048256752Sbrooks	case SIOCSIFFLAGS:
1049256752Sbrooks		ATSE_LOCK(sc);
1050256752Sbrooks		if (ifp->if_flags & IFF_UP) {
1051256752Sbrooks			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 &&
1052256752Sbrooks			    ((ifp->if_flags ^ sc->atse_if_flags) &
1053256752Sbrooks			    (IFF_PROMISC | IFF_ALLMULTI)) != 0)
1054256752Sbrooks				atse_rxfilter_locked(sc);
1055256752Sbrooks			else
1056256752Sbrooks				atse_init_locked(sc);
1057256752Sbrooks		} else if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1058256752Sbrooks			atse_stop_locked(sc);
1059256752Sbrooks                sc->atse_if_flags = ifp->if_flags;
1060256752Sbrooks		ATSE_UNLOCK(sc);
1061256752Sbrooks		break;
1062256752Sbrooks	case SIOCSIFCAP:
1063256752Sbrooks		ATSE_LOCK(sc);
1064256752Sbrooks		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1065256752Sbrooks#ifdef DEVICE_POLLING
1066256752Sbrooks		if ((mask & IFCAP_POLLING) != 0 &&
1067256752Sbrooks		    (IFCAP_POLLING & ifp->if_capabilities) != 0) {
1068256752Sbrooks			ifp->if_capenable ^= IFCAP_POLLING;
1069256752Sbrooks			if ((IFCAP_POLLING & ifp->if_capenable) != 0) {
1070256752Sbrooks
1071256752Sbrooks				error = ether_poll_register(atse_poll, ifp);
1072256752Sbrooks				if (error != 0) {
1073256752Sbrooks					ATSE_UNLOCK(sc);
1074256752Sbrooks					break;
1075256752Sbrooks				}
1076256752Sbrooks				/* Disable interrupts. */
1077256752Sbrooks				ATSE_RX_INTR_DISABLE(sc);
1078256752Sbrooks				ATSE_TX_INTR_DISABLE(sc);
1079256752Sbrooks				ATSE_RX_EVENT_CLEAR(sc);
1080256752Sbrooks				ATSE_TX_EVENT_CLEAR(sc);
1081256752Sbrooks
1082256752Sbrooks			/*
1083256752Sbrooks			 * Do not allow disabling of polling if we do
1084256752Sbrooks			 * not have interrupts.
1085256752Sbrooks			 */
1086256752Sbrooks			} else if (sc->atse_rx_irq_res != NULL ||
1087256752Sbrooks			    sc->atse_tx_irq_res != NULL) {
1088256752Sbrooks				error = ether_poll_deregister(ifp);
1089256752Sbrooks				/* Enable interrupts. */
1090256752Sbrooks				ATSE_RX_INTR_ENABLE(sc);
1091256752Sbrooks				ATSE_TX_INTR_ENABLE(sc);
1092256752Sbrooks			} else {
1093256752Sbrooks				ifp->if_capenable ^= IFCAP_POLLING;
1094256752Sbrooks				error = EINVAL;
1095256752Sbrooks			}
1096256752Sbrooks		}
1097256752Sbrooks#endif /* DEVICE_POLLING */
1098256752Sbrooks		ATSE_UNLOCK(sc);
1099256752Sbrooks		break;
1100256752Sbrooks	case SIOCADDMULTI:
1101256752Sbrooks	case SIOCDELMULTI:
1102256752Sbrooks		ATSE_LOCK(sc);
1103256752Sbrooks		atse_rxfilter_locked(sc);
1104256752Sbrooks		ATSE_UNLOCK(sc);
1105256752Sbrooks		break;
1106256752Sbrooks	case SIOCGIFMEDIA:
1107256752Sbrooks	case SIOCSIFMEDIA:
1108256752Sbrooks	{
1109256752Sbrooks		struct mii_data *mii;
1110256752Sbrooks		struct ifreq *ifr;
1111256752Sbrooks
1112256752Sbrooks		mii = device_get_softc(sc->atse_miibus);
1113256752Sbrooks		ifr = (struct ifreq *)data;
1114256752Sbrooks		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
1115256752Sbrooks		break;
1116256752Sbrooks	}
1117256752Sbrooks	default:
1118256752Sbrooks		error = ether_ioctl(ifp, command, data);
1119256752Sbrooks		break;
1120256752Sbrooks	}
1121256752Sbrooks
1122256752Sbrooks	return (error);
1123256752Sbrooks}
1124256752Sbrooks
1125256752Sbrooksstatic void
1126271969Sbzatse_intr_debug(struct atse_softc *sc, const char *intrname)
1127271969Sbz{
1128271969Sbz	uint32_t rxs, rxe, rxi, rxf, txs, txe, txi, txf;
1129271969Sbz
1130271969Sbz	if (!atse_intr_debug_enable)
1131271969Sbz		return;
1132271969Sbz
1133271969Sbz	rxs = ATSE_RX_STATUS_READ(sc);
1134271969Sbz	rxe = ATSE_RX_EVENT_READ(sc);
1135271969Sbz	rxi = ATSE_RX_INTR_READ(sc);
1136271969Sbz	rxf = ATSE_RX_READ_FILL_LEVEL(sc);
1137271969Sbz
1138271969Sbz	txs = ATSE_TX_STATUS_READ(sc);
1139271969Sbz	txe = ATSE_TX_EVENT_READ(sc);
1140271969Sbz	txi = ATSE_TX_INTR_READ(sc);
1141271969Sbz	txf = ATSE_TX_READ_FILL_LEVEL(sc);
1142271969Sbz
1143271969Sbz	printf(
1144271969Sbz	    "%s - %s: "
1145271969Sbz	    "rxs 0x%x rxe 0x%x rxi 0x%x rxf 0x%x "
1146271969Sbz	    "txs 0x%x txe 0x%x txi 0x%x txf 0x%x\n",
1147271969Sbz	    __func__, intrname,
1148271969Sbz	    rxs, rxe, rxi, rxf,
1149271969Sbz	    txs, txe, txi, txf);
1150271969Sbz}
1151271969Sbz
1152271969Sbzstatic void
1153256752Sbrooksatse_watchdog(struct atse_softc *sc)
1154256752Sbrooks{
1155256752Sbrooks
1156256752Sbrooks	ATSE_LOCK_ASSERT(sc);
1157256752Sbrooks
1158256752Sbrooks	if (sc->atse_watchdog_timer == 0 || --sc->atse_watchdog_timer > 0)
1159256752Sbrooks		return;
1160256752Sbrooks
1161256752Sbrooks	device_printf(sc->atse_dev, "watchdog timeout\n");
1162256752Sbrooks	sc->atse_ifp->if_oerrors++;
1163256752Sbrooks
1164271969Sbz	atse_intr_debug(sc, "poll");
1165271969Sbz
1166256752Sbrooks	sc->atse_ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1167256752Sbrooks	atse_init_locked(sc);
1168256752Sbrooks
1169271969Sbz	atse_rx_locked(sc);
1170256752Sbrooks	if (!IFQ_DRV_IS_EMPTY(&sc->atse_ifp->if_snd))
1171256752Sbrooks		atse_start_locked(sc->atse_ifp);
1172256752Sbrooks}
1173256752Sbrooks
1174256752Sbrooksstatic void
1175256752Sbrooksatse_tick(void *xsc)
1176256752Sbrooks{
1177256752Sbrooks	struct atse_softc *sc;
1178256752Sbrooks	struct mii_data *mii;
1179256752Sbrooks	struct ifnet *ifp;
1180256752Sbrooks
1181256752Sbrooks	sc = (struct atse_softc *)xsc;
1182256752Sbrooks	ATSE_LOCK_ASSERT(sc);
1183256752Sbrooks	ifp = sc->atse_ifp;
1184256752Sbrooks
1185256752Sbrooks	mii = device_get_softc(sc->atse_miibus);
1186256752Sbrooks	mii_tick(mii);
1187256752Sbrooks	atse_watchdog(sc);
1188256752Sbrooks	if ((sc->atse_flags & ATSE_FLAGS_LINK) == 0)
1189256752Sbrooks		atse_miibus_statchg(sc->atse_dev);
1190256752Sbrooks	callout_reset(&sc->atse_tick, hz, atse_tick, sc);
1191256752Sbrooks}
1192256752Sbrooks
1193256752Sbrooks/*
1194256752Sbrooks * Set media options.
1195256752Sbrooks */
1196256752Sbrooksstatic int
1197256752Sbrooksatse_ifmedia_upd(struct ifnet *ifp)
1198256752Sbrooks{
1199256752Sbrooks	struct atse_softc *sc;
1200256752Sbrooks	struct mii_data *mii;
1201256752Sbrooks	struct mii_softc *miisc;
1202256752Sbrooks	int error;
1203256752Sbrooks
1204256752Sbrooks	sc = ifp->if_softc;
1205256752Sbrooks
1206256752Sbrooks	ATSE_LOCK(sc);
1207256752Sbrooks	mii = device_get_softc(sc->atse_miibus);
1208256752Sbrooks	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
1209256752Sbrooks		PHY_RESET(miisc);
1210256752Sbrooks	error = mii_mediachg(mii);
1211256752Sbrooks	ATSE_UNLOCK(sc);
1212256752Sbrooks
1213256752Sbrooks	return (error);
1214256752Sbrooks}
1215256752Sbrooks
1216256752Sbrooksstatic void
1217256752Sbrooksatse_update_rx_err(struct atse_softc *sc, uint32_t mask)
1218256752Sbrooks{
1219256752Sbrooks	int i;
1220256752Sbrooks
1221256752Sbrooks	/* RX error are 6 bits, we only know 4 of them. */
1222256752Sbrooks	for (i = 0; i < ATSE_RX_ERR_MAX; i++)
1223256752Sbrooks		if ((mask & (1 << i)) != 0)
1224256752Sbrooks			sc->atse_rx_err[i]++;
1225256752Sbrooks}
1226256752Sbrooks
1227256752Sbrooksstatic int
1228256752Sbrooksatse_rx_locked(struct atse_softc *sc)
1229256752Sbrooks{
1230256752Sbrooks	struct ifnet *ifp;
1231256752Sbrooks	struct mbuf *m;
1232256752Sbrooks	uint32_t fill, i, j;
1233256752Sbrooks	uint32_t data, meta;
1234256752Sbrooks	int rx_npkts = 0;
1235256752Sbrooks
1236256752Sbrooks	ATSE_LOCK_ASSERT(sc);
1237256752Sbrooks
1238256752Sbrooks	ifp = sc->atse_ifp;
1239256752Sbrooks	j = 0;
1240256752Sbrooks	meta = 0;
1241256752Sbrooks	do {
1242256752Sbrooksouter:
1243256752Sbrooks		if (sc->atse_rx_m == NULL) {
1244256752Sbrooks			m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1245256752Sbrooks			if (m == NULL)
1246256752Sbrooks				return (rx_npkts);
1247256752Sbrooks			m->m_len = m->m_pkthdr.len = MCLBYTES;
1248256752Sbrooks			/* Make sure upper layers will be aligned. */
1249270059Sbz			m_adj(m, ETHER_ALIGN);
1250256752Sbrooks			sc->atse_rx_m = m;
1251256752Sbrooks		}
1252256752Sbrooks
1253256752Sbrooks		fill = ATSE_RX_READ_FILL_LEVEL(sc);
1254256752Sbrooks		for (i = 0; i < fill; i++) {
1255256752Sbrooks			/*
1256256752Sbrooks			 * XXX-BZ for whatever reason the FIFO requires the
1257256752Sbrooks			 * the data read before we can access the meta data.
1258256752Sbrooks			 */
1259256752Sbrooks			data = ATSE_RX_DATA_READ(sc);
1260256752Sbrooks			meta = ATSE_RX_META_READ(sc);
1261256752Sbrooks			if (meta & A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) {
1262256752Sbrooks				/* XXX-BZ evaluate error. */
1263256752Sbrooks				atse_update_rx_err(sc, ((meta &
1264256752Sbrooks				    A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) >>
1265256752Sbrooks				    A_ONCHIP_FIFO_MEM_CORE_ERROR_SHIFT) & 0xff);
1266256752Sbrooks				ifp->if_ierrors++;
1267256752Sbrooks				sc->atse_rx_buf_len = 0;
1268256752Sbrooks				/*
1269256752Sbrooks				 * Should still read till EOP or next SOP.
1270256752Sbrooks				 *
1271256752Sbrooks				 * XXX-BZ might also depend on
1272256752Sbrooks				 * BASE_CFG_COMMAND_CONFIG_RX_ERR_DISC
1273256752Sbrooks				 */
1274256752Sbrooks				sc->atse_flags |= ATSE_FLAGS_ERROR;
1275256752Sbrooks				return (rx_npkts);
1276256752Sbrooks			}
1277256752Sbrooks			if ((meta & A_ONCHIP_FIFO_MEM_CORE_CHANNEL_MASK) != 0)
1278256752Sbrooks				device_printf(sc->atse_dev, "%s: unexpected "
1279256752Sbrooks				    "channel %u\n", __func__, (meta &
1280256752Sbrooks				    A_ONCHIP_FIFO_MEM_CORE_CHANNEL_MASK) >>
1281256752Sbrooks				    A_ONCHIP_FIFO_MEM_CORE_CHANNEL_SHIFT);
1282256752Sbrooks
1283256752Sbrooks			if (meta & A_ONCHIP_FIFO_MEM_CORE_SOP) {
1284256752Sbrooks				/*
1285256752Sbrooks				 * There is no need to clear SOP between 1st
1286256752Sbrooks				 * and subsequent packet data junks.
1287256752Sbrooks				 */
1288256752Sbrooks				if (sc->atse_rx_buf_len != 0 &&
1289256752Sbrooks				    (sc->atse_flags & ATSE_FLAGS_SOP_SEEN) == 0)
1290256752Sbrooks				{
1291256752Sbrooks					device_printf(sc->atse_dev, "%s: SOP "
1292256752Sbrooks					    "without empty buffer: %u\n",
1293256752Sbrooks					    __func__, sc->atse_rx_buf_len);
1294256752Sbrooks					/* XXX-BZ any better counter? */
1295256752Sbrooks					ifp->if_ierrors++;
1296256752Sbrooks				}
1297256752Sbrooks
1298256752Sbrooks				if ((sc->atse_flags & ATSE_FLAGS_SOP_SEEN) == 0)
1299256752Sbrooks				{
1300256752Sbrooks					sc->atse_flags |= ATSE_FLAGS_SOP_SEEN;
1301256752Sbrooks					sc->atse_rx_buf_len = 0;
1302256752Sbrooks				}
1303256752Sbrooks			}
1304256752Sbrooks#if 0 /* We had to read the data before we could access meta data. See above. */
1305256752Sbrooks			data = ATSE_RX_DATA_READ(sc);
1306256752Sbrooks#endif
1307256752Sbrooks			/* Make sure to not overflow the mbuf data size. */
1308271969Sbz			if (sc->atse_rx_buf_len >= sc->atse_rx_m->m_len -
1309271969Sbz			    sizeof(data)) {
1310256752Sbrooks				/*
1311256752Sbrooks				 * XXX-BZ Error.  We need more mbufs and are
1312256752Sbrooks				 * not setup for this yet.
1313256752Sbrooks				 */
1314256752Sbrooks				ifp->if_ierrors++;
1315256752Sbrooks				sc->atse_flags |= ATSE_FLAGS_ERROR;
1316256752Sbrooks			}
1317256752Sbrooks			if ((sc->atse_flags & ATSE_FLAGS_ERROR) == 0)
1318256752Sbrooks				/*
1319256752Sbrooks				 * MUST keep this bcopy as m_data after m_adj
1320256752Sbrooks				 * for IP header aligment is on half-word
1321256752Sbrooks				 * and not word alignment.
1322256752Sbrooks				 */
1323256752Sbrooks				bcopy(&data, (uint8_t *)(sc->atse_rx_m->m_data +
1324256752Sbrooks				    sc->atse_rx_buf_len), sizeof(data));
1325256752Sbrooks			if (meta & A_ONCHIP_FIFO_MEM_CORE_EOP) {
1326256752Sbrooks				uint8_t empty;
1327256752Sbrooks
1328256752Sbrooks				empty = (meta &
1329256752Sbrooks				    A_ONCHIP_FIFO_MEM_CORE_EMPTY_MASK) >>
1330256752Sbrooks				    A_ONCHIP_FIFO_MEM_CORE_EMPTY_SHIFT;
1331256752Sbrooks				sc->atse_rx_buf_len += (4 - empty);
1332256752Sbrooks
1333256752Sbrooks				ifp->if_ipackets++;
1334256752Sbrooks				rx_npkts++;
1335256752Sbrooks
1336256752Sbrooks				m = sc->atse_rx_m;
1337256752Sbrooks				m->m_pkthdr.len = m->m_len =
1338256752Sbrooks				    sc->atse_rx_buf_len;
1339256752Sbrooks				sc->atse_rx_m = NULL;
1340256752Sbrooks
1341256752Sbrooks				sc->atse_rx_buf_len = 0;
1342256752Sbrooks				sc->atse_flags &= ~ATSE_FLAGS_SOP_SEEN;
1343256752Sbrooks				if (sc->atse_flags & ATSE_FLAGS_ERROR) {
1344256752Sbrooks					sc->atse_flags &= ~ATSE_FLAGS_ERROR;
1345256752Sbrooks					m_freem(m);
1346271969Sbz				} else {
1347271969Sbz					m->m_pkthdr.rcvif = ifp;
1348271969Sbz					ATSE_UNLOCK(sc);
1349271969Sbz					(*ifp->if_input)(ifp, m);
1350271969Sbz					ATSE_LOCK(sc);
1351256752Sbrooks				}
1352271969Sbz#ifdef DEVICE_POLLING
1353271969Sbz				if (ifp->if_capenable & IFCAP_POLLING) {
1354271969Sbz					if (sc->atse_rx_cycles <= 0)
1355271969Sbz						return (rx_npkts);
1356271969Sbz					sc->atse_rx_cycles--;
1357271969Sbz				}
1358271969Sbz#endif
1359256752Sbrooks				goto outer;	/* Need a new mbuf. */
1360256752Sbrooks			} else {
1361256752Sbrooks				sc->atse_rx_buf_len += sizeof(data);
1362256752Sbrooks			}
1363256752Sbrooks		} /* for */
1364256752Sbrooks
1365256752Sbrooks	/* XXX-BZ could optimize in case of another packet waiting. */
1366271969Sbz	} while (fill > 0);
1367256752Sbrooks
1368256752Sbrooks	return (rx_npkts);
1369256752Sbrooks}
1370256752Sbrooks
1371256752Sbrooks
1372256752Sbrooks/*
1373256752Sbrooks * Report current media status.
1374256752Sbrooks */
1375256752Sbrooksstatic void
1376256752Sbrooksatse_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
1377256752Sbrooks{
1378256752Sbrooks	struct atse_softc *sc;
1379256752Sbrooks	struct mii_data *mii;
1380256752Sbrooks
1381256752Sbrooks	sc = ifp->if_softc;
1382256752Sbrooks
1383256752Sbrooks	ATSE_LOCK(sc);
1384256752Sbrooks	mii = device_get_softc(sc->atse_miibus);
1385256752Sbrooks	mii_pollstat(mii);
1386256752Sbrooks	ifmr->ifm_active = mii->mii_media_active;
1387256752Sbrooks	ifmr->ifm_status = mii->mii_media_status;
1388256752Sbrooks	ATSE_UNLOCK(sc);
1389256752Sbrooks}
1390256752Sbrooks
1391256752Sbrooksstatic void
1392271969Sbzatse_rx_intr(void *arg)
1393256752Sbrooks{
1394256752Sbrooks	struct atse_softc *sc;
1395256752Sbrooks	struct ifnet *ifp;
1396271969Sbz	uint32_t rxe;
1397256752Sbrooks
1398256752Sbrooks	sc = (struct atse_softc *)arg;
1399256752Sbrooks	ifp = sc->atse_ifp;
1400256752Sbrooks
1401256752Sbrooks	ATSE_LOCK(sc);
1402256752Sbrooks#ifdef DEVICE_POLLING
1403256752Sbrooks	if (ifp->if_capenable & IFCAP_POLLING) {
1404256752Sbrooks		ATSE_UNLOCK(sc);
1405256752Sbrooks		return;
1406256752Sbrooks	}
1407256752Sbrooks#endif
1408256752Sbrooks
1409271969Sbz	atse_intr_debug(sc, "rx");
1410271969Sbz	rxe = ATSE_RX_EVENT_READ(sc);
1411271969Sbz	if (rxe & (A_ONCHIP_FIFO_MEM_CORE_EVENT_OVERFLOW|
1412271969Sbz	    A_ONCHIP_FIFO_MEM_CORE_EVENT_UNDERFLOW)) {
1413271969Sbz		/* XXX-BZ ERROR HANDLING. */
1414271969Sbz		atse_update_rx_err(sc, ((rxe &
1415271969Sbz		    A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) >>
1416271969Sbz		    A_ONCHIP_FIFO_MEM_CORE_ERROR_SHIFT) & 0xff);
1417271969Sbz		ifp->if_ierrors++;
1418271969Sbz	}
1419256752Sbrooks
1420271969Sbz	/*
1421271969Sbz	 * There is considerable subtlety in the race-free handling of rx
1422271969Sbz	 * interrupts: we must disable interrupts whenever we manipulate the
1423271969Sbz	 * FIFO to prevent further interrupts from firing before we are done;
1424271969Sbz	 * we must clear the event after processing to prevent the event from
1425271969Sbz	 * being immediately reposted due to data remaining; we must clear the
1426271969Sbz	 * event mask before reenabling interrupts or risk missing a positive
1427271969Sbz	 * edge; and we must recheck everything after completing in case the
1428271969Sbz	 * event posted between clearing events and reenabling interrupts.  If
1429271969Sbz	 * a race is experienced, we must restart the whole mechanism.
1430271969Sbz	 */
1431271969Sbz	do {
1432271969Sbz		ATSE_RX_INTR_DISABLE(sc);
1433256752Sbrooks#if 0
1434271969Sbz		sc->atse_rx_cycles = RX_CYCLES_IN_INTR;
1435256752Sbrooks#endif
1436271969Sbz		atse_rx_locked(sc);
1437271969Sbz		ATSE_RX_EVENT_CLEAR(sc);
1438256752Sbrooks
1439271969Sbz		/* Disable interrupts if interface is down. */
1440271969Sbz		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1441271969Sbz			ATSE_RX_INTR_ENABLE(sc);
1442271969Sbz	} while (!(ATSE_RX_STATUS_READ(sc) &
1443271969Sbz	    A_ONCHIP_FIFO_MEM_CORE_STATUS_EMPTY));
1444271969Sbz	ATSE_UNLOCK(sc);
1445256752Sbrooks
1446271969Sbz}
1447256752Sbrooks
1448271969Sbzstatic void
1449271969Sbzatse_tx_intr(void *arg)
1450271969Sbz{
1451271969Sbz	struct atse_softc *sc;
1452271969Sbz	struct ifnet *ifp;
1453271969Sbz	uint32_t txe;
1454271969Sbz
1455271969Sbz	sc = (struct atse_softc *)arg;
1456271969Sbz	ifp = sc->atse_ifp;
1457271969Sbz
1458271969Sbz	ATSE_LOCK(sc);
1459271969Sbz#ifdef DEVICE_POLLING
1460271969Sbz	if (ifp->if_capenable & IFCAP_POLLING) {
1461271969Sbz		ATSE_UNLOCK(sc);
1462271969Sbz		return;
1463271969Sbz	}
1464271969Sbz#endif
1465271969Sbz
1466271969Sbz	/* XXX-BZ build histogram. */
1467271969Sbz	atse_intr_debug(sc, "tx");
1468271969Sbz	txe = ATSE_TX_EVENT_READ(sc);
1469271969Sbz	if (txe & (A_ONCHIP_FIFO_MEM_CORE_EVENT_OVERFLOW|
1470271969Sbz	    A_ONCHIP_FIFO_MEM_CORE_EVENT_UNDERFLOW)) {
1471271969Sbz		/* XXX-BZ ERROR HANDLING. */
1472271969Sbz		ifp->if_oerrors++;
1473256752Sbrooks	}
1474256752Sbrooks
1475271969Sbz	/*
1476271969Sbz	 * There is also considerable subtlety in the race-free handling of
1477271969Sbz	 * tx interrupts: all processing occurs with interrupts disabled to
1478271969Sbz	 * prevent spurious refiring while transmit is in progress (which
1479271969Sbz	 * could occur if the FIFO drains while sending -- quite likely); we
1480271969Sbz	 * must not clear the event mask until after we've sent, also to
1481271969Sbz	 * prevent spurious refiring; once we've cleared the event mask we can
1482271969Sbz	 * reenable interrupts, but there is a possible race between clear and
1483271969Sbz	 * enable, so we must recheck and potentially repeat the whole process
1484271969Sbz	 * if it is detected.
1485271969Sbz	 */
1486271969Sbz	do {
1487271969Sbz		ATSE_TX_INTR_DISABLE(sc);
1488271969Sbz		sc->atse_watchdog_timer = 0;
1489271969Sbz		atse_start_locked(ifp);
1490271969Sbz		ATSE_TX_EVENT_CLEAR(sc);
1491271969Sbz
1492271969Sbz		/* Disable interrupts if interface is down. */
1493271969Sbz		if (ifp->if_drv_flags & IFF_DRV_RUNNING)
1494271969Sbz			ATSE_TX_INTR_ENABLE(sc);
1495271969Sbz	} while (ATSE_TX_PENDING(sc) &&
1496271969Sbz	    !(ATSE_TX_STATUS_READ(sc) & A_ONCHIP_FIFO_MEM_CORE_STATUS_FULL));
1497256752Sbrooks	ATSE_UNLOCK(sc);
1498256752Sbrooks}
1499256752Sbrooks
1500256752Sbrooks#ifdef DEVICE_POLLING
1501256752Sbrooksstatic int
1502256752Sbrooksatse_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1503256752Sbrooks{
1504256752Sbrooks	struct atse_softc *sc;
1505256752Sbrooks	int rx_npkts = 0;
1506256752Sbrooks
1507256752Sbrooks	sc = ifp->if_softc;
1508256752Sbrooks	ATSE_LOCK(sc);
1509256752Sbrooks	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
1510256752Sbrooks		ATSE_UNLOCK(sc);
1511256752Sbrooks		return (rx_npkts);
1512256752Sbrooks	}
1513256752Sbrooks
1514256752Sbrooks	sc->atse_rx_cycles = count;
1515256752Sbrooks	rx_npkts = atse_rx_locked(sc);
1516256752Sbrooks	atse_start_locked(ifp);
1517256752Sbrooks
1518256752Sbrooks	if (sc->atse_rx_cycles > 0 || cmd == POLL_AND_CHECK_STATUS) {
1519256752Sbrooks		uint32_t rx, tx;
1520256752Sbrooks
1521256752Sbrooks		rx = ATSE_RX_EVENT_READ(sc);
1522256752Sbrooks		tx = ATSE_TX_EVENT_READ(sc);
1523256752Sbrooks
1524256752Sbrooks		if (rx & (A_ONCHIP_FIFO_MEM_CORE_EVENT_OVERFLOW|
1525256752Sbrooks		    A_ONCHIP_FIFO_MEM_CORE_EVENT_UNDERFLOW)) {
1526256752Sbrooks			/* XXX-BZ ERROR HANDLING. */
1527256752Sbrooks			atse_update_rx_err(sc, ((rx &
1528256752Sbrooks			    A_ONCHIP_FIFO_MEM_CORE_ERROR_MASK) >>
1529256752Sbrooks			    A_ONCHIP_FIFO_MEM_CORE_ERROR_SHIFT) & 0xff);
1530256752Sbrooks			ifp->if_ierrors++;
1531256752Sbrooks		}
1532256752Sbrooks		if (tx & (A_ONCHIP_FIFO_MEM_CORE_EVENT_OVERFLOW|
1533256752Sbrooks		    A_ONCHIP_FIFO_MEM_CORE_EVENT_UNDERFLOW)) {
1534256752Sbrooks			/* XXX-BZ ERROR HANDLING. */
1535256752Sbrooks			ifp->if_oerrors++;
1536256752Sbrooks		}
1537271969Sbz		if (ATSE_TX_READ_FILL_LEVEL(sc) == 0)
1538256752Sbrooks			sc->atse_watchdog_timer = 0;
1539256752Sbrooks
1540256752Sbrooks#if 0
1541256752Sbrooks		if (/* Severe error; if only we could find out. */) {
1542256752Sbrooks			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1543256752Sbrooks			atse_init_locked(sc);
1544256752Sbrooks		}
1545256752Sbrooks#endif
1546256752Sbrooks	}
1547256752Sbrooks
1548256752Sbrooks	ATSE_UNLOCK(sc);
1549256752Sbrooks	return (rx_npkts);
1550256752Sbrooks}
1551256752Sbrooks#endif /* DEVICE_POLLING */
1552256752Sbrooks
1553256752Sbrooksstatic struct atse_mac_stats_regs {
1554256752Sbrooks	const char *name;
1555256752Sbrooks	const char *descr;	/* Mostly copied from Altera datasheet. */
1556256752Sbrooks} atse_mac_stats_regs[] = {
1557256752Sbrooks	[0x1a] =
1558256752Sbrooks	{ "aFramesTransmittedOK",
1559256752Sbrooks	    "The number of frames that are successfully transmitted including "
1560256752Sbrooks	    "the pause frames." },
1561256752Sbrooks	{ "aFramesReceivedOK",
1562256752Sbrooks	    "The number of frames that are successfully received including the "
1563256752Sbrooks	    "pause frames." },
1564256752Sbrooks	{ "aFrameCheckSequenceErrors",
1565256752Sbrooks	    "The number of receive frames with CRC error." },
1566256752Sbrooks	{ "aAlignmentErrors",
1567256752Sbrooks	    "The number of receive frames with alignment error." },
1568256752Sbrooks	{ "aOctetsTransmittedOK",
1569256752Sbrooks	    "The lower 32 bits of the number of data and padding octets that "
1570256752Sbrooks	    "are successfully transmitted." },
1571256752Sbrooks	{ "aOctetsReceivedOK",
1572256752Sbrooks	    "The lower 32 bits of the number of data and padding octets that "
1573256752Sbrooks	    " are successfully received." },
1574256752Sbrooks	{ "aTxPAUSEMACCtrlFrames",
1575256752Sbrooks	    "The number of pause frames transmitted." },
1576256752Sbrooks	{ "aRxPAUSEMACCtrlFrames",
1577256752Sbrooks	    "The number received pause frames received." },
1578256752Sbrooks	{ "ifInErrors",
1579256752Sbrooks	    "The number of errored frames received." },
1580256752Sbrooks	{ "ifOutErrors",
1581256752Sbrooks	    "The number of transmit frames with either a FIFO overflow error, "
1582256752Sbrooks	    "a FIFO underflow error, or a error defined by the user "
1583256752Sbrooks	    "application." },
1584256752Sbrooks	{ "ifInUcastPkts",
1585256752Sbrooks	    "The number of valid unicast frames received." },
1586256752Sbrooks	{ "ifInMulticastPkts",
1587256752Sbrooks	    "The number of valid multicast frames received. The count does "
1588256752Sbrooks	    "not include pause frames." },
1589256752Sbrooks	{ "ifInBroadcastPkts",
1590256752Sbrooks	    "The number of valid broadcast frames received." },
1591256752Sbrooks	{ "ifOutDiscards",
1592256752Sbrooks	    "This statistics counter is not in use.  The MAC function does not "
1593256752Sbrooks	    "discard frames that are written to the FIFO buffer by the user "
1594256752Sbrooks	    "application." },
1595256752Sbrooks	{ "ifOutUcastPkts",
1596256752Sbrooks	    "The number of valid unicast frames transmitted." },
1597256752Sbrooks	{ "ifOutMulticastPkts",
1598256752Sbrooks	    "The number of valid multicast frames transmitted, excluding pause "
1599256752Sbrooks	    "frames." },
1600256752Sbrooks	{ "ifOutBroadcastPkts",
1601256752Sbrooks	    "The number of valid broadcast frames transmitted." },
1602256752Sbrooks	{ "etherStatsDropEvents",
1603256752Sbrooks	    "The number of frames that are dropped due to MAC internal errors "
1604256752Sbrooks	    "when FIFO buffer overflow persists." },
1605256752Sbrooks	{ "etherStatsOctets",
1606256752Sbrooks	    "The lower 32 bits of the total number of octets received. This "
1607256752Sbrooks	    "count includes both good and errored frames." },
1608256752Sbrooks	{ "etherStatsPkts",
1609256752Sbrooks	    "The total number of good and errored frames received." },
1610256752Sbrooks	{ "etherStatsUndersizePkts",
1611256752Sbrooks	    "The number of frames received with length less than 64 bytes. "
1612256752Sbrooks	    "This count does not include errored frames." },
1613256752Sbrooks	{ "etherStatsOversizePkts",
1614256752Sbrooks	    "The number of frames received that are longer than the value "
1615256752Sbrooks	    "configured in the frm_length register. This count does not "
1616256752Sbrooks	    "include errored frames." },
1617256752Sbrooks	{ "etherStatsPkts64Octets",
1618256752Sbrooks	    "The number of 64-byte frames received. This count includes good "
1619256752Sbrooks	    "and errored frames." },
1620256752Sbrooks	{ "etherStatsPkts65to127Octets",
1621256752Sbrooks	    "The number of received good and errored frames between the length "
1622256752Sbrooks	    "of 65 and 127 bytes." },
1623256752Sbrooks	{ "etherStatsPkts128to255Octets",
1624256752Sbrooks	    "The number of received good and errored frames between the length "
1625256752Sbrooks	    "of 128 and 255 bytes." },
1626256752Sbrooks	{ "etherStatsPkts256to511Octets",
1627256752Sbrooks	    "The number of received good and errored frames between the length "
1628256752Sbrooks	    "of 256 and 511 bytes." },
1629256752Sbrooks	{ "etherStatsPkts512to1023Octets",
1630256752Sbrooks	    "The number of received good and errored frames between the length "
1631256752Sbrooks	    "of 512 and 1023 bytes." },
1632256752Sbrooks	{ "etherStatsPkts1024to1518Octets",
1633256752Sbrooks	    "The number of received good and errored frames between the length "
1634256752Sbrooks	    "of 1024 and 1518 bytes." },
1635256752Sbrooks	{ "etherStatsPkts1519toXOctets",
1636256752Sbrooks	    "The number of received good and errored frames between the length "
1637256752Sbrooks	    "of 1519 and the maximum frame length configured in the frm_length "
1638256752Sbrooks	    "register." },
1639256752Sbrooks	{ "etherStatsJabbers",
1640256752Sbrooks	    "Too long frames with CRC error." },
1641256752Sbrooks	{ "etherStatsFragments",
1642256752Sbrooks	    "Too short frames with CRC error." },
1643256752Sbrooks	/* 0x39 unused, 0x3a/b non-stats. */
1644256752Sbrooks	[0x3c] =
1645256752Sbrooks	/* Extended Statistics Counters */
1646256752Sbrooks	{ "msb_aOctetsTransmittedOK",
1647256752Sbrooks	    "Upper 32 bits of the number of data and padding octets that are "
1648256752Sbrooks	    "successfully transmitted." },
1649256752Sbrooks	{ "msb_aOctetsReceivedOK",
1650256752Sbrooks	    "Upper 32 bits of the number of data and padding octets that are "
1651256752Sbrooks	    "successfully received." },
1652256752Sbrooks	{ "msb_etherStatsOctets",
1653256752Sbrooks	    "Upper 32 bits of the total number of octets received. This count "
1654256752Sbrooks	    "includes both good and errored frames." }
1655256752Sbrooks};
1656256752Sbrooks
1657256752Sbrooksstatic int
1658256752Sbrookssysctl_atse_mac_stats_proc(SYSCTL_HANDLER_ARGS)
1659256752Sbrooks{
1660256752Sbrooks	struct atse_softc *sc;
1661256752Sbrooks        int error, offset, s;
1662256752Sbrooks
1663256752Sbrooks        sc = arg1;
1664256752Sbrooks	offset = arg2;
1665256752Sbrooks
1666256752Sbrooks	s = CSR_READ_4(sc, offset);
1667256752Sbrooks	error = sysctl_handle_int(oidp, &s, 0, req);
1668256752Sbrooks	if (error || !req->newptr)
1669256752Sbrooks		return (error);
1670256752Sbrooks
1671256752Sbrooks        return (0);
1672256752Sbrooks}
1673256752Sbrooks
1674256752Sbrooksstatic struct atse_rx_err_stats_regs {
1675256752Sbrooks	const char *name;
1676256752Sbrooks	const char *descr;
1677256752Sbrooks} atse_rx_err_stats_regs[] = {
1678256752Sbrooks
1679256752Sbrooks#define ATSE_RX_ERR_FIFO_THRES_EOP      0 /* FIFO threshold reached, on EOP. */
1680256752Sbrooks#define ATSE_RX_ERR_ELEN                1 /* Frame/payload length not valid. */
1681256752Sbrooks#define ATSE_RX_ERR_CRC32               2 /* CRC-32 error. */
1682256752Sbrooks#define ATSE_RX_ERR_FIFO_THRES_TRUNC    3 /* FIFO thresh., truncated frame. */
1683256752Sbrooks#define ATSE_RX_ERR_4                   4 /* ? */
1684256752Sbrooks#define ATSE_RX_ERR_5                   5 /* / */
1685256752Sbrooks
1686256752Sbrooks	{ "rx_err_fifo_thres_eop",
1687256752Sbrooks	    "FIFO threshold reached, reported on EOP." },
1688256752Sbrooks	{ "rx_err_fifo_elen",
1689256752Sbrooks	    "Frame or payload length not valid." },
1690256752Sbrooks	{ "rx_err_fifo_crc32",
1691256752Sbrooks	    "CRC-32 error." },
1692256752Sbrooks	{ "rx_err_fifo_thres_trunc",
1693256752Sbrooks	    "FIFO threshold reached, truncated frame" },
1694256752Sbrooks	{ "rx_err_4",
1695256752Sbrooks	    "?" },
1696256752Sbrooks	{ "rx_err_5",
1697256752Sbrooks	    "?" },
1698256752Sbrooks};
1699256752Sbrooks
1700256752Sbrooksstatic int
1701256752Sbrookssysctl_atse_rx_err_stats_proc(SYSCTL_HANDLER_ARGS)
1702256752Sbrooks{
1703256752Sbrooks	struct atse_softc *sc;
1704256752Sbrooks        int error, offset, s;
1705256752Sbrooks
1706256752Sbrooks        sc = arg1;
1707256752Sbrooks	offset = arg2;
1708256752Sbrooks
1709256752Sbrooks	s = sc->atse_rx_err[offset];
1710256752Sbrooks	error = sysctl_handle_int(oidp, &s, 0, req);
1711256752Sbrooks	if (error || !req->newptr)
1712256752Sbrooks		return (error);
1713256752Sbrooks
1714256752Sbrooks        return (0);
1715256752Sbrooks}
1716256752Sbrooks
1717256752Sbrooksstatic void
1718256752Sbrooksatse_sysctl_stats_attach(device_t dev)
1719256752Sbrooks{
1720256752Sbrooks	struct sysctl_ctx_list *sctx;
1721256752Sbrooks	struct sysctl_oid *soid;
1722256752Sbrooks	struct atse_softc *sc;
1723256752Sbrooks	int i;
1724256752Sbrooks
1725256752Sbrooks	sc = device_get_softc(dev);
1726256752Sbrooks        sctx = device_get_sysctl_ctx(dev);
1727256752Sbrooks        soid = device_get_sysctl_tree(dev);
1728256752Sbrooks
1729256752Sbrooks	/* MAC statistics. */
1730256752Sbrooks	for (i = 0; i < sizeof(atse_mac_stats_regs) /
1731256752Sbrooks	    sizeof(*atse_mac_stats_regs); i++) {
1732256752Sbrooks		if (atse_mac_stats_regs[i].name == NULL ||
1733256752Sbrooks		    atse_mac_stats_regs[i].descr == NULL)
1734256752Sbrooks			continue;
1735256752Sbrooks
1736256752Sbrooks		SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO,
1737256752Sbrooks		    atse_mac_stats_regs[i].name, CTLTYPE_UINT|CTLFLAG_RD,
1738256752Sbrooks		    sc, i, sysctl_atse_mac_stats_proc, "IU",
1739256752Sbrooks		    atse_mac_stats_regs[i].descr);
1740256752Sbrooks	}
1741256752Sbrooks
1742256752Sbrooks	/* rx_err[]. */
1743256752Sbrooks	for (i = 0; i < ATSE_RX_ERR_MAX; i++) {
1744256752Sbrooks		if (atse_rx_err_stats_regs[i].name == NULL ||
1745256752Sbrooks		    atse_rx_err_stats_regs[i].descr == NULL)
1746256752Sbrooks			continue;
1747256752Sbrooks
1748256752Sbrooks		SYSCTL_ADD_PROC(sctx, SYSCTL_CHILDREN(soid), OID_AUTO,
1749256752Sbrooks		    atse_rx_err_stats_regs[i].name, CTLTYPE_UINT|CTLFLAG_RD,
1750256752Sbrooks		    sc, i, sysctl_atse_rx_err_stats_proc, "IU",
1751256752Sbrooks		    atse_rx_err_stats_regs[i].descr);
1752256752Sbrooks	}
1753256752Sbrooks}
1754256752Sbrooks
1755256752Sbrooks/*
1756256752Sbrooks * Generic device handling routines.
1757256752Sbrooks */
1758256752Sbrooksint
1759256752Sbrooksatse_attach(device_t dev)
1760256752Sbrooks{
1761256752Sbrooks	struct atse_softc *sc;
1762256752Sbrooks	struct ifnet *ifp;
1763256752Sbrooks	int error;
1764256752Sbrooks
1765256752Sbrooks	sc = device_get_softc(dev);
1766256752Sbrooks
1767256752Sbrooks	atse_ethernet_option_bits_read(dev);
1768256752Sbrooks
1769256752Sbrooks	mtx_init(&sc->atse_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
1770256752Sbrooks	    MTX_DEF);
1771256752Sbrooks
1772256752Sbrooks	callout_init_mtx(&sc->atse_tick, &sc->atse_mtx, 0);
1773256752Sbrooks
1774256752Sbrooks	sc->atse_tx_buf = malloc(ETHER_MAX_LEN_JUMBO, M_DEVBUF, M_WAITOK);
1775256752Sbrooks
1776256752Sbrooks	/*
1777256752Sbrooks	 * We are only doing single-PHY with this driver currently.  The
1778256752Sbrooks	 * defaults would be right so that BASE_CFG_MDIO_ADDR0 points to the
1779256752Sbrooks	 * 1st PHY address (0) apart from the fact that BMCR0 is always
1780256752Sbrooks	 * the PCS mapping, so we always use BMCR1. See Table 5-1 0xA0-0xBF.
1781256752Sbrooks	 */
1782256752Sbrooks#if 0	/* Always PCS. */
1783256752Sbrooks	sc->atse_bmcr0 = MDIO_0_START;
1784256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_MDIO_ADDR0, 0x00);
1785256752Sbrooks#endif
1786256752Sbrooks	/* Always use matching PHY for atse[0..]. */
1787256752Sbrooks	sc->atse_phy_addr = device_get_unit(dev);
1788256752Sbrooks	sc->atse_bmcr1 = MDIO_1_START;
1789256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_MDIO_ADDR1, sc->atse_phy_addr);
1790256752Sbrooks
1791256752Sbrooks	/* Reset the adapter. */
1792256752Sbrooks	atse_reset(sc);
1793256752Sbrooks
1794256752Sbrooks	/* Setup interface. */
1795256752Sbrooks	ifp = sc->atse_ifp = if_alloc(IFT_ETHER);
1796256752Sbrooks	if (ifp == NULL) {
1797256752Sbrooks		device_printf(dev, "if_alloc() failed\n");
1798256752Sbrooks		error = ENOSPC;
1799256752Sbrooks		goto err;
1800256752Sbrooks	}
1801256752Sbrooks	ifp->if_softc = sc;
1802256752Sbrooks	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1803256752Sbrooks	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
1804256752Sbrooks	ifp->if_ioctl = atse_ioctl;
1805256752Sbrooks	ifp->if_start = atse_start;
1806256752Sbrooks	ifp->if_init = atse_init;
1807256752Sbrooks	IFQ_SET_MAXLEN(&ifp->if_snd, ATSE_TX_LIST_CNT - 1);
1808256752Sbrooks	ifp->if_snd.ifq_drv_maxlen = ATSE_TX_LIST_CNT - 1;
1809256752Sbrooks	IFQ_SET_READY(&ifp->if_snd);
1810256752Sbrooks
1811256752Sbrooks	/* MII setup. */
1812256752Sbrooks	error = mii_attach(dev, &sc->atse_miibus, ifp, atse_ifmedia_upd,
1813256752Sbrooks	    atse_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0);
1814256752Sbrooks	if (error != 0) {
1815256752Sbrooks		device_printf(dev, "attaching PHY failed: %d\n", error);
1816256752Sbrooks		goto err;
1817256752Sbrooks	}
1818256752Sbrooks
1819256752Sbrooks	/* Call media-indepedent attach routine. */
1820256752Sbrooks	ether_ifattach(ifp, sc->atse_eth_addr);
1821256752Sbrooks
1822256752Sbrooks	/* Tell the upper layer(s) about vlan mtu support. */
1823256752Sbrooks	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
1824256752Sbrooks	ifp->if_capabilities |= IFCAP_VLAN_MTU;
1825256752Sbrooks	ifp->if_capenable = ifp->if_capabilities;
1826256752Sbrooks#ifdef DEVICE_POLLING
1827256752Sbrooks	/* We will enable polling by default if no irqs available. See below. */
1828256752Sbrooks	ifp->if_capabilities |= IFCAP_POLLING;
1829256752Sbrooks#endif
1830256752Sbrooks
1831256752Sbrooks	/* Hook up interrupts. */
1832256752Sbrooks	if (sc->atse_rx_irq_res != NULL) {
1833256752Sbrooks		error = bus_setup_intr(dev, sc->atse_rx_irq_res, INTR_TYPE_NET |
1834271969Sbz		    INTR_MPSAFE, NULL, atse_rx_intr, sc, &sc->atse_rx_intrhand);
1835256752Sbrooks		if (error != 0) {
1836256752Sbrooks			device_printf(dev, "enabling RX IRQ failed\n");
1837256752Sbrooks			ether_ifdetach(ifp);
1838256752Sbrooks			goto err;
1839256752Sbrooks		}
1840256752Sbrooks	}
1841256752Sbrooks
1842256752Sbrooks	if (sc->atse_tx_irq_res != NULL) {
1843256752Sbrooks		error = bus_setup_intr(dev, sc->atse_tx_irq_res, INTR_TYPE_NET |
1844271969Sbz		    INTR_MPSAFE, NULL, atse_tx_intr, sc, &sc->atse_tx_intrhand);
1845256752Sbrooks		if (error != 0) {
1846256752Sbrooks			bus_teardown_intr(dev, sc->atse_rx_irq_res,
1847256752Sbrooks			    sc->atse_rx_intrhand);
1848256752Sbrooks			device_printf(dev, "enabling TX IRQ failed\n");
1849256752Sbrooks			ether_ifdetach(ifp);
1850256752Sbrooks			goto err;
1851256752Sbrooks		}
1852256752Sbrooks	}
1853256752Sbrooks
1854256752Sbrooks	if ((ifp->if_capenable & IFCAP_POLLING) != 0 ||
1855256752Sbrooks	   (sc->atse_rx_irq_res == NULL && sc->atse_tx_irq_res == NULL)) {
1856256752Sbrooks#ifdef DEVICE_POLLING
1857256752Sbrooks		/* If not on and no IRQs force it on. */
1858256752Sbrooks		if (sc->atse_rx_irq_res == NULL && sc->atse_tx_irq_res == NULL){
1859256752Sbrooks			ifp->if_capenable |= IFCAP_POLLING;
1860256752Sbrooks			device_printf(dev, "forcing to polling due to no "
1861256752Sbrooks			    "interrupts\n");
1862256752Sbrooks		}
1863256752Sbrooks		error = ether_poll_register(atse_poll, ifp);
1864256752Sbrooks		if (error != 0)
1865256752Sbrooks			goto err;
1866256752Sbrooks#else
1867256752Sbrooks		device_printf(dev, "no DEVICE_POLLING in kernel and no IRQs\n");
1868256752Sbrooks		error = ENXIO;
1869256752Sbrooks#endif
1870256752Sbrooks	} else {
1871256752Sbrooks		ATSE_RX_INTR_ENABLE(sc);
1872256752Sbrooks		ATSE_TX_INTR_ENABLE(sc);
1873256752Sbrooks	}
1874256752Sbrooks
1875256752Sbrookserr:
1876256752Sbrooks	if (error != 0)
1877256752Sbrooks		atse_detach(dev);
1878256752Sbrooks
1879256752Sbrooks	if (error == 0)
1880256752Sbrooks		atse_sysctl_stats_attach(dev);
1881256752Sbrooks
1882256752Sbrooks	return (error);
1883256752Sbrooks}
1884256752Sbrooks
1885256752Sbrooksstatic int
1886256752Sbrooksatse_detach(device_t dev)
1887256752Sbrooks{
1888256752Sbrooks	struct atse_softc *sc;
1889256752Sbrooks	struct ifnet *ifp;
1890256752Sbrooks
1891256752Sbrooks	sc = device_get_softc(dev);
1892256752Sbrooks	KASSERT(mtx_initialized(&sc->atse_mtx), ("%s: mutex not initialized",
1893256752Sbrooks	    device_get_nameunit(dev)));
1894256752Sbrooks	ifp = sc->atse_ifp;
1895256752Sbrooks
1896256752Sbrooks#ifdef DEVICE_POLLING
1897256752Sbrooks	if (ifp->if_capenable & IFCAP_POLLING)
1898256752Sbrooks		ether_poll_deregister(ifp);
1899256752Sbrooks#endif
1900256752Sbrooks
1901256752Sbrooks	/* Only cleanup if attach succeeded. */
1902256752Sbrooks	if (device_is_attached(dev)) {
1903256752Sbrooks		ATSE_LOCK(sc);
1904256752Sbrooks		atse_stop_locked(sc);
1905256752Sbrooks		ATSE_UNLOCK(sc);
1906256752Sbrooks		callout_drain(&sc->atse_tick);
1907256752Sbrooks		ether_ifdetach(ifp);
1908256752Sbrooks	}
1909256752Sbrooks	if (sc->atse_miibus != NULL)
1910256752Sbrooks		device_delete_child(dev, sc->atse_miibus);
1911256752Sbrooks
1912256752Sbrooks	if (sc->atse_tx_intrhand)
1913256752Sbrooks		bus_teardown_intr(dev, sc->atse_tx_irq_res,
1914256752Sbrooks		    sc->atse_tx_intrhand);
1915256752Sbrooks	if (sc->atse_rx_intrhand)
1916256752Sbrooks		bus_teardown_intr(dev, sc->atse_rx_irq_res,
1917256752Sbrooks		    sc->atse_rx_intrhand);
1918256752Sbrooks
1919256752Sbrooks	if (ifp != NULL)
1920256752Sbrooks		if_free(ifp);
1921256752Sbrooks
1922256752Sbrooks	if (sc->atse_tx_buf != NULL)
1923256752Sbrooks		free(sc->atse_tx_buf, M_DEVBUF);
1924256752Sbrooks
1925256752Sbrooks	mtx_destroy(&sc->atse_mtx);
1926256752Sbrooks
1927256752Sbrooks	return (0);
1928256752Sbrooks}
1929256752Sbrooks
1930270059Sbz/* Shared between nexus and fdt implementation. */
1931256752Sbrooksvoid
1932256752Sbrooksatse_detach_resources(device_t dev)
1933256752Sbrooks{
1934256752Sbrooks	struct atse_softc *sc;
1935256752Sbrooks
1936256752Sbrooks	sc = device_get_softc(dev);
1937256752Sbrooks
1938256752Sbrooks	if (sc->atse_txc_mem_res != NULL) {
1939256752Sbrooks		bus_release_resource(dev, SYS_RES_MEMORY, sc->atse_txc_mem_rid,
1940256752Sbrooks		    sc->atse_txc_mem_res);
1941256752Sbrooks		sc->atse_txc_mem_res = NULL;
1942256752Sbrooks	}
1943256752Sbrooks	if (sc->atse_tx_mem_res != NULL) {
1944256752Sbrooks		bus_release_resource(dev, SYS_RES_MEMORY, sc->atse_tx_mem_rid,
1945256752Sbrooks		    sc->atse_tx_mem_res);
1946256752Sbrooks		sc->atse_tx_mem_res = NULL;
1947256752Sbrooks	}
1948256752Sbrooks	if (sc->atse_tx_irq_res != NULL) {
1949256752Sbrooks		bus_release_resource(dev, SYS_RES_IRQ, sc->atse_tx_irq_rid,
1950256752Sbrooks		    sc->atse_tx_irq_res);
1951256752Sbrooks		sc->atse_tx_irq_res = NULL;
1952256752Sbrooks	}
1953256752Sbrooks	if (sc->atse_rxc_mem_res != NULL) {
1954256752Sbrooks		bus_release_resource(dev, SYS_RES_MEMORY, sc->atse_rxc_mem_rid,
1955256752Sbrooks		    sc->atse_rxc_mem_res);
1956256752Sbrooks		sc->atse_rxc_mem_res = NULL;
1957256752Sbrooks	}
1958256752Sbrooks	if (sc->atse_rx_mem_res != NULL) {
1959256752Sbrooks		bus_release_resource(dev, SYS_RES_MEMORY, sc->atse_rx_mem_rid,
1960256752Sbrooks		    sc->atse_rx_mem_res);
1961256752Sbrooks		sc->atse_rx_mem_res = NULL;
1962256752Sbrooks	}
1963256752Sbrooks	if (sc->atse_rx_irq_res != NULL) {
1964256752Sbrooks		bus_release_resource(dev, SYS_RES_IRQ, sc->atse_rx_irq_rid,
1965256752Sbrooks		    sc->atse_rx_irq_res);
1966256752Sbrooks		sc->atse_rx_irq_res = NULL;
1967256752Sbrooks	}
1968256752Sbrooks	if (sc->atse_mem_res != NULL) {
1969256752Sbrooks		bus_release_resource(dev, SYS_RES_MEMORY, sc->atse_mem_rid,
1970256752Sbrooks		    sc->atse_mem_res);
1971256752Sbrooks		sc->atse_mem_res = NULL;
1972256752Sbrooks	}
1973256752Sbrooks}
1974256752Sbrooks
1975256752Sbrooksint
1976256752Sbrooksatse_detach_dev(device_t dev)
1977256752Sbrooks{
1978256752Sbrooks	int error;
1979256752Sbrooks
1980256752Sbrooks	error = atse_detach(dev);
1981256752Sbrooks	if (error) {
1982256752Sbrooks		/* We are basically in undefined state now. */
1983256752Sbrooks		device_printf(dev, "atse_detach() failed: %d\n", error);
1984256752Sbrooks		return (error);
1985256752Sbrooks	}
1986256752Sbrooks
1987256752Sbrooks	atse_detach_resources(dev);
1988256752Sbrooks
1989256752Sbrooks	return (0);
1990256752Sbrooks}
1991256752Sbrooks
1992256752Sbrooksint
1993256752Sbrooksatse_miibus_readreg(device_t dev, int phy, int reg)
1994256752Sbrooks{
1995256752Sbrooks	struct atse_softc *sc;
1996256752Sbrooks
1997256752Sbrooks	sc = device_get_softc(dev);
1998256752Sbrooks
1999256752Sbrooks	/*
2000256752Sbrooks	 * We currently do not support re-mapping of MDIO space on-the-fly
2001256752Sbrooks	 * but de-facto hard-code the phy#.
2002256752Sbrooks	 */
2003256752Sbrooks	if (phy != sc->atse_phy_addr)
2004256752Sbrooks		return (0);
2005256752Sbrooks
2006256752Sbrooks	return (PHY_READ_2(sc, reg));
2007256752Sbrooks}
2008256752Sbrooks
2009256752Sbrooksint
2010256752Sbrooksatse_miibus_writereg(device_t dev, int phy, int reg, int data)
2011256752Sbrooks{
2012256752Sbrooks	struct atse_softc *sc;
2013256752Sbrooks
2014256752Sbrooks	sc = device_get_softc(dev);
2015256752Sbrooks
2016256752Sbrooks	/*
2017256752Sbrooks	 * We currently do not support re-mapping of MDIO space on-the-fly
2018256752Sbrooks	 * but de-facto hard-code the phy#.
2019256752Sbrooks	 */
2020256752Sbrooks	if (phy != sc->atse_phy_addr)
2021256752Sbrooks		return (0);
2022256752Sbrooks
2023256752Sbrooks	PHY_WRITE_2(sc, reg, data);
2024256752Sbrooks	return (0);
2025256752Sbrooks}
2026256752Sbrooks
2027256752Sbrooksvoid
2028256752Sbrooksatse_miibus_statchg(device_t dev)
2029256752Sbrooks{
2030256752Sbrooks	struct atse_softc *sc;
2031256752Sbrooks	struct mii_data *mii;
2032256752Sbrooks	struct ifnet *ifp;
2033256752Sbrooks	uint32_t val4;
2034256752Sbrooks
2035256752Sbrooks	sc = device_get_softc(dev);
2036256752Sbrooks	ATSE_LOCK_ASSERT(sc);
2037256752Sbrooks
2038256752Sbrooks        mii = device_get_softc(sc->atse_miibus);
2039256752Sbrooks        ifp = sc->atse_ifp;
2040256752Sbrooks        if (mii == NULL || ifp == NULL ||
2041256752Sbrooks            (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
2042256752Sbrooks                return;
2043256752Sbrooks
2044256752Sbrooks	val4 = CSR_READ_4(sc, BASE_CFG_COMMAND_CONFIG);
2045256752Sbrooks
2046256752Sbrooks	/* Assume no link. */
2047256752Sbrooks	sc->atse_flags &= ~ATSE_FLAGS_LINK;
2048256752Sbrooks
2049256752Sbrooks	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
2050256752Sbrooks	    (IFM_ACTIVE | IFM_AVALID)) {
2051256752Sbrooks
2052256752Sbrooks		switch (IFM_SUBTYPE(mii->mii_media_active)) {
2053256752Sbrooks		case IFM_10_T:
2054256752Sbrooks			val4 |= BASE_CFG_COMMAND_CONFIG_ENA_10;
2055256752Sbrooks			val4 &= ~BASE_CFG_COMMAND_CONFIG_ETH_SPEED;
2056256752Sbrooks			sc->atse_flags |= ATSE_FLAGS_LINK;
2057256752Sbrooks			break;
2058256752Sbrooks		case IFM_100_TX:
2059256752Sbrooks			val4 &= ~BASE_CFG_COMMAND_CONFIG_ENA_10;
2060256752Sbrooks			val4 &= ~BASE_CFG_COMMAND_CONFIG_ETH_SPEED;
2061256752Sbrooks			sc->atse_flags |= ATSE_FLAGS_LINK;
2062256752Sbrooks			break;
2063256752Sbrooks		case IFM_1000_T:
2064256752Sbrooks			val4 &= ~BASE_CFG_COMMAND_CONFIG_ENA_10;
2065256752Sbrooks			val4 |= BASE_CFG_COMMAND_CONFIG_ETH_SPEED;
2066256752Sbrooks			sc->atse_flags |= ATSE_FLAGS_LINK;
2067256752Sbrooks			break;
2068256752Sbrooks		default:
2069256752Sbrooks			break;
2070256752Sbrooks		}
2071256752Sbrooks	}
2072256752Sbrooks
2073256752Sbrooks        if ((sc->atse_flags & ATSE_FLAGS_LINK) == 0) {
2074256752Sbrooks		/* XXX-BZ need to stop the MAC? */
2075256752Sbrooks                return;
2076256752Sbrooks        }
2077256752Sbrooks
2078256752Sbrooks	if (IFM_OPTIONS(mii->mii_media_active & IFM_FDX) != 0)
2079256752Sbrooks		val4 &= ~BASE_CFG_COMMAND_CONFIG_HD_ENA;
2080256752Sbrooks        else
2081256752Sbrooks		val4 |= BASE_CFG_COMMAND_CONFIG_HD_ENA;
2082256752Sbrooks	/* XXX-BZ flow control? */
2083256752Sbrooks
2084256752Sbrooks	/* Make sure the MAC is activated. */
2085256752Sbrooks	val4 |= BASE_CFG_COMMAND_CONFIG_TX_ENA;
2086256752Sbrooks	val4 |= BASE_CFG_COMMAND_CONFIG_RX_ENA;
2087256752Sbrooks
2088256752Sbrooks	CSR_WRITE_4(sc, BASE_CFG_COMMAND_CONFIG, val4);
2089256752Sbrooks}
2090256752Sbrooks
2091256752Sbrooks/* end */
2092