1216829Syongari/*-
2216829Syongari * Copyright (c) 2010, Pyun YongHyeon <yongari@FreeBSD.org>
3216829Syongari * All rights reserved.
4216829Syongari *
5216829Syongari * Redistribution and use in source and binary forms, with or without
6216829Syongari * modification, are permitted provided that the following conditions
7216829Syongari * are met:
8216829Syongari * 1. Redistributions of source code must retain the above copyright
9216829Syongari *    notice unmodified, this list of conditions, and the following
10216829Syongari *    disclaimer.
11216829Syongari * 2. Redistributions in binary form must reproduce the above copyright
12216829Syongari *    notice, this list of conditions and the following disclaimer in the
13216829Syongari *    documentation and/or other materials provided with the distribution.
14216829Syongari *
15216829Syongari * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16216829Syongari * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17216829Syongari * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18216829Syongari * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19216829Syongari * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20216829Syongari * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21216829Syongari * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22216829Syongari * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23216829Syongari * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24216829Syongari * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25216829Syongari * SUCH DAMAGE.
26216829Syongari */
27216829Syongari
28216829Syongari/* Driver for DM&P Electronics, Inc, Vortex86 RDC R6040 FastEthernet. */
29216829Syongari
30216829Syongari#include <sys/cdefs.h>
31216829Syongari__FBSDID("$FreeBSD$");
32216829Syongari
33216829Syongari#include <sys/param.h>
34216829Syongari#include <sys/systm.h>
35216829Syongari#include <sys/bus.h>
36216829Syongari#include <sys/endian.h>
37216829Syongari#include <sys/kernel.h>
38216829Syongari#include <sys/lock.h>
39216829Syongari#include <sys/malloc.h>
40216829Syongari#include <sys/mbuf.h>
41216829Syongari#include <sys/module.h>
42216829Syongari#include <sys/mutex.h>
43216829Syongari#include <sys/rman.h>
44216829Syongari#include <sys/socket.h>
45216829Syongari#include <sys/sockio.h>
46216829Syongari#include <sys/sysctl.h>
47216829Syongari
48216829Syongari#include <net/bpf.h>
49216829Syongari#include <net/if.h>
50257176Sglebius#include <net/if_var.h>
51216829Syongari#include <net/if_arp.h>
52216829Syongari#include <net/ethernet.h>
53216829Syongari#include <net/if_dl.h>
54216829Syongari#include <net/if_llc.h>
55216829Syongari#include <net/if_media.h>
56216829Syongari#include <net/if_types.h>
57216829Syongari#include <net/if_vlan_var.h>
58216829Syongari
59216829Syongari#include <netinet/in.h>
60216829Syongari#include <netinet/in_systm.h>
61216829Syongari
62216829Syongari#include <dev/mii/mii.h>
63216829Syongari#include <dev/mii/miivar.h>
64216829Syongari
65216829Syongari#include <dev/pci/pcireg.h>
66216829Syongari#include <dev/pci/pcivar.h>
67216829Syongari
68216829Syongari#include <machine/bus.h>
69216829Syongari
70216829Syongari#include <dev/vte/if_vtereg.h>
71216829Syongari#include <dev/vte/if_vtevar.h>
72216829Syongari
73216829Syongari/* "device miibus" required.  See GENERIC if you get errors here. */
74216829Syongari#include "miibus_if.h"
75216829Syongari
76216829SyongariMODULE_DEPEND(vte, pci, 1, 1, 1);
77216829SyongariMODULE_DEPEND(vte, ether, 1, 1, 1);
78216829SyongariMODULE_DEPEND(vte, miibus, 1, 1, 1);
79216829Syongari
80216829Syongari/* Tunables. */
81216829Syongaristatic int tx_deep_copy = 1;
82216829SyongariTUNABLE_INT("hw.vte.tx_deep_copy", &tx_deep_copy);
83216829Syongari
84216829Syongari/*
85216829Syongari * Devices supported by this driver.
86216829Syongari */
87216829Syongaristatic const struct vte_ident vte_ident_table[] = {
88216829Syongari	{ VENDORID_RDC, DEVICEID_RDC_R6040, "RDC R6040 FastEthernet"},
89216829Syongari	{ 0, 0, NULL}
90216829Syongari};
91216829Syongari
92216829Syongaristatic int	vte_attach(device_t);
93216829Syongaristatic int	vte_detach(device_t);
94216829Syongaristatic int	vte_dma_alloc(struct vte_softc *);
95216829Syongaristatic void	vte_dma_free(struct vte_softc *);
96216829Syongaristatic void	vte_dmamap_cb(void *, bus_dma_segment_t *, int, int);
97216829Syongaristatic struct vte_txdesc *
98216829Syongari		vte_encap(struct vte_softc *, struct mbuf **);
99216829Syongaristatic const struct vte_ident *
100216829Syongari		vte_find_ident(device_t);
101216829Syongari#ifndef __NO_STRICT_ALIGNMENT
102216829Syongaristatic struct mbuf *
103216829Syongari		vte_fixup_rx(struct ifnet *, struct mbuf *);
104216829Syongari#endif
105216829Syongaristatic void	vte_get_macaddr(struct vte_softc *);
106216829Syongaristatic void	vte_init(void *);
107216829Syongaristatic void	vte_init_locked(struct vte_softc *);
108216829Syongaristatic int	vte_init_rx_ring(struct vte_softc *);
109216829Syongaristatic int	vte_init_tx_ring(struct vte_softc *);
110216829Syongaristatic void	vte_intr(void *);
111216829Syongaristatic int	vte_ioctl(struct ifnet *, u_long, caddr_t);
112272065Sglebiusstatic uint64_t	vte_get_counter(struct ifnet *, ift_counter);
113216829Syongaristatic void	vte_mac_config(struct vte_softc *);
114216829Syongaristatic int	vte_miibus_readreg(device_t, int, int);
115216829Syongaristatic void	vte_miibus_statchg(device_t);
116216829Syongaristatic int	vte_miibus_writereg(device_t, int, int, int);
117216829Syongaristatic int	vte_mediachange(struct ifnet *);
118216829Syongaristatic int	vte_mediachange_locked(struct ifnet *);
119216829Syongaristatic void	vte_mediastatus(struct ifnet *, struct ifmediareq *);
120216829Syongaristatic int	vte_newbuf(struct vte_softc *, struct vte_rxdesc *);
121216829Syongaristatic int	vte_probe(device_t);
122216829Syongaristatic void	vte_reset(struct vte_softc *);
123216829Syongaristatic int	vte_resume(device_t);
124216829Syongaristatic void	vte_rxeof(struct vte_softc *);
125216829Syongaristatic void	vte_rxfilter(struct vte_softc *);
126216829Syongaristatic int	vte_shutdown(device_t);
127216829Syongaristatic void	vte_start(struct ifnet *);
128216829Syongaristatic void	vte_start_locked(struct vte_softc *);
129216829Syongaristatic void	vte_start_mac(struct vte_softc *);
130216829Syongaristatic void	vte_stats_clear(struct vte_softc *);
131216829Syongaristatic void	vte_stats_update(struct vte_softc *);
132216829Syongaristatic void	vte_stop(struct vte_softc *);
133216829Syongaristatic void	vte_stop_mac(struct vte_softc *);
134216829Syongaristatic int	vte_suspend(device_t);
135216829Syongaristatic void	vte_sysctl_node(struct vte_softc *);
136216829Syongaristatic void	vte_tick(void *);
137216829Syongaristatic void	vte_txeof(struct vte_softc *);
138216829Syongaristatic void	vte_watchdog(struct vte_softc *);
139216829Syongaristatic int	sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int);
140216829Syongaristatic int	sysctl_hw_vte_int_mod(SYSCTL_HANDLER_ARGS);
141216829Syongari
142216829Syongaristatic device_method_t vte_methods[] = {
143216829Syongari	/* Device interface. */
144216829Syongari	DEVMETHOD(device_probe,		vte_probe),
145216829Syongari	DEVMETHOD(device_attach,	vte_attach),
146216829Syongari	DEVMETHOD(device_detach,	vte_detach),
147216829Syongari	DEVMETHOD(device_shutdown,	vte_shutdown),
148216829Syongari	DEVMETHOD(device_suspend,	vte_suspend),
149216829Syongari	DEVMETHOD(device_resume,	vte_resume),
150216829Syongari
151216829Syongari	/* MII interface. */
152216829Syongari	DEVMETHOD(miibus_readreg,	vte_miibus_readreg),
153216829Syongari	DEVMETHOD(miibus_writereg,	vte_miibus_writereg),
154216829Syongari	DEVMETHOD(miibus_statchg,	vte_miibus_statchg),
155216829Syongari
156227848Smarius	DEVMETHOD_END
157216829Syongari};
158216829Syongari
159216829Syongaristatic driver_t vte_driver = {
160216829Syongari	"vte",
161216829Syongari	vte_methods,
162216829Syongari	sizeof(struct vte_softc)
163216829Syongari};
164216829Syongari
165216829Syongaristatic devclass_t vte_devclass;
166216829Syongari
167216829SyongariDRIVER_MODULE(vte, pci, vte_driver, vte_devclass, 0, 0);
168216829SyongariDRIVER_MODULE(miibus, vte, miibus_driver, miibus_devclass, 0, 0);
169216829Syongari
170216829Syongaristatic int
171216829Syongarivte_miibus_readreg(device_t dev, int phy, int reg)
172216829Syongari{
173216829Syongari	struct vte_softc *sc;
174216829Syongari	int i;
175216829Syongari
176216829Syongari	sc = device_get_softc(dev);
177216829Syongari
178216829Syongari	CSR_WRITE_2(sc, VTE_MMDIO, MMDIO_READ |
179216829Syongari	    (phy << MMDIO_PHY_ADDR_SHIFT) | (reg << MMDIO_REG_ADDR_SHIFT));
180216829Syongari	for (i = VTE_PHY_TIMEOUT; i > 0; i--) {
181216829Syongari		DELAY(5);
182216829Syongari		if ((CSR_READ_2(sc, VTE_MMDIO) & MMDIO_READ) == 0)
183216829Syongari			break;
184216829Syongari	}
185216829Syongari
186216829Syongari	if (i == 0) {
187216829Syongari		device_printf(sc->vte_dev, "phy read timeout : %d\n", reg);
188216829Syongari		return (0);
189216829Syongari	}
190216829Syongari
191216829Syongari	return (CSR_READ_2(sc, VTE_MMRD));
192216829Syongari}
193216829Syongari
194216829Syongaristatic int
195216829Syongarivte_miibus_writereg(device_t dev, int phy, int reg, int val)
196216829Syongari{
197216829Syongari	struct vte_softc *sc;
198216829Syongari	int i;
199216829Syongari
200216829Syongari	sc = device_get_softc(dev);
201216829Syongari
202216829Syongari	CSR_WRITE_2(sc, VTE_MMWD, val);
203216829Syongari	CSR_WRITE_2(sc, VTE_MMDIO, MMDIO_WRITE |
204216829Syongari	    (phy << MMDIO_PHY_ADDR_SHIFT) | (reg << MMDIO_REG_ADDR_SHIFT));
205216829Syongari	for (i = VTE_PHY_TIMEOUT; i > 0; i--) {
206216829Syongari		DELAY(5);
207216829Syongari		if ((CSR_READ_2(sc, VTE_MMDIO) & MMDIO_WRITE) == 0)
208216829Syongari			break;
209216829Syongari	}
210216829Syongari
211216829Syongari	if (i == 0)
212216829Syongari		device_printf(sc->vte_dev, "phy write timeout : %d\n", reg);
213216829Syongari
214216829Syongari	return (0);
215216829Syongari}
216216829Syongari
217216829Syongaristatic void
218216829Syongarivte_miibus_statchg(device_t dev)
219216829Syongari{
220216829Syongari	struct vte_softc *sc;
221216829Syongari	struct mii_data *mii;
222216829Syongari	struct ifnet *ifp;
223216829Syongari	uint16_t val;
224216829Syongari
225216829Syongari	sc = device_get_softc(dev);
226216829Syongari
227216829Syongari	mii = device_get_softc(sc->vte_miibus);
228216829Syongari	ifp = sc->vte_ifp;
229216829Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
230216829Syongari		return;
231216829Syongari
232216829Syongari	sc->vte_flags &= ~VTE_FLAG_LINK;
233216829Syongari	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
234216829Syongari	    (IFM_ACTIVE | IFM_AVALID)) {
235216829Syongari		switch (IFM_SUBTYPE(mii->mii_media_active)) {
236216829Syongari		case IFM_10_T:
237216829Syongari		case IFM_100_TX:
238216829Syongari			sc->vte_flags |= VTE_FLAG_LINK;
239216829Syongari			break;
240216829Syongari		default:
241216829Syongari			break;
242216829Syongari		}
243216829Syongari	}
244216829Syongari
245216829Syongari	/* Stop RX/TX MACs. */
246216829Syongari	vte_stop_mac(sc);
247216829Syongari	/* Program MACs with resolved duplex and flow control. */
248216829Syongari	if ((sc->vte_flags & VTE_FLAG_LINK) != 0) {
249216829Syongari		/*
250216829Syongari		 * Timer waiting time : (63 + TIMER * 64) MII clock.
251216829Syongari		 * MII clock : 25MHz(100Mbps) or 2.5MHz(10Mbps).
252216829Syongari		 */
253216829Syongari		if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX)
254216829Syongari			val = 18 << VTE_IM_TIMER_SHIFT;
255216829Syongari		else
256216829Syongari			val = 1 << VTE_IM_TIMER_SHIFT;
257216829Syongari		val |= sc->vte_int_rx_mod << VTE_IM_BUNDLE_SHIFT;
258216829Syongari		/* 48.6us for 100Mbps, 50.8us for 10Mbps */
259216829Syongari		CSR_WRITE_2(sc, VTE_MRICR, val);
260216829Syongari
261216829Syongari		if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX)
262216829Syongari			val = 18 << VTE_IM_TIMER_SHIFT;
263216829Syongari		else
264216829Syongari			val = 1 << VTE_IM_TIMER_SHIFT;
265216829Syongari		val |= sc->vte_int_tx_mod << VTE_IM_BUNDLE_SHIFT;
266216829Syongari		/* 48.6us for 100Mbps, 50.8us for 10Mbps */
267216829Syongari		CSR_WRITE_2(sc, VTE_MTICR, val);
268216829Syongari
269216829Syongari		vte_mac_config(sc);
270216829Syongari		vte_start_mac(sc);
271216829Syongari	}
272216829Syongari}
273216829Syongari
274216829Syongaristatic void
275216829Syongarivte_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr)
276216829Syongari{
277216829Syongari	struct vte_softc *sc;
278216829Syongari	struct mii_data *mii;
279216829Syongari
280216829Syongari	sc = ifp->if_softc;
281216829Syongari	VTE_LOCK(sc);
282216829Syongari	if ((ifp->if_flags & IFF_UP) == 0) {
283216829Syongari		VTE_UNLOCK(sc);
284216829Syongari		return;
285216829Syongari	}
286216829Syongari	mii = device_get_softc(sc->vte_miibus);
287216829Syongari
288216829Syongari	mii_pollstat(mii);
289216829Syongari	ifmr->ifm_status = mii->mii_media_status;
290216829Syongari	ifmr->ifm_active = mii->mii_media_active;
291226478Syongari	VTE_UNLOCK(sc);
292216829Syongari}
293216829Syongari
294216829Syongaristatic int
295216829Syongarivte_mediachange(struct ifnet *ifp)
296216829Syongari{
297216829Syongari	struct vte_softc *sc;
298216829Syongari	int error;
299216829Syongari
300216829Syongari	sc = ifp->if_softc;
301216829Syongari	VTE_LOCK(sc);
302216829Syongari	error = vte_mediachange_locked(ifp);
303216829Syongari	VTE_UNLOCK(sc);
304216829Syongari	return (error);
305216829Syongari}
306216829Syongari
307216829Syongaristatic int
308216829Syongarivte_mediachange_locked(struct ifnet *ifp)
309216829Syongari{
310216829Syongari	struct vte_softc *sc;
311216829Syongari	struct mii_data *mii;
312216829Syongari	struct mii_softc *miisc;
313216829Syongari	int error;
314216829Syongari
315216829Syongari	sc = ifp->if_softc;
316216829Syongari	mii = device_get_softc(sc->vte_miibus);
317221407Smarius	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
318221407Smarius		PHY_RESET(miisc);
319216829Syongari	error = mii_mediachg(mii);
320216829Syongari
321216829Syongari	return (error);
322216829Syongari}
323216829Syongari
324216829Syongaristatic const struct vte_ident *
325216829Syongarivte_find_ident(device_t dev)
326216829Syongari{
327216829Syongari	const struct vte_ident *ident;
328216829Syongari	uint16_t vendor, devid;
329216829Syongari
330216829Syongari	vendor = pci_get_vendor(dev);
331216829Syongari	devid = pci_get_device(dev);
332216829Syongari	for (ident = vte_ident_table; ident->name != NULL; ident++) {
333216829Syongari		if (vendor == ident->vendorid && devid == ident->deviceid)
334216829Syongari			return (ident);
335216829Syongari	}
336216829Syongari
337216829Syongari	return (NULL);
338216829Syongari}
339216829Syongari
340216829Syongaristatic int
341216829Syongarivte_probe(device_t dev)
342216829Syongari{
343216829Syongari	const struct vte_ident *ident;
344216829Syongari
345216829Syongari	ident = vte_find_ident(dev);
346216829Syongari	if (ident != NULL) {
347216829Syongari		device_set_desc(dev, ident->name);
348216829Syongari		return (BUS_PROBE_DEFAULT);
349216829Syongari	}
350216829Syongari
351216829Syongari	return (ENXIO);
352216829Syongari}
353216829Syongari
354216829Syongaristatic void
355216829Syongarivte_get_macaddr(struct vte_softc *sc)
356216829Syongari{
357216829Syongari	uint16_t mid;
358216829Syongari
359216829Syongari	/*
360216829Syongari	 * It seems there is no way to reload station address and
361216829Syongari	 * it is supposed to be set by BIOS.
362216829Syongari	 */
363216829Syongari	mid = CSR_READ_2(sc, VTE_MID0L);
364216829Syongari	sc->vte_eaddr[0] = (mid >> 0) & 0xFF;
365216829Syongari	sc->vte_eaddr[1] = (mid >> 8) & 0xFF;
366216829Syongari	mid = CSR_READ_2(sc, VTE_MID0M);
367216829Syongari	sc->vte_eaddr[2] = (mid >> 0) & 0xFF;
368216829Syongari	sc->vte_eaddr[3] = (mid >> 8) & 0xFF;
369216829Syongari	mid = CSR_READ_2(sc, VTE_MID0H);
370216829Syongari	sc->vte_eaddr[4] = (mid >> 0) & 0xFF;
371216829Syongari	sc->vte_eaddr[5] = (mid >> 8) & 0xFF;
372216829Syongari}
373216829Syongari
374216829Syongaristatic int
375216829Syongarivte_attach(device_t dev)
376216829Syongari{
377216829Syongari	struct vte_softc *sc;
378216829Syongari	struct ifnet *ifp;
379216829Syongari	uint16_t macid;
380216829Syongari	int error, rid;
381216829Syongari
382216829Syongari	error = 0;
383216829Syongari	sc = device_get_softc(dev);
384216829Syongari	sc->vte_dev = dev;
385216829Syongari
386216829Syongari	mtx_init(&sc->vte_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
387216829Syongari	    MTX_DEF);
388216829Syongari	callout_init_mtx(&sc->vte_tick_ch, &sc->vte_mtx, 0);
389216829Syongari	sc->vte_ident = vte_find_ident(dev);
390216829Syongari
391216829Syongari	/* Map the device. */
392216829Syongari	pci_enable_busmaster(dev);
393216829Syongari	sc->vte_res_id = PCIR_BAR(1);
394216829Syongari	sc->vte_res_type = SYS_RES_MEMORY;
395216829Syongari	sc->vte_res = bus_alloc_resource_any(dev, sc->vte_res_type,
396216829Syongari	    &sc->vte_res_id, RF_ACTIVE);
397216829Syongari	if (sc->vte_res == NULL) {
398216829Syongari		sc->vte_res_id = PCIR_BAR(0);
399216829Syongari		sc->vte_res_type = SYS_RES_IOPORT;
400216829Syongari		sc->vte_res = bus_alloc_resource_any(dev, sc->vte_res_type,
401216829Syongari		    &sc->vte_res_id, RF_ACTIVE);
402216829Syongari		if (sc->vte_res == NULL) {
403216829Syongari			device_printf(dev, "cannot map memory/ports.\n");
404216829Syongari			mtx_destroy(&sc->vte_mtx);
405216829Syongari			return (ENXIO);
406216829Syongari		}
407216829Syongari	}
408216829Syongari	if (bootverbose) {
409216829Syongari		device_printf(dev, "using %s space register mapping\n",
410216829Syongari		    sc->vte_res_type == SYS_RES_MEMORY ? "memory" : "I/O");
411216829Syongari		device_printf(dev, "MAC Identifier : 0x%04x\n",
412216829Syongari		    CSR_READ_2(sc, VTE_MACID));
413216829Syongari		macid = CSR_READ_2(sc, VTE_MACID_REV);
414216829Syongari		device_printf(dev, "MAC Id. 0x%02x, Rev. 0x%02x\n",
415216829Syongari		    (macid & VTE_MACID_MASK) >> VTE_MACID_SHIFT,
416216829Syongari		    (macid & VTE_MACID_REV_MASK) >> VTE_MACID_REV_SHIFT);
417216829Syongari	}
418216829Syongari
419216829Syongari	rid = 0;
420216829Syongari	sc->vte_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
421216829Syongari	    RF_SHAREABLE | RF_ACTIVE);
422216829Syongari	if (sc->vte_irq == NULL) {
423216829Syongari		device_printf(dev, "cannot allocate IRQ resources.\n");
424216829Syongari		error = ENXIO;
425216829Syongari		goto fail;
426216829Syongari	}
427216829Syongari
428216829Syongari	/* Reset the ethernet controller. */
429216829Syongari	vte_reset(sc);
430216829Syongari
431295735Syongari	if ((error = vte_dma_alloc(sc)) != 0)
432216829Syongari		goto fail;
433216829Syongari
434216829Syongari	/* Create device sysctl node. */
435216829Syongari	vte_sysctl_node(sc);
436216829Syongari
437216829Syongari	/* Load station address. */
438216829Syongari	vte_get_macaddr(sc);
439216829Syongari
440216829Syongari	ifp = sc->vte_ifp = if_alloc(IFT_ETHER);
441216829Syongari	if (ifp == NULL) {
442216829Syongari		device_printf(dev, "cannot allocate ifnet structure.\n");
443216829Syongari		error = ENXIO;
444216829Syongari		goto fail;
445216829Syongari	}
446216829Syongari
447216829Syongari	ifp->if_softc = sc;
448216829Syongari	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
449216829Syongari	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
450216829Syongari	ifp->if_ioctl = vte_ioctl;
451216829Syongari	ifp->if_start = vte_start;
452216829Syongari	ifp->if_init = vte_init;
453272065Sglebius	ifp->if_get_counter = vte_get_counter;
454216829Syongari	ifp->if_snd.ifq_drv_maxlen = VTE_TX_RING_CNT - 1;
455216829Syongari	IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen);
456216829Syongari	IFQ_SET_READY(&ifp->if_snd);
457216829Syongari
458216829Syongari	/*
459216829Syongari	 * Set up MII bus.
460216829Syongari	 * BIOS would have initialized VTE_MPSCCR to catch PHY
461216829Syongari	 * status changes so driver may be able to extract
462216829Syongari	 * configured PHY address.  Since it's common to see BIOS
463216829Syongari	 * fails to initialize the register(including the sample
464216829Syongari	 * board I have), let mii(4) probe it.  This is more
465216829Syongari	 * reliable than relying on BIOS's initialization.
466216829Syongari	 *
467216829Syongari	 * Advertising flow control capability to mii(4) was
468216829Syongari	 * intentionally disabled due to severe problems in TX
469216829Syongari	 * pause frame generation.  See vte_rxeof() for more
470216829Syongari	 * details.
471216829Syongari	 */
472216829Syongari	error = mii_attach(dev, &sc->vte_miibus, ifp, vte_mediachange,
473216829Syongari	    vte_mediastatus, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0);
474216829Syongari	if (error != 0) {
475216829Syongari		device_printf(dev, "attaching PHYs failed\n");
476216829Syongari		goto fail;
477216829Syongari	}
478216829Syongari
479216829Syongari	ether_ifattach(ifp, sc->vte_eaddr);
480216829Syongari
481216829Syongari	/* VLAN capability setup. */
482216829Syongari	ifp->if_capabilities |= IFCAP_VLAN_MTU;
483216829Syongari	ifp->if_capenable = ifp->if_capabilities;
484216829Syongari	/* Tell the upper layer we support VLAN over-sized frames. */
485216829Syongari	ifp->if_hdrlen = sizeof(struct ether_vlan_header);
486216829Syongari
487216829Syongari	error = bus_setup_intr(dev, sc->vte_irq, INTR_TYPE_NET | INTR_MPSAFE,
488216829Syongari	    NULL, vte_intr, sc, &sc->vte_intrhand);
489216829Syongari	if (error != 0) {
490216829Syongari		device_printf(dev, "could not set up interrupt handler.\n");
491216829Syongari		ether_ifdetach(ifp);
492216829Syongari		goto fail;
493216829Syongari	}
494216829Syongari
495216829Syongarifail:
496216829Syongari	if (error != 0)
497216829Syongari		vte_detach(dev);
498216829Syongari
499216829Syongari	return (error);
500216829Syongari}
501216829Syongari
502216829Syongaristatic int
503216829Syongarivte_detach(device_t dev)
504216829Syongari{
505216829Syongari	struct vte_softc *sc;
506216829Syongari	struct ifnet *ifp;
507216829Syongari
508216829Syongari	sc = device_get_softc(dev);
509216829Syongari
510216829Syongari	ifp = sc->vte_ifp;
511216829Syongari	if (device_is_attached(dev)) {
512216829Syongari		VTE_LOCK(sc);
513216829Syongari		vte_stop(sc);
514216829Syongari		VTE_UNLOCK(sc);
515216829Syongari		callout_drain(&sc->vte_tick_ch);
516216829Syongari		ether_ifdetach(ifp);
517216829Syongari	}
518216829Syongari
519216829Syongari	if (sc->vte_miibus != NULL) {
520216829Syongari		device_delete_child(dev, sc->vte_miibus);
521216829Syongari		sc->vte_miibus = NULL;
522216829Syongari	}
523216829Syongari	bus_generic_detach(dev);
524216829Syongari
525216829Syongari	if (sc->vte_intrhand != NULL) {
526216829Syongari		bus_teardown_intr(dev, sc->vte_irq, sc->vte_intrhand);
527216829Syongari		sc->vte_intrhand = NULL;
528216829Syongari	}
529216829Syongari	if (sc->vte_irq != NULL) {
530216829Syongari		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->vte_irq);
531216829Syongari		sc->vte_irq = NULL;
532216829Syongari	}
533216829Syongari	if (sc->vte_res != NULL) {
534216829Syongari		bus_release_resource(dev, sc->vte_res_type, sc->vte_res_id,
535216829Syongari		    sc->vte_res);
536216829Syongari		sc->vte_res = NULL;
537216829Syongari	}
538216829Syongari	if (ifp != NULL) {
539216829Syongari		if_free(ifp);
540216829Syongari		sc->vte_ifp = NULL;
541216829Syongari	}
542216829Syongari	vte_dma_free(sc);
543216829Syongari	mtx_destroy(&sc->vte_mtx);
544216829Syongari
545216829Syongari	return (0);
546216829Syongari}
547216829Syongari
548216829Syongari#define	VTE_SYSCTL_STAT_ADD32(c, h, n, p, d)	\
549216829Syongari	    SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d)
550216829Syongari
551216829Syongaristatic void
552216829Syongarivte_sysctl_node(struct vte_softc *sc)
553216829Syongari{
554216829Syongari	struct sysctl_ctx_list *ctx;
555216829Syongari	struct sysctl_oid_list *child, *parent;
556216829Syongari	struct sysctl_oid *tree;
557216829Syongari	struct vte_hw_stats *stats;
558216829Syongari	int error;
559216829Syongari
560216829Syongari	stats = &sc->vte_stats;
561216829Syongari	ctx = device_get_sysctl_ctx(sc->vte_dev);
562216829Syongari	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->vte_dev));
563216829Syongari
564216829Syongari	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "int_rx_mod",
565216829Syongari	    CTLTYPE_INT | CTLFLAG_RW, &sc->vte_int_rx_mod, 0,
566216829Syongari	    sysctl_hw_vte_int_mod, "I", "vte RX interrupt moderation");
567216829Syongari	SYSCTL_ADD_PROC(ctx, child, OID_AUTO, "int_tx_mod",
568216829Syongari	    CTLTYPE_INT | CTLFLAG_RW, &sc->vte_int_tx_mod, 0,
569216829Syongari	    sysctl_hw_vte_int_mod, "I", "vte TX interrupt moderation");
570216829Syongari	/* Pull in device tunables. */
571216829Syongari	sc->vte_int_rx_mod = VTE_IM_RX_BUNDLE_DEFAULT;
572216829Syongari	error = resource_int_value(device_get_name(sc->vte_dev),
573216829Syongari	    device_get_unit(sc->vte_dev), "int_rx_mod", &sc->vte_int_rx_mod);
574216829Syongari	if (error == 0) {
575216829Syongari		if (sc->vte_int_rx_mod < VTE_IM_BUNDLE_MIN ||
576216829Syongari		    sc->vte_int_rx_mod > VTE_IM_BUNDLE_MAX) {
577216829Syongari			device_printf(sc->vte_dev, "int_rx_mod value out of "
578216829Syongari			    "range; using default: %d\n",
579216829Syongari			    VTE_IM_RX_BUNDLE_DEFAULT);
580216829Syongari			sc->vte_int_rx_mod = VTE_IM_RX_BUNDLE_DEFAULT;
581216829Syongari		}
582216829Syongari	}
583216829Syongari
584216829Syongari	sc->vte_int_tx_mod = VTE_IM_TX_BUNDLE_DEFAULT;
585216829Syongari	error = resource_int_value(device_get_name(sc->vte_dev),
586216829Syongari	    device_get_unit(sc->vte_dev), "int_tx_mod", &sc->vte_int_tx_mod);
587216829Syongari	if (error == 0) {
588216829Syongari		if (sc->vte_int_tx_mod < VTE_IM_BUNDLE_MIN ||
589216829Syongari		    sc->vte_int_tx_mod > VTE_IM_BUNDLE_MAX) {
590216829Syongari			device_printf(sc->vte_dev, "int_tx_mod value out of "
591216829Syongari			    "range; using default: %d\n",
592216829Syongari			    VTE_IM_TX_BUNDLE_DEFAULT);
593216829Syongari			sc->vte_int_tx_mod = VTE_IM_TX_BUNDLE_DEFAULT;
594216829Syongari		}
595216829Syongari	}
596216829Syongari
597216829Syongari	tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD,
598216829Syongari	    NULL, "VTE statistics");
599216829Syongari	parent = SYSCTL_CHILDREN(tree);
600216829Syongari
601216829Syongari	/* RX statistics. */
602216829Syongari	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD,
603216829Syongari	    NULL, "RX MAC statistics");
604216829Syongari	child = SYSCTL_CHILDREN(tree);
605216829Syongari	VTE_SYSCTL_STAT_ADD32(ctx, child, "good_frames",
606216829Syongari	    &stats->rx_frames, "Good frames");
607216829Syongari	VTE_SYSCTL_STAT_ADD32(ctx, child, "good_bcast_frames",
608216829Syongari	    &stats->rx_bcast_frames, "Good broadcast frames");
609216829Syongari	VTE_SYSCTL_STAT_ADD32(ctx, child, "good_mcast_frames",
610216829Syongari	    &stats->rx_mcast_frames, "Good multicast frames");
611216829Syongari	VTE_SYSCTL_STAT_ADD32(ctx, child, "runt",
612216829Syongari	    &stats->rx_runts, "Too short frames");
613216829Syongari	VTE_SYSCTL_STAT_ADD32(ctx, child, "crc_errs",
614216829Syongari	    &stats->rx_crcerrs, "CRC errors");
615216829Syongari	VTE_SYSCTL_STAT_ADD32(ctx, child, "long_frames",
616216829Syongari	    &stats->rx_long_frames,
617216829Syongari	    "Frames that have longer length than maximum packet length");
618216829Syongari	VTE_SYSCTL_STAT_ADD32(ctx, child, "fifo_full",
619216829Syongari	    &stats->rx_fifo_full, "FIFO full");
620216829Syongari	VTE_SYSCTL_STAT_ADD32(ctx, child, "desc_unavail",
621216829Syongari	    &stats->rx_desc_unavail, "Descriptor unavailable frames");
622216829Syongari	VTE_SYSCTL_STAT_ADD32(ctx, child, "pause_frames",
623216829Syongari	    &stats->rx_pause_frames, "Pause control frames");
624216829Syongari
625216829Syongari	/* TX statistics. */
626216829Syongari	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD,
627216829Syongari	    NULL, "TX MAC statistics");
628216829Syongari	child = SYSCTL_CHILDREN(tree);
629216829Syongari	VTE_SYSCTL_STAT_ADD32(ctx, child, "good_frames",
630216829Syongari	    &stats->tx_frames, "Good frames");
631216829Syongari	VTE_SYSCTL_STAT_ADD32(ctx, child, "underruns",
632216829Syongari	    &stats->tx_underruns, "FIFO underruns");
633216829Syongari	VTE_SYSCTL_STAT_ADD32(ctx, child, "late_colls",
634216829Syongari	    &stats->tx_late_colls, "Late collisions");
635216829Syongari	VTE_SYSCTL_STAT_ADD32(ctx, child, "pause_frames",
636216829Syongari	    &stats->tx_pause_frames, "Pause control frames");
637216829Syongari}
638216829Syongari
639216829Syongari#undef VTE_SYSCTL_STAT_ADD32
640216829Syongari
641216829Syongaristruct vte_dmamap_arg {
642216829Syongari	bus_addr_t	vte_busaddr;
643216829Syongari};
644216829Syongari
645216829Syongaristatic void
646216829Syongarivte_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
647216829Syongari{
648216829Syongari	struct vte_dmamap_arg *ctx;
649216829Syongari
650216829Syongari	if (error != 0)
651216829Syongari		return;
652216829Syongari
653216829Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
654216829Syongari
655216829Syongari	ctx = (struct vte_dmamap_arg *)arg;
656216829Syongari	ctx->vte_busaddr = segs[0].ds_addr;
657216829Syongari}
658216829Syongari
659216829Syongaristatic int
660216829Syongarivte_dma_alloc(struct vte_softc *sc)
661216829Syongari{
662216829Syongari	struct vte_txdesc *txd;
663216829Syongari	struct vte_rxdesc *rxd;
664216829Syongari	struct vte_dmamap_arg ctx;
665216829Syongari	int error, i;
666216829Syongari
667216829Syongari	/* Create parent DMA tag. */
668216829Syongari	error = bus_dma_tag_create(
669216829Syongari	    bus_get_dma_tag(sc->vte_dev), /* parent */
670216829Syongari	    1, 0,			/* alignment, boundary */
671216829Syongari	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
672216829Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
673216829Syongari	    NULL, NULL,			/* filter, filterarg */
674216829Syongari	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
675216829Syongari	    0,				/* nsegments */
676216829Syongari	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
677216829Syongari	    0,				/* flags */
678216829Syongari	    NULL, NULL,			/* lockfunc, lockarg */
679216829Syongari	    &sc->vte_cdata.vte_parent_tag);
680216829Syongari	if (error != 0) {
681216829Syongari		device_printf(sc->vte_dev,
682216829Syongari		    "could not create parent DMA tag.\n");
683216829Syongari		goto fail;
684216829Syongari	}
685216829Syongari
686216829Syongari	/* Create DMA tag for TX descriptor ring. */
687216829Syongari	error = bus_dma_tag_create(
688216829Syongari	    sc->vte_cdata.vte_parent_tag, /* parent */
689216829Syongari	    VTE_TX_RING_ALIGN, 0,	/* alignment, boundary */
690216829Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
691216829Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
692216829Syongari	    NULL, NULL,			/* filter, filterarg */
693216829Syongari	    VTE_TX_RING_SZ,		/* maxsize */
694216829Syongari	    1,				/* nsegments */
695216829Syongari	    VTE_TX_RING_SZ,		/* maxsegsize */
696216829Syongari	    0,				/* flags */
697216829Syongari	    NULL, NULL,			/* lockfunc, lockarg */
698216829Syongari	    &sc->vte_cdata.vte_tx_ring_tag);
699216829Syongari	if (error != 0) {
700216829Syongari		device_printf(sc->vte_dev,
701216829Syongari		    "could not create TX ring DMA tag.\n");
702216829Syongari		goto fail;
703216829Syongari	}
704216829Syongari
705216829Syongari	/* Create DMA tag for RX free descriptor ring. */
706216829Syongari	error = bus_dma_tag_create(
707216829Syongari	    sc->vte_cdata.vte_parent_tag, /* parent */
708216829Syongari	    VTE_RX_RING_ALIGN, 0,	/* alignment, boundary */
709216829Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
710216829Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
711216829Syongari	    NULL, NULL,			/* filter, filterarg */
712216829Syongari	    VTE_RX_RING_SZ,		/* maxsize */
713216829Syongari	    1,				/* nsegments */
714216829Syongari	    VTE_RX_RING_SZ,		/* maxsegsize */
715216829Syongari	    0,				/* flags */
716216829Syongari	    NULL, NULL,			/* lockfunc, lockarg */
717216829Syongari	    &sc->vte_cdata.vte_rx_ring_tag);
718216829Syongari	if (error != 0) {
719216829Syongari		device_printf(sc->vte_dev,
720216829Syongari		    "could not create RX ring DMA tag.\n");
721216829Syongari		goto fail;
722216829Syongari	}
723216829Syongari
724216829Syongari	/* Allocate DMA'able memory and load the DMA map for TX ring. */
725216829Syongari	error = bus_dmamem_alloc(sc->vte_cdata.vte_tx_ring_tag,
726216829Syongari	    (void **)&sc->vte_cdata.vte_tx_ring,
727216829Syongari	    BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT,
728216829Syongari	    &sc->vte_cdata.vte_tx_ring_map);
729216829Syongari	if (error != 0) {
730216829Syongari		device_printf(sc->vte_dev,
731216829Syongari		    "could not allocate DMA'able memory for TX ring.\n");
732216829Syongari		goto fail;
733216829Syongari	}
734216829Syongari	ctx.vte_busaddr = 0;
735216829Syongari	error = bus_dmamap_load(sc->vte_cdata.vte_tx_ring_tag,
736216829Syongari	    sc->vte_cdata.vte_tx_ring_map, sc->vte_cdata.vte_tx_ring,
737216829Syongari	    VTE_TX_RING_SZ, vte_dmamap_cb, &ctx, 0);
738216829Syongari	if (error != 0 || ctx.vte_busaddr == 0) {
739216829Syongari		device_printf(sc->vte_dev,
740216829Syongari		    "could not load DMA'able memory for TX ring.\n");
741216829Syongari		goto fail;
742216829Syongari	}
743216829Syongari	sc->vte_cdata.vte_tx_ring_paddr = ctx.vte_busaddr;
744216829Syongari
745216829Syongari	/* Allocate DMA'able memory and load the DMA map for RX ring. */
746216829Syongari	error = bus_dmamem_alloc(sc->vte_cdata.vte_rx_ring_tag,
747216829Syongari	    (void **)&sc->vte_cdata.vte_rx_ring,
748216829Syongari	    BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT,
749216829Syongari	    &sc->vte_cdata.vte_rx_ring_map);
750216829Syongari	if (error != 0) {
751216829Syongari		device_printf(sc->vte_dev,
752216829Syongari		    "could not allocate DMA'able memory for RX ring.\n");
753216829Syongari		goto fail;
754216829Syongari	}
755216829Syongari	ctx.vte_busaddr = 0;
756216829Syongari	error = bus_dmamap_load(sc->vte_cdata.vte_rx_ring_tag,
757216829Syongari	    sc->vte_cdata.vte_rx_ring_map, sc->vte_cdata.vte_rx_ring,
758216829Syongari	    VTE_RX_RING_SZ, vte_dmamap_cb, &ctx, 0);
759216829Syongari	if (error != 0 || ctx.vte_busaddr == 0) {
760216829Syongari		device_printf(sc->vte_dev,
761216829Syongari		    "could not load DMA'able memory for RX ring.\n");
762216829Syongari		goto fail;
763216829Syongari	}
764216829Syongari	sc->vte_cdata.vte_rx_ring_paddr = ctx.vte_busaddr;
765216829Syongari
766216829Syongari	/* Create TX buffer parent tag. */
767216829Syongari	error = bus_dma_tag_create(
768216829Syongari	    bus_get_dma_tag(sc->vte_dev), /* parent */
769216829Syongari	    1, 0,			/* alignment, boundary */
770216829Syongari	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
771216829Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
772216829Syongari	    NULL, NULL,			/* filter, filterarg */
773216829Syongari	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
774216829Syongari	    0,				/* nsegments */
775216829Syongari	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
776216829Syongari	    0,				/* flags */
777216829Syongari	    NULL, NULL,			/* lockfunc, lockarg */
778216829Syongari	    &sc->vte_cdata.vte_buffer_tag);
779216829Syongari	if (error != 0) {
780216829Syongari		device_printf(sc->vte_dev,
781216829Syongari		    "could not create parent buffer DMA tag.\n");
782216829Syongari		goto fail;
783216829Syongari	}
784216829Syongari
785216829Syongari	/* Create DMA tag for TX buffers. */
786216829Syongari	error = bus_dma_tag_create(
787216829Syongari	    sc->vte_cdata.vte_buffer_tag, /* parent */
788216829Syongari	    1, 0,			/* alignment, boundary */
789216829Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
790216829Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
791216829Syongari	    NULL, NULL,			/* filter, filterarg */
792216829Syongari	    MCLBYTES,			/* maxsize */
793216829Syongari	    1,				/* nsegments */
794216829Syongari	    MCLBYTES,			/* maxsegsize */
795216829Syongari	    0,				/* flags */
796216829Syongari	    NULL, NULL,			/* lockfunc, lockarg */
797216829Syongari	    &sc->vte_cdata.vte_tx_tag);
798216829Syongari	if (error != 0) {
799216829Syongari		device_printf(sc->vte_dev, "could not create TX DMA tag.\n");
800216829Syongari		goto fail;
801216829Syongari	}
802216829Syongari
803216829Syongari	/* Create DMA tag for RX buffers. */
804216829Syongari	error = bus_dma_tag_create(
805216829Syongari	    sc->vte_cdata.vte_buffer_tag, /* parent */
806216829Syongari	    VTE_RX_BUF_ALIGN, 0,	/* alignment, boundary */
807216829Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
808216829Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
809216829Syongari	    NULL, NULL,			/* filter, filterarg */
810216829Syongari	    MCLBYTES,			/* maxsize */
811216829Syongari	    1,				/* nsegments */
812216829Syongari	    MCLBYTES,			/* maxsegsize */
813216829Syongari	    0,				/* flags */
814216829Syongari	    NULL, NULL,			/* lockfunc, lockarg */
815216829Syongari	    &sc->vte_cdata.vte_rx_tag);
816216829Syongari	if (error != 0) {
817216829Syongari		device_printf(sc->vte_dev, "could not create RX DMA tag.\n");
818216829Syongari		goto fail;
819216829Syongari	}
820216829Syongari	/* Create DMA maps for TX buffers. */
821216829Syongari	for (i = 0; i < VTE_TX_RING_CNT; i++) {
822216829Syongari		txd = &sc->vte_cdata.vte_txdesc[i];
823216829Syongari		txd->tx_m = NULL;
824216829Syongari		txd->tx_dmamap = NULL;
825216829Syongari		error = bus_dmamap_create(sc->vte_cdata.vte_tx_tag, 0,
826216829Syongari		    &txd->tx_dmamap);
827216829Syongari		if (error != 0) {
828216829Syongari			device_printf(sc->vte_dev,
829216829Syongari			    "could not create TX dmamap.\n");
830216829Syongari			goto fail;
831216829Syongari		}
832216829Syongari	}
833216829Syongari	/* Create DMA maps for RX buffers. */
834216829Syongari	if ((error = bus_dmamap_create(sc->vte_cdata.vte_rx_tag, 0,
835216829Syongari	    &sc->vte_cdata.vte_rx_sparemap)) != 0) {
836216829Syongari		device_printf(sc->vte_dev,
837216829Syongari		    "could not create spare RX dmamap.\n");
838216829Syongari		goto fail;
839216829Syongari	}
840216829Syongari	for (i = 0; i < VTE_RX_RING_CNT; i++) {
841216829Syongari		rxd = &sc->vte_cdata.vte_rxdesc[i];
842216829Syongari		rxd->rx_m = NULL;
843216829Syongari		rxd->rx_dmamap = NULL;
844216829Syongari		error = bus_dmamap_create(sc->vte_cdata.vte_rx_tag, 0,
845216829Syongari		    &rxd->rx_dmamap);
846216829Syongari		if (error != 0) {
847216829Syongari			device_printf(sc->vte_dev,
848216829Syongari			    "could not create RX dmamap.\n");
849216829Syongari			goto fail;
850216829Syongari		}
851216829Syongari	}
852216829Syongari
853216829Syongarifail:
854216829Syongari	return (error);
855216829Syongari}
856216829Syongari
857216829Syongaristatic void
858216829Syongarivte_dma_free(struct vte_softc *sc)
859216829Syongari{
860216829Syongari	struct vte_txdesc *txd;
861216829Syongari	struct vte_rxdesc *rxd;
862216829Syongari	int i;
863216829Syongari
864216829Syongari	/* TX buffers. */
865216829Syongari	if (sc->vte_cdata.vte_tx_tag != NULL) {
866216829Syongari		for (i = 0; i < VTE_TX_RING_CNT; i++) {
867216829Syongari			txd = &sc->vte_cdata.vte_txdesc[i];
868216829Syongari			if (txd->tx_dmamap != NULL) {
869216829Syongari				bus_dmamap_destroy(sc->vte_cdata.vte_tx_tag,
870216829Syongari				    txd->tx_dmamap);
871216829Syongari				txd->tx_dmamap = NULL;
872216829Syongari			}
873216829Syongari		}
874216829Syongari		bus_dma_tag_destroy(sc->vte_cdata.vte_tx_tag);
875216829Syongari		sc->vte_cdata.vte_tx_tag = NULL;
876216829Syongari	}
877216829Syongari	/* RX buffers */
878216829Syongari	if (sc->vte_cdata.vte_rx_tag != NULL) {
879216829Syongari		for (i = 0; i < VTE_RX_RING_CNT; i++) {
880216829Syongari			rxd = &sc->vte_cdata.vte_rxdesc[i];
881216829Syongari			if (rxd->rx_dmamap != NULL) {
882216829Syongari				bus_dmamap_destroy(sc->vte_cdata.vte_rx_tag,
883216829Syongari				    rxd->rx_dmamap);
884216829Syongari				rxd->rx_dmamap = NULL;
885216829Syongari			}
886216829Syongari		}
887216829Syongari		if (sc->vte_cdata.vte_rx_sparemap != NULL) {
888216829Syongari			bus_dmamap_destroy(sc->vte_cdata.vte_rx_tag,
889216829Syongari			    sc->vte_cdata.vte_rx_sparemap);
890216829Syongari			sc->vte_cdata.vte_rx_sparemap = NULL;
891216829Syongari		}
892216829Syongari		bus_dma_tag_destroy(sc->vte_cdata.vte_rx_tag);
893216829Syongari		sc->vte_cdata.vte_rx_tag = NULL;
894216829Syongari	}
895216829Syongari	/* TX descriptor ring. */
896216829Syongari	if (sc->vte_cdata.vte_tx_ring_tag != NULL) {
897267363Sjhb		if (sc->vte_cdata.vte_tx_ring_paddr != 0)
898216829Syongari			bus_dmamap_unload(sc->vte_cdata.vte_tx_ring_tag,
899216829Syongari			    sc->vte_cdata.vte_tx_ring_map);
900267363Sjhb		if (sc->vte_cdata.vte_tx_ring != NULL)
901216829Syongari			bus_dmamem_free(sc->vte_cdata.vte_tx_ring_tag,
902216829Syongari			    sc->vte_cdata.vte_tx_ring,
903216829Syongari			    sc->vte_cdata.vte_tx_ring_map);
904216829Syongari		sc->vte_cdata.vte_tx_ring = NULL;
905267363Sjhb		sc->vte_cdata.vte_tx_ring_paddr = 0;
906216829Syongari		bus_dma_tag_destroy(sc->vte_cdata.vte_tx_ring_tag);
907216829Syongari		sc->vte_cdata.vte_tx_ring_tag = NULL;
908216829Syongari	}
909216829Syongari	/* RX ring. */
910216829Syongari	if (sc->vte_cdata.vte_rx_ring_tag != NULL) {
911267363Sjhb		if (sc->vte_cdata.vte_rx_ring_paddr != 0)
912216829Syongari			bus_dmamap_unload(sc->vte_cdata.vte_rx_ring_tag,
913216829Syongari			    sc->vte_cdata.vte_rx_ring_map);
914267363Sjhb		if (sc->vte_cdata.vte_rx_ring != NULL)
915216829Syongari			bus_dmamem_free(sc->vte_cdata.vte_rx_ring_tag,
916216829Syongari			    sc->vte_cdata.vte_rx_ring,
917216829Syongari			    sc->vte_cdata.vte_rx_ring_map);
918216829Syongari		sc->vte_cdata.vte_rx_ring = NULL;
919267363Sjhb		sc->vte_cdata.vte_rx_ring_paddr = 0;
920216829Syongari		bus_dma_tag_destroy(sc->vte_cdata.vte_rx_ring_tag);
921216829Syongari		sc->vte_cdata.vte_rx_ring_tag = NULL;
922216829Syongari	}
923216829Syongari	if (sc->vte_cdata.vte_buffer_tag != NULL) {
924216829Syongari		bus_dma_tag_destroy(sc->vte_cdata.vte_buffer_tag);
925216829Syongari		sc->vte_cdata.vte_buffer_tag = NULL;
926216829Syongari	}
927216829Syongari	if (sc->vte_cdata.vte_parent_tag != NULL) {
928216829Syongari		bus_dma_tag_destroy(sc->vte_cdata.vte_parent_tag);
929216829Syongari		sc->vte_cdata.vte_parent_tag = NULL;
930216829Syongari	}
931216829Syongari}
932216829Syongari
933216829Syongaristatic int
934216829Syongarivte_shutdown(device_t dev)
935216829Syongari{
936216829Syongari
937216829Syongari	return (vte_suspend(dev));
938216829Syongari}
939216829Syongari
940216829Syongaristatic int
941216829Syongarivte_suspend(device_t dev)
942216829Syongari{
943216829Syongari	struct vte_softc *sc;
944216829Syongari	struct ifnet *ifp;
945216829Syongari
946216829Syongari	sc = device_get_softc(dev);
947216829Syongari
948216829Syongari	VTE_LOCK(sc);
949216829Syongari	ifp = sc->vte_ifp;
950216829Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
951216829Syongari		vte_stop(sc);
952216829Syongari	VTE_UNLOCK(sc);
953216829Syongari
954216829Syongari	return (0);
955216829Syongari}
956216829Syongari
957216829Syongaristatic int
958216829Syongarivte_resume(device_t dev)
959216829Syongari{
960216829Syongari	struct vte_softc *sc;
961216829Syongari	struct ifnet *ifp;
962216829Syongari
963216829Syongari	sc = device_get_softc(dev);
964216829Syongari
965216829Syongari	VTE_LOCK(sc);
966216829Syongari	ifp = sc->vte_ifp;
967216829Syongari	if ((ifp->if_flags & IFF_UP) != 0) {
968216829Syongari		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
969216829Syongari		vte_init_locked(sc);
970216829Syongari	}
971216829Syongari	VTE_UNLOCK(sc);
972216829Syongari
973216829Syongari	return (0);
974216829Syongari}
975216829Syongari
976216829Syongaristatic struct vte_txdesc *
977216829Syongarivte_encap(struct vte_softc *sc, struct mbuf **m_head)
978216829Syongari{
979216829Syongari	struct vte_txdesc *txd;
980216829Syongari	struct mbuf *m, *n;
981216829Syongari	bus_dma_segment_t txsegs[1];
982216829Syongari	int copy, error, nsegs, padlen;
983216829Syongari
984216829Syongari	VTE_LOCK_ASSERT(sc);
985216829Syongari
986216829Syongari	M_ASSERTPKTHDR((*m_head));
987216829Syongari
988216829Syongari	txd = &sc->vte_cdata.vte_txdesc[sc->vte_cdata.vte_tx_prod];
989216829Syongari	m = *m_head;
990216829Syongari	/*
991216829Syongari	 * Controller doesn't auto-pad, so we have to make sure pad
992216829Syongari	 * short frames out to the minimum frame length.
993216829Syongari	 */
994216829Syongari	if (m->m_pkthdr.len < VTE_MIN_FRAMELEN)
995216829Syongari		padlen = VTE_MIN_FRAMELEN - m->m_pkthdr.len;
996216829Syongari	else
997216829Syongari		padlen = 0;
998216829Syongari
999216829Syongari	/*
1000216829Syongari	 * Controller does not support multi-fragmented TX buffers.
1001216829Syongari	 * Controller spends most of its TX processing time in
1002216829Syongari	 * de-fragmenting TX buffers.  Either faster CPU or more
1003216829Syongari	 * advanced controller DMA engine is required to speed up
1004216829Syongari	 * TX path processing.
1005216829Syongari	 * To mitigate the de-fragmenting issue, perform deep copy
1006216829Syongari	 * from fragmented mbuf chains to a pre-allocated mbuf
1007216829Syongari	 * cluster with extra cost of kernel memory.  For frames
1008216829Syongari	 * that is composed of single TX buffer, the deep copy is
1009216829Syongari	 * bypassed.
1010216829Syongari	 */
1011216829Syongari	if (tx_deep_copy != 0) {
1012216829Syongari		copy = 0;
1013216829Syongari		if (m->m_next != NULL)
1014216829Syongari			copy++;
1015216829Syongari		if (padlen > 0 && (M_WRITABLE(m) == 0 ||
1016216829Syongari		    padlen > M_TRAILINGSPACE(m)))
1017216829Syongari			copy++;
1018216829Syongari		if (copy != 0) {
1019216829Syongari			/* Avoid expensive m_defrag(9) and do deep copy. */
1020216829Syongari			n = sc->vte_cdata.vte_txmbufs[sc->vte_cdata.vte_tx_prod];
1021216829Syongari			m_copydata(m, 0, m->m_pkthdr.len, mtod(n, char *));
1022216829Syongari			n->m_pkthdr.len = m->m_pkthdr.len;
1023216829Syongari			n->m_len = m->m_pkthdr.len;
1024216829Syongari			m = n;
1025216829Syongari			txd->tx_flags |= VTE_TXMBUF;
1026216829Syongari		}
1027216829Syongari
1028216829Syongari		if (padlen > 0) {
1029216829Syongari			/* Zero out the bytes in the pad area. */
1030216829Syongari			bzero(mtod(m, char *) + m->m_pkthdr.len, padlen);
1031216829Syongari			m->m_pkthdr.len += padlen;
1032216829Syongari			m->m_len = m->m_pkthdr.len;
1033216829Syongari		}
1034216829Syongari	} else {
1035216829Syongari		if (M_WRITABLE(m) == 0) {
1036216829Syongari			if (m->m_next != NULL || padlen > 0) {
1037216829Syongari				/* Get a writable copy. */
1038243857Sglebius				m = m_dup(*m_head, M_NOWAIT);
1039216829Syongari				/* Release original mbuf chains. */
1040216829Syongari				m_freem(*m_head);
1041216829Syongari				if (m == NULL) {
1042216829Syongari					*m_head = NULL;
1043216829Syongari					return (NULL);
1044216829Syongari				}
1045216829Syongari				*m_head = m;
1046216829Syongari			}
1047216829Syongari		}
1048216829Syongari
1049216829Syongari		if (m->m_next != NULL) {
1050243857Sglebius			m = m_defrag(*m_head, M_NOWAIT);
1051216829Syongari			if (m == NULL) {
1052216829Syongari				m_freem(*m_head);
1053216829Syongari				*m_head = NULL;
1054216829Syongari				return (NULL);
1055216829Syongari			}
1056216829Syongari			*m_head = m;
1057216829Syongari		}
1058216829Syongari
1059216829Syongari		if (padlen > 0) {
1060216829Syongari			if (M_TRAILINGSPACE(m) < padlen) {
1061243857Sglebius				m = m_defrag(*m_head, M_NOWAIT);
1062216829Syongari				if (m == NULL) {
1063216829Syongari					m_freem(*m_head);
1064216829Syongari					*m_head = NULL;
1065216829Syongari					return (NULL);
1066216829Syongari				}
1067216829Syongari				*m_head = m;
1068216829Syongari			}
1069216829Syongari			/* Zero out the bytes in the pad area. */
1070216829Syongari			bzero(mtod(m, char *) + m->m_pkthdr.len, padlen);
1071216829Syongari			m->m_pkthdr.len += padlen;
1072216829Syongari			m->m_len = m->m_pkthdr.len;
1073216829Syongari		}
1074216829Syongari	}
1075216829Syongari
1076216829Syongari	error = bus_dmamap_load_mbuf_sg(sc->vte_cdata.vte_tx_tag,
1077216829Syongari	    txd->tx_dmamap, m, txsegs, &nsegs, 0);
1078216829Syongari	if (error != 0) {
1079216829Syongari		txd->tx_flags &= ~VTE_TXMBUF;
1080216829Syongari		return (NULL);
1081216829Syongari	}
1082216829Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
1083216829Syongari	bus_dmamap_sync(sc->vte_cdata.vte_tx_tag, txd->tx_dmamap,
1084216829Syongari	    BUS_DMASYNC_PREWRITE);
1085216829Syongari
1086216829Syongari	txd->tx_desc->dtlen = htole16(VTE_TX_LEN(txsegs[0].ds_len));
1087216829Syongari	txd->tx_desc->dtbp = htole32(txsegs[0].ds_addr);
1088216829Syongari	sc->vte_cdata.vte_tx_cnt++;
1089216829Syongari	/* Update producer index. */
1090216829Syongari	VTE_DESC_INC(sc->vte_cdata.vte_tx_prod, VTE_TX_RING_CNT);
1091216829Syongari
1092216829Syongari	/* Finally hand over ownership to controller. */
1093216829Syongari	txd->tx_desc->dtst = htole16(VTE_DTST_TX_OWN);
1094216829Syongari	txd->tx_m = m;
1095216829Syongari
1096216829Syongari	return (txd);
1097216829Syongari}
1098216829Syongari
1099216829Syongaristatic void
1100216829Syongarivte_start(struct ifnet *ifp)
1101216829Syongari{
1102216829Syongari	struct vte_softc *sc;
1103216829Syongari
1104216829Syongari	sc = ifp->if_softc;
1105216829Syongari	VTE_LOCK(sc);
1106216829Syongari	vte_start_locked(sc);
1107216829Syongari	VTE_UNLOCK(sc);
1108216829Syongari}
1109216829Syongari
1110216829Syongaristatic void
1111216829Syongarivte_start_locked(struct vte_softc *sc)
1112216829Syongari{
1113216829Syongari	struct ifnet *ifp;
1114216829Syongari	struct vte_txdesc *txd;
1115216829Syongari	struct mbuf *m_head;
1116216829Syongari	int enq;
1117216829Syongari
1118216829Syongari	ifp = sc->vte_ifp;
1119216829Syongari
1120216829Syongari	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1121216829Syongari	    IFF_DRV_RUNNING || (sc->vte_flags & VTE_FLAG_LINK) == 0)
1122216829Syongari		return;
1123216829Syongari
1124216829Syongari	for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd); ) {
1125216829Syongari		/* Reserve one free TX descriptor. */
1126216829Syongari		if (sc->vte_cdata.vte_tx_cnt >= VTE_TX_RING_CNT - 1) {
1127216829Syongari			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
1128216829Syongari			break;
1129216829Syongari		}
1130216829Syongari		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
1131216829Syongari		if (m_head == NULL)
1132216829Syongari			break;
1133216829Syongari		/*
1134216829Syongari		 * Pack the data into the transmit ring. If we
1135216829Syongari		 * don't have room, set the OACTIVE flag and wait
1136216829Syongari		 * for the NIC to drain the ring.
1137216829Syongari		 */
1138216829Syongari		if ((txd = vte_encap(sc, &m_head)) == NULL) {
1139216829Syongari			if (m_head != NULL)
1140216829Syongari				IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
1141216829Syongari			break;
1142216829Syongari		}
1143216829Syongari
1144216829Syongari		enq++;
1145216829Syongari		/*
1146216829Syongari		 * If there's a BPF listener, bounce a copy of this frame
1147216829Syongari		 * to him.
1148216829Syongari		 */
1149216829Syongari		ETHER_BPF_MTAP(ifp, m_head);
1150216829Syongari		/* Free consumed TX frame. */
1151216829Syongari		if ((txd->tx_flags & VTE_TXMBUF) != 0)
1152216829Syongari			m_freem(m_head);
1153216829Syongari	}
1154216829Syongari
1155216829Syongari	if (enq > 0) {
1156216829Syongari		bus_dmamap_sync(sc->vte_cdata.vte_tx_ring_tag,
1157216829Syongari		    sc->vte_cdata.vte_tx_ring_map, BUS_DMASYNC_PREREAD |
1158216829Syongari		    BUS_DMASYNC_PREWRITE);
1159216829Syongari		CSR_WRITE_2(sc, VTE_TX_POLL, TX_POLL_START);
1160216829Syongari		sc->vte_watchdog_timer = VTE_TX_TIMEOUT;
1161216829Syongari	}
1162216829Syongari}
1163216829Syongari
1164216829Syongaristatic void
1165216829Syongarivte_watchdog(struct vte_softc *sc)
1166216829Syongari{
1167216829Syongari	struct ifnet *ifp;
1168216829Syongari
1169216829Syongari	VTE_LOCK_ASSERT(sc);
1170216829Syongari
1171216829Syongari	if (sc->vte_watchdog_timer == 0 || --sc->vte_watchdog_timer)
1172216829Syongari		return;
1173216829Syongari
1174216829Syongari	ifp = sc->vte_ifp;
1175216829Syongari	if_printf(sc->vte_ifp, "watchdog timeout -- resetting\n");
1176272065Sglebius	if_inc_counter(ifp, IFCOUNTER_OERRORS, 1);
1177216829Syongari	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1178216829Syongari	vte_init_locked(sc);
1179216829Syongari	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1180216829Syongari		vte_start_locked(sc);
1181216829Syongari}
1182216829Syongari
1183216829Syongaristatic int
1184216829Syongarivte_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data)
1185216829Syongari{
1186216829Syongari	struct vte_softc *sc;
1187216829Syongari	struct ifreq *ifr;
1188216829Syongari	struct mii_data *mii;
1189216829Syongari	int error;
1190216829Syongari
1191216829Syongari	sc = ifp->if_softc;
1192216829Syongari	ifr = (struct ifreq *)data;
1193216829Syongari	error = 0;
1194216829Syongari	switch (cmd) {
1195216829Syongari	case SIOCSIFFLAGS:
1196216829Syongari		VTE_LOCK(sc);
1197216829Syongari		if ((ifp->if_flags & IFF_UP) != 0) {
1198216829Syongari			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 &&
1199216829Syongari			    ((ifp->if_flags ^ sc->vte_if_flags) &
1200216829Syongari			    (IFF_PROMISC | IFF_ALLMULTI)) != 0)
1201216829Syongari				vte_rxfilter(sc);
1202216829Syongari			else
1203216829Syongari				vte_init_locked(sc);
1204216829Syongari		} else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
1205216829Syongari			vte_stop(sc);
1206216829Syongari		sc->vte_if_flags = ifp->if_flags;
1207216829Syongari		VTE_UNLOCK(sc);
1208216829Syongari		break;
1209216829Syongari	case SIOCADDMULTI:
1210216829Syongari	case SIOCDELMULTI:
1211216829Syongari		VTE_LOCK(sc);
1212216829Syongari		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
1213216829Syongari			vte_rxfilter(sc);
1214216829Syongari		VTE_UNLOCK(sc);
1215216829Syongari		break;
1216216829Syongari	case SIOCSIFMEDIA:
1217216829Syongari	case SIOCGIFMEDIA:
1218216829Syongari		mii = device_get_softc(sc->vte_miibus);
1219216829Syongari		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, cmd);
1220216829Syongari		break;
1221216829Syongari	default:
1222216829Syongari		error = ether_ioctl(ifp, cmd, data);
1223216829Syongari		break;
1224216829Syongari	}
1225216829Syongari
1226216829Syongari	return (error);
1227216829Syongari}
1228216829Syongari
1229216829Syongaristatic void
1230216829Syongarivte_mac_config(struct vte_softc *sc)
1231216829Syongari{
1232216829Syongari	struct mii_data *mii;
1233216829Syongari	uint16_t mcr;
1234216829Syongari
1235216829Syongari	VTE_LOCK_ASSERT(sc);
1236216829Syongari
1237216829Syongari	mii = device_get_softc(sc->vte_miibus);
1238216829Syongari	mcr = CSR_READ_2(sc, VTE_MCR0);
1239216829Syongari	mcr &= ~(MCR0_FC_ENB | MCR0_FULL_DUPLEX);
1240216829Syongari	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
1241216829Syongari		mcr |= MCR0_FULL_DUPLEX;
1242216829Syongari#ifdef notyet
1243216829Syongari		if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_TXPAUSE) != 0)
1244216829Syongari			mcr |= MCR0_FC_ENB;
1245216829Syongari		/*
1246216829Syongari		 * The data sheet is not clear whether the controller
1247216829Syongari		 * honors received pause frames or not.  The is no
1248216829Syongari		 * separate control bit for RX pause frame so just
1249216829Syongari		 * enable MCR0_FC_ENB bit.
1250216829Syongari		 */
1251216829Syongari		if ((IFM_OPTIONS(mii->mii_media_active) & IFM_ETH_RXPAUSE) != 0)
1252216829Syongari			mcr |= MCR0_FC_ENB;
1253216829Syongari#endif
1254216829Syongari	}
1255216829Syongari	CSR_WRITE_2(sc, VTE_MCR0, mcr);
1256216829Syongari}
1257216829Syongari
1258216829Syongaristatic void
1259216829Syongarivte_stats_clear(struct vte_softc *sc)
1260216829Syongari{
1261216829Syongari
1262216829Syongari	/* Reading counter registers clears its contents. */
1263216829Syongari	CSR_READ_2(sc, VTE_CNT_RX_DONE);
1264216829Syongari	CSR_READ_2(sc, VTE_CNT_MECNT0);
1265216829Syongari	CSR_READ_2(sc, VTE_CNT_MECNT1);
1266216829Syongari	CSR_READ_2(sc, VTE_CNT_MECNT2);
1267216829Syongari	CSR_READ_2(sc, VTE_CNT_MECNT3);
1268216829Syongari	CSR_READ_2(sc, VTE_CNT_TX_DONE);
1269216829Syongari	CSR_READ_2(sc, VTE_CNT_MECNT4);
1270216829Syongari	CSR_READ_2(sc, VTE_CNT_PAUSE);
1271216829Syongari}
1272216829Syongari
1273216829Syongaristatic void
1274216829Syongarivte_stats_update(struct vte_softc *sc)
1275216829Syongari{
1276216829Syongari	struct vte_hw_stats *stat;
1277216829Syongari	uint16_t value;
1278216829Syongari
1279216829Syongari	VTE_LOCK_ASSERT(sc);
1280216829Syongari
1281216829Syongari	stat = &sc->vte_stats;
1282216829Syongari
1283216829Syongari	CSR_READ_2(sc, VTE_MECISR);
1284216829Syongari	/* RX stats. */
1285216829Syongari	stat->rx_frames += CSR_READ_2(sc, VTE_CNT_RX_DONE);
1286216829Syongari	value = CSR_READ_2(sc, VTE_CNT_MECNT0);
1287216829Syongari	stat->rx_bcast_frames += (value >> 8);
1288216829Syongari	stat->rx_mcast_frames += (value & 0xFF);
1289216829Syongari	value = CSR_READ_2(sc, VTE_CNT_MECNT1);
1290216829Syongari	stat->rx_runts += (value >> 8);
1291216829Syongari	stat->rx_crcerrs += (value & 0xFF);
1292216829Syongari	value = CSR_READ_2(sc, VTE_CNT_MECNT2);
1293216829Syongari	stat->rx_long_frames += (value & 0xFF);
1294216829Syongari	value = CSR_READ_2(sc, VTE_CNT_MECNT3);
1295216829Syongari	stat->rx_fifo_full += (value >> 8);
1296216829Syongari	stat->rx_desc_unavail += (value & 0xFF);
1297216829Syongari
1298216829Syongari	/* TX stats. */
1299216829Syongari	stat->tx_frames += CSR_READ_2(sc, VTE_CNT_TX_DONE);
1300216829Syongari	value = CSR_READ_2(sc, VTE_CNT_MECNT4);
1301216829Syongari	stat->tx_underruns += (value >> 8);
1302216829Syongari	stat->tx_late_colls += (value & 0xFF);
1303216829Syongari
1304216829Syongari	value = CSR_READ_2(sc, VTE_CNT_PAUSE);
1305216829Syongari	stat->tx_pause_frames += (value >> 8);
1306216829Syongari	stat->rx_pause_frames += (value & 0xFF);
1307272065Sglebius}
1308216829Syongari
1309272065Sglebiusstatic uint64_t
1310272065Sglebiusvte_get_counter(struct ifnet *ifp, ift_counter cnt)
1311272065Sglebius{
1312272065Sglebius	struct vte_softc *sc;
1313272065Sglebius	struct vte_hw_stats *stat;
1314272065Sglebius
1315272065Sglebius	sc = if_getsoftc(ifp);
1316272065Sglebius	stat = &sc->vte_stats;
1317272065Sglebius
1318272065Sglebius	switch (cnt) {
1319272065Sglebius	case IFCOUNTER_OPACKETS:
1320272065Sglebius		return (stat->tx_frames);
1321272065Sglebius	case IFCOUNTER_COLLISIONS:
1322272065Sglebius		return (stat->tx_late_colls);
1323272065Sglebius	case IFCOUNTER_OERRORS:
1324272065Sglebius		return (stat->tx_late_colls + stat->tx_underruns);
1325272065Sglebius	case IFCOUNTER_IPACKETS:
1326272065Sglebius		return (stat->rx_frames);
1327272065Sglebius	case IFCOUNTER_IERRORS:
1328272065Sglebius		return (stat->rx_crcerrs + stat->rx_runts +
1329272065Sglebius		    stat->rx_long_frames + stat->rx_fifo_full);
1330272065Sglebius	default:
1331272065Sglebius		return (if_get_counter_default(ifp, cnt));
1332272065Sglebius	}
1333216829Syongari}
1334216829Syongari
1335216829Syongaristatic void
1336216829Syongarivte_intr(void *arg)
1337216829Syongari{
1338216829Syongari	struct vte_softc *sc;
1339216829Syongari	struct ifnet *ifp;
1340216829Syongari	uint16_t status;
1341216829Syongari	int n;
1342216829Syongari
1343216829Syongari	sc = (struct vte_softc *)arg;
1344216829Syongari	VTE_LOCK(sc);
1345216829Syongari
1346216829Syongari	ifp = sc->vte_ifp;
1347216829Syongari	/* Reading VTE_MISR acknowledges interrupts. */
1348216829Syongari	status = CSR_READ_2(sc, VTE_MISR);
1349216829Syongari	if ((status & VTE_INTRS) == 0) {
1350216829Syongari		/* Not ours. */
1351216829Syongari		VTE_UNLOCK(sc);
1352216829Syongari		return;
1353216829Syongari	}
1354216829Syongari
1355216829Syongari	/* Disable interrupts. */
1356216829Syongari	CSR_WRITE_2(sc, VTE_MIER, 0);
1357216829Syongari	for (n = 8; (status & VTE_INTRS) != 0;) {
1358216829Syongari		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
1359216829Syongari			break;
1360216829Syongari		if ((status & (MISR_RX_DONE | MISR_RX_DESC_UNAVAIL |
1361216829Syongari		    MISR_RX_FIFO_FULL)) != 0)
1362216829Syongari			vte_rxeof(sc);
1363216829Syongari		if ((status & MISR_TX_DONE) != 0)
1364216829Syongari			vte_txeof(sc);
1365216829Syongari		if ((status & MISR_EVENT_CNT_OFLOW) != 0)
1366216829Syongari			vte_stats_update(sc);
1367216829Syongari		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1368216829Syongari			vte_start_locked(sc);
1369216829Syongari		if (--n > 0)
1370216829Syongari			status = CSR_READ_2(sc, VTE_MISR);
1371216829Syongari		else
1372216829Syongari			break;
1373216829Syongari	}
1374216829Syongari
1375216829Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1376216829Syongari		/* Re-enable interrupts. */
1377216829Syongari		CSR_WRITE_2(sc, VTE_MIER, VTE_INTRS);
1378216829Syongari	}
1379216829Syongari	VTE_UNLOCK(sc);
1380216829Syongari}
1381216829Syongari
1382216829Syongaristatic void
1383216829Syongarivte_txeof(struct vte_softc *sc)
1384216829Syongari{
1385216829Syongari	struct ifnet *ifp;
1386216829Syongari	struct vte_txdesc *txd;
1387216829Syongari	uint16_t status;
1388216829Syongari	int cons, prog;
1389216829Syongari
1390216829Syongari	VTE_LOCK_ASSERT(sc);
1391216829Syongari
1392216829Syongari	ifp = sc->vte_ifp;
1393216829Syongari
1394216829Syongari	if (sc->vte_cdata.vte_tx_cnt == 0)
1395216829Syongari		return;
1396216829Syongari	bus_dmamap_sync(sc->vte_cdata.vte_tx_ring_tag,
1397216829Syongari	    sc->vte_cdata.vte_tx_ring_map, BUS_DMASYNC_POSTREAD |
1398216829Syongari	    BUS_DMASYNC_POSTWRITE);
1399216829Syongari	cons = sc->vte_cdata.vte_tx_cons;
1400216829Syongari	/*
1401216829Syongari	 * Go through our TX list and free mbufs for those
1402216829Syongari	 * frames which have been transmitted.
1403216829Syongari	 */
1404216829Syongari	for (prog = 0; sc->vte_cdata.vte_tx_cnt > 0; prog++) {
1405216829Syongari		txd = &sc->vte_cdata.vte_txdesc[cons];
1406216829Syongari		status = le16toh(txd->tx_desc->dtst);
1407216829Syongari		if ((status & VTE_DTST_TX_OWN) != 0)
1408216829Syongari			break;
1409216829Syongari		sc->vte_cdata.vte_tx_cnt--;
1410216829Syongari		/* Reclaim transmitted mbufs. */
1411216829Syongari		bus_dmamap_sync(sc->vte_cdata.vte_tx_tag, txd->tx_dmamap,
1412216829Syongari		    BUS_DMASYNC_POSTWRITE);
1413216829Syongari		bus_dmamap_unload(sc->vte_cdata.vte_tx_tag, txd->tx_dmamap);
1414216829Syongari		if ((txd->tx_flags & VTE_TXMBUF) == 0)
1415216829Syongari			m_freem(txd->tx_m);
1416216829Syongari		txd->tx_flags &= ~VTE_TXMBUF;
1417216829Syongari		txd->tx_m = NULL;
1418216829Syongari		prog++;
1419216829Syongari		VTE_DESC_INC(cons, VTE_TX_RING_CNT);
1420216829Syongari	}
1421216829Syongari
1422216829Syongari	if (prog > 0) {
1423216829Syongari		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1424216829Syongari		sc->vte_cdata.vte_tx_cons = cons;
1425216829Syongari		/*
1426216829Syongari		 * Unarm watchdog timer only when there is no pending
1427216829Syongari		 * frames in TX queue.
1428216829Syongari		 */
1429216829Syongari		if (sc->vte_cdata.vte_tx_cnt == 0)
1430216829Syongari			sc->vte_watchdog_timer = 0;
1431216829Syongari	}
1432216829Syongari}
1433216829Syongari
1434216829Syongaristatic int
1435216829Syongarivte_newbuf(struct vte_softc *sc, struct vte_rxdesc *rxd)
1436216829Syongari{
1437216829Syongari	struct mbuf *m;
1438216829Syongari	bus_dma_segment_t segs[1];
1439216829Syongari	bus_dmamap_t map;
1440216829Syongari	int nsegs;
1441216829Syongari
1442243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
1443216829Syongari	if (m == NULL)
1444216829Syongari		return (ENOBUFS);
1445216829Syongari	m->m_len = m->m_pkthdr.len = MCLBYTES;
1446216829Syongari	m_adj(m, sizeof(uint32_t));
1447216829Syongari
1448216829Syongari	if (bus_dmamap_load_mbuf_sg(sc->vte_cdata.vte_rx_tag,
1449216829Syongari	    sc->vte_cdata.vte_rx_sparemap, m, segs, &nsegs, 0) != 0) {
1450216829Syongari		m_freem(m);
1451216829Syongari		return (ENOBUFS);
1452216829Syongari	}
1453216829Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
1454216829Syongari
1455216829Syongari	if (rxd->rx_m != NULL) {
1456216829Syongari		bus_dmamap_sync(sc->vte_cdata.vte_rx_tag, rxd->rx_dmamap,
1457216829Syongari		    BUS_DMASYNC_POSTREAD);
1458216829Syongari		bus_dmamap_unload(sc->vte_cdata.vte_rx_tag, rxd->rx_dmamap);
1459216829Syongari	}
1460216829Syongari	map = rxd->rx_dmamap;
1461216829Syongari	rxd->rx_dmamap = sc->vte_cdata.vte_rx_sparemap;
1462216829Syongari	sc->vte_cdata.vte_rx_sparemap = map;
1463216829Syongari	bus_dmamap_sync(sc->vte_cdata.vte_rx_tag, rxd->rx_dmamap,
1464216829Syongari	    BUS_DMASYNC_PREREAD);
1465216829Syongari	rxd->rx_m = m;
1466216829Syongari	rxd->rx_desc->drbp = htole32(segs[0].ds_addr);
1467216829Syongari	rxd->rx_desc->drlen = htole16(VTE_RX_LEN(segs[0].ds_len));
1468216829Syongari	rxd->rx_desc->drst = htole16(VTE_DRST_RX_OWN);
1469216829Syongari
1470216829Syongari	return (0);
1471216829Syongari}
1472216829Syongari
1473216829Syongari/*
1474216829Syongari * It's not supposed to see this controller on strict-alignment
1475216829Syongari * architectures but make it work for completeness.
1476216829Syongari */
1477216829Syongari#ifndef __NO_STRICT_ALIGNMENT
1478216829Syongaristatic struct mbuf *
1479216829Syongarivte_fixup_rx(struct ifnet *ifp, struct mbuf *m)
1480216829Syongari{
1481216829Syongari        uint16_t *src, *dst;
1482216829Syongari        int i;
1483216829Syongari
1484216829Syongari	src = mtod(m, uint16_t *);
1485216829Syongari	dst = src - 1;
1486216829Syongari
1487216829Syongari	for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++)
1488216829Syongari		*dst++ = *src++;
1489216829Syongari	m->m_data -= ETHER_ALIGN;
1490216829Syongari	return (m);
1491216829Syongari}
1492216829Syongari#endif
1493216829Syongari
1494216829Syongaristatic void
1495216829Syongarivte_rxeof(struct vte_softc *sc)
1496216829Syongari{
1497216829Syongari	struct ifnet *ifp;
1498216829Syongari	struct vte_rxdesc *rxd;
1499216829Syongari	struct mbuf *m;
1500216829Syongari	uint16_t status, total_len;
1501216829Syongari	int cons, prog;
1502216829Syongari
1503216829Syongari	bus_dmamap_sync(sc->vte_cdata.vte_rx_ring_tag,
1504216829Syongari	    sc->vte_cdata.vte_rx_ring_map, BUS_DMASYNC_POSTREAD |
1505216829Syongari	    BUS_DMASYNC_POSTWRITE);
1506216829Syongari	cons = sc->vte_cdata.vte_rx_cons;
1507216829Syongari	ifp = sc->vte_ifp;
1508216829Syongari	for (prog = 0; (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0; prog++,
1509216829Syongari	    VTE_DESC_INC(cons, VTE_RX_RING_CNT)) {
1510216829Syongari		rxd = &sc->vte_cdata.vte_rxdesc[cons];
1511216829Syongari		status = le16toh(rxd->rx_desc->drst);
1512216829Syongari		if ((status & VTE_DRST_RX_OWN) != 0)
1513216829Syongari			break;
1514216829Syongari		total_len = VTE_RX_LEN(le16toh(rxd->rx_desc->drlen));
1515216829Syongari		m = rxd->rx_m;
1516216829Syongari		if ((status & VTE_DRST_RX_OK) == 0) {
1517216829Syongari			/* Discard errored frame. */
1518216829Syongari			rxd->rx_desc->drlen =
1519216829Syongari			    htole16(MCLBYTES - sizeof(uint32_t));
1520216829Syongari			rxd->rx_desc->drst = htole16(VTE_DRST_RX_OWN);
1521216829Syongari			continue;
1522216829Syongari		}
1523216829Syongari		if (vte_newbuf(sc, rxd) != 0) {
1524272065Sglebius			if_inc_counter(ifp, IFCOUNTER_IQDROPS, 1);
1525216829Syongari			rxd->rx_desc->drlen =
1526216829Syongari			    htole16(MCLBYTES - sizeof(uint32_t));
1527216829Syongari			rxd->rx_desc->drst = htole16(VTE_DRST_RX_OWN);
1528216829Syongari			continue;
1529216829Syongari		}
1530216829Syongari
1531216829Syongari		/*
1532216829Syongari		 * It seems there is no way to strip FCS bytes.
1533216829Syongari		 */
1534216829Syongari		m->m_pkthdr.len = m->m_len = total_len - ETHER_CRC_LEN;
1535216829Syongari		m->m_pkthdr.rcvif = ifp;
1536216829Syongari#ifndef __NO_STRICT_ALIGNMENT
1537216829Syongari		vte_fixup_rx(ifp, m);
1538216829Syongari#endif
1539216829Syongari		VTE_UNLOCK(sc);
1540216829Syongari		(*ifp->if_input)(ifp, m);
1541216829Syongari		VTE_LOCK(sc);
1542216829Syongari	}
1543216829Syongari
1544216829Syongari	if (prog > 0) {
1545216829Syongari		/* Update the consumer index. */
1546216829Syongari		sc->vte_cdata.vte_rx_cons = cons;
1547216829Syongari		/*
1548216829Syongari		 * Sync updated RX descriptors such that controller see
1549216829Syongari		 * modified RX buffer addresses.
1550216829Syongari		 */
1551216829Syongari		bus_dmamap_sync(sc->vte_cdata.vte_rx_ring_tag,
1552216829Syongari		    sc->vte_cdata.vte_rx_ring_map,
1553216829Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1554216829Syongari#ifdef notyet
1555216829Syongari		/*
1556216829Syongari		 * Update residue counter.  Controller does not
1557216829Syongari		 * keep track of number of available RX descriptors
1558216829Syongari		 * such that driver should have to update VTE_MRDCR
1559216829Syongari		 * to make controller know how many free RX
1560216829Syongari		 * descriptors were added to controller.  This is
1561216829Syongari		 * a similar mechanism used in VIA velocity
1562216829Syongari		 * controllers and it indicates controller just
1563216829Syongari		 * polls OWN bit of current RX descriptor pointer.
1564216829Syongari		 * A couple of severe issues were seen on sample
1565216829Syongari		 * board where the controller continuously emits TX
1566216829Syongari		 * pause frames once RX pause threshold crossed.
1567216829Syongari		 * Once triggered it never recovered form that
1568216829Syongari		 * state, I couldn't find a way to make it back to
1569216829Syongari		 * work at least.  This issue effectively
1570216829Syongari		 * disconnected the system from network.  Also, the
1571216829Syongari		 * controller used 00:00:00:00:00:00 as source
1572216829Syongari		 * station address of TX pause frame. Probably this
1573216829Syongari		 * is one of reason why vendor recommends not to
1574216829Syongari		 * enable flow control on R6040 controller.
1575216829Syongari		 */
1576216829Syongari		CSR_WRITE_2(sc, VTE_MRDCR, prog |
1577216829Syongari		    (((VTE_RX_RING_CNT * 2) / 10) <<
1578216829Syongari		    VTE_MRDCR_RX_PAUSE_THRESH_SHIFT));
1579216829Syongari#endif
1580216829Syongari	}
1581216829Syongari}
1582216829Syongari
1583216829Syongaristatic void
1584216829Syongarivte_tick(void *arg)
1585216829Syongari{
1586216829Syongari	struct vte_softc *sc;
1587216829Syongari	struct mii_data *mii;
1588216829Syongari
1589216829Syongari	sc = (struct vte_softc *)arg;
1590216829Syongari
1591216829Syongari	VTE_LOCK_ASSERT(sc);
1592216829Syongari
1593216829Syongari	mii = device_get_softc(sc->vte_miibus);
1594216829Syongari	mii_tick(mii);
1595216829Syongari	vte_stats_update(sc);
1596216829Syongari	vte_txeof(sc);
1597216829Syongari	vte_watchdog(sc);
1598216829Syongari	callout_reset(&sc->vte_tick_ch, hz, vte_tick, sc);
1599216829Syongari}
1600216829Syongari
1601216829Syongaristatic void
1602216829Syongarivte_reset(struct vte_softc *sc)
1603216829Syongari{
1604216829Syongari	uint16_t mcr;
1605216829Syongari	int i;
1606216829Syongari
1607216829Syongari	mcr = CSR_READ_2(sc, VTE_MCR1);
1608216829Syongari	CSR_WRITE_2(sc, VTE_MCR1, mcr | MCR1_MAC_RESET);
1609216829Syongari	for (i = VTE_RESET_TIMEOUT; i > 0; i--) {
1610216829Syongari		DELAY(10);
1611216829Syongari		if ((CSR_READ_2(sc, VTE_MCR1) & MCR1_MAC_RESET) == 0)
1612216829Syongari			break;
1613216829Syongari	}
1614216829Syongari	if (i == 0)
1615216829Syongari		device_printf(sc->vte_dev, "reset timeout(0x%04x)!\n", mcr);
1616216829Syongari	/*
1617216829Syongari	 * Follow the guide of vendor recommended way to reset MAC.
1618216829Syongari	 * Vendor confirms relying on MCR1_MAC_RESET of VTE_MCR1 is
1619216829Syongari	 * not reliable so manually reset internal state machine.
1620216829Syongari	 */
1621216829Syongari	CSR_WRITE_2(sc, VTE_MACSM, 0x0002);
1622216829Syongari	CSR_WRITE_2(sc, VTE_MACSM, 0);
1623216829Syongari	DELAY(5000);
1624216829Syongari}
1625216829Syongari
1626216829Syongaristatic void
1627216829Syongarivte_init(void *xsc)
1628216829Syongari{
1629216829Syongari	struct vte_softc *sc;
1630216829Syongari
1631216829Syongari	sc = (struct vte_softc *)xsc;
1632216829Syongari	VTE_LOCK(sc);
1633216829Syongari	vte_init_locked(sc);
1634216829Syongari	VTE_UNLOCK(sc);
1635216829Syongari}
1636216829Syongari
1637216829Syongaristatic void
1638216829Syongarivte_init_locked(struct vte_softc *sc)
1639216829Syongari{
1640216829Syongari	struct ifnet *ifp;
1641216829Syongari	bus_addr_t paddr;
1642216829Syongari	uint8_t *eaddr;
1643216829Syongari
1644216829Syongari	VTE_LOCK_ASSERT(sc);
1645216829Syongari
1646216829Syongari	ifp = sc->vte_ifp;
1647216829Syongari
1648216829Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
1649216829Syongari		return;
1650216829Syongari	/*
1651216829Syongari	 * Cancel any pending I/O.
1652216829Syongari	 */
1653216829Syongari	vte_stop(sc);
1654216829Syongari	/*
1655216829Syongari	 * Reset the chip to a known state.
1656216829Syongari	 */
1657216829Syongari	vte_reset(sc);
1658216829Syongari
1659216829Syongari	/* Initialize RX descriptors. */
1660216829Syongari	if (vte_init_rx_ring(sc) != 0) {
1661216829Syongari		device_printf(sc->vte_dev, "no memory for RX buffers.\n");
1662216829Syongari		vte_stop(sc);
1663216829Syongari		return;
1664216829Syongari	}
1665216829Syongari	if (vte_init_tx_ring(sc) != 0) {
1666216829Syongari		device_printf(sc->vte_dev, "no memory for TX buffers.\n");
1667216829Syongari		vte_stop(sc);
1668216829Syongari		return;
1669216829Syongari	}
1670216829Syongari
1671216829Syongari	/*
1672216829Syongari	 * Reprogram the station address.  Controller supports up
1673216829Syongari	 * to 4 different station addresses so driver programs the
1674216829Syongari	 * first station address as its own ethernet address and
1675216829Syongari	 * configure the remaining three addresses as perfect
1676216829Syongari	 * multicast addresses.
1677216829Syongari	 */
1678216829Syongari	eaddr = IF_LLADDR(sc->vte_ifp);
1679216829Syongari	CSR_WRITE_2(sc, VTE_MID0L, eaddr[1] << 8 | eaddr[0]);
1680216829Syongari	CSR_WRITE_2(sc, VTE_MID0M, eaddr[3] << 8 | eaddr[2]);
1681216829Syongari	CSR_WRITE_2(sc, VTE_MID0H, eaddr[5] << 8 | eaddr[4]);
1682216829Syongari
1683216829Syongari	/* Set TX descriptor base addresses. */
1684216829Syongari	paddr = sc->vte_cdata.vte_tx_ring_paddr;
1685216829Syongari	CSR_WRITE_2(sc, VTE_MTDSA1, paddr >> 16);
1686216829Syongari	CSR_WRITE_2(sc, VTE_MTDSA0, paddr & 0xFFFF);
1687216829Syongari	/* Set RX descriptor base addresses. */
1688216829Syongari	paddr = sc->vte_cdata.vte_rx_ring_paddr;
1689216829Syongari	CSR_WRITE_2(sc, VTE_MRDSA1, paddr >> 16);
1690216829Syongari	CSR_WRITE_2(sc, VTE_MRDSA0, paddr & 0xFFFF);
1691216829Syongari	/*
1692216829Syongari	 * Initialize RX descriptor residue counter and set RX
1693216829Syongari	 * pause threshold to 20% of available RX descriptors.
1694216829Syongari	 * See comments on vte_rxeof() for details on flow control
1695216829Syongari	 * issues.
1696216829Syongari	 */
1697216829Syongari	CSR_WRITE_2(sc, VTE_MRDCR, (VTE_RX_RING_CNT & VTE_MRDCR_RESIDUE_MASK) |
1698216829Syongari	    (((VTE_RX_RING_CNT * 2) / 10) << VTE_MRDCR_RX_PAUSE_THRESH_SHIFT));
1699216829Syongari
1700216829Syongari	/*
1701216829Syongari	 * Always use maximum frame size that controller can
1702216829Syongari	 * support.  Otherwise received frames that has longer
1703216829Syongari	 * frame length than vte(4) MTU would be silently dropped
1704216829Syongari	 * in controller.  This would break path-MTU discovery as
1705216829Syongari	 * sender wouldn't get any responses from receiver. The
1706216829Syongari	 * RX buffer size should be multiple of 4.
1707216829Syongari	 * Note, jumbo frames are silently ignored by controller
1708216829Syongari	 * and even MAC counters do not detect them.
1709216829Syongari	 */
1710216829Syongari	CSR_WRITE_2(sc, VTE_MRBSR, VTE_RX_BUF_SIZE_MAX);
1711216829Syongari
1712216829Syongari	/* Configure FIFO. */
1713216829Syongari	CSR_WRITE_2(sc, VTE_MBCR, MBCR_FIFO_XFER_LENGTH_16 |
1714216829Syongari	    MBCR_TX_FIFO_THRESH_64 | MBCR_RX_FIFO_THRESH_16 |
1715216829Syongari	    MBCR_SDRAM_BUS_REQ_TIMER_DEFAULT);
1716216829Syongari
1717216829Syongari	/*
1718216829Syongari	 * Configure TX/RX MACs.  Actual resolved duplex and flow
1719216829Syongari	 * control configuration is done after detecting a valid
1720216829Syongari	 * link.  Note, we don't generate early interrupt here
1721216829Syongari	 * as well since FreeBSD does not have interrupt latency
1722216829Syongari	 * problems like Windows.
1723216829Syongari	 */
1724216829Syongari	CSR_WRITE_2(sc, VTE_MCR0, MCR0_ACCPT_LONG_PKT);
1725216829Syongari	/*
1726216829Syongari	 * We manually keep track of PHY status changes to
1727216829Syongari	 * configure resolved duplex and flow control since only
1728216829Syongari	 * duplex configuration can be automatically reflected to
1729216829Syongari	 * MCR0.
1730216829Syongari	 */
1731216829Syongari	CSR_WRITE_2(sc, VTE_MCR1, MCR1_PKT_LENGTH_1537 |
1732216829Syongari	    MCR1_EXCESS_COL_RETRY_16);
1733216829Syongari
1734216829Syongari	/* Initialize RX filter. */
1735216829Syongari	vte_rxfilter(sc);
1736216829Syongari
1737216829Syongari	/* Disable TX/RX interrupt moderation control. */
1738216829Syongari	CSR_WRITE_2(sc, VTE_MRICR, 0);
1739216829Syongari	CSR_WRITE_2(sc, VTE_MTICR, 0);
1740216829Syongari
1741216829Syongari	/* Enable MAC event counter interrupts. */
1742216829Syongari	CSR_WRITE_2(sc, VTE_MECIER, VTE_MECIER_INTRS);
1743216829Syongari	/* Clear MAC statistics. */
1744216829Syongari	vte_stats_clear(sc);
1745216829Syongari
1746216829Syongari	/* Acknowledge all pending interrupts and clear it. */
1747216829Syongari	CSR_WRITE_2(sc, VTE_MIER, VTE_INTRS);
1748216829Syongari	CSR_WRITE_2(sc, VTE_MISR, 0);
1749216829Syongari
1750216829Syongari	sc->vte_flags &= ~VTE_FLAG_LINK;
1751216829Syongari	/* Switch to the current media. */
1752216829Syongari	vte_mediachange_locked(ifp);
1753216829Syongari
1754216829Syongari	callout_reset(&sc->vte_tick_ch, hz, vte_tick, sc);
1755216829Syongari
1756216829Syongari	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1757216829Syongari	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1758216829Syongari}
1759216829Syongari
1760216829Syongaristatic void
1761216829Syongarivte_stop(struct vte_softc *sc)
1762216829Syongari{
1763216829Syongari	struct ifnet *ifp;
1764216829Syongari	struct vte_txdesc *txd;
1765216829Syongari	struct vte_rxdesc *rxd;
1766216829Syongari	int i;
1767216829Syongari
1768216829Syongari	VTE_LOCK_ASSERT(sc);
1769216829Syongari	/*
1770216829Syongari	 * Mark the interface down and cancel the watchdog timer.
1771216829Syongari	 */
1772216829Syongari	ifp = sc->vte_ifp;
1773216829Syongari	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
1774216829Syongari	sc->vte_flags &= ~VTE_FLAG_LINK;
1775216829Syongari	callout_stop(&sc->vte_tick_ch);
1776216829Syongari	sc->vte_watchdog_timer = 0;
1777216829Syongari	vte_stats_update(sc);
1778216829Syongari	/* Disable interrupts. */
1779216829Syongari	CSR_WRITE_2(sc, VTE_MIER, 0);
1780216829Syongari	CSR_WRITE_2(sc, VTE_MECIER, 0);
1781216829Syongari	/* Stop RX/TX MACs. */
1782216829Syongari	vte_stop_mac(sc);
1783216829Syongari	/* Clear interrupts. */
1784216829Syongari	CSR_READ_2(sc, VTE_MISR);
1785216829Syongari	/*
1786216829Syongari	 * Free TX/RX mbufs still in the queues.
1787216829Syongari	 */
1788216829Syongari	for (i = 0; i < VTE_RX_RING_CNT; i++) {
1789216829Syongari		rxd = &sc->vte_cdata.vte_rxdesc[i];
1790216829Syongari		if (rxd->rx_m != NULL) {
1791216829Syongari			bus_dmamap_sync(sc->vte_cdata.vte_rx_tag,
1792216829Syongari			    rxd->rx_dmamap, BUS_DMASYNC_POSTREAD);
1793216829Syongari			bus_dmamap_unload(sc->vte_cdata.vte_rx_tag,
1794216829Syongari			    rxd->rx_dmamap);
1795216829Syongari			m_freem(rxd->rx_m);
1796216829Syongari			rxd->rx_m = NULL;
1797216829Syongari		}
1798216829Syongari	}
1799216829Syongari	for (i = 0; i < VTE_TX_RING_CNT; i++) {
1800216829Syongari		txd = &sc->vte_cdata.vte_txdesc[i];
1801216829Syongari		if (txd->tx_m != NULL) {
1802216829Syongari			bus_dmamap_sync(sc->vte_cdata.vte_tx_tag,
1803216829Syongari			    txd->tx_dmamap, BUS_DMASYNC_POSTWRITE);
1804216829Syongari			bus_dmamap_unload(sc->vte_cdata.vte_tx_tag,
1805216829Syongari			    txd->tx_dmamap);
1806216829Syongari			if ((txd->tx_flags & VTE_TXMBUF) == 0)
1807216829Syongari				m_freem(txd->tx_m);
1808216829Syongari			txd->tx_m = NULL;
1809216829Syongari			txd->tx_flags &= ~VTE_TXMBUF;
1810216829Syongari		}
1811216829Syongari	}
1812216829Syongari	/* Free TX mbuf pools used for deep copy. */
1813216829Syongari	for (i = 0; i < VTE_TX_RING_CNT; i++) {
1814216829Syongari		if (sc->vte_cdata.vte_txmbufs[i] != NULL) {
1815216829Syongari			m_freem(sc->vte_cdata.vte_txmbufs[i]);
1816216829Syongari			sc->vte_cdata.vte_txmbufs[i] = NULL;
1817216829Syongari		}
1818216829Syongari	}
1819216829Syongari}
1820216829Syongari
1821216829Syongaristatic void
1822216829Syongarivte_start_mac(struct vte_softc *sc)
1823216829Syongari{
1824216829Syongari	uint16_t mcr;
1825216829Syongari	int i;
1826216829Syongari
1827216829Syongari	VTE_LOCK_ASSERT(sc);
1828216829Syongari
1829216829Syongari	/* Enable RX/TX MACs. */
1830216829Syongari	mcr = CSR_READ_2(sc, VTE_MCR0);
1831216829Syongari	if ((mcr & (MCR0_RX_ENB | MCR0_TX_ENB)) !=
1832216829Syongari	    (MCR0_RX_ENB | MCR0_TX_ENB)) {
1833216829Syongari		mcr |= MCR0_RX_ENB | MCR0_TX_ENB;
1834216829Syongari		CSR_WRITE_2(sc, VTE_MCR0, mcr);
1835216829Syongari		for (i = VTE_TIMEOUT; i > 0; i--) {
1836216829Syongari			mcr = CSR_READ_2(sc, VTE_MCR0);
1837216829Syongari			if ((mcr & (MCR0_RX_ENB | MCR0_TX_ENB)) ==
1838216829Syongari			    (MCR0_RX_ENB | MCR0_TX_ENB))
1839216829Syongari				break;
1840216829Syongari			DELAY(10);
1841216829Syongari		}
1842216829Syongari		if (i == 0)
1843216829Syongari			device_printf(sc->vte_dev,
1844216829Syongari			    "could not enable RX/TX MAC(0x%04x)!\n", mcr);
1845216829Syongari	}
1846216829Syongari}
1847216829Syongari
1848216829Syongaristatic void
1849216829Syongarivte_stop_mac(struct vte_softc *sc)
1850216829Syongari{
1851216829Syongari	uint16_t mcr;
1852216829Syongari	int i;
1853216829Syongari
1854216829Syongari	VTE_LOCK_ASSERT(sc);
1855216829Syongari
1856216829Syongari	/* Disable RX/TX MACs. */
1857216829Syongari	mcr = CSR_READ_2(sc, VTE_MCR0);
1858216829Syongari	if ((mcr & (MCR0_RX_ENB | MCR0_TX_ENB)) != 0) {
1859216829Syongari		mcr &= ~(MCR0_RX_ENB | MCR0_TX_ENB);
1860216829Syongari		CSR_WRITE_2(sc, VTE_MCR0, mcr);
1861216829Syongari		for (i = VTE_TIMEOUT; i > 0; i--) {
1862216829Syongari			mcr = CSR_READ_2(sc, VTE_MCR0);
1863216829Syongari			if ((mcr & (MCR0_RX_ENB | MCR0_TX_ENB)) == 0)
1864216829Syongari				break;
1865216829Syongari			DELAY(10);
1866216829Syongari		}
1867216829Syongari		if (i == 0)
1868216829Syongari			device_printf(sc->vte_dev,
1869216829Syongari			    "could not disable RX/TX MAC(0x%04x)!\n", mcr);
1870216829Syongari	}
1871216829Syongari}
1872216829Syongari
1873216829Syongaristatic int
1874216829Syongarivte_init_tx_ring(struct vte_softc *sc)
1875216829Syongari{
1876216829Syongari	struct vte_tx_desc *desc;
1877216829Syongari	struct vte_txdesc *txd;
1878216829Syongari	bus_addr_t addr;
1879216829Syongari	int i;
1880216829Syongari
1881216829Syongari	VTE_LOCK_ASSERT(sc);
1882216829Syongari
1883216829Syongari	sc->vte_cdata.vte_tx_prod = 0;
1884216829Syongari	sc->vte_cdata.vte_tx_cons = 0;
1885216829Syongari	sc->vte_cdata.vte_tx_cnt = 0;
1886216829Syongari
1887216829Syongari	/* Pre-allocate TX mbufs for deep copy. */
1888216829Syongari	if (tx_deep_copy != 0) {
1889216829Syongari		for (i = 0; i < VTE_TX_RING_CNT; i++) {
1890243857Sglebius			sc->vte_cdata.vte_txmbufs[i] = m_getcl(M_NOWAIT,
1891216829Syongari			    MT_DATA, M_PKTHDR);
1892216829Syongari			if (sc->vte_cdata.vte_txmbufs[i] == NULL)
1893216829Syongari				return (ENOBUFS);
1894216829Syongari			sc->vte_cdata.vte_txmbufs[i]->m_pkthdr.len = MCLBYTES;
1895216829Syongari			sc->vte_cdata.vte_txmbufs[i]->m_len = MCLBYTES;
1896216829Syongari		}
1897216829Syongari	}
1898216829Syongari	desc = sc->vte_cdata.vte_tx_ring;
1899216829Syongari	bzero(desc, VTE_TX_RING_SZ);
1900216829Syongari	for (i = 0; i < VTE_TX_RING_CNT; i++) {
1901216829Syongari		txd = &sc->vte_cdata.vte_txdesc[i];
1902216829Syongari		txd->tx_m = NULL;
1903216829Syongari		if (i != VTE_TX_RING_CNT - 1)
1904216829Syongari			addr = sc->vte_cdata.vte_tx_ring_paddr +
1905216829Syongari			    sizeof(struct vte_tx_desc) * (i + 1);
1906216829Syongari		else
1907216829Syongari			addr = sc->vte_cdata.vte_tx_ring_paddr +
1908216829Syongari			    sizeof(struct vte_tx_desc) * 0;
1909216829Syongari		desc = &sc->vte_cdata.vte_tx_ring[i];
1910216829Syongari		desc->dtnp = htole32(addr);
1911216829Syongari		txd->tx_desc = desc;
1912216829Syongari	}
1913216829Syongari
1914216829Syongari	bus_dmamap_sync(sc->vte_cdata.vte_tx_ring_tag,
1915216829Syongari	    sc->vte_cdata.vte_tx_ring_map, BUS_DMASYNC_PREREAD |
1916216829Syongari	    BUS_DMASYNC_PREWRITE);
1917216829Syongari	return (0);
1918216829Syongari}
1919216829Syongari
1920216829Syongaristatic int
1921216829Syongarivte_init_rx_ring(struct vte_softc *sc)
1922216829Syongari{
1923216829Syongari	struct vte_rx_desc *desc;
1924216829Syongari	struct vte_rxdesc *rxd;
1925216829Syongari	bus_addr_t addr;
1926216829Syongari	int i;
1927216829Syongari
1928216829Syongari	VTE_LOCK_ASSERT(sc);
1929216829Syongari
1930216829Syongari	sc->vte_cdata.vte_rx_cons = 0;
1931216829Syongari	desc = sc->vte_cdata.vte_rx_ring;
1932216829Syongari	bzero(desc, VTE_RX_RING_SZ);
1933216829Syongari	for (i = 0; i < VTE_RX_RING_CNT; i++) {
1934216829Syongari		rxd = &sc->vte_cdata.vte_rxdesc[i];
1935216829Syongari		rxd->rx_m = NULL;
1936216829Syongari		if (i != VTE_RX_RING_CNT - 1)
1937216829Syongari			addr = sc->vte_cdata.vte_rx_ring_paddr +
1938216829Syongari			    sizeof(struct vte_rx_desc) * (i + 1);
1939216829Syongari		else
1940216829Syongari			addr = sc->vte_cdata.vte_rx_ring_paddr +
1941216829Syongari			    sizeof(struct vte_rx_desc) * 0;
1942216829Syongari		desc = &sc->vte_cdata.vte_rx_ring[i];
1943216829Syongari		desc->drnp = htole32(addr);
1944216829Syongari		rxd->rx_desc = desc;
1945216829Syongari		if (vte_newbuf(sc, rxd) != 0)
1946216829Syongari			return (ENOBUFS);
1947216829Syongari	}
1948216829Syongari
1949216829Syongari	bus_dmamap_sync(sc->vte_cdata.vte_rx_ring_tag,
1950216829Syongari	    sc->vte_cdata.vte_rx_ring_map, BUS_DMASYNC_PREREAD |
1951216829Syongari	    BUS_DMASYNC_PREWRITE);
1952216829Syongari
1953216829Syongari	return (0);
1954216829Syongari}
1955216829Syongari
1956216829Syongaristatic void
1957216829Syongarivte_rxfilter(struct vte_softc *sc)
1958216829Syongari{
1959216829Syongari	struct ifnet *ifp;
1960216829Syongari	struct ifmultiaddr *ifma;
1961216829Syongari	uint8_t *eaddr;
1962216829Syongari	uint32_t crc;
1963216829Syongari	uint16_t rxfilt_perf[VTE_RXFILT_PERFECT_CNT][3];
1964216829Syongari	uint16_t mchash[4], mcr;
1965216829Syongari	int i, nperf;
1966216829Syongari
1967216829Syongari	VTE_LOCK_ASSERT(sc);
1968216829Syongari
1969216829Syongari	ifp = sc->vte_ifp;
1970216829Syongari
1971216829Syongari	bzero(mchash, sizeof(mchash));
1972216829Syongari	for (i = 0; i < VTE_RXFILT_PERFECT_CNT; i++) {
1973216829Syongari		rxfilt_perf[i][0] = 0xFFFF;
1974216829Syongari		rxfilt_perf[i][1] = 0xFFFF;
1975216829Syongari		rxfilt_perf[i][2] = 0xFFFF;
1976216829Syongari	}
1977216829Syongari
1978216829Syongari	mcr = CSR_READ_2(sc, VTE_MCR0);
1979219787Syongari	mcr &= ~(MCR0_PROMISC | MCR0_MULTICAST);
1980219787Syongari	mcr |= MCR0_BROADCAST_DIS;
1981216829Syongari	if ((ifp->if_flags & IFF_BROADCAST) != 0)
1982219787Syongari		mcr &= ~MCR0_BROADCAST_DIS;
1983216829Syongari	if ((ifp->if_flags & (IFF_PROMISC | IFF_ALLMULTI)) != 0) {
1984216829Syongari		if ((ifp->if_flags & IFF_PROMISC) != 0)
1985216829Syongari			mcr |= MCR0_PROMISC;
1986216829Syongari		if ((ifp->if_flags & IFF_ALLMULTI) != 0)
1987216829Syongari			mcr |= MCR0_MULTICAST;
1988216829Syongari		mchash[0] = 0xFFFF;
1989216829Syongari		mchash[1] = 0xFFFF;
1990216829Syongari		mchash[2] = 0xFFFF;
1991216829Syongari		mchash[3] = 0xFFFF;
1992216829Syongari		goto chipit;
1993216829Syongari	}
1994216829Syongari
1995216829Syongari	nperf = 0;
1996216829Syongari	if_maddr_rlock(ifp);
1997216829Syongari	TAILQ_FOREACH(ifma, &sc->vte_ifp->if_multiaddrs, ifma_link) {
1998216829Syongari		if (ifma->ifma_addr->sa_family != AF_LINK)
1999216829Syongari			continue;
2000216829Syongari		/*
2001216829Syongari		 * Program the first 3 multicast groups into
2002216829Syongari		 * the perfect filter.  For all others, use the
2003216829Syongari		 * hash table.
2004216829Syongari		 */
2005216829Syongari		if (nperf < VTE_RXFILT_PERFECT_CNT) {
2006216829Syongari			eaddr = LLADDR((struct sockaddr_dl *)ifma->ifma_addr);
2007216829Syongari			rxfilt_perf[nperf][0] = eaddr[1] << 8 | eaddr[0];
2008216829Syongari			rxfilt_perf[nperf][1] = eaddr[3] << 8 | eaddr[2];
2009216829Syongari			rxfilt_perf[nperf][2] = eaddr[5] << 8 | eaddr[4];
2010216829Syongari			nperf++;
2011216829Syongari			continue;
2012216829Syongari		}
2013216829Syongari		crc = ether_crc32_be(LLADDR((struct sockaddr_dl *)
2014216829Syongari		    ifma->ifma_addr), ETHER_ADDR_LEN);
2015216829Syongari		mchash[crc >> 30] |= 1 << ((crc >> 26) & 0x0F);
2016216829Syongari	}
2017216829Syongari	if_maddr_runlock(ifp);
2018216829Syongari	if (mchash[0] != 0 || mchash[1] != 0 || mchash[2] != 0 ||
2019216829Syongari	    mchash[3] != 0)
2020216829Syongari		mcr |= MCR0_MULTICAST;
2021216829Syongari
2022216829Syongarichipit:
2023216829Syongari	/* Program multicast hash table. */
2024216829Syongari	CSR_WRITE_2(sc, VTE_MAR0, mchash[0]);
2025216829Syongari	CSR_WRITE_2(sc, VTE_MAR1, mchash[1]);
2026216829Syongari	CSR_WRITE_2(sc, VTE_MAR2, mchash[2]);
2027216829Syongari	CSR_WRITE_2(sc, VTE_MAR3, mchash[3]);
2028216829Syongari	/* Program perfect filter table. */
2029216829Syongari	for (i = 0; i < VTE_RXFILT_PERFECT_CNT; i++) {
2030216829Syongari		CSR_WRITE_2(sc, VTE_RXFILTER_PEEFECT_BASE + 8 * i + 0,
2031216829Syongari		    rxfilt_perf[i][0]);
2032216829Syongari		CSR_WRITE_2(sc, VTE_RXFILTER_PEEFECT_BASE + 8 * i + 2,
2033216829Syongari		    rxfilt_perf[i][1]);
2034216829Syongari		CSR_WRITE_2(sc, VTE_RXFILTER_PEEFECT_BASE + 8 * i + 4,
2035216829Syongari		    rxfilt_perf[i][2]);
2036216829Syongari	}
2037216829Syongari	CSR_WRITE_2(sc, VTE_MCR0, mcr);
2038216829Syongari	CSR_READ_2(sc, VTE_MCR0);
2039216829Syongari}
2040216829Syongari
2041216829Syongaristatic int
2042216829Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high)
2043216829Syongari{
2044216829Syongari	int error, value;
2045216829Syongari
2046216829Syongari	if (arg1 == NULL)
2047216829Syongari		return (EINVAL);
2048216829Syongari	value = *(int *)arg1;
2049216829Syongari	error = sysctl_handle_int(oidp, &value, 0, req);
2050216829Syongari	if (error || req->newptr == NULL)
2051216829Syongari		return (error);
2052216829Syongari	if (value < low || value > high)
2053216829Syongari		return (EINVAL);
2054216829Syongari	*(int *)arg1 = value;
2055216829Syongari
2056216829Syongari	return (0);
2057216829Syongari}
2058216829Syongari
2059216829Syongaristatic int
2060216829Syongarisysctl_hw_vte_int_mod(SYSCTL_HANDLER_ARGS)
2061216829Syongari{
2062216829Syongari
2063216829Syongari	return (sysctl_int_range(oidp, arg1, arg2, req,
2064216829Syongari	    VTE_IM_BUNDLE_MIN, VTE_IM_BUNDLE_MAX));
2065216829Syongari}
2066