1139825Simp/*-
250128Swpaul * Copyright (c) 1997, 1998, 1999
350128Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
450128Swpaul *
550128Swpaul * Redistribution and use in source and binary forms, with or without
650128Swpaul * modification, are permitted provided that the following conditions
750128Swpaul * are met:
850128Swpaul * 1. Redistributions of source code must retain the above copyright
950128Swpaul *    notice, this list of conditions and the following disclaimer.
1050128Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1150128Swpaul *    notice, this list of conditions and the following disclaimer in the
1250128Swpaul *    documentation and/or other materials provided with the distribution.
1350128Swpaul * 3. All advertising materials mentioning features or use of this software
1450128Swpaul *    must display the following acknowledgement:
1550128Swpaul *	This product includes software developed by Bill Paul.
1650128Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1750128Swpaul *    may be used to endorse or promote products derived from this software
1850128Swpaul *    without specific prior written permission.
1950128Swpaul *
2050128Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2150128Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2250128Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2350128Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2450128Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2550128Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2650128Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2750128Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2850128Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2950128Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3050128Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
3150128Swpaul */
3250128Swpaul
33113038Sobrien#include <sys/cdefs.h>
34113038Sobrien__FBSDID("$FreeBSD: releng/10.3/sys/dev/ste/if_ste.c 243857 2012-12-04 09:32:43Z glebius $");
35113038Sobrien
36150968Sglebius#ifdef HAVE_KERNEL_OPTION_HEADERS
37150968Sglebius#include "opt_device_polling.h"
38150968Sglebius#endif
39150968Sglebius
4050128Swpaul#include <sys/param.h>
4150128Swpaul#include <sys/systm.h>
42200853Syongari#include <sys/bus.h>
43200853Syongari#include <sys/endian.h>
44200853Syongari#include <sys/kernel.h>
45200853Syongari#include <sys/lock.h>
46200853Syongari#include <sys/malloc.h>
4750128Swpaul#include <sys/mbuf.h>
48129878Sphk#include <sys/module.h>
49200853Syongari#include <sys/rman.h>
5050128Swpaul#include <sys/socket.h>
51200853Syongari#include <sys/sockio.h>
52127688Sru#include <sys/sysctl.h>
5350128Swpaul
54200853Syongari#include <net/bpf.h>
5550128Swpaul#include <net/if.h>
5650128Swpaul#include <net/if_arp.h>
5750128Swpaul#include <net/ethernet.h>
5850128Swpaul#include <net/if_dl.h>
5950128Swpaul#include <net/if_media.h>
60147256Sbrooks#include <net/if_types.h>
61101493Sambrisko#include <net/if_vlan_var.h>
6250128Swpaul
6350128Swpaul#include <machine/bus.h>
6450128Swpaul#include <machine/resource.h>
6550128Swpaul
6650128Swpaul#include <dev/mii/mii.h>
67226995Smarius#include <dev/mii/mii_bitbang.h>
6850128Swpaul#include <dev/mii/miivar.h>
6950128Swpaul
70119288Simp#include <dev/pci/pcireg.h>
71119288Simp#include <dev/pci/pcivar.h>
7250128Swpaul
73200853Syongari#include <dev/ste/if_stereg.h>
74200853Syongari
75151545Simp/* "device miibus" required.  See GENERIC if you get errors here. */
7650128Swpaul#include "miibus_if.h"
7750128Swpaul
78113506SmdoddMODULE_DEPEND(ste, pci, 1, 1, 1);
79113506SmdoddMODULE_DEPEND(ste, ether, 1, 1, 1);
8059758SpeterMODULE_DEPEND(ste, miibus, 1, 1, 1);
8159758Speter
82200884Syongari/* Define to show Tx error status. */
83200884Syongari#define	STE_SHOW_TXERRORS
84200884Syongari
8550128Swpaul/*
8650128Swpaul * Various supported device vendors/types and their names.
8750128Swpaul */
88242625Sdimstatic const struct ste_type ste_devs[] = {
89167407Syongari	{ ST_VENDORID, ST_DEVICEID_ST201_1, "Sundance ST201 10/100BaseTX" },
90167407Syongari	{ ST_VENDORID, ST_DEVICEID_ST201_2, "Sundance ST201 10/100BaseTX" },
91108237Sphk	{ DL_VENDORID, DL_DEVICEID_DL10050, "D-Link DL10050 10/100BaseTX" },
9250128Swpaul	{ 0, 0, NULL }
9350128Swpaul};
9450128Swpaul
95200810Syongaristatic int	ste_attach(device_t);
96200810Syongaristatic int	ste_detach(device_t);
97200810Syongaristatic int	ste_probe(device_t);
98200955Syongaristatic int	ste_resume(device_t);
99200810Syongaristatic int	ste_shutdown(device_t);
100200955Syongaristatic int	ste_suspend(device_t);
10150128Swpaul
102200853Syongaristatic int	ste_dma_alloc(struct ste_softc *);
103200853Syongaristatic void	ste_dma_free(struct ste_softc *);
104200853Syongaristatic void	ste_dmamap_cb(void *, bus_dma_segment_t *, int, int);
105200810Syongaristatic int 	ste_eeprom_wait(struct ste_softc *);
106200853Syongaristatic int	ste_encap(struct ste_softc *, struct mbuf **,
107200853Syongari		    struct ste_chain *);
108200810Syongaristatic int	ste_ifmedia_upd(struct ifnet *);
109200810Syongaristatic void	ste_ifmedia_sts(struct ifnet *, struct ifmediareq *);
110200810Syongaristatic void	ste_init(void *);
111200810Syongaristatic void	ste_init_locked(struct ste_softc *);
112200810Syongaristatic int	ste_init_rx_list(struct ste_softc *);
113200810Syongaristatic void	ste_init_tx_list(struct ste_softc *);
114200810Syongaristatic void	ste_intr(void *);
115200810Syongaristatic int	ste_ioctl(struct ifnet *, u_long, caddr_t);
116226995Smariusstatic uint32_t ste_mii_bitbang_read(device_t);
117226995Smariusstatic void	ste_mii_bitbang_write(device_t, uint32_t);
118200810Syongaristatic int	ste_miibus_readreg(device_t, int, int);
119200810Syongaristatic void	ste_miibus_statchg(device_t);
120200810Syongaristatic int	ste_miibus_writereg(device_t, int, int, int);
121200853Syongaristatic int	ste_newbuf(struct ste_softc *, struct ste_chain_onefrag *);
122201767Syongaristatic int	ste_read_eeprom(struct ste_softc *, uint16_t *, int, int);
123200810Syongaristatic void	ste_reset(struct ste_softc *);
124200884Syongaristatic void	ste_restart_tx(struct ste_softc *);
125200853Syongaristatic int	ste_rxeof(struct ste_softc *, int);
126200906Syongaristatic void	ste_rxfilter(struct ste_softc *);
127200955Syongaristatic void	ste_setwol(struct ste_softc *);
128200810Syongaristatic void	ste_start(struct ifnet *);
129200810Syongaristatic void	ste_start_locked(struct ifnet *);
130200910Syongaristatic void	ste_stats_clear(struct ste_softc *);
131200865Syongaristatic void	ste_stats_update(struct ste_softc *);
132200810Syongaristatic void	ste_stop(struct ste_softc *);
133200910Syongaristatic void	ste_sysctl_node(struct ste_softc *);
134200865Syongaristatic void	ste_tick(void *);
135200810Syongaristatic void	ste_txeoc(struct ste_softc *);
136200810Syongaristatic void	ste_txeof(struct ste_softc *);
137200810Syongaristatic void	ste_wait(struct ste_softc *);
138200810Syongaristatic void	ste_watchdog(struct ste_softc *);
13950128Swpaul
140226995Smarius/*
141226995Smarius * MII bit-bang glue
142226995Smarius */
143226995Smariusstatic const struct mii_bitbang_ops ste_mii_bitbang_ops = {
144226995Smarius	ste_mii_bitbang_read,
145226995Smarius	ste_mii_bitbang_write,
146226995Smarius	{
147226995Smarius		STE_PHYCTL_MDATA,	/* MII_BIT_MDO */
148226995Smarius		STE_PHYCTL_MDATA,	/* MII_BIT_MDI */
149226995Smarius		STE_PHYCTL_MCLK,	/* MII_BIT_MDC */
150226995Smarius		STE_PHYCTL_MDIR,	/* MII_BIT_DIR_HOST_PHY */
151226995Smarius		0,			/* MII_BIT_DIR_PHY_HOST */
152226995Smarius	}
153226995Smarius};
154226995Smarius
15550128Swpaulstatic device_method_t ste_methods[] = {
15650128Swpaul	/* Device interface */
15750128Swpaul	DEVMETHOD(device_probe,		ste_probe),
15850128Swpaul	DEVMETHOD(device_attach,	ste_attach),
15950128Swpaul	DEVMETHOD(device_detach,	ste_detach),
16050128Swpaul	DEVMETHOD(device_shutdown,	ste_shutdown),
161200955Syongari	DEVMETHOD(device_suspend,	ste_suspend),
162200955Syongari	DEVMETHOD(device_resume,	ste_resume),
16350128Swpaul
16450128Swpaul	/* MII interface */
16550128Swpaul	DEVMETHOD(miibus_readreg,	ste_miibus_readreg),
16650128Swpaul	DEVMETHOD(miibus_writereg,	ste_miibus_writereg),
16750128Swpaul	DEVMETHOD(miibus_statchg,	ste_miibus_statchg),
16850128Swpaul
169227843Smarius	DEVMETHOD_END
17050128Swpaul};
17150128Swpaul
17250128Swpaulstatic driver_t ste_driver = {
17351455Swpaul	"ste",
17450128Swpaul	ste_methods,
17550128Swpaul	sizeof(struct ste_softc)
17650128Swpaul};
17750128Swpaul
17850128Swpaulstatic devclass_t ste_devclass;
17950128Swpaul
180113506SmdoddDRIVER_MODULE(ste, pci, ste_driver, ste_devclass, 0, 0);
18151473SwpaulDRIVER_MODULE(miibus, ste, miibus_driver, miibus_devclass, 0, 0);
18250128Swpaul
18350128Swpaul#define STE_SETBIT4(sc, reg, x)				\
184106696Salfred	CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) | (x))
18550128Swpaul
18650128Swpaul#define STE_CLRBIT4(sc, reg, x)				\
187106696Salfred	CSR_WRITE_4(sc, reg, CSR_READ_4(sc, reg) & ~(x))
18850128Swpaul
18950128Swpaul#define STE_SETBIT2(sc, reg, x)				\
190106696Salfred	CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) | (x))
19150128Swpaul
19250128Swpaul#define STE_CLRBIT2(sc, reg, x)				\
193106696Salfred	CSR_WRITE_2(sc, reg, CSR_READ_2(sc, reg) & ~(x))
19450128Swpaul
19550128Swpaul#define STE_SETBIT1(sc, reg, x)				\
196106696Salfred	CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) | (x))
19750128Swpaul
19850128Swpaul#define STE_CLRBIT1(sc, reg, x)				\
199106696Salfred	CSR_WRITE_1(sc, reg, CSR_READ_1(sc, reg) & ~(x))
20050128Swpaul
20150128Swpaul/*
202226995Smarius * Read the MII serial port for the MII bit-bang module.
20350128Swpaul */
204226995Smariusstatic uint32_t
205226995Smariusste_mii_bitbang_read(device_t dev)
20650128Swpaul{
207226995Smarius	struct ste_softc *sc;
208226995Smarius	uint32_t val;
20950128Swpaul
210226995Smarius	sc = device_get_softc(dev);
21150128Swpaul
212226995Smarius	val = CSR_READ_1(sc, STE_PHYCTL);
213226995Smarius	CSR_BARRIER(sc, STE_PHYCTL, 1,
214226995Smarius	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
215226995Smarius
216226995Smarius	return (val);
21750128Swpaul}
21850128Swpaul
21950128Swpaul/*
220226995Smarius * Write the MII serial port for the MII bit-bang module.
22150128Swpaul */
222102335Salfredstatic void
223226995Smariusste_mii_bitbang_write(device_t dev, uint32_t val)
22450128Swpaul{
225226995Smarius	struct ste_softc *sc;
22650128Swpaul
227226995Smarius	sc = device_get_softc(dev);
22850128Swpaul
229226995Smarius	CSR_WRITE_1(sc, STE_PHYCTL, val);
230226995Smarius	CSR_BARRIER(sc, STE_PHYCTL, 1,
231226995Smarius	    BUS_SPACE_BARRIER_READ | BUS_SPACE_BARRIER_WRITE);
23250128Swpaul}
23350128Swpaul
234102335Salfredstatic int
235200798Syongariste_miibus_readreg(device_t dev, int phy, int reg)
23650128Swpaul{
23750128Swpaul
238226995Smarius	return (mii_bitbang_readreg(dev, &ste_mii_bitbang_ops, phy, reg));
23950128Swpaul}
24050128Swpaul
241102335Salfredstatic int
242200798Syongariste_miibus_writereg(device_t dev, int phy, int reg, int data)
24350128Swpaul{
24450128Swpaul
245226995Smarius	mii_bitbang_writereg(dev, &ste_mii_bitbang_ops, phy, reg, data);
24650128Swpaul
247200808Syongari	return (0);
24850128Swpaul}
24950128Swpaul
250102335Salfredstatic void
251200798Syongariste_miibus_statchg(device_t dev)
25250128Swpaul{
253200808Syongari	struct ste_softc *sc;
254200808Syongari	struct mii_data *mii;
255200865Syongari	struct ifnet *ifp;
256200865Syongari	uint16_t cfg;
25750128Swpaul
25850128Swpaul	sc = device_get_softc(dev);
259149646Sjhb
26050128Swpaul	mii = device_get_softc(sc->ste_miibus);
261200865Syongari	ifp = sc->ste_ifp;
262200865Syongari	if (mii == NULL || ifp == NULL ||
263200865Syongari	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
264200865Syongari		return;
26550128Swpaul
266200865Syongari	sc->ste_flags &= ~STE_FLAG_LINK;
267200865Syongari	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
268200865Syongari	    (IFM_ACTIVE | IFM_AVALID)) {
269200865Syongari		switch (IFM_SUBTYPE(mii->mii_media_active)) {
270200865Syongari		case IFM_10_T:
271200865Syongari		case IFM_100_TX:
272200865Syongari		case IFM_100_FX:
273200865Syongari		case IFM_100_T4:
274200865Syongari			sc->ste_flags |= STE_FLAG_LINK;
275200865Syongari		default:
276200865Syongari			break;
277200865Syongari		}
27850128Swpaul	}
279200865Syongari
280200865Syongari	/* Program MACs with resolved speed/duplex/flow-control. */
281200865Syongari	if ((sc->ste_flags & STE_FLAG_LINK) != 0) {
282200865Syongari		cfg = CSR_READ_2(sc, STE_MACCTL0);
283200865Syongari		cfg &= ~(STE_MACCTL0_FLOWCTL_ENABLE | STE_MACCTL0_FULLDUPLEX);
284200865Syongari		if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
285200865Syongari			/*
286200865Syongari			 * ST201 data sheet says driver should enable receiving
287200865Syongari			 * MAC control frames bit of receive mode register to
288200865Syongari			 * receive flow-control frames but the register has no
289200865Syongari			 * such bits. In addition the controller has no ability
290200865Syongari			 * to send pause frames so it should be handled in
291200865Syongari			 * driver. Implementing pause timer handling in driver
292200865Syongari			 * layer is not trivial, so don't enable flow-control
293200865Syongari			 * here.
294200865Syongari			 */
295200865Syongari			cfg |= STE_MACCTL0_FULLDUPLEX;
296200865Syongari		}
297200865Syongari		CSR_WRITE_2(sc, STE_MACCTL0, cfg);
298200865Syongari	}
29950128Swpaul}
300200804Syongari
301102335Salfredstatic int
302200798Syongariste_ifmedia_upd(struct ifnet *ifp)
30350128Swpaul{
304200808Syongari	struct ste_softc *sc;
305200908Syongari	struct mii_data	*mii;
306200908Syongari	struct mii_softc *miisc;
307200908Syongari	int error;
308149646Sjhb
309149646Sjhb	sc = ifp->if_softc;
310149646Sjhb	STE_LOCK(sc);
31150128Swpaul	mii = device_get_softc(sc->ste_miibus);
312221407Smarius	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
313221407Smarius		PHY_RESET(miisc);
314200908Syongari	error = mii_mediachg(mii);
315200908Syongari	STE_UNLOCK(sc);
316200908Syongari
317200908Syongari	return (error);
31850128Swpaul}
31950128Swpaul
320102335Salfredstatic void
321200798Syongariste_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
32250128Swpaul{
323200808Syongari	struct ste_softc *sc;
324200808Syongari	struct mii_data *mii;
32550128Swpaul
32650128Swpaul	sc = ifp->if_softc;
32750128Swpaul	mii = device_get_softc(sc->ste_miibus);
32850128Swpaul
329149646Sjhb	STE_LOCK(sc);
330200907Syongari	if ((ifp->if_flags & IFF_UP) == 0) {
331200907Syongari		STE_UNLOCK(sc);
332200907Syongari		return;
333200907Syongari	}
33450128Swpaul	mii_pollstat(mii);
33550128Swpaul	ifmr->ifm_active = mii->mii_media_active;
33650128Swpaul	ifmr->ifm_status = mii->mii_media_status;
337149646Sjhb	STE_UNLOCK(sc);
33850128Swpaul}
33950128Swpaul
340102335Salfredstatic void
341200798Syongariste_wait(struct ste_softc *sc)
34250128Swpaul{
343200808Syongari	int i;
34450128Swpaul
34550128Swpaul	for (i = 0; i < STE_TIMEOUT; i++) {
34650128Swpaul		if (!(CSR_READ_4(sc, STE_DMACTL) & STE_DMACTL_DMA_HALTINPROG))
34750128Swpaul			break;
348200854Syongari		DELAY(1);
34950128Swpaul	}
35050128Swpaul
35150128Swpaul	if (i == STE_TIMEOUT)
352162315Sglebius		device_printf(sc->ste_dev, "command never completed!\n");
35350128Swpaul}
35450128Swpaul
35550128Swpaul/*
35650128Swpaul * The EEPROM is slow: give it time to come ready after issuing
35750128Swpaul * it a command.
35850128Swpaul */
359102335Salfredstatic int
360200798Syongariste_eeprom_wait(struct ste_softc *sc)
36150128Swpaul{
362200808Syongari	int i;
36350128Swpaul
36450128Swpaul	DELAY(1000);
36550128Swpaul
36650128Swpaul	for (i = 0; i < 100; i++) {
36750128Swpaul		if (CSR_READ_2(sc, STE_EEPROM_CTL) & STE_EECTL_BUSY)
36850128Swpaul			DELAY(1000);
36950128Swpaul		else
37050128Swpaul			break;
37150128Swpaul	}
37250128Swpaul
37350128Swpaul	if (i == 100) {
374162315Sglebius		device_printf(sc->ste_dev, "eeprom failed to come ready\n");
375200808Syongari		return (1);
37650128Swpaul	}
37750128Swpaul
378200808Syongari	return (0);
37950128Swpaul}
38050128Swpaul
38150128Swpaul/*
38250128Swpaul * Read a sequence of words from the EEPROM. Note that ethernet address
38350128Swpaul * data is stored in the EEPROM in network byte order.
38450128Swpaul */
385102335Salfredstatic int
386201767Syongariste_read_eeprom(struct ste_softc *sc, uint16_t *dest, int off, int cnt)
38750128Swpaul{
388200808Syongari	int err = 0, i;
38950128Swpaul
39050128Swpaul	if (ste_eeprom_wait(sc))
391200808Syongari		return (1);
39250128Swpaul
39350128Swpaul	for (i = 0; i < cnt; i++) {
39450128Swpaul		CSR_WRITE_2(sc, STE_EEPROM_CTL, STE_EEOPCODE_READ | (off + i));
39550128Swpaul		err = ste_eeprom_wait(sc);
39650128Swpaul		if (err)
39750128Swpaul			break;
398201767Syongari		*dest = le16toh(CSR_READ_2(sc, STE_EEPROM_DATA));
399201767Syongari		dest++;
40050128Swpaul	}
40150128Swpaul
402200808Syongari	return (err ? 1 : 0);
40350128Swpaul}
40450128Swpaul
405102335Salfredstatic void
406200906Syongariste_rxfilter(struct ste_softc *sc)
40750128Swpaul{
408200808Syongari	struct ifnet *ifp;
409200808Syongari	struct ifmultiaddr *ifma;
410200808Syongari	uint32_t hashes[2] = { 0, 0 };
411200906Syongari	uint8_t rxcfg;
412200808Syongari	int h;
41350128Swpaul
414200906Syongari	STE_LOCK_ASSERT(sc);
415200906Syongari
416147256Sbrooks	ifp = sc->ste_ifp;
417200906Syongari	rxcfg = CSR_READ_1(sc, STE_RX_MODE);
418200906Syongari	rxcfg |= STE_RXMODE_UNICAST;
419200906Syongari	rxcfg &= ~(STE_RXMODE_ALLMULTI | STE_RXMODE_MULTIHASH |
420200906Syongari	    STE_RXMODE_BROADCAST | STE_RXMODE_PROMISC);
421200906Syongari	if (ifp->if_flags & IFF_BROADCAST)
422200906Syongari		rxcfg |= STE_RXMODE_BROADCAST;
423200906Syongari	if ((ifp->if_flags & (IFF_ALLMULTI | IFF_PROMISC)) != 0) {
424200906Syongari		if ((ifp->if_flags & IFF_ALLMULTI) != 0)
425200906Syongari			rxcfg |= STE_RXMODE_ALLMULTI;
426200906Syongari		if ((ifp->if_flags & IFF_PROMISC) != 0)
427200906Syongari			rxcfg |= STE_RXMODE_PROMISC;
428200906Syongari		goto chipit;
42950128Swpaul	}
43050128Swpaul
431200906Syongari	rxcfg |= STE_RXMODE_MULTIHASH;
432200906Syongari	/* Now program new ones. */
433195049Srwatson	if_maddr_rlock(ifp);
43472084Sphk	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
43550128Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
43650128Swpaul			continue;
437130270Snaddy		h = ether_crc32_be(LLADDR((struct sockaddr_dl *)
438130270Snaddy		    ifma->ifma_addr), ETHER_ADDR_LEN) & 0x3F;
43950128Swpaul		if (h < 32)
44050128Swpaul			hashes[0] |= (1 << h);
44150128Swpaul		else
44250128Swpaul			hashes[1] |= (1 << (h - 32));
44350128Swpaul	}
444195049Srwatson	if_maddr_runlock(ifp);
44550128Swpaul
446200906Syongarichipit:
44782214Swpaul	CSR_WRITE_2(sc, STE_MAR0, hashes[0] & 0xFFFF);
44882214Swpaul	CSR_WRITE_2(sc, STE_MAR1, (hashes[0] >> 16) & 0xFFFF);
44982214Swpaul	CSR_WRITE_2(sc, STE_MAR2, hashes[1] & 0xFFFF);
45082214Swpaul	CSR_WRITE_2(sc, STE_MAR3, (hashes[1] >> 16) & 0xFFFF);
451200906Syongari	CSR_WRITE_1(sc, STE_RX_MODE, rxcfg);
452200906Syongari	CSR_READ_1(sc, STE_RX_MODE);
45350128Swpaul}
45450128Swpaul
455127686Sru#ifdef DEVICE_POLLING
456149646Sjhbstatic poll_handler_t ste_poll, ste_poll_locked;
457127686Sru
458193096Sattiliostatic int
459127686Sruste_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
460127686Sru{
461127686Sru	struct ste_softc *sc = ifp->if_softc;
462193096Sattilio	int rx_npkts = 0;
463127686Sru
464127686Sru	STE_LOCK(sc);
465150789Sglebius	if (ifp->if_drv_flags & IFF_DRV_RUNNING)
466193096Sattilio		rx_npkts = ste_poll_locked(ifp, cmd, count);
467149646Sjhb	STE_UNLOCK(sc);
468193096Sattilio	return (rx_npkts);
469149646Sjhb}
470149646Sjhb
471193096Sattiliostatic int
472149646Sjhbste_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
473149646Sjhb{
474149646Sjhb	struct ste_softc *sc = ifp->if_softc;
475193096Sattilio	int rx_npkts;
476149646Sjhb
477149646Sjhb	STE_LOCK_ASSERT(sc);
478127686Sru
479200853Syongari	rx_npkts = ste_rxeof(sc, count);
480127686Sru	ste_txeof(sc);
481200884Syongari	ste_txeoc(sc);
482147828Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
483149646Sjhb		ste_start_locked(ifp);
484127686Sru
485127937Sru	if (cmd == POLL_AND_CHECK_STATUS) {
486200803Syongari		uint16_t status;
487127686Sru
488127686Sru		status = CSR_READ_2(sc, STE_ISR_ACK);
489127686Sru
490200865Syongari		if (status & STE_ISR_STATS_OFLOW)
491127686Sru			ste_stats_update(sc);
492127686Sru
493200904Syongari		if (status & STE_ISR_HOSTERR) {
494200904Syongari			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
495149646Sjhb			ste_init_locked(sc);
496200904Syongari		}
497127686Sru	}
498193096Sattilio	return (rx_npkts);
499127686Sru}
500127686Sru#endif /* DEVICE_POLLING */
501127686Sru
502127686Srustatic void
503200798Syongariste_intr(void *xsc)
50450128Swpaul{
505200808Syongari	struct ste_softc *sc;
506200808Syongari	struct ifnet *ifp;
507200950Syongari	uint16_t intrs, status;
50850128Swpaul
50950128Swpaul	sc = xsc;
51067089Swpaul	STE_LOCK(sc);
511147256Sbrooks	ifp = sc->ste_ifp;
51250128Swpaul
513127686Sru#ifdef DEVICE_POLLING
514150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING) {
515150789Sglebius		STE_UNLOCK(sc);
516150789Sglebius		return;
517127686Sru	}
518150789Sglebius#endif
519200950Syongari	/* Reading STE_ISR_ACK clears STE_IMR register. */
520200950Syongari	status = CSR_READ_2(sc, STE_ISR_ACK);
521200950Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
52267089Swpaul		STE_UNLOCK(sc);
52350128Swpaul		return;
52467089Swpaul	}
52550128Swpaul
526200950Syongari	intrs = STE_INTRS;
527200950Syongari	if (status == 0xFFFF || (status & intrs) == 0)
528200950Syongari		goto done;
52950128Swpaul
530200950Syongari	if (sc->ste_int_rx_act > 0) {
531200950Syongari		status &= ~STE_ISR_RX_DMADONE;
532200950Syongari		intrs &= ~STE_IMR_RX_DMADONE;
533200950Syongari	}
53450128Swpaul
535200950Syongari	if ((status & (STE_ISR_SOFTINTR | STE_ISR_RX_DMADONE)) != 0) {
536200950Syongari		ste_rxeof(sc, -1);
537200950Syongari		/*
538200950Syongari		 * The controller has no ability to Rx interrupt
539200950Syongari		 * moderation feature. Receiving 64 bytes frames
540200950Syongari		 * from wire generates too many interrupts which in
541200950Syongari		 * turn make system useless to process other useful
542200950Syongari		 * things. Fortunately ST201 supports single shot
543200950Syongari		 * timer so use the timer to implement Rx interrupt
544200950Syongari		 * moderation in driver. This adds more register
545200950Syongari		 * access but it greatly reduces number of Rx
546200950Syongari		 * interrupts under high network load.
547200950Syongari		 */
548200950Syongari		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 &&
549200950Syongari		    (sc->ste_int_rx_mod != 0)) {
550200950Syongari			if ((status & STE_ISR_RX_DMADONE) != 0) {
551200950Syongari				CSR_WRITE_2(sc, STE_COUNTDOWN,
552200950Syongari				    STE_TIMER_USECS(sc->ste_int_rx_mod));
553200950Syongari				intrs &= ~STE_IMR_RX_DMADONE;
554200950Syongari				sc->ste_int_rx_act = 1;
555200950Syongari			} else {
556200950Syongari				intrs |= STE_IMR_RX_DMADONE;
557200950Syongari				sc->ste_int_rx_act = 0;
558200950Syongari			}
559200950Syongari		}
560200950Syongari	}
561200950Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
562200950Syongari		if ((status & STE_ISR_TX_DMADONE) != 0)
56350128Swpaul			ste_txeof(sc);
564200950Syongari		if ((status & STE_ISR_TX_DONE) != 0)
56550128Swpaul			ste_txeoc(sc);
566200950Syongari		if ((status & STE_ISR_STATS_OFLOW) != 0)
56750128Swpaul			ste_stats_update(sc);
568200950Syongari		if ((status & STE_ISR_HOSTERR) != 0) {
569200950Syongari			ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
570149646Sjhb			ste_init_locked(sc);
571200950Syongari			STE_UNLOCK(sc);
572200950Syongari			return;
573200904Syongari		}
574200950Syongari		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
575200950Syongari			ste_start_locked(ifp);
576200950Syongaridone:
577200950Syongari		/* Re-enable interrupts */
578200950Syongari		CSR_WRITE_2(sc, STE_IMR, intrs);
57950128Swpaul	}
58067089Swpaul	STE_UNLOCK(sc);
58150128Swpaul}
58250128Swpaul
58350128Swpaul/*
58450128Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
58550128Swpaul * the higher level protocols.
58650128Swpaul */
587193096Sattiliostatic int
588200853Syongariste_rxeof(struct ste_softc *sc, int count)
58950128Swpaul{
590200808Syongari        struct mbuf *m;
591200808Syongari        struct ifnet *ifp;
592200808Syongari	struct ste_chain_onefrag *cur_rx;
593200808Syongari	uint32_t rxstat;
594200853Syongari	int total_len, rx_npkts;
59550128Swpaul
596147256Sbrooks	ifp = sc->ste_ifp;
59750128Swpaul
598200853Syongari	bus_dmamap_sync(sc->ste_cdata.ste_rx_list_tag,
599200853Syongari	    sc->ste_cdata.ste_rx_list_map,
600200853Syongari	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
601200853Syongari
602200853Syongari	cur_rx = sc->ste_cdata.ste_rx_head;
603200853Syongari	for (rx_npkts = 0; rx_npkts < STE_RX_LIST_CNT; rx_npkts++,
604200853Syongari	    cur_rx = cur_rx->ste_next) {
605200853Syongari		rxstat = le32toh(cur_rx->ste_ptr->ste_status);
606200853Syongari		if ((rxstat & STE_RXSTAT_DMADONE) == 0)
607200853Syongari			break;
608127686Sru#ifdef DEVICE_POLLING
609150789Sglebius		if (ifp->if_capenable & IFCAP_POLLING) {
610200853Syongari			if (count == 0)
611127686Sru				break;
612200853Syongari			count--;
613127686Sru		}
614150789Sglebius#endif
615200853Syongari		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
616101493Sambrisko			break;
61750128Swpaul		/*
61850128Swpaul		 * If an error occurs, update stats, clear the
61950128Swpaul		 * status word and leave the mbuf cluster in place:
62050128Swpaul		 * it should simply get re-used next time this descriptor
62150128Swpaul	 	 * comes up in the ring.
62250128Swpaul		 */
62350128Swpaul		if (rxstat & STE_RXSTAT_FRAME_ERR) {
62450128Swpaul			ifp->if_ierrors++;
62550128Swpaul			cur_rx->ste_ptr->ste_status = 0;
62650128Swpaul			continue;
62750128Swpaul		}
62850128Swpaul
629200804Syongari		/* No errors; receive the packet. */
63050128Swpaul		m = cur_rx->ste_mbuf;
631200853Syongari		total_len = STE_RX_BYTES(rxstat);
63250128Swpaul
63350128Swpaul		/*
63450128Swpaul		 * Try to conjure up a new mbuf cluster. If that
63550128Swpaul		 * fails, it means we have an out of memory condition and
63650128Swpaul		 * should leave the buffer in place and continue. This will
63750128Swpaul		 * result in a lost packet, but there's little else we
63850128Swpaul		 * can do in this situation.
63950128Swpaul		 */
640200853Syongari		if (ste_newbuf(sc, cur_rx) != 0) {
641200965Syongari			ifp->if_iqdrops++;
64250128Swpaul			cur_rx->ste_ptr->ste_status = 0;
64350128Swpaul			continue;
64450128Swpaul		}
64550128Swpaul
64650128Swpaul		m->m_pkthdr.rcvif = ifp;
64750128Swpaul		m->m_pkthdr.len = m->m_len = total_len;
64850128Swpaul
649106936Ssam		ifp->if_ipackets++;
650122689Ssam		STE_UNLOCK(sc);
651106936Ssam		(*ifp->if_input)(ifp, m);
652122689Ssam		STE_LOCK(sc);
653200853Syongari	}
65450128Swpaul
655200853Syongari	if (rx_npkts > 0) {
656200853Syongari		sc->ste_cdata.ste_rx_head = cur_rx;
657200853Syongari		bus_dmamap_sync(sc->ste_cdata.ste_rx_list_tag,
658200853Syongari		    sc->ste_cdata.ste_rx_list_map,
659200853Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
66050128Swpaul	}
66150128Swpaul
662193096Sattilio	return (rx_npkts);
66350128Swpaul}
66450128Swpaul
665102335Salfredstatic void
666200798Syongariste_txeoc(struct ste_softc *sc)
66750128Swpaul{
668200884Syongari	uint16_t txstat;
669200808Syongari	struct ifnet *ifp;
67050128Swpaul
671200884Syongari	STE_LOCK_ASSERT(sc);
672200884Syongari
673147256Sbrooks	ifp = sc->ste_ifp;
67450128Swpaul
675200884Syongari	/*
676200884Syongari	 * STE_TX_STATUS register implements a queue of up to 31
677200884Syongari	 * transmit status byte. Writing an arbitrary value to the
678200884Syongari	 * register will advance the queue to the next transmit
679200884Syongari	 * status byte. This means if driver does not read
680200884Syongari	 * STE_TX_STATUS register after completing sending more
681200884Syongari	 * than 31 frames the controller would be stalled so driver
682200884Syongari	 * should re-wake the Tx MAC. This is the most severe
683200884Syongari	 * limitation of ST201 based controller.
684200884Syongari	 */
685200884Syongari	for (;;) {
686200884Syongari		txstat = CSR_READ_2(sc, STE_TX_STATUS);
687200884Syongari		if ((txstat & STE_TXSTATUS_TXDONE) == 0)
688200884Syongari			break;
689200884Syongari		if ((txstat & (STE_TXSTATUS_UNDERRUN |
690200884Syongari		    STE_TXSTATUS_EXCESSCOLLS | STE_TXSTATUS_RECLAIMERR |
691200884Syongari		    STE_TXSTATUS_STATSOFLOW)) != 0) {
69250128Swpaul			ifp->if_oerrors++;
693200884Syongari#ifdef	STE_SHOW_TXERRORS
694200884Syongari			device_printf(sc->ste_dev, "TX error : 0x%b\n",
695200884Syongari			    txstat & 0xFF, STE_ERR_BITS);
696200884Syongari#endif
697200884Syongari			if ((txstat & STE_TXSTATUS_UNDERRUN) != 0 &&
69850128Swpaul			    sc->ste_tx_thresh < STE_PACKET_SIZE) {
69950128Swpaul				sc->ste_tx_thresh += STE_MIN_FRAMELEN;
700200884Syongari				if (sc->ste_tx_thresh > STE_PACKET_SIZE)
701200884Syongari					sc->ste_tx_thresh = STE_PACKET_SIZE;
702162315Sglebius				device_printf(sc->ste_dev,
703200884Syongari				    "TX underrun, increasing TX"
70450128Swpaul				    " start threshold to %d bytes\n",
705149189Sjhb				    sc->ste_tx_thresh);
706200884Syongari				/* Make sure to disable active DMA cycles. */
707200884Syongari				STE_SETBIT4(sc, STE_DMACTL,
708200884Syongari				    STE_DMACTL_TXDMA_STALL);
709200884Syongari				ste_wait(sc);
710200904Syongari				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
711200884Syongari				ste_init_locked(sc);
712200884Syongari				break;
71350128Swpaul			}
714200884Syongari			/* Restart Tx. */
715200884Syongari			ste_restart_tx(sc);
71650128Swpaul		}
717200884Syongari		/*
718200884Syongari		 * Advance to next status and ACK TxComplete
719200884Syongari		 * interrupt. ST201 data sheet was wrong here, to
720200884Syongari		 * get next Tx status, we have to write both
721200884Syongari		 * STE_TX_STATUS and STE_TX_FRAMEID register.
722200884Syongari		 * Otherwise controller returns the same status
723200884Syongari		 * as well as not acknowledge Tx completion
724200884Syongari		 * interrupt.
725200884Syongari		 */
72650128Swpaul		CSR_WRITE_2(sc, STE_TX_STATUS, txstat);
72750128Swpaul	}
72850128Swpaul}
72950128Swpaul
730102335Salfredstatic void
731200865Syongariste_tick(void *arg)
732200865Syongari{
733200865Syongari	struct ste_softc *sc;
734200865Syongari	struct mii_data *mii;
735200865Syongari
736200865Syongari	sc = (struct ste_softc *)arg;
737200865Syongari
738200865Syongari	STE_LOCK_ASSERT(sc);
739200865Syongari
740200865Syongari	mii = device_get_softc(sc->ste_miibus);
741200865Syongari	mii_tick(mii);
742200865Syongari	/*
743200865Syongari	 * ukphy(4) does not seem to generate CB that reports
744200865Syongari	 * resolved link state so if we know we lost a link,
745200865Syongari	 * explicitly check the link state.
746200865Syongari	 */
747200865Syongari	if ((sc->ste_flags & STE_FLAG_LINK) == 0)
748200865Syongari		ste_miibus_statchg(sc->ste_dev);
749200913Syongari	/*
750200913Syongari	 * Because we are not generating Tx completion
751200913Syongari	 * interrupt for every frame, reclaim transmitted
752200913Syongari	 * buffers here.
753200913Syongari	 */
754200913Syongari	ste_txeof(sc);
755200913Syongari	ste_txeoc(sc);
756200865Syongari	ste_stats_update(sc);
757200865Syongari	ste_watchdog(sc);
758200865Syongari	callout_reset(&sc->ste_callout, hz, ste_tick, sc);
759200865Syongari}
760200865Syongari
761200865Syongaristatic void
762200798Syongariste_txeof(struct ste_softc *sc)
76350128Swpaul{
764200808Syongari	struct ifnet *ifp;
765200808Syongari	struct ste_chain *cur_tx;
766200853Syongari	uint32_t txstat;
767200808Syongari	int idx;
76850128Swpaul
769200853Syongari	STE_LOCK_ASSERT(sc);
770200853Syongari
771147256Sbrooks	ifp = sc->ste_ifp;
772200853Syongari	idx = sc->ste_cdata.ste_tx_cons;
773200853Syongari	if (idx == sc->ste_cdata.ste_tx_prod)
774200853Syongari		return;
77550128Swpaul
776200853Syongari	bus_dmamap_sync(sc->ste_cdata.ste_tx_list_tag,
777200853Syongari	    sc->ste_cdata.ste_tx_list_map,
778200853Syongari	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
779200853Syongari
780200808Syongari	while (idx != sc->ste_cdata.ste_tx_prod) {
78154268Swpaul		cur_tx = &sc->ste_cdata.ste_tx_chain[idx];
782200853Syongari		txstat = le32toh(cur_tx->ste_ptr->ste_ctl);
783200853Syongari		if ((txstat & STE_TXCTL_DMADONE) == 0)
78450128Swpaul			break;
785200853Syongari		bus_dmamap_sync(sc->ste_cdata.ste_tx_tag, cur_tx->ste_map,
786200853Syongari		    BUS_DMASYNC_POSTWRITE);
787200853Syongari		bus_dmamap_unload(sc->ste_cdata.ste_tx_tag, cur_tx->ste_map);
788200853Syongari		KASSERT(cur_tx->ste_mbuf != NULL,
789200853Syongari		    ("%s: freeing NULL mbuf!\n", __func__));
790127775Sru		m_freem(cur_tx->ste_mbuf);
791127775Sru		cur_tx->ste_mbuf = NULL;
792148887Srwatson		ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
79350128Swpaul		ifp->if_opackets++;
794200853Syongari		sc->ste_cdata.ste_tx_cnt--;
79554268Swpaul		STE_INC(idx, STE_TX_LIST_CNT);
79650128Swpaul	}
79750128Swpaul
798127927Sru	sc->ste_cdata.ste_tx_cons = idx;
799200853Syongari	if (sc->ste_cdata.ste_tx_cnt == 0)
800199559Sjhb		sc->ste_timer = 0;
80150128Swpaul}
80250128Swpaul
803102335Salfredstatic void
804200910Syongariste_stats_clear(struct ste_softc *sc)
805200910Syongari{
806200910Syongari
807200910Syongari	STE_LOCK_ASSERT(sc);
808200910Syongari
809200910Syongari	/* Rx stats. */
810200910Syongari	CSR_READ_2(sc, STE_STAT_RX_OCTETS_LO);
811200910Syongari	CSR_READ_2(sc, STE_STAT_RX_OCTETS_HI);
812200910Syongari	CSR_READ_2(sc, STE_STAT_RX_FRAMES);
813200910Syongari	CSR_READ_1(sc, STE_STAT_RX_BCAST);
814200910Syongari	CSR_READ_1(sc, STE_STAT_RX_MCAST);
815200910Syongari	CSR_READ_1(sc, STE_STAT_RX_LOST);
816200910Syongari	/* Tx stats. */
817200910Syongari	CSR_READ_2(sc, STE_STAT_TX_OCTETS_LO);
818200910Syongari	CSR_READ_2(sc, STE_STAT_TX_OCTETS_HI);
819200910Syongari	CSR_READ_2(sc, STE_STAT_TX_FRAMES);
820200910Syongari	CSR_READ_1(sc, STE_STAT_TX_BCAST);
821200910Syongari	CSR_READ_1(sc, STE_STAT_TX_MCAST);
822200910Syongari	CSR_READ_1(sc, STE_STAT_CARRIER_ERR);
823200910Syongari	CSR_READ_1(sc, STE_STAT_SINGLE_COLLS);
824200910Syongari	CSR_READ_1(sc, STE_STAT_MULTI_COLLS);
825200910Syongari	CSR_READ_1(sc, STE_STAT_LATE_COLLS);
826200910Syongari	CSR_READ_1(sc, STE_STAT_TX_DEFER);
827200910Syongari	CSR_READ_1(sc, STE_STAT_TX_EXDEFER);
828200910Syongari	CSR_READ_1(sc, STE_STAT_TX_ABORT);
829200910Syongari}
830200910Syongari
831200910Syongaristatic void
832200865Syongariste_stats_update(struct ste_softc *sc)
83350128Swpaul{
834200808Syongari	struct ifnet *ifp;
835200910Syongari	struct ste_hw_stats *stats;
836200910Syongari	uint32_t val;
83750128Swpaul
838149646Sjhb	STE_LOCK_ASSERT(sc);
83950128Swpaul
840147256Sbrooks	ifp = sc->ste_ifp;
841200910Syongari	stats = &sc->ste_stats;
842200910Syongari	/* Rx stats. */
843200910Syongari	val = (uint32_t)CSR_READ_2(sc, STE_STAT_RX_OCTETS_LO) |
844200910Syongari	    ((uint32_t)CSR_READ_2(sc, STE_STAT_RX_OCTETS_HI)) << 16;
845200910Syongari	val &= 0x000FFFFF;
846200910Syongari	stats->rx_bytes += val;
847200910Syongari	stats->rx_frames += CSR_READ_2(sc, STE_STAT_RX_FRAMES);
848200910Syongari	stats->rx_bcast_frames += CSR_READ_1(sc, STE_STAT_RX_BCAST);
849200910Syongari	stats->rx_mcast_frames += CSR_READ_1(sc, STE_STAT_RX_MCAST);
850200910Syongari	stats->rx_lost_frames += CSR_READ_1(sc, STE_STAT_RX_LOST);
851200910Syongari	/* Tx stats. */
852200910Syongari	val = (uint32_t)CSR_READ_2(sc, STE_STAT_TX_OCTETS_LO) |
853200910Syongari	    ((uint32_t)CSR_READ_2(sc, STE_STAT_TX_OCTETS_HI)) << 16;
854200910Syongari	val &= 0x000FFFFF;
855200910Syongari	stats->tx_bytes += val;
856200910Syongari	stats->tx_frames += CSR_READ_2(sc, STE_STAT_TX_FRAMES);
857200910Syongari	stats->tx_bcast_frames += CSR_READ_1(sc, STE_STAT_TX_BCAST);
858200910Syongari	stats->tx_mcast_frames += CSR_READ_1(sc, STE_STAT_TX_MCAST);
859200910Syongari	stats->tx_carrsense_errs += CSR_READ_1(sc, STE_STAT_CARRIER_ERR);
860200910Syongari	val = CSR_READ_1(sc, STE_STAT_SINGLE_COLLS);
861200910Syongari	stats->tx_single_colls += val;
862200910Syongari	ifp->if_collisions += val;
863200910Syongari	val = CSR_READ_1(sc, STE_STAT_MULTI_COLLS);
864200910Syongari	stats->tx_multi_colls += val;
865200910Syongari	ifp->if_collisions += val;
866200910Syongari	val += CSR_READ_1(sc, STE_STAT_LATE_COLLS);
867200910Syongari	stats->tx_late_colls += val;
868200910Syongari	ifp->if_collisions += val;
869200910Syongari	stats->tx_frames_defered += CSR_READ_1(sc, STE_STAT_TX_DEFER);
870200910Syongari	stats->tx_excess_defers += CSR_READ_1(sc, STE_STAT_TX_EXDEFER);
871200910Syongari	stats->tx_abort += CSR_READ_1(sc, STE_STAT_TX_ABORT);
87250128Swpaul}
87350128Swpaul
87450128Swpaul/*
87550128Swpaul * Probe for a Sundance ST201 chip. Check the PCI vendor and device
87650128Swpaul * IDs against our list and return a device name if we find a match.
87750128Swpaul */
878102335Salfredstatic int
879200798Syongariste_probe(device_t dev)
88050128Swpaul{
881226995Smarius	const struct ste_type *t;
88250128Swpaul
88350128Swpaul	t = ste_devs;
88450128Swpaul
885200808Syongari	while (t->ste_name != NULL) {
88650128Swpaul		if ((pci_get_vendor(dev) == t->ste_vid) &&
88750128Swpaul		    (pci_get_device(dev) == t->ste_did)) {
88850128Swpaul			device_set_desc(dev, t->ste_name);
889142398Simp			return (BUS_PROBE_DEFAULT);
89050128Swpaul		}
89150128Swpaul		t++;
89250128Swpaul	}
89350128Swpaul
894200808Syongari	return (ENXIO);
89550128Swpaul}
89650128Swpaul
89750128Swpaul/*
89850128Swpaul * Attach the interface. Allocate softc structures, do ifmedia
89950128Swpaul * setup and ethernet/BPF attach.
90050128Swpaul */
901102335Salfredstatic int
902200798Syongariste_attach(device_t dev)
90350128Swpaul{
904200808Syongari	struct ste_softc *sc;
905200808Syongari	struct ifnet *ifp;
906201767Syongari	uint16_t eaddr[ETHER_ADDR_LEN / 2];
907213893Smarius	int error = 0, phy, pmc, prefer_iomap, rid;
90850128Swpaul
90950128Swpaul	sc = device_get_softc(dev);
910101493Sambrisko	sc->ste_dev = dev;
91150128Swpaul
912102113Sambrisko	/*
913103238Sambrisko	 * Only use one PHY since this chip reports multiple
914103238Sambrisko	 * Note on the DFE-550 the PHY is at 1 on the DFE-580
915103238Sambrisko	 * it is at 0 & 1.  It is rev 0x12.
916102113Sambrisko	 */
917102113Sambrisko	if (pci_get_vendor(dev) == DL_VENDORID &&
918108237Sphk	    pci_get_device(dev) == DL_DEVICEID_DL10050 &&
919103238Sambrisko	    pci_get_revid(dev) == 0x12 )
920200856Syongari		sc->ste_flags |= STE_FLAG_ONE_PHY;
921102113Sambrisko
92293818Sjhb	mtx_init(&sc->ste_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
923149646Sjhb	    MTX_DEF);
92450128Swpaul	/*
92550128Swpaul	 * Map control/status registers.
92650128Swpaul	 */
92772813Swpaul	pci_enable_busmaster(dev);
92850128Swpaul
929211089Syongari	/*
930211089Syongari	 * Prefer memory space register mapping over IO space but use
931211089Syongari	 * IO space for a device that is known to have issues on memory
932211089Syongari	 * mapping.
933211089Syongari	 */
934211089Syongari	prefer_iomap = 0;
935211089Syongari	if (pci_get_device(dev) == ST_DEVICEID_ST201_1)
936211089Syongari		prefer_iomap = 1;
937211089Syongari	else
938211089Syongari		resource_int_value(device_get_name(sc->ste_dev),
939211089Syongari		    device_get_unit(sc->ste_dev), "prefer_iomap",
940211089Syongari		    &prefer_iomap);
941211089Syongari	if (prefer_iomap == 0) {
942211089Syongari		sc->ste_res_id = PCIR_BAR(1);
943211089Syongari		sc->ste_res_type = SYS_RES_MEMORY;
944211089Syongari		sc->ste_res = bus_alloc_resource_any(dev, sc->ste_res_type,
945211089Syongari		    &sc->ste_res_id, RF_ACTIVE);
946211089Syongari	}
947211089Syongari	if (prefer_iomap || sc->ste_res == NULL) {
948200875Syongari		sc->ste_res_id = PCIR_BAR(0);
949200875Syongari		sc->ste_res_type = SYS_RES_IOPORT;
950200875Syongari		sc->ste_res = bus_alloc_resource_any(dev, sc->ste_res_type,
951200875Syongari		    &sc->ste_res_id, RF_ACTIVE);
952200875Syongari	}
953200875Syongari	if (sc->ste_res == NULL) {
954149189Sjhb		device_printf(dev, "couldn't map ports/memory\n");
95550128Swpaul		error = ENXIO;
95650128Swpaul		goto fail;
95750128Swpaul	}
95850128Swpaul
959112872Snjl	/* Allocate interrupt */
96050128Swpaul	rid = 0;
961127135Snjl	sc->ste_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
96250128Swpaul	    RF_SHAREABLE | RF_ACTIVE);
96350128Swpaul
96450128Swpaul	if (sc->ste_irq == NULL) {
965149189Sjhb		device_printf(dev, "couldn't map interrupt\n");
96650128Swpaul		error = ENXIO;
96750128Swpaul		goto fail;
96850128Swpaul	}
96950128Swpaul
970200865Syongari	callout_init_mtx(&sc->ste_callout, &sc->ste_mtx, 0);
97150128Swpaul
97250128Swpaul	/* Reset the adapter. */
97350128Swpaul	ste_reset(sc);
97450128Swpaul
97550128Swpaul	/*
97650128Swpaul	 * Get station address from the EEPROM.
97750128Swpaul	 */
978201767Syongari	if (ste_read_eeprom(sc, eaddr, STE_EEADDR_NODE0, ETHER_ADDR_LEN / 2)) {
979149189Sjhb		device_printf(dev, "failed to read station address\n");
980201758Smbr		error = ENXIO;
98150128Swpaul		goto fail;
98250128Swpaul	}
983200910Syongari	ste_sysctl_node(sc);
98450128Swpaul
985200853Syongari	if ((error = ste_dma_alloc(sc)) != 0)
98650128Swpaul		goto fail;
98750128Swpaul
988147291Sbrooks	ifp = sc->ste_ifp = if_alloc(IFT_ETHER);
989147291Sbrooks	if (ifp == NULL) {
990149189Sjhb		device_printf(dev, "can not if_alloc()\n");
991147291Sbrooks		error = ENOSPC;
992147291Sbrooks		goto fail;
993147291Sbrooks	}
994147291Sbrooks
99550128Swpaul	/* Do MII setup. */
996213893Smarius	phy = MII_PHY_ANY;
997213893Smarius	if ((sc->ste_flags & STE_FLAG_ONE_PHY) != 0)
998213893Smarius		phy = 0;
999213893Smarius	error = mii_attach(dev, &sc->ste_miibus, ifp, ste_ifmedia_upd,
1000213893Smarius		ste_ifmedia_sts, BMSR_DEFCAPMASK, phy, MII_OFFSET_ANY, 0);
1001213893Smarius	if (error != 0) {
1002213893Smarius		device_printf(dev, "attaching PHYs failed\n");
100350128Swpaul		goto fail;
100450128Swpaul	}
100550128Swpaul
100650128Swpaul	ifp->if_softc = sc;
1007121816Sbrooks	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
1008149646Sjhb	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
100950128Swpaul	ifp->if_ioctl = ste_ioctl;
101050128Swpaul	ifp->if_start = ste_start;
101150128Swpaul	ifp->if_init = ste_init;
1012147828Smlaier	IFQ_SET_MAXLEN(&ifp->if_snd, STE_TX_LIST_CNT - 1);
1013147828Smlaier	ifp->if_snd.ifq_drv_maxlen = STE_TX_LIST_CNT - 1;
1014147828Smlaier	IFQ_SET_READY(&ifp->if_snd);
101550128Swpaul
1016101493Sambrisko	sc->ste_tx_thresh = STE_TXSTART_THRESH;
1017101493Sambrisko
101850128Swpaul	/*
101963090Sarchie	 * Call MI attach routine.
102050128Swpaul	 */
1021201767Syongari	ether_ifattach(ifp, (uint8_t *)eaddr);
1022101493Sambrisko
1023101493Sambrisko	/*
1024101493Sambrisko	 * Tell the upper layer(s) we support long frames.
1025101493Sambrisko	 */
1026101493Sambrisko	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
1027106936Ssam	ifp->if_capabilities |= IFCAP_VLAN_MTU;
1028219902Sjhb	if (pci_find_cap(dev, PCIY_PMG, &pmc) == 0)
1029200955Syongari		ifp->if_capabilities |= IFCAP_WOL_MAGIC;
1030150789Sglebius	ifp->if_capenable = ifp->if_capabilities;
1031128117Sru#ifdef DEVICE_POLLING
1032128117Sru	ifp->if_capabilities |= IFCAP_POLLING;
1033128117Sru#endif
1034101493Sambrisko
1035113609Snjl	/* Hook interrupt last to avoid having to lock softc */
1036149646Sjhb	error = bus_setup_intr(dev, sc->ste_irq, INTR_TYPE_NET | INTR_MPSAFE,
1037166901Spiso	    NULL, ste_intr, sc, &sc->ste_intrhand);
103850128Swpaul
1039112872Snjl	if (error) {
1040149189Sjhb		device_printf(dev, "couldn't set up irq\n");
1041113609Snjl		ether_ifdetach(ifp);
1042112872Snjl		goto fail;
1043112872Snjl	}
1044112872Snjl
104550128Swpaulfail:
1046112872Snjl	if (error)
1047112872Snjl		ste_detach(dev);
1048112872Snjl
1049200808Syongari	return (error);
105050128Swpaul}
105150128Swpaul
1052113609Snjl/*
1053113609Snjl * Shutdown hardware and free up resources. This can be called any
1054113609Snjl * time after the mutex has been initialized. It is called in both
1055113609Snjl * the error case in attach and the normal detach case so it needs
1056113609Snjl * to be careful about only freeing resources that have actually been
1057113609Snjl * allocated.
1058113609Snjl */
1059102335Salfredstatic int
1060200798Syongariste_detach(device_t dev)
106150128Swpaul{
1062200808Syongari	struct ste_softc *sc;
1063200808Syongari	struct ifnet *ifp;
106450128Swpaul
106550128Swpaul	sc = device_get_softc(dev);
1066112880Sjhb	KASSERT(mtx_initialized(&sc->ste_mtx), ("ste mutex not initialized"));
1067147256Sbrooks	ifp = sc->ste_ifp;
106850128Swpaul
1069150789Sglebius#ifdef DEVICE_POLLING
1070150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
1071150789Sglebius		ether_poll_deregister(ifp);
1072150789Sglebius#endif
1073150789Sglebius
1074113609Snjl	/* These should only be active if attach succeeded */
1075113812Simp	if (device_is_attached(dev)) {
1076199559Sjhb		ether_ifdetach(ifp);
1077149646Sjhb		STE_LOCK(sc);
1078113609Snjl		ste_stop(sc);
1079149646Sjhb		STE_UNLOCK(sc);
1080200865Syongari		callout_drain(&sc->ste_callout);
1081150213Sru	}
1082113609Snjl	if (sc->ste_miibus)
1083112872Snjl		device_delete_child(dev, sc->ste_miibus);
1084113609Snjl	bus_generic_detach(dev);
108550128Swpaul
1086112872Snjl	if (sc->ste_intrhand)
1087112872Snjl		bus_teardown_intr(dev, sc->ste_irq, sc->ste_intrhand);
1088112872Snjl	if (sc->ste_irq)
1089112872Snjl		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->ste_irq);
1090112872Snjl	if (sc->ste_res)
1091200875Syongari		bus_release_resource(dev, sc->ste_res_type, sc->ste_res_id,
1092200875Syongari		    sc->ste_res);
109350128Swpaul
1094151297Sru	if (ifp)
1095151297Sru		if_free(ifp);
1096151297Sru
1097200853Syongari	ste_dma_free(sc);
109867089Swpaul	mtx_destroy(&sc->ste_mtx);
109950128Swpaul
1100200808Syongari	return (0);
110150128Swpaul}
110250128Swpaul
1103200853Syongaristruct ste_dmamap_arg {
1104200853Syongari	bus_addr_t	ste_busaddr;
1105200853Syongari};
1106200853Syongari
1107200853Syongaristatic void
1108200853Syongariste_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int error)
1109200853Syongari{
1110200853Syongari	struct ste_dmamap_arg *ctx;
1111200853Syongari
1112200853Syongari	if (error != 0)
1113200853Syongari		return;
1114200853Syongari
1115200853Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
1116200853Syongari
1117200853Syongari	ctx = (struct ste_dmamap_arg *)arg;
1118200853Syongari	ctx->ste_busaddr = segs[0].ds_addr;
1119200853Syongari}
1120200853Syongari
1121102335Salfredstatic int
1122200853Syongariste_dma_alloc(struct ste_softc *sc)
112350128Swpaul{
1124200853Syongari	struct ste_chain *txc;
1125200853Syongari	struct ste_chain_onefrag *rxc;
1126200853Syongari	struct ste_dmamap_arg ctx;
1127200853Syongari	int error, i;
112850128Swpaul
1129200853Syongari	/* Create parent DMA tag. */
1130200853Syongari	error = bus_dma_tag_create(
1131200853Syongari	    bus_get_dma_tag(sc->ste_dev), /* parent */
1132200853Syongari	    1, 0,			/* alignment, boundary */
1133200853Syongari	    BUS_SPACE_MAXADDR_32BIT,	/* lowaddr */
1134200853Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1135200853Syongari	    NULL, NULL,			/* filter, filterarg */
1136200853Syongari	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
1137200853Syongari	    0,				/* nsegments */
1138200853Syongari	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
1139200853Syongari	    0,				/* flags */
1140200853Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1141200853Syongari	    &sc->ste_cdata.ste_parent_tag);
1142200853Syongari	if (error != 0) {
1143200853Syongari		device_printf(sc->ste_dev,
1144200853Syongari		    "could not create parent DMA tag.\n");
1145200853Syongari		goto fail;
1146200853Syongari	}
1147200853Syongari
1148200853Syongari	/* Create DMA tag for Tx descriptor list. */
1149200853Syongari	error = bus_dma_tag_create(
1150200853Syongari	    sc->ste_cdata.ste_parent_tag, /* parent */
1151200853Syongari	    STE_DESC_ALIGN, 0,		/* alignment, boundary */
1152200853Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
1153200853Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1154200853Syongari	    NULL, NULL,			/* filter, filterarg */
1155200853Syongari	    STE_TX_LIST_SZ,		/* maxsize */
1156200853Syongari	    1,				/* nsegments */
1157200853Syongari	    STE_TX_LIST_SZ,		/* maxsegsize */
1158200853Syongari	    0,				/* flags */
1159200853Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1160200853Syongari	    &sc->ste_cdata.ste_tx_list_tag);
1161200853Syongari	if (error != 0) {
1162200853Syongari		device_printf(sc->ste_dev,
1163200853Syongari		    "could not create Tx list DMA tag.\n");
1164200853Syongari		goto fail;
1165200853Syongari	}
1166200853Syongari
1167200853Syongari	/* Create DMA tag for Rx descriptor list. */
1168200853Syongari	error = bus_dma_tag_create(
1169200853Syongari	    sc->ste_cdata.ste_parent_tag, /* parent */
1170200853Syongari	    STE_DESC_ALIGN, 0,		/* alignment, boundary */
1171200853Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
1172200853Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1173200853Syongari	    NULL, NULL,			/* filter, filterarg */
1174200853Syongari	    STE_RX_LIST_SZ,		/* maxsize */
1175200853Syongari	    1,				/* nsegments */
1176200853Syongari	    STE_RX_LIST_SZ,		/* maxsegsize */
1177200853Syongari	    0,				/* flags */
1178200853Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1179200853Syongari	    &sc->ste_cdata.ste_rx_list_tag);
1180200853Syongari	if (error != 0) {
1181200853Syongari		device_printf(sc->ste_dev,
1182200853Syongari		    "could not create Rx list DMA tag.\n");
1183200853Syongari		goto fail;
1184200853Syongari	}
1185200853Syongari
1186200853Syongari	/* Create DMA tag for Tx buffers. */
1187200853Syongari	error = bus_dma_tag_create(
1188200853Syongari	    sc->ste_cdata.ste_parent_tag, /* parent */
1189200853Syongari	    1, 0,			/* alignment, boundary */
1190200853Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
1191200853Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1192200853Syongari	    NULL, NULL,			/* filter, filterarg */
1193200853Syongari	    MCLBYTES * STE_MAXFRAGS,	/* maxsize */
1194200853Syongari	    STE_MAXFRAGS,		/* nsegments */
1195200853Syongari	    MCLBYTES,			/* maxsegsize */
1196200853Syongari	    0,				/* flags */
1197200853Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1198200853Syongari	    &sc->ste_cdata.ste_tx_tag);
1199200853Syongari	if (error != 0) {
1200200853Syongari		device_printf(sc->ste_dev, "could not create Tx DMA tag.\n");
1201200853Syongari		goto fail;
1202200853Syongari	}
1203200853Syongari
1204200853Syongari	/* Create DMA tag for Rx buffers. */
1205200853Syongari	error = bus_dma_tag_create(
1206200853Syongari	    sc->ste_cdata.ste_parent_tag, /* parent */
1207200853Syongari	    1, 0,			/* alignment, boundary */
1208200853Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
1209200853Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1210200853Syongari	    NULL, NULL,			/* filter, filterarg */
1211200853Syongari	    MCLBYTES,			/* maxsize */
1212200853Syongari	    1,				/* nsegments */
1213200853Syongari	    MCLBYTES,			/* maxsegsize */
1214200853Syongari	    0,				/* flags */
1215200853Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1216200853Syongari	    &sc->ste_cdata.ste_rx_tag);
1217200853Syongari	if (error != 0) {
1218200853Syongari		device_printf(sc->ste_dev, "could not create Rx DMA tag.\n");
1219200853Syongari		goto fail;
1220200853Syongari	}
1221200853Syongari
1222200853Syongari	/* Allocate DMA'able memory and load the DMA map for Tx list. */
1223200853Syongari	error = bus_dmamem_alloc(sc->ste_cdata.ste_tx_list_tag,
1224200853Syongari	    (void **)&sc->ste_ldata.ste_tx_list,
1225200853Syongari	    BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT,
1226200853Syongari	    &sc->ste_cdata.ste_tx_list_map);
1227200853Syongari	if (error != 0) {
1228200853Syongari		device_printf(sc->ste_dev,
1229200853Syongari		    "could not allocate DMA'able memory for Tx list.\n");
1230200853Syongari		goto fail;
1231200853Syongari	}
1232200853Syongari	ctx.ste_busaddr = 0;
1233200853Syongari	error = bus_dmamap_load(sc->ste_cdata.ste_tx_list_tag,
1234200853Syongari	    sc->ste_cdata.ste_tx_list_map, sc->ste_ldata.ste_tx_list,
1235200853Syongari	    STE_TX_LIST_SZ, ste_dmamap_cb, &ctx, 0);
1236200853Syongari	if (error != 0 || ctx.ste_busaddr == 0) {
1237200853Syongari		device_printf(sc->ste_dev,
1238200853Syongari		    "could not load DMA'able memory for Tx list.\n");
1239200853Syongari		goto fail;
1240200853Syongari	}
1241200853Syongari	sc->ste_ldata.ste_tx_list_paddr = ctx.ste_busaddr;
1242200853Syongari
1243200853Syongari	/* Allocate DMA'able memory and load the DMA map for Rx list. */
1244200853Syongari	error = bus_dmamem_alloc(sc->ste_cdata.ste_rx_list_tag,
1245200853Syongari	    (void **)&sc->ste_ldata.ste_rx_list,
1246200853Syongari	    BUS_DMA_WAITOK | BUS_DMA_ZERO | BUS_DMA_COHERENT,
1247200853Syongari	    &sc->ste_cdata.ste_rx_list_map);
1248200853Syongari	if (error != 0) {
1249200853Syongari		device_printf(sc->ste_dev,
1250200853Syongari		    "could not allocate DMA'able memory for Rx list.\n");
1251200853Syongari		goto fail;
1252200853Syongari	}
1253200853Syongari	ctx.ste_busaddr = 0;
1254200853Syongari	error = bus_dmamap_load(sc->ste_cdata.ste_rx_list_tag,
1255200853Syongari	    sc->ste_cdata.ste_rx_list_map, sc->ste_ldata.ste_rx_list,
1256200853Syongari	    STE_RX_LIST_SZ, ste_dmamap_cb, &ctx, 0);
1257200853Syongari	if (error != 0 || ctx.ste_busaddr == 0) {
1258200853Syongari		device_printf(sc->ste_dev,
1259200853Syongari		    "could not load DMA'able memory for Rx list.\n");
1260200853Syongari		goto fail;
1261200853Syongari	}
1262200853Syongari	sc->ste_ldata.ste_rx_list_paddr = ctx.ste_busaddr;
1263200853Syongari
1264200853Syongari	/* Create DMA maps for Tx buffers. */
1265200853Syongari	for (i = 0; i < STE_TX_LIST_CNT; i++) {
1266200853Syongari		txc = &sc->ste_cdata.ste_tx_chain[i];
1267200853Syongari		txc->ste_ptr = NULL;
1268200853Syongari		txc->ste_mbuf = NULL;
1269200853Syongari		txc->ste_next = NULL;
1270200853Syongari		txc->ste_phys = 0;
1271200853Syongari		txc->ste_map = NULL;
1272200853Syongari		error = bus_dmamap_create(sc->ste_cdata.ste_tx_tag, 0,
1273200853Syongari		    &txc->ste_map);
1274200853Syongari		if (error != 0) {
1275200853Syongari			device_printf(sc->ste_dev,
1276200853Syongari			    "could not create Tx dmamap.\n");
1277200853Syongari			goto fail;
127850128Swpaul		}
127950128Swpaul	}
1280200853Syongari	/* Create DMA maps for Rx buffers. */
1281200853Syongari	if ((error = bus_dmamap_create(sc->ste_cdata.ste_rx_tag, 0,
1282200853Syongari	    &sc->ste_cdata.ste_rx_sparemap)) != 0) {
1283200853Syongari		device_printf(sc->ste_dev,
1284200853Syongari		    "could not create spare Rx dmamap.\n");
1285200853Syongari		goto fail;
1286200853Syongari	}
1287200853Syongari	for (i = 0; i < STE_RX_LIST_CNT; i++) {
1288200853Syongari		rxc = &sc->ste_cdata.ste_rx_chain[i];
1289200853Syongari		rxc->ste_ptr = NULL;
1290200853Syongari		rxc->ste_mbuf = NULL;
1291200853Syongari		rxc->ste_next = NULL;
1292200853Syongari		rxc->ste_map = NULL;
1293200853Syongari		error = bus_dmamap_create(sc->ste_cdata.ste_rx_tag, 0,
1294200853Syongari		    &rxc->ste_map);
1295200853Syongari		if (error != 0) {
1296200853Syongari			device_printf(sc->ste_dev,
1297200853Syongari			    "could not create Rx dmamap.\n");
1298200853Syongari			goto fail;
1299200853Syongari		}
1300200853Syongari	}
130150128Swpaul
1302200853Syongarifail:
1303200853Syongari	return (error);
1304200853Syongari}
130550128Swpaul
1306200853Syongaristatic void
1307200853Syongariste_dma_free(struct ste_softc *sc)
1308200853Syongari{
1309200853Syongari	struct ste_chain *txc;
1310200853Syongari	struct ste_chain_onefrag *rxc;
1311200853Syongari	int i;
131250128Swpaul
1313200853Syongari	/* Tx buffers. */
1314200853Syongari	if (sc->ste_cdata.ste_tx_tag != NULL) {
1315200853Syongari		for (i = 0; i < STE_TX_LIST_CNT; i++) {
1316200853Syongari			txc = &sc->ste_cdata.ste_tx_chain[i];
1317200853Syongari			if (txc->ste_map != NULL) {
1318200853Syongari				bus_dmamap_destroy(sc->ste_cdata.ste_tx_tag,
1319200853Syongari				    txc->ste_map);
1320200853Syongari				txc->ste_map = NULL;
1321200853Syongari			}
1322200853Syongari		}
1323200853Syongari		bus_dma_tag_destroy(sc->ste_cdata.ste_tx_tag);
1324200853Syongari		sc->ste_cdata.ste_tx_tag = NULL;
1325200853Syongari	}
1326200853Syongari	/* Rx buffers. */
1327200853Syongari	if (sc->ste_cdata.ste_rx_tag != NULL) {
1328200853Syongari		for (i = 0; i < STE_RX_LIST_CNT; i++) {
1329200853Syongari			rxc = &sc->ste_cdata.ste_rx_chain[i];
1330200853Syongari			if (rxc->ste_map != NULL) {
1331200853Syongari				bus_dmamap_destroy(sc->ste_cdata.ste_rx_tag,
1332200853Syongari				    rxc->ste_map);
1333200853Syongari				rxc->ste_map = NULL;
1334200853Syongari			}
1335200853Syongari		}
1336200853Syongari		if (sc->ste_cdata.ste_rx_sparemap != NULL) {
1337200853Syongari			bus_dmamap_destroy(sc->ste_cdata.ste_rx_tag,
1338200853Syongari			    sc->ste_cdata.ste_rx_sparemap);
1339200853Syongari			sc->ste_cdata.ste_rx_sparemap = NULL;
1340200853Syongari		}
1341200853Syongari		bus_dma_tag_destroy(sc->ste_cdata.ste_rx_tag);
1342200853Syongari		sc->ste_cdata.ste_rx_tag = NULL;
1343200853Syongari	}
1344200853Syongari	/* Tx descriptor list. */
1345200853Syongari	if (sc->ste_cdata.ste_tx_list_tag != NULL) {
1346200853Syongari		if (sc->ste_cdata.ste_tx_list_map != NULL)
1347200853Syongari			bus_dmamap_unload(sc->ste_cdata.ste_tx_list_tag,
1348200853Syongari			    sc->ste_cdata.ste_tx_list_map);
1349200853Syongari		if (sc->ste_cdata.ste_tx_list_map != NULL &&
1350200853Syongari		    sc->ste_ldata.ste_tx_list != NULL)
1351200853Syongari			bus_dmamem_free(sc->ste_cdata.ste_tx_list_tag,
1352200853Syongari			    sc->ste_ldata.ste_tx_list,
1353200853Syongari			    sc->ste_cdata.ste_tx_list_map);
1354200853Syongari		sc->ste_ldata.ste_tx_list = NULL;
1355200853Syongari		sc->ste_cdata.ste_tx_list_map = NULL;
1356200853Syongari		bus_dma_tag_destroy(sc->ste_cdata.ste_tx_list_tag);
1357200853Syongari		sc->ste_cdata.ste_tx_list_tag = NULL;
1358200853Syongari	}
1359200853Syongari	/* Rx descriptor list. */
1360200853Syongari	if (sc->ste_cdata.ste_rx_list_tag != NULL) {
1361200853Syongari		if (sc->ste_cdata.ste_rx_list_map != NULL)
1362200853Syongari			bus_dmamap_unload(sc->ste_cdata.ste_rx_list_tag,
1363200853Syongari			    sc->ste_cdata.ste_rx_list_map);
1364200853Syongari		if (sc->ste_cdata.ste_rx_list_map != NULL &&
1365200853Syongari		    sc->ste_ldata.ste_rx_list != NULL)
1366200853Syongari			bus_dmamem_free(sc->ste_cdata.ste_rx_list_tag,
1367200853Syongari			    sc->ste_ldata.ste_rx_list,
1368200853Syongari			    sc->ste_cdata.ste_rx_list_map);
1369200853Syongari		sc->ste_ldata.ste_rx_list = NULL;
1370200853Syongari		sc->ste_cdata.ste_rx_list_map = NULL;
1371200853Syongari		bus_dma_tag_destroy(sc->ste_cdata.ste_rx_list_tag);
1372200853Syongari		sc->ste_cdata.ste_rx_list_tag = NULL;
1373200853Syongari	}
1374200853Syongari	if (sc->ste_cdata.ste_parent_tag != NULL) {
1375200853Syongari		bus_dma_tag_destroy(sc->ste_cdata.ste_parent_tag);
1376200853Syongari		sc->ste_cdata.ste_parent_tag = NULL;
1377200853Syongari	}
1378200853Syongari}
1379200853Syongari
1380200853Syongaristatic int
1381200853Syongariste_newbuf(struct ste_softc *sc, struct ste_chain_onefrag *rxc)
1382200853Syongari{
1383200853Syongari	struct mbuf *m;
1384200853Syongari	bus_dma_segment_t segs[1];
1385200853Syongari	bus_dmamap_t map;
1386200853Syongari	int error, nsegs;
1387200853Syongari
1388243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
1389200853Syongari	if (m == NULL)
1390200853Syongari		return (ENOBUFS);
1391200853Syongari	m->m_len = m->m_pkthdr.len = MCLBYTES;
1392200853Syongari	m_adj(m, ETHER_ALIGN);
1393200853Syongari
1394200853Syongari	if ((error = bus_dmamap_load_mbuf_sg(sc->ste_cdata.ste_rx_tag,
1395200853Syongari	    sc->ste_cdata.ste_rx_sparemap, m, segs, &nsegs, 0)) != 0) {
1396200853Syongari		m_freem(m);
1397200853Syongari		return (error);
1398200853Syongari	}
1399200853Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
1400200853Syongari
1401200853Syongari	if (rxc->ste_mbuf != NULL) {
1402200853Syongari		bus_dmamap_sync(sc->ste_cdata.ste_rx_tag, rxc->ste_map,
1403200853Syongari		    BUS_DMASYNC_POSTREAD);
1404200853Syongari		bus_dmamap_unload(sc->ste_cdata.ste_rx_tag, rxc->ste_map);
1405200853Syongari	}
1406200853Syongari	map = rxc->ste_map;
1407200853Syongari	rxc->ste_map = sc->ste_cdata.ste_rx_sparemap;
1408200853Syongari	sc->ste_cdata.ste_rx_sparemap = map;
1409200853Syongari	bus_dmamap_sync(sc->ste_cdata.ste_rx_tag, rxc->ste_map,
1410200853Syongari	    BUS_DMASYNC_PREREAD);
1411200853Syongari	rxc->ste_mbuf = m;
1412200853Syongari	rxc->ste_ptr->ste_status = 0;
1413200853Syongari	rxc->ste_ptr->ste_frag.ste_addr = htole32(segs[0].ds_addr);
1414200853Syongari	rxc->ste_ptr->ste_frag.ste_len = htole32(segs[0].ds_len |
1415200853Syongari	    STE_FRAG_LAST);
1416200808Syongari	return (0);
141750128Swpaul}
141850128Swpaul
1419102335Salfredstatic int
1420200798Syongariste_init_rx_list(struct ste_softc *sc)
142150128Swpaul{
1422200808Syongari	struct ste_chain_data *cd;
1423200808Syongari	struct ste_list_data *ld;
1424200853Syongari	int error, i;
142550128Swpaul
1426200950Syongari	sc->ste_int_rx_act = 0;
142750128Swpaul	cd = &sc->ste_cdata;
1428200853Syongari	ld = &sc->ste_ldata;
1429200853Syongari	bzero(ld->ste_rx_list, STE_RX_LIST_SZ);
143050128Swpaul	for (i = 0; i < STE_RX_LIST_CNT; i++) {
143150128Swpaul		cd->ste_rx_chain[i].ste_ptr = &ld->ste_rx_list[i];
1432200853Syongari		error = ste_newbuf(sc, &cd->ste_rx_chain[i]);
1433200853Syongari		if (error != 0)
1434200853Syongari			return (error);
143550128Swpaul		if (i == (STE_RX_LIST_CNT - 1)) {
1436200853Syongari			cd->ste_rx_chain[i].ste_next = &cd->ste_rx_chain[0];
1437201768Syongari			ld->ste_rx_list[i].ste_next =
1438201768Syongari			    htole32(ld->ste_rx_list_paddr +
1439201768Syongari			    (sizeof(struct ste_desc_onefrag) * 0));
144050128Swpaul		} else {
1441200853Syongari			cd->ste_rx_chain[i].ste_next = &cd->ste_rx_chain[i + 1];
1442201768Syongari			ld->ste_rx_list[i].ste_next =
1443201768Syongari			    htole32(ld->ste_rx_list_paddr +
1444201768Syongari			    (sizeof(struct ste_desc_onefrag) * (i + 1)));
144550128Swpaul		}
144650128Swpaul	}
144750128Swpaul
144850128Swpaul	cd->ste_rx_head = &cd->ste_rx_chain[0];
1449200853Syongari	bus_dmamap_sync(sc->ste_cdata.ste_rx_list_tag,
1450200853Syongari	    sc->ste_cdata.ste_rx_list_map,
1451200853Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
145250128Swpaul
1453200808Syongari	return (0);
145450128Swpaul}
145550128Swpaul
1456102335Salfredstatic void
1457200798Syongariste_init_tx_list(struct ste_softc *sc)
145850128Swpaul{
1459200808Syongari	struct ste_chain_data *cd;
1460200808Syongari	struct ste_list_data *ld;
1461200808Syongari	int i;
146250128Swpaul
146350128Swpaul	cd = &sc->ste_cdata;
1464200853Syongari	ld = &sc->ste_ldata;
1465200853Syongari	bzero(ld->ste_tx_list, STE_TX_LIST_SZ);
146650128Swpaul	for (i = 0; i < STE_TX_LIST_CNT; i++) {
146750128Swpaul		cd->ste_tx_chain[i].ste_ptr = &ld->ste_tx_list[i];
1468200853Syongari		cd->ste_tx_chain[i].ste_mbuf = NULL;
1469200853Syongari		if (i == (STE_TX_LIST_CNT - 1)) {
1470200853Syongari			cd->ste_tx_chain[i].ste_next = &cd->ste_tx_chain[0];
1471200853Syongari			cd->ste_tx_chain[i].ste_phys = htole32(STE_ADDR_LO(
1472200853Syongari			    ld->ste_tx_list_paddr +
1473200853Syongari			    (sizeof(struct ste_desc) * 0)));
1474200853Syongari		} else {
1475200853Syongari			cd->ste_tx_chain[i].ste_next = &cd->ste_tx_chain[i + 1];
1476200853Syongari			cd->ste_tx_chain[i].ste_phys = htole32(STE_ADDR_LO(
1477200853Syongari			    ld->ste_tx_list_paddr +
1478200853Syongari			    (sizeof(struct ste_desc) * (i + 1))));
1479200853Syongari		}
148050128Swpaul	}
148150128Swpaul
1482200853Syongari	cd->ste_last_tx = NULL;
148354268Swpaul	cd->ste_tx_prod = 0;
148454268Swpaul	cd->ste_tx_cons = 0;
1485200853Syongari	cd->ste_tx_cnt = 0;
1486200853Syongari
1487200853Syongari	bus_dmamap_sync(sc->ste_cdata.ste_tx_list_tag,
1488200853Syongari	    sc->ste_cdata.ste_tx_list_map,
1489200853Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
149050128Swpaul}
149150128Swpaul
1492102335Salfredstatic void
1493200798Syongariste_init(void *xsc)
149450128Swpaul{
1495200808Syongari	struct ste_softc *sc;
1496149646Sjhb
1497149646Sjhb	sc = xsc;
1498149646Sjhb	STE_LOCK(sc);
1499149646Sjhb	ste_init_locked(sc);
1500149646Sjhb	STE_UNLOCK(sc);
1501149646Sjhb}
1502149646Sjhb
1503149646Sjhbstatic void
1504200798Syongariste_init_locked(struct ste_softc *sc)
1505149646Sjhb{
1506200808Syongari	struct ifnet *ifp;
1507200908Syongari	struct mii_data *mii;
1508200955Syongari	uint8_t val;
1509200808Syongari	int i;
151050128Swpaul
1511149646Sjhb	STE_LOCK_ASSERT(sc);
1512147256Sbrooks	ifp = sc->ste_ifp;
1513200908Syongari	mii = device_get_softc(sc->ste_miibus);
151450128Swpaul
1515200904Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
1516200904Syongari		return;
1517200904Syongari
151850128Swpaul	ste_stop(sc);
1519200873Syongari	/* Reset the chip to a known state. */
1520200873Syongari	ste_reset(sc);
152150128Swpaul
152250128Swpaul	/* Init our MAC address */
1523170794Sthompsa	for (i = 0; i < ETHER_ADDR_LEN; i += 2) {
1524170794Sthompsa		CSR_WRITE_2(sc, STE_PAR0 + i,
1525170794Sthompsa		    ((IF_LLADDR(sc->ste_ifp)[i] & 0xff) |
1526170794Sthompsa		     IF_LLADDR(sc->ste_ifp)[i + 1] << 8));
152750128Swpaul	}
152850128Swpaul
152950128Swpaul	/* Init RX list */
1530200853Syongari	if (ste_init_rx_list(sc) != 0) {
1531162315Sglebius		device_printf(sc->ste_dev,
1532149189Sjhb		    "initialization failed: no memory for RX buffers\n");
153350128Swpaul		ste_stop(sc);
153450128Swpaul		return;
153550128Swpaul	}
153650128Swpaul
1537101493Sambrisko	/* Set RX polling interval */
1538127688Sru	CSR_WRITE_1(sc, STE_RX_DMAPOLL_PERIOD, 64);
1539101493Sambrisko
154050128Swpaul	/* Init TX descriptors */
154150128Swpaul	ste_init_tx_list(sc);
154250128Swpaul
1543200955Syongari	/* Clear and disable WOL. */
1544200955Syongari	val = CSR_READ_1(sc, STE_WAKE_EVENT);
1545200955Syongari	val &= ~(STE_WAKEEVENT_WAKEPKT_ENB | STE_WAKEEVENT_MAGICPKT_ENB |
1546200955Syongari	    STE_WAKEEVENT_LINKEVT_ENB | STE_WAKEEVENT_WAKEONLAN_ENB);
1547200955Syongari	CSR_WRITE_1(sc, STE_WAKE_EVENT, val);
1548200955Syongari
154950128Swpaul	/* Set the TX freethresh value */
155050128Swpaul	CSR_WRITE_1(sc, STE_TX_DMABURST_THRESH, STE_PACKET_SIZE >> 8);
155150128Swpaul
155250128Swpaul	/* Set the TX start threshold for best performance. */
155350128Swpaul	CSR_WRITE_2(sc, STE_TX_STARTTHRESH, sc->ste_tx_thresh);
155450128Swpaul
155550128Swpaul	/* Set the TX reclaim threshold. */
155650128Swpaul	CSR_WRITE_1(sc, STE_TX_RECLAIM_THRESH, (STE_PACKET_SIZE >> 4));
155750128Swpaul
1558200906Syongari	/* Accept VLAN length packets */
1559200906Syongari	CSR_WRITE_2(sc, STE_MAX_FRAMELEN, ETHER_MAX_LEN + ETHER_VLAN_ENCAP_LEN);
1560200906Syongari
156150128Swpaul	/* Set up the RX filter. */
1562200906Syongari	ste_rxfilter(sc);
156350128Swpaul
156450128Swpaul	/* Load the address of the RX list. */
156550128Swpaul	STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_STALL);
156650128Swpaul	ste_wait(sc);
156750128Swpaul	CSR_WRITE_4(sc, STE_RX_DMALIST_PTR,
1568200853Syongari	    STE_ADDR_LO(sc->ste_ldata.ste_rx_list_paddr));
156950128Swpaul	STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_UNSTALL);
157050128Swpaul	STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_RXDMA_UNSTALL);
157150128Swpaul
1572200853Syongari	/* Set TX polling interval(defer until we TX first packet). */
1573101493Sambrisko	CSR_WRITE_1(sc, STE_TX_DMAPOLL_PERIOD, 0);
157454268Swpaul
157554268Swpaul	/* Load address of the TX list */
157654268Swpaul	STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_STALL);
157754268Swpaul	ste_wait(sc);
1578101493Sambrisko	CSR_WRITE_4(sc, STE_TX_DMALIST_PTR, 0);
157954268Swpaul	STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL);
158054268Swpaul	STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL);
158154268Swpaul	ste_wait(sc);
1582200950Syongari	/* Select 3.2us timer. */
1583200950Syongari	STE_CLRBIT4(sc, STE_DMACTL, STE_DMACTL_COUNTDOWN_SPEED |
1584200950Syongari	    STE_DMACTL_COUNTDOWN_MODE);
158554268Swpaul
158650128Swpaul	/* Enable receiver and transmitter */
158750128Swpaul	CSR_WRITE_2(sc, STE_MACCTL0, 0);
1588101493Sambrisko	CSR_WRITE_2(sc, STE_MACCTL1, 0);
158950128Swpaul	STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_TX_ENABLE);
159050128Swpaul	STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_RX_ENABLE);
159150128Swpaul
159250128Swpaul	/* Enable stats counters. */
159350128Swpaul	STE_SETBIT2(sc, STE_MACCTL1, STE_MACCTL1_STATS_ENABLE);
1594200910Syongari	/* Clear stats counters. */
1595200910Syongari	ste_stats_clear(sc);
159650128Swpaul
1597200950Syongari	CSR_WRITE_2(sc, STE_COUNTDOWN, 0);
1598127686Sru	CSR_WRITE_2(sc, STE_ISR, 0xFFFF);
1599127686Sru#ifdef DEVICE_POLLING
1600127686Sru	/* Disable interrupts if we are polling. */
1601150789Sglebius	if (ifp->if_capenable & IFCAP_POLLING)
1602127686Sru		CSR_WRITE_2(sc, STE_IMR, 0);
1603200804Syongari	else
1604150789Sglebius#endif
160550128Swpaul	/* Enable interrupts. */
160650128Swpaul	CSR_WRITE_2(sc, STE_IMR, STE_INTRS);
160750128Swpaul
1608200908Syongari	sc->ste_flags &= ~STE_FLAG_LINK;
1609200908Syongari	/* Switch to the current media. */
1610200908Syongari	mii_mediachg(mii);
161150128Swpaul
1612148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
1613148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
161450128Swpaul
1615200865Syongari	callout_reset(&sc->ste_callout, hz, ste_tick, sc);
161650128Swpaul}
161750128Swpaul
1618102335Salfredstatic void
1619200798Syongariste_stop(struct ste_softc *sc)
162050128Swpaul{
1621200808Syongari	struct ifnet *ifp;
1622200853Syongari	struct ste_chain_onefrag *cur_rx;
1623200853Syongari	struct ste_chain *cur_tx;
1624200873Syongari	uint32_t val;
1625200808Syongari	int i;
162650128Swpaul
1627149646Sjhb	STE_LOCK_ASSERT(sc);
1628147256Sbrooks	ifp = sc->ste_ifp;
162950128Swpaul
1630200865Syongari	callout_stop(&sc->ste_callout);
1631200865Syongari	sc->ste_timer = 0;
1632148887Srwatson	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING|IFF_DRV_OACTIVE);
163350128Swpaul
163450128Swpaul	CSR_WRITE_2(sc, STE_IMR, 0);
1635200950Syongari	CSR_WRITE_2(sc, STE_COUNTDOWN, 0);
1636200873Syongari	/* Stop pending DMA. */
1637200873Syongari	val = CSR_READ_4(sc, STE_DMACTL);
1638200873Syongari	val |= STE_DMACTL_TXDMA_STALL | STE_DMACTL_RXDMA_STALL;
1639200873Syongari	CSR_WRITE_4(sc, STE_DMACTL, val);
164050128Swpaul	ste_wait(sc);
1641200873Syongari	/* Disable auto-polling. */
1642200873Syongari	CSR_WRITE_1(sc, STE_RX_DMAPOLL_PERIOD, 0);
1643200873Syongari	CSR_WRITE_1(sc, STE_TX_DMAPOLL_PERIOD, 0);
1644200873Syongari	/* Nullify DMA address to stop any further DMA. */
1645200873Syongari	CSR_WRITE_4(sc, STE_RX_DMALIST_PTR, 0);
1646200873Syongari	CSR_WRITE_4(sc, STE_TX_DMALIST_PTR, 0);
1647200873Syongari	/* Stop TX/RX MAC. */
1648200873Syongari	val = CSR_READ_2(sc, STE_MACCTL1);
1649200873Syongari	val |= STE_MACCTL1_TX_DISABLE | STE_MACCTL1_RX_DISABLE |
1650200873Syongari	    STE_MACCTL1_STATS_DISABLE;
1651200873Syongari	CSR_WRITE_2(sc, STE_MACCTL1, val);
1652200873Syongari	for (i = 0; i < STE_TIMEOUT; i++) {
1653200873Syongari		DELAY(10);
1654200873Syongari		if ((CSR_READ_2(sc, STE_MACCTL1) & (STE_MACCTL1_TX_DISABLE |
1655200873Syongari		    STE_MACCTL1_RX_DISABLE | STE_MACCTL1_STATS_DISABLE)) == 0)
1656200873Syongari			break;
1657200873Syongari	}
1658200873Syongari	if (i == STE_TIMEOUT)
1659200873Syongari		device_printf(sc->ste_dev, "Stopping MAC timed out\n");
1660200873Syongari	/* Acknowledge any pending interrupts. */
1661200873Syongari	CSR_READ_2(sc, STE_ISR_ACK);
1662200873Syongari	ste_stats_update(sc);
166350128Swpaul
166450128Swpaul	for (i = 0; i < STE_RX_LIST_CNT; i++) {
1665200853Syongari		cur_rx = &sc->ste_cdata.ste_rx_chain[i];
1666200853Syongari		if (cur_rx->ste_mbuf != NULL) {
1667200853Syongari			bus_dmamap_sync(sc->ste_cdata.ste_rx_tag,
1668200853Syongari			    cur_rx->ste_map, BUS_DMASYNC_POSTREAD);
1669200853Syongari			bus_dmamap_unload(sc->ste_cdata.ste_rx_tag,
1670200853Syongari			    cur_rx->ste_map);
1671200853Syongari			m_freem(cur_rx->ste_mbuf);
1672200853Syongari			cur_rx->ste_mbuf = NULL;
167350128Swpaul		}
167450128Swpaul	}
167550128Swpaul
167650128Swpaul	for (i = 0; i < STE_TX_LIST_CNT; i++) {
1677200853Syongari		cur_tx = &sc->ste_cdata.ste_tx_chain[i];
1678200853Syongari		if (cur_tx->ste_mbuf != NULL) {
1679200853Syongari			bus_dmamap_sync(sc->ste_cdata.ste_tx_tag,
1680200853Syongari			    cur_tx->ste_map, BUS_DMASYNC_POSTWRITE);
1681200853Syongari			bus_dmamap_unload(sc->ste_cdata.ste_tx_tag,
1682200853Syongari			    cur_tx->ste_map);
1683200853Syongari			m_freem(cur_tx->ste_mbuf);
1684200853Syongari			cur_tx->ste_mbuf = NULL;
168550128Swpaul		}
168650128Swpaul	}
168750128Swpaul}
168850128Swpaul
1689102335Salfredstatic void
1690200798Syongariste_reset(struct ste_softc *sc)
169150128Swpaul{
1692200905Syongari	uint32_t ctl;
1693200808Syongari	int i;
169450128Swpaul
1695200905Syongari	ctl = CSR_READ_4(sc, STE_ASICCTL);
1696200905Syongari	ctl |= STE_ASICCTL_GLOBAL_RESET | STE_ASICCTL_RX_RESET |
1697200905Syongari	    STE_ASICCTL_TX_RESET | STE_ASICCTL_DMA_RESET |
1698200905Syongari	    STE_ASICCTL_FIFO_RESET | STE_ASICCTL_NETWORK_RESET |
1699200905Syongari	    STE_ASICCTL_AUTOINIT_RESET |STE_ASICCTL_HOST_RESET |
1700200905Syongari	    STE_ASICCTL_EXTRESET_RESET;
1701200905Syongari	CSR_WRITE_4(sc, STE_ASICCTL, ctl);
1702200905Syongari	CSR_READ_4(sc, STE_ASICCTL);
1703200905Syongari	/*
1704200905Syongari	 * Due to the need of accessing EEPROM controller can take
1705200905Syongari	 * up to 1ms to complete the global reset.
1706200905Syongari	 */
1707200905Syongari	DELAY(1000);
170850128Swpaul
170950128Swpaul	for (i = 0; i < STE_TIMEOUT; i++) {
171050128Swpaul		if (!(CSR_READ_4(sc, STE_ASICCTL) & STE_ASICCTL_RESET_BUSY))
171150128Swpaul			break;
1712200905Syongari		DELAY(10);
171350128Swpaul	}
171450128Swpaul
171550128Swpaul	if (i == STE_TIMEOUT)
1716162315Sglebius		device_printf(sc->ste_dev, "global reset never completed\n");
171750128Swpaul}
171850128Swpaul
1719200884Syongaristatic void
1720200884Syongariste_restart_tx(struct ste_softc *sc)
1721200884Syongari{
1722200884Syongari	uint16_t mac;
1723200884Syongari	int i;
1724200884Syongari
1725200884Syongari	for (i = 0; i < STE_TIMEOUT; i++) {
1726200884Syongari		mac = CSR_READ_2(sc, STE_MACCTL1);
1727200884Syongari		mac |= STE_MACCTL1_TX_ENABLE;
1728200884Syongari		CSR_WRITE_2(sc, STE_MACCTL1, mac);
1729200884Syongari		mac = CSR_READ_2(sc, STE_MACCTL1);
1730200884Syongari		if ((mac & STE_MACCTL1_TX_ENABLED) != 0)
1731200884Syongari			break;
1732200884Syongari		DELAY(10);
1733200884Syongari	}
1734200884Syongari
1735200884Syongari	if (i == STE_TIMEOUT)
1736200884Syongari		device_printf(sc->ste_dev, "starting Tx failed");
1737200884Syongari}
1738200884Syongari
1739102335Salfredstatic int
1740200798Syongariste_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
174150128Swpaul{
1742200808Syongari	struct ste_softc *sc;
1743200808Syongari	struct ifreq *ifr;
1744200808Syongari	struct mii_data *mii;
1745200955Syongari	int error = 0, mask;
174650128Swpaul
174750128Swpaul	sc = ifp->if_softc;
174850128Swpaul	ifr = (struct ifreq *)data;
174950128Swpaul
1750200808Syongari	switch (command) {
175150128Swpaul	case SIOCSIFFLAGS:
1752149646Sjhb		STE_LOCK(sc);
1753200906Syongari		if ((ifp->if_flags & IFF_UP) != 0) {
1754200906Syongari			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0 &&
1755200906Syongari			    ((ifp->if_flags ^ sc->ste_if_flags) &
1756200906Syongari			     (IFF_PROMISC | IFF_ALLMULTI)) != 0)
1757200906Syongari				ste_rxfilter(sc);
1758200906Syongari			else
1759149646Sjhb				ste_init_locked(sc);
1760200906Syongari		} else if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
1761200906Syongari			ste_stop(sc);
176254268Swpaul		sc->ste_if_flags = ifp->if_flags;
1763149646Sjhb		STE_UNLOCK(sc);
176450128Swpaul		break;
176550128Swpaul	case SIOCADDMULTI:
176650128Swpaul	case SIOCDELMULTI:
1767149646Sjhb		STE_LOCK(sc);
1768200906Syongari		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
1769200906Syongari			ste_rxfilter(sc);
1770149646Sjhb		STE_UNLOCK(sc);
177150128Swpaul		break;
177250128Swpaul	case SIOCGIFMEDIA:
177350128Swpaul	case SIOCSIFMEDIA:
177450128Swpaul		mii = device_get_softc(sc->ste_miibus);
177550128Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
177650128Swpaul		break;
1777128117Sru	case SIOCSIFCAP:
1778200955Syongari		STE_LOCK(sc);
1779200955Syongari		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
1780150789Sglebius#ifdef DEVICE_POLLING
1781200955Syongari		if ((mask & IFCAP_POLLING) != 0 &&
1782200955Syongari		    (IFCAP_POLLING & ifp->if_capabilities) != 0) {
1783200955Syongari			ifp->if_capenable ^= IFCAP_POLLING;
1784200955Syongari			if ((IFCAP_POLLING & ifp->if_capenable) != 0) {
1785200955Syongari				error = ether_poll_register(ste_poll, ifp);
1786200955Syongari				if (error != 0) {
1787200955Syongari					STE_UNLOCK(sc);
1788200955Syongari					break;
1789200955Syongari				}
1790200955Syongari				/* Disable interrupts. */
1791200955Syongari				CSR_WRITE_2(sc, STE_IMR, 0);
1792200955Syongari			} else {
1793200955Syongari				error = ether_poll_deregister(ifp);
1794200955Syongari				/* Enable interrupts. */
1795200955Syongari				CSR_WRITE_2(sc, STE_IMR, STE_INTRS);
1796200955Syongari			}
1797150789Sglebius		}
1798150789Sglebius#endif /* DEVICE_POLLING */
1799200955Syongari		if ((mask & IFCAP_WOL_MAGIC) != 0 &&
1800200955Syongari		    (ifp->if_capabilities & IFCAP_WOL_MAGIC) != 0)
1801200955Syongari			ifp->if_capenable ^= IFCAP_WOL_MAGIC;
1802200955Syongari		STE_UNLOCK(sc);
1803128117Sru		break;
180450128Swpaul	default:
1805106936Ssam		error = ether_ioctl(ifp, command, data);
180650128Swpaul		break;
180750128Swpaul	}
180850128Swpaul
1809200808Syongari	return (error);
181050128Swpaul}
181150128Swpaul
1812102335Salfredstatic int
1813200853Syongariste_encap(struct ste_softc *sc, struct mbuf **m_head, struct ste_chain *txc)
181450128Swpaul{
1815200853Syongari	struct ste_frag *frag;
1816200808Syongari	struct mbuf *m;
1817200853Syongari	struct ste_desc *desc;
1818200853Syongari	bus_dma_segment_t txsegs[STE_MAXFRAGS];
1819200853Syongari	int error, i, nsegs;
182050128Swpaul
1821200853Syongari	STE_LOCK_ASSERT(sc);
1822200853Syongari	M_ASSERTPKTHDR((*m_head));
182350128Swpaul
1824200853Syongari	error = bus_dmamap_load_mbuf_sg(sc->ste_cdata.ste_tx_tag,
1825200853Syongari	    txc->ste_map, *m_head, txsegs, &nsegs, 0);
1826200853Syongari	if (error == EFBIG) {
1827243857Sglebius		m = m_collapse(*m_head, M_NOWAIT, STE_MAXFRAGS);
1828200853Syongari		if (m == NULL) {
1829200853Syongari			m_freem(*m_head);
1830200853Syongari			*m_head = NULL;
1831200853Syongari			return (ENOMEM);
183250128Swpaul		}
1833200853Syongari		*m_head = m;
1834200853Syongari		error = bus_dmamap_load_mbuf_sg(sc->ste_cdata.ste_tx_tag,
1835200853Syongari		    txc->ste_map, *m_head, txsegs, &nsegs, 0);
1836200853Syongari		if (error != 0) {
1837200853Syongari			m_freem(*m_head);
1838200853Syongari			*m_head = NULL;
1839200853Syongari			return (error);
1840200853Syongari		}
1841200853Syongari	} else if (error != 0)
1842200853Syongari		return (error);
1843200853Syongari	if (nsegs == 0) {
1844200853Syongari		m_freem(*m_head);
1845200853Syongari		*m_head = NULL;
1846200853Syongari		return (EIO);
184750128Swpaul	}
1848200853Syongari	bus_dmamap_sync(sc->ste_cdata.ste_tx_tag, txc->ste_map,
1849200853Syongari	    BUS_DMASYNC_PREWRITE);
185050128Swpaul
1851200853Syongari	desc = txc->ste_ptr;
1852200853Syongari	for (i = 0; i < nsegs; i++) {
1853200853Syongari		frag = &desc->ste_frags[i];
1854200853Syongari		frag->ste_addr = htole32(STE_ADDR_LO(txsegs[i].ds_addr));
1855200853Syongari		frag->ste_len = htole32(txsegs[i].ds_len);
1856103238Sambrisko	}
1857200853Syongari	desc->ste_frags[i - 1].ste_len |= htole32(STE_FRAG_LAST);
1858200853Syongari	/*
1859200853Syongari	 * Because we use Tx polling we can't chain multiple
1860200853Syongari	 * Tx descriptors here. Otherwise we race with controller.
1861200853Syongari	 */
1862200853Syongari	desc->ste_next = 0;
1863200913Syongari	if ((sc->ste_cdata.ste_tx_prod % STE_TX_INTR_FRAMES) == 0)
1864200913Syongari		desc->ste_ctl = htole32(STE_TXCTL_ALIGN_DIS |
1865200913Syongari		    STE_TXCTL_DMAINTR);
1866200913Syongari	else
1867200913Syongari		desc->ste_ctl = htole32(STE_TXCTL_ALIGN_DIS);
1868200853Syongari	txc->ste_mbuf = *m_head;
1869200853Syongari	STE_INC(sc->ste_cdata.ste_tx_prod, STE_TX_LIST_CNT);
1870200853Syongari	sc->ste_cdata.ste_tx_cnt++;
1871103238Sambrisko
1872200808Syongari	return (0);
187350128Swpaul}
187450128Swpaul
1875102335Salfredstatic void
1876200798Syongariste_start(struct ifnet *ifp)
187750128Swpaul{
1878200808Syongari	struct ste_softc *sc;
1879149646Sjhb
1880149646Sjhb	sc = ifp->if_softc;
1881149646Sjhb	STE_LOCK(sc);
1882149646Sjhb	ste_start_locked(ifp);
1883149646Sjhb	STE_UNLOCK(sc);
1884149646Sjhb}
1885149646Sjhb
1886149646Sjhbstatic void
1887200798Syongariste_start_locked(struct ifnet *ifp)
1888149646Sjhb{
1889200808Syongari	struct ste_softc *sc;
1890200808Syongari	struct ste_chain *cur_tx;
1891200808Syongari	struct mbuf *m_head = NULL;
1892200853Syongari	int enq;
189350128Swpaul
189450128Swpaul	sc = ifp->if_softc;
1895149646Sjhb	STE_LOCK_ASSERT(sc);
189650128Swpaul
1897200856Syongari	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
1898200856Syongari	    IFF_DRV_RUNNING || (sc->ste_flags & STE_FLAG_LINK) == 0)
189950128Swpaul		return;
190050128Swpaul
1901200853Syongari	for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd);) {
1902200853Syongari		if (sc->ste_cdata.ste_tx_cnt == STE_TX_LIST_CNT - 1) {
1903200853Syongari			/*
1904200853Syongari			 * Controller may have cached copy of the last used
1905200853Syongari			 * next ptr so we have to reserve one TFD to avoid
1906200853Syongari			 * TFD overruns.
1907200853Syongari			 */
1908148887Srwatson			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
190954268Swpaul			break;
191054268Swpaul		}
1911147828Smlaier		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
191250128Swpaul		if (m_head == NULL)
191350128Swpaul			break;
1914200853Syongari		cur_tx = &sc->ste_cdata.ste_tx_chain[sc->ste_cdata.ste_tx_prod];
1915200853Syongari		if (ste_encap(sc, &m_head, cur_tx) != 0) {
1916200853Syongari			if (m_head == NULL)
1917200853Syongari				break;
1918200853Syongari			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
1919103238Sambrisko			break;
1920200853Syongari		}
1921200853Syongari		if (sc->ste_cdata.ste_last_tx == NULL) {
1922200853Syongari			bus_dmamap_sync(sc->ste_cdata.ste_tx_list_tag,
1923200853Syongari			    sc->ste_cdata.ste_tx_list_map,
1924200853Syongari			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1925101493Sambrisko			STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_STALL);
1926101493Sambrisko			ste_wait(sc);
1927101493Sambrisko			CSR_WRITE_4(sc, STE_TX_DMALIST_PTR,
1928200853Syongari	    		    STE_ADDR_LO(sc->ste_ldata.ste_tx_list_paddr));
1929101493Sambrisko			CSR_WRITE_1(sc, STE_TX_DMAPOLL_PERIOD, 64);
1930101493Sambrisko			STE_SETBIT4(sc, STE_DMACTL, STE_DMACTL_TXDMA_UNSTALL);
1931101493Sambrisko			ste_wait(sc);
1932200853Syongari		} else {
1933200853Syongari			sc->ste_cdata.ste_last_tx->ste_ptr->ste_next =
1934200853Syongari			    sc->ste_cdata.ste_last_tx->ste_phys;
1935200853Syongari			bus_dmamap_sync(sc->ste_cdata.ste_tx_list_tag,
1936200853Syongari			    sc->ste_cdata.ste_tx_list_map,
1937200853Syongari			    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1938101493Sambrisko		}
1939200853Syongari		sc->ste_cdata.ste_last_tx = cur_tx;
1940101493Sambrisko
1941200853Syongari		enq++;
194250128Swpaul		/*
194354268Swpaul		 * If there's a BPF listener, bounce a copy of this frame
194450128Swpaul		 * to him.
194550128Swpaul	 	 */
1946200853Syongari		BPF_MTAP(ifp, m_head);
1947200853Syongari	}
194854268Swpaul
1949200853Syongari	if (enq > 0)
1950200853Syongari		sc->ste_timer = STE_TX_TIMEOUT;
195150128Swpaul}
195250128Swpaul
1953102335Salfredstatic void
1954199559Sjhbste_watchdog(struct ste_softc *sc)
1955199559Sjhb{
1956200808Syongari	struct ifnet *ifp;
195750128Swpaul
1958199559Sjhb	ifp = sc->ste_ifp;
1959199559Sjhb	STE_LOCK_ASSERT(sc);
196050128Swpaul
1961200865Syongari	if (sc->ste_timer == 0 || --sc->ste_timer)
1962200865Syongari		return;
1963200865Syongari
196450128Swpaul	ifp->if_oerrors++;
1965149189Sjhb	if_printf(ifp, "watchdog timeout\n");
196650128Swpaul
1967200884Syongari	ste_txeof(sc);
196850128Swpaul	ste_txeoc(sc);
1969200853Syongari	ste_rxeof(sc, -1);
1970200904Syongari	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1971149646Sjhb	ste_init_locked(sc);
197250128Swpaul
1973147828Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1974149646Sjhb		ste_start_locked(ifp);
197550128Swpaul}
197650128Swpaul
1977173839Syongaristatic int
1978200798Syongariste_shutdown(device_t dev)
197950128Swpaul{
1980200955Syongari
1981200955Syongari	return (ste_suspend(dev));
1982200955Syongari}
1983200955Syongari
1984200955Syongaristatic int
1985200955Syongariste_suspend(device_t dev)
1986200955Syongari{
1987200808Syongari	struct ste_softc *sc;
198850128Swpaul
198950128Swpaul	sc = device_get_softc(dev);
199050128Swpaul
1991149646Sjhb	STE_LOCK(sc);
199250128Swpaul	ste_stop(sc);
1993200955Syongari	ste_setwol(sc);
1994149646Sjhb	STE_UNLOCK(sc);
199550128Swpaul
1996173839Syongari	return (0);
199750128Swpaul}
1998200910Syongari
1999200955Syongaristatic int
2000200955Syongariste_resume(device_t dev)
2001200955Syongari{
2002200955Syongari	struct ste_softc *sc;
2003200955Syongari	struct ifnet *ifp;
2004200955Syongari	int pmc;
2005200955Syongari	uint16_t pmstat;
2006200955Syongari
2007200955Syongari	sc = device_get_softc(dev);
2008200955Syongari	STE_LOCK(sc);
2009219902Sjhb	if (pci_find_cap(sc->ste_dev, PCIY_PMG, &pmc) == 0) {
2010200955Syongari		/* Disable PME and clear PME status. */
2011200955Syongari		pmstat = pci_read_config(sc->ste_dev,
2012200955Syongari		    pmc + PCIR_POWER_STATUS, 2);
2013200955Syongari		if ((pmstat & PCIM_PSTAT_PMEENABLE) != 0) {
2014200955Syongari			pmstat &= ~PCIM_PSTAT_PMEENABLE;
2015200955Syongari			pci_write_config(sc->ste_dev,
2016200955Syongari			    pmc + PCIR_POWER_STATUS, pmstat, 2);
2017200955Syongari		}
2018200955Syongari	}
2019200955Syongari	ifp = sc->ste_ifp;
2020200955Syongari	if ((ifp->if_flags & IFF_UP) != 0) {
2021200955Syongari		ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2022200955Syongari		ste_init_locked(sc);
2023200955Syongari	}
2024200955Syongari	STE_UNLOCK(sc);
2025200955Syongari
2026200955Syongari	return (0);
2027200955Syongari}
2028200955Syongari
2029200910Syongari#define	STE_SYSCTL_STAT_ADD32(c, h, n, p, d)	\
2030200910Syongari	    SYSCTL_ADD_UINT(c, h, OID_AUTO, n, CTLFLAG_RD, p, 0, d)
2031200910Syongari#define	STE_SYSCTL_STAT_ADD64(c, h, n, p, d)	\
2032217323Smdf	    SYSCTL_ADD_UQUAD(c, h, OID_AUTO, n, CTLFLAG_RD, p, d)
2033200910Syongari
2034200910Syongaristatic void
2035200910Syongariste_sysctl_node(struct ste_softc *sc)
2036200910Syongari{
2037200910Syongari	struct sysctl_ctx_list *ctx;
2038200910Syongari	struct sysctl_oid_list *child, *parent;
2039200910Syongari	struct sysctl_oid *tree;
2040200910Syongari	struct ste_hw_stats *stats;
2041200910Syongari
2042200910Syongari	stats = &sc->ste_stats;
2043200910Syongari	ctx = device_get_sysctl_ctx(sc->ste_dev);
2044200910Syongari	child = SYSCTL_CHILDREN(device_get_sysctl_tree(sc->ste_dev));
2045200910Syongari
2046200950Syongari	SYSCTL_ADD_INT(ctx, child, OID_AUTO, "int_rx_mod",
2047200950Syongari	    CTLFLAG_RW, &sc->ste_int_rx_mod, 0, "ste RX interrupt moderation");
2048200950Syongari	/* Pull in device tunables. */
2049200950Syongari	sc->ste_int_rx_mod = STE_IM_RX_TIMER_DEFAULT;
2050200950Syongari	resource_int_value(device_get_name(sc->ste_dev),
2051200950Syongari	    device_get_unit(sc->ste_dev), "int_rx_mod", &sc->ste_int_rx_mod);
2052200950Syongari
2053200910Syongari	tree = SYSCTL_ADD_NODE(ctx, child, OID_AUTO, "stats", CTLFLAG_RD,
2054200910Syongari	    NULL, "STE statistics");
2055200910Syongari	parent = SYSCTL_CHILDREN(tree);
2056200910Syongari
2057200910Syongari	/* Rx statistics. */
2058200910Syongari	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "rx", CTLFLAG_RD,
2059200910Syongari	    NULL, "Rx MAC statistics");
2060200910Syongari	child = SYSCTL_CHILDREN(tree);
2061200910Syongari	STE_SYSCTL_STAT_ADD64(ctx, child, "good_octets",
2062200910Syongari	    &stats->rx_bytes, "Good octets");
2063200910Syongari	STE_SYSCTL_STAT_ADD32(ctx, child, "good_frames",
2064200910Syongari	    &stats->rx_frames, "Good frames");
2065200910Syongari	STE_SYSCTL_STAT_ADD32(ctx, child, "good_bcast_frames",
2066200910Syongari	    &stats->rx_bcast_frames, "Good broadcast frames");
2067200910Syongari	STE_SYSCTL_STAT_ADD32(ctx, child, "good_mcast_frames",
2068200910Syongari	    &stats->rx_mcast_frames, "Good multicast frames");
2069200910Syongari	STE_SYSCTL_STAT_ADD32(ctx, child, "lost_frames",
2070200910Syongari	    &stats->rx_lost_frames, "Lost frames");
2071200910Syongari
2072200910Syongari	/* Tx statistics. */
2073200910Syongari	tree = SYSCTL_ADD_NODE(ctx, parent, OID_AUTO, "tx", CTLFLAG_RD,
2074200910Syongari	    NULL, "Tx MAC statistics");
2075200910Syongari	child = SYSCTL_CHILDREN(tree);
2076200910Syongari	STE_SYSCTL_STAT_ADD64(ctx, child, "good_octets",
2077200910Syongari	    &stats->tx_bytes, "Good octets");
2078200910Syongari	STE_SYSCTL_STAT_ADD32(ctx, child, "good_frames",
2079200910Syongari	    &stats->tx_frames, "Good frames");
2080200910Syongari	STE_SYSCTL_STAT_ADD32(ctx, child, "good_bcast_frames",
2081200910Syongari	    &stats->tx_bcast_frames, "Good broadcast frames");
2082200910Syongari	STE_SYSCTL_STAT_ADD32(ctx, child, "good_mcast_frames",
2083200910Syongari	    &stats->tx_mcast_frames, "Good multicast frames");
2084200910Syongari	STE_SYSCTL_STAT_ADD32(ctx, child, "carrier_errs",
2085200910Syongari	    &stats->tx_carrsense_errs, "Carrier sense errors");
2086200910Syongari	STE_SYSCTL_STAT_ADD32(ctx, child, "single_colls",
2087200910Syongari	    &stats->tx_single_colls, "Single collisions");
2088200910Syongari	STE_SYSCTL_STAT_ADD32(ctx, child, "multi_colls",
2089200910Syongari	    &stats->tx_multi_colls, "Multiple collisions");
2090200910Syongari	STE_SYSCTL_STAT_ADD32(ctx, child, "late_colls",
2091200910Syongari	    &stats->tx_late_colls, "Late collisions");
2092200910Syongari	STE_SYSCTL_STAT_ADD32(ctx, child, "defers",
2093200910Syongari	    &stats->tx_frames_defered, "Frames with deferrals");
2094200910Syongari	STE_SYSCTL_STAT_ADD32(ctx, child, "excess_defers",
2095200910Syongari	    &stats->tx_excess_defers, "Frames with excessive derferrals");
2096200910Syongari	STE_SYSCTL_STAT_ADD32(ctx, child, "abort",
2097200910Syongari	    &stats->tx_abort, "Aborted frames due to Excessive collisions");
2098200910Syongari}
2099200910Syongari
2100200910Syongari#undef STE_SYSCTL_STAT_ADD32
2101200910Syongari#undef STE_SYSCTL_STAT_ADD64
2102200955Syongari
2103200955Syongaristatic void
2104200955Syongariste_setwol(struct ste_softc *sc)
2105200955Syongari{
2106200955Syongari	struct ifnet *ifp;
2107200955Syongari	uint16_t pmstat;
2108200955Syongari	uint8_t val;
2109200955Syongari	int pmc;
2110200955Syongari
2111200955Syongari	STE_LOCK_ASSERT(sc);
2112200955Syongari
2113219902Sjhb	if (pci_find_cap(sc->ste_dev, PCIY_PMG, &pmc) != 0) {
2114200955Syongari		/* Disable WOL. */
2115200955Syongari		CSR_READ_1(sc, STE_WAKE_EVENT);
2116200955Syongari		CSR_WRITE_1(sc, STE_WAKE_EVENT, 0);
2117200955Syongari		return;
2118200955Syongari	}
2119200955Syongari
2120200955Syongari	ifp = sc->ste_ifp;
2121200955Syongari	val = CSR_READ_1(sc, STE_WAKE_EVENT);
2122200955Syongari	val &= ~(STE_WAKEEVENT_WAKEPKT_ENB | STE_WAKEEVENT_MAGICPKT_ENB |
2123200955Syongari	    STE_WAKEEVENT_LINKEVT_ENB | STE_WAKEEVENT_WAKEONLAN_ENB);
2124200955Syongari	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
2125200955Syongari		val |= STE_WAKEEVENT_MAGICPKT_ENB | STE_WAKEEVENT_WAKEONLAN_ENB;
2126200955Syongari	CSR_WRITE_1(sc, STE_WAKE_EVENT, val);
2127200955Syongari	/* Request PME. */
2128200955Syongari	pmstat = pci_read_config(sc->ste_dev, pmc + PCIR_POWER_STATUS, 2);
2129200955Syongari	pmstat &= ~(PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE);
2130200955Syongari	if ((ifp->if_capenable & IFCAP_WOL_MAGIC) != 0)
2131200955Syongari		pmstat |= PCIM_PSTAT_PME | PCIM_PSTAT_PMEENABLE;
2132200955Syongari	pci_write_config(sc->ste_dev, pmc + PCIR_POWER_STATUS, pmstat, 2);
2133200955Syongari}
2134