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