1139825Simp/*-
249076Swpaul * Copyright (c) 1997, 1998, 1999
349076Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
449076Swpaul *
549076Swpaul * Redistribution and use in source and binary forms, with or without
649076Swpaul * modification, are permitted provided that the following conditions
749076Swpaul * are met:
849076Swpaul * 1. Redistributions of source code must retain the above copyright
949076Swpaul *    notice, this list of conditions and the following disclaimer.
1049076Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1149076Swpaul *    notice, this list of conditions and the following disclaimer in the
1249076Swpaul *    documentation and/or other materials provided with the distribution.
1349076Swpaul * 3. All advertising materials mentioning features or use of this software
1449076Swpaul *    must display the following acknowledgement:
1549076Swpaul *	This product includes software developed by Bill Paul.
1649076Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1749076Swpaul *    may be used to endorse or promote products derived from this software
1849076Swpaul *    without specific prior written permission.
1949076Swpaul *
2049076Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2149076Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2249076Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2349076Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2449076Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2549076Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2649076Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2749076Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2849076Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2949076Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3049076Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
3149076Swpaul */
3249076Swpaul
33122678Sobrien#include <sys/cdefs.h>
34122678Sobrien__FBSDID("$FreeBSD$");
35122678Sobrien
3649076Swpaul/*
3749076Swpaul * Adaptec AIC-6915 "Starfire" PCI fast ethernet driver for FreeBSD.
3851682Swpaul * Programming manual is available from:
39137835Sbrueffer * http://download.adaptec.com/pdfs/user_guides/aic6915_pg.pdf.
4049076Swpaul *
4149076Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu>
4249076Swpaul * Department of Electical Engineering
4349076Swpaul * Columbia University, New York City
4449076Swpaul */
4549076Swpaul/*
4649076Swpaul * The Adaptec AIC-6915 "Starfire" is a 64-bit 10/100 PCI ethernet
4749076Swpaul * controller designed with flexibility and reducing CPU load in mind.
4849076Swpaul * The Starfire offers high and low priority buffer queues, a
4949076Swpaul * producer/consumer index mechanism and several different buffer
5049076Swpaul * queue and completion queue descriptor types. Any one of a number
5149076Swpaul * of different driver designs can be used, depending on system and
52175526Syongari * OS requirements. This driver makes use of type2 transmit frame
53175526Syongari * descriptors to take full advantage of fragmented packets buffers
5449076Swpaul * and two RX buffer queues prioritized on size (one queue for small
5549076Swpaul * frames that will fit into a single mbuf, another with full size
5649076Swpaul * mbuf clusters for everything else). The producer/consumer indexes
5749076Swpaul * and completion queues are also used.
5849076Swpaul *
5949076Swpaul * One downside to the Starfire has to do with alignment: buffer
6049076Swpaul * queues must be aligned on 256-byte boundaries, and receive buffers
6149076Swpaul * must be aligned on longword boundaries. The receive buffer alignment
62175526Syongari * causes problems on the strict alignment architecture, where the
63175526Syongari * packet payload should be longword aligned. There is no simple way
64175526Syongari * around this.
6549076Swpaul *
6649076Swpaul * For receive filtering, the Starfire offers 16 perfect filter slots
6749076Swpaul * and a 512-bit hash table.
6849076Swpaul *
6949076Swpaul * The Starfire has no internal transceiver, relying instead on an
7049076Swpaul * external MII-based transceiver. Accessing registers on external
7149076Swpaul * PHYs is done through a special register map rather than with the
7249076Swpaul * usual bitbang MDIO method.
7349076Swpaul *
7449076Swpaul * Acesssing the registers on the Starfire is a little tricky. The
7549076Swpaul * Starfire has a 512K internal register space. When programmed for
7649076Swpaul * PCI memory mapped mode, the entire register space can be accessed
7749076Swpaul * directly. However in I/O space mode, only 256 bytes are directly
7849076Swpaul * mapped into PCI I/O space. The other registers can be accessed
7949076Swpaul * indirectly using the SF_INDIRECTIO_ADDR and SF_INDIRECTIO_DATA
8049076Swpaul * registers inside the 256-byte I/O window.
8149076Swpaul */
8249076Swpaul
83150968Sglebius#ifdef HAVE_KERNEL_OPTION_HEADERS
84150968Sglebius#include "opt_device_polling.h"
85150968Sglebius#endif
86150968Sglebius
8749076Swpaul#include <sys/param.h>
8849076Swpaul#include <sys/systm.h>
89175526Syongari#include <sys/bus.h>
90175526Syongari#include <sys/endian.h>
91175526Syongari#include <sys/kernel.h>
92175526Syongari#include <sys/malloc.h>
9349076Swpaul#include <sys/mbuf.h>
94175526Syongari#include <sys/rman.h>
95129878Sphk#include <sys/module.h>
9649076Swpaul#include <sys/socket.h>
97175526Syongari#include <sys/sockio.h>
98175526Syongari#include <sys/sysctl.h>
9949076Swpaul
100175526Syongari#include <net/bpf.h>
10149076Swpaul#include <net/if.h>
10249076Swpaul#include <net/if_arp.h>
10349076Swpaul#include <net/ethernet.h>
10449076Swpaul#include <net/if_dl.h>
10549076Swpaul#include <net/if_media.h>
106147256Sbrooks#include <net/if_types.h>
107175526Syongari#include <net/if_vlan_var.h>
10849076Swpaul
10950675Swpaul#include <dev/mii/mii.h>
11050675Swpaul#include <dev/mii/miivar.h>
11150675Swpaul
112119288Simp#include <dev/pci/pcireg.h>
113119288Simp#include <dev/pci/pcivar.h>
11449076Swpaul
115175526Syongari#include <machine/bus.h>
11649076Swpaul
117175520Syongari#include <dev/sf/if_sfreg.h>
118175526Syongari#include <dev/sf/starfire_rx.h>
119175526Syongari#include <dev/sf/starfire_tx.h>
12049076Swpaul
121175526Syongari/* "device miibus" required.  See GENERIC if you get errors here. */
122175526Syongari#include "miibus_if.h"
123175526Syongari
124113506SmdoddMODULE_DEPEND(sf, pci, 1, 1, 1);
125113506SmdoddMODULE_DEPEND(sf, ether, 1, 1, 1);
12659758SpeterMODULE_DEPEND(sf, miibus, 1, 1, 1);
12759758Speter
128175526Syongari#undef	SF_GFP_DEBUG
129175526Syongari#define	SF_CSUM_FEATURES	(CSUM_TCP | CSUM_UDP)
130175526Syongari/* Define this to activate partial TCP/UDP checksum offload. */
131175526Syongari#undef	SF_PARTIAL_CSUM_SUPPORT
132175526Syongari
13349076Swpaulstatic struct sf_type sf_devs[] = {
134175526Syongari	{ AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX",
135175526Syongari	    AD_SUBSYSID_62011_REV0, "Adaptec ANA-62011 (rev 0) 10/100BaseTX" },
136175526Syongari	{ AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX",
137175526Syongari	    AD_SUBSYSID_62011_REV1, "Adaptec ANA-62011 (rev 1) 10/100BaseTX" },
138175526Syongari	{ AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX",
139175526Syongari	    AD_SUBSYSID_62022, "Adaptec ANA-62022 10/100BaseTX" },
140175526Syongari	{ AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX",
141175526Syongari	    AD_SUBSYSID_62044_REV0, "Adaptec ANA-62044 (rev 0) 10/100BaseTX" },
142175526Syongari	{ AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX",
143175526Syongari	    AD_SUBSYSID_62044_REV1, "Adaptec ANA-62044 (rev 1) 10/100BaseTX" },
144175526Syongari	{ AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX",
145175526Syongari	    AD_SUBSYSID_62020, "Adaptec ANA-62020 10/100BaseFX" },
146175526Syongari	{ AD_VENDORID, AD_DEVICEID_STARFIRE, "Adaptec AIC-6915 10/100BaseTX",
147175526Syongari	    AD_SUBSYSID_69011, "Adaptec ANA-69011 10/100BaseTX" },
14849076Swpaul};
14949076Swpaul
150142407Simpstatic int sf_probe(device_t);
151142407Simpstatic int sf_attach(device_t);
152142407Simpstatic int sf_detach(device_t);
153175526Syongaristatic int sf_shutdown(device_t);
154175526Syongaristatic int sf_suspend(device_t);
155175526Syongaristatic int sf_resume(device_t);
156142407Simpstatic void sf_intr(void *);
157175526Syongaristatic void sf_tick(void *);
158175526Syongaristatic void sf_stats_update(struct sf_softc *);
159175526Syongari#ifndef __NO_STRICT_ALIGNMENT
160175526Syongaristatic __inline void sf_fixup_rx(struct mbuf *);
161175526Syongari#endif
162193096Sattiliostatic int sf_rxeof(struct sf_softc *);
163142407Simpstatic void sf_txeof(struct sf_softc *);
164175526Syongaristatic int sf_encap(struct sf_softc *, struct mbuf **);
165142407Simpstatic void sf_start(struct ifnet *);
166149240Sjhbstatic void sf_start_locked(struct ifnet *);
167142407Simpstatic int sf_ioctl(struct ifnet *, u_long, caddr_t);
168175526Syongaristatic void sf_download_fw(struct sf_softc *);
169142407Simpstatic void sf_init(void *);
170149240Sjhbstatic void sf_init_locked(struct sf_softc *);
171142407Simpstatic void sf_stop(struct sf_softc *);
172175526Syongaristatic void sf_watchdog(struct sf_softc *);
173142407Simpstatic int sf_ifmedia_upd(struct ifnet *);
174232025Syongaristatic int sf_ifmedia_upd_locked(struct ifnet *);
175142407Simpstatic void sf_ifmedia_sts(struct ifnet *, struct ifmediareq *);
176142407Simpstatic void sf_reset(struct sf_softc *);
177175526Syongaristatic int sf_dma_alloc(struct sf_softc *);
178175526Syongaristatic void sf_dma_free(struct sf_softc *);
179142407Simpstatic int sf_init_rx_ring(struct sf_softc *);
180142407Simpstatic void sf_init_tx_ring(struct sf_softc *);
181175526Syongaristatic int sf_newbuf(struct sf_softc *, int);
182175526Syongaristatic void sf_rxfilter(struct sf_softc *);
183175526Syongaristatic int sf_setperf(struct sf_softc *, int, uint8_t *);
184142407Simpstatic int sf_sethash(struct sf_softc *, caddr_t, int);
18549076Swpaul#ifdef notdef
186175526Syongaristatic int sf_setvlan(struct sf_softc *, int, uint32_t);
18749076Swpaul#endif
18849076Swpaul
189175526Syongaristatic uint8_t sf_read_eeprom(struct sf_softc *, int);
19049076Swpaul
191142407Simpstatic int sf_miibus_readreg(device_t, int, int);
192142407Simpstatic int sf_miibus_writereg(device_t, int, int, int);
193142407Simpstatic void sf_miibus_statchg(device_t);
194137557Sbrueffer#ifdef DEVICE_POLLING
195193096Sattiliostatic int sf_poll(struct ifnet *ifp, enum poll_cmd cmd, int count);
196150789Sglebius#endif
19749076Swpaul
198175526Syongaristatic uint32_t csr_read_4(struct sf_softc *, int);
199175526Syongaristatic void csr_write_4(struct sf_softc *, int, uint32_t);
200142407Simpstatic void sf_txthresh_adjust(struct sf_softc *);
201175526Syongaristatic int sf_sysctl_stats(SYSCTL_HANDLER_ARGS);
202175526Syongaristatic int sysctl_int_range(SYSCTL_HANDLER_ARGS, int, int);
203175526Syongaristatic int sysctl_hw_sf_int_mod(SYSCTL_HANDLER_ARGS);
20449076Swpaul
20549076Swpaulstatic device_method_t sf_methods[] = {
20649076Swpaul	/* Device interface */
20749076Swpaul	DEVMETHOD(device_probe,		sf_probe),
20849076Swpaul	DEVMETHOD(device_attach,	sf_attach),
20949076Swpaul	DEVMETHOD(device_detach,	sf_detach),
21049076Swpaul	DEVMETHOD(device_shutdown,	sf_shutdown),
211175526Syongari	DEVMETHOD(device_suspend,	sf_suspend),
212175526Syongari	DEVMETHOD(device_resume,	sf_resume),
21350675Swpaul
21450675Swpaul	/* MII interface */
21550675Swpaul	DEVMETHOD(miibus_readreg,	sf_miibus_readreg),
21650675Swpaul	DEVMETHOD(miibus_writereg,	sf_miibus_writereg),
21750675Swpaul	DEVMETHOD(miibus_statchg,	sf_miibus_statchg),
21850675Swpaul
219227843Smarius	DEVMETHOD_END
22049076Swpaul};
22149076Swpaul
22249076Swpaulstatic driver_t sf_driver = {
22351455Swpaul	"sf",
22449076Swpaul	sf_methods,
22549076Swpaul	sizeof(struct sf_softc),
22649076Swpaul};
22749076Swpaul
22849076Swpaulstatic devclass_t sf_devclass;
22949076Swpaul
230113506SmdoddDRIVER_MODULE(sf, pci, sf_driver, sf_devclass, 0, 0);
23151473SwpaulDRIVER_MODULE(miibus, sf, miibus_driver, miibus_devclass, 0, 0);
23249076Swpaul
23349076Swpaul#define SF_SETBIT(sc, reg, x)	\
234105221Sphk	csr_write_4(sc, reg, csr_read_4(sc, reg) | (x))
23549076Swpaul
23649076Swpaul#define SF_CLRBIT(sc, reg, x)				\
237105221Sphk	csr_write_4(sc, reg, csr_read_4(sc, reg) & ~(x))
23849076Swpaul
239175526Syongaristatic uint32_t
240175526Syongaricsr_read_4(struct sf_softc *sc, int reg)
24149076Swpaul{
242175526Syongari	uint32_t		val;
24349076Swpaul
244175526Syongari	if (sc->sf_restype == SYS_RES_MEMORY)
245175526Syongari		val = CSR_READ_4(sc, (reg + SF_RMAP_INTREG_BASE));
246175526Syongari	else {
247175526Syongari		CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE);
248175526Syongari		val = CSR_READ_4(sc, SF_INDIRECTIO_DATA);
249175526Syongari	}
25049076Swpaul
251175526Syongari	return (val);
25249076Swpaul}
25349076Swpaul
254175526Syongaristatic uint8_t
255175526Syongarisf_read_eeprom(struct sf_softc *sc, int reg)
25649076Swpaul{
257175526Syongari	uint8_t		val;
25849076Swpaul
25949076Swpaul	val = (csr_read_4(sc, SF_EEADDR_BASE +
26049076Swpaul	    (reg & 0xFFFFFFFC)) >> (8 * (reg & 3))) & 0xFF;
26149076Swpaul
262175526Syongari	return (val);
26349076Swpaul}
26449076Swpaul
265102335Salfredstatic void
266175526Syongaricsr_write_4(struct sf_softc *sc, int reg, uint32_t val)
26749076Swpaul{
268175526Syongari
269175526Syongari	if (sc->sf_restype == SYS_RES_MEMORY)
270175526Syongari		CSR_WRITE_4(sc, (reg + SF_RMAP_INTREG_BASE), val);
271175526Syongari	else {
272175526Syongari		CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE);
273175526Syongari		CSR_WRITE_4(sc, SF_INDIRECTIO_DATA, val);
274175526Syongari	}
27549076Swpaul}
27649076Swpaul
27749076Swpaul/*
27849076Swpaul * Copy the address 'mac' into the perfect RX filter entry at
27949076Swpaul * offset 'idx.' The perfect filter only has 16 entries so do
28049076Swpaul * some sanity tests.
28149076Swpaul */
282102335Salfredstatic int
283175526Syongarisf_setperf(struct sf_softc *sc, int idx, uint8_t *mac)
28449076Swpaul{
28549076Swpaul
28649076Swpaul	if (idx < 0 || idx > SF_RXFILT_PERFECT_CNT)
287175526Syongari		return (EINVAL);
28849076Swpaul
28949076Swpaul	if (mac == NULL)
290175526Syongari		return (EINVAL);
29149076Swpaul
29249076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
293175526Syongari	    (idx * SF_RXFILT_PERFECT_SKIP) + 0, mac[5] | (mac[4] << 8));
29449076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
295175526Syongari	    (idx * SF_RXFILT_PERFECT_SKIP) + 4, mac[3] | (mac[2] << 8));
29649076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
297175526Syongari	    (idx * SF_RXFILT_PERFECT_SKIP) + 8, mac[1] | (mac[0] << 8));
29849076Swpaul
299175526Syongari	return (0);
30049076Swpaul}
30149076Swpaul
30249076Swpaul/*
30349076Swpaul * Set the bit in the 512-bit hash table that corresponds to the
30449076Swpaul * specified mac address 'mac.' If 'prio' is nonzero, update the
30549076Swpaul * priority hash table instead of the filter hash table.
30649076Swpaul */
307102335Salfredstatic int
308175526Syongarisf_sethash(struct sf_softc *sc, caddr_t	mac, int prio)
30949076Swpaul{
310175526Syongari	uint32_t		h;
31149076Swpaul
31249076Swpaul	if (mac == NULL)
313175526Syongari		return (EINVAL);
31449076Swpaul
315130270Snaddy	h = ether_crc32_be(mac, ETHER_ADDR_LEN) >> 23;
31649076Swpaul
31749076Swpaul	if (prio) {
31849076Swpaul		SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_PRIOOFF +
31949076Swpaul		    (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF)));
32049076Swpaul	} else {
32149076Swpaul		SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_ADDROFF +
32249076Swpaul		    (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF)));
32349076Swpaul	}
32449076Swpaul
325175526Syongari	return (0);
32649076Swpaul}
32749076Swpaul
32849076Swpaul#ifdef notdef
32949076Swpaul/*
33049076Swpaul * Set a VLAN tag in the receive filter.
33149076Swpaul */
332102335Salfredstatic int
333175526Syongarisf_setvlan(struct sf_softc *sc, int idx, uint32_t vlan)
33449076Swpaul{
335175526Syongari
33649076Swpaul	if (idx < 0 || idx >> SF_RXFILT_HASH_CNT)
337175526Syongari		return (EINVAL);
33849076Swpaul
33949076Swpaul	csr_write_4(sc, SF_RXFILT_HASH_BASE +
34049076Swpaul	    (idx * SF_RXFILT_HASH_SKIP) + SF_RXFILT_HASH_VLANOFF, vlan);
34149076Swpaul
342175526Syongari	return (0);
34349076Swpaul}
34449076Swpaul#endif
34549076Swpaul
346102335Salfredstatic int
347175526Syongarisf_miibus_readreg(device_t dev, int phy, int reg)
34850675Swpaul{
34949076Swpaul	struct sf_softc		*sc;
35049076Swpaul	int			i;
351175526Syongari	uint32_t		val = 0;
35249076Swpaul
35350675Swpaul	sc = device_get_softc(dev);
35450675Swpaul
35549076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
35650675Swpaul		val = csr_read_4(sc, SF_PHY_REG(phy, reg));
357175526Syongari		if ((val & SF_MII_DATAVALID) != 0)
35849076Swpaul			break;
35949076Swpaul	}
36049076Swpaul
36149076Swpaul	if (i == SF_TIMEOUT)
362175526Syongari		return (0);
36349076Swpaul
364175526Syongari	val &= SF_MII_DATAPORT;
365175526Syongari	if (val == 0xffff)
366175526Syongari		return (0);
36749076Swpaul
368175526Syongari	return (val);
36949076Swpaul}
37049076Swpaul
371102335Salfredstatic int
372175526Syongarisf_miibus_writereg(device_t dev, int phy, int reg, int val)
37350675Swpaul{
37449076Swpaul	struct sf_softc		*sc;
37549076Swpaul	int			i;
37649076Swpaul	int			busy;
37749076Swpaul
37850675Swpaul	sc = device_get_softc(dev);
37949076Swpaul
38050675Swpaul	csr_write_4(sc, SF_PHY_REG(phy, reg), val);
38150675Swpaul
38249076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
38350675Swpaul		busy = csr_read_4(sc, SF_PHY_REG(phy, reg));
384175526Syongari		if ((busy & SF_MII_BUSY) == 0)
38549076Swpaul			break;
38649076Swpaul	}
38749076Swpaul
388175526Syongari	return (0);
38950675Swpaul}
39050675Swpaul
391102335Salfredstatic void
392175526Syongarisf_miibus_statchg(device_t dev)
39350675Swpaul{
39450675Swpaul	struct sf_softc		*sc;
39550675Swpaul	struct mii_data		*mii;
396175526Syongari	struct ifnet		*ifp;
397175526Syongari	uint32_t		val;
39850675Swpaul
399232029Syongari	sc = device_get_softc(dev);
40050675Swpaul	mii = device_get_softc(sc->sf_miibus);
401175526Syongari	ifp = sc->sf_ifp;
402175526Syongari	if (mii == NULL || ifp == NULL ||
403232029Syongari	    (ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
404175526Syongari		return;
40550675Swpaul
406232031Syongari	sc->sf_link = 0;
407232031Syongari	if ((mii->mii_media_status & (IFM_ACTIVE | IFM_AVALID)) ==
408232031Syongari	    (IFM_ACTIVE | IFM_AVALID)) {
409232031Syongari		switch (IFM_SUBTYPE(mii->mii_media_active)) {
410232031Syongari		case IFM_10_T:
411232031Syongari		case IFM_100_TX:
412232031Syongari		case IFM_100_FX:
413175526Syongari			sc->sf_link = 1;
414232031Syongari			break;
415232031Syongari		}
416232031Syongari	}
417232031Syongari	if (sc->sf_link == 0)
418232031Syongari		return;
419175526Syongari
420175526Syongari	val = csr_read_4(sc, SF_MACCFG_1);
421175526Syongari	val &= ~SF_MACCFG1_FULLDUPLEX;
422175526Syongari	val &= ~(SF_MACCFG1_RX_FLOWENB | SF_MACCFG1_TX_FLOWENB);
423175526Syongari	if ((IFM_OPTIONS(mii->mii_media_active) & IFM_FDX) != 0) {
424175526Syongari		val |= SF_MACCFG1_FULLDUPLEX;
42554161Swpaul		csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_FDX);
426175526Syongari#ifdef notyet
427175526Syongari		/* Configure flow-control bits. */
428175526Syongari		if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) &
429175526Syongari		    IFM_ETH_RXPAUSE) != 0)
430175526Syongari			val |= SF_MACCFG1_RX_FLOWENB;
431175526Syongari		if ((IFM_OPTIONS(sc->sc_mii->mii_media_active) &
432175526Syongari		    IFM_ETH_TXPAUSE) != 0)
433175526Syongari			val |= SF_MACCFG1_TX_FLOWENB;
434175526Syongari#endif
435175526Syongari	} else
43654161Swpaul		csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_HDX);
437175526Syongari
438175526Syongari	/* Make sure to reset MAC to take changes effect. */
439175526Syongari	csr_write_4(sc, SF_MACCFG_1, val | SF_MACCFG1_SOFTRESET);
440175526Syongari	DELAY(1000);
441175526Syongari	csr_write_4(sc, SF_MACCFG_1, val);
442175526Syongari
443175526Syongari	val = csr_read_4(sc, SF_TIMER_CTL);
444175526Syongari	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX)
445175526Syongari		val |= SF_TIMER_TIMES_TEN;
446175526Syongari	else
447175526Syongari		val &= ~SF_TIMER_TIMES_TEN;
448175526Syongari	csr_write_4(sc, SF_TIMER_CTL, val);
44949076Swpaul}
45049076Swpaul
451102335Salfredstatic void
452175526Syongarisf_rxfilter(struct sf_softc *sc)
45349076Swpaul{
45449076Swpaul	struct ifnet		*ifp;
45549076Swpaul	int			i;
45649076Swpaul	struct ifmultiaddr	*ifma;
457175526Syongari	uint8_t			dummy[ETHER_ADDR_LEN] = { 0, 0, 0, 0, 0, 0 };
458175526Syongari	uint32_t		rxfilt;
45949076Swpaul
460147256Sbrooks	ifp = sc->sf_ifp;
46149076Swpaul
46249076Swpaul	/* First zot all the existing filters. */
46349076Swpaul	for (i = 1; i < SF_RXFILT_PERFECT_CNT; i++)
464175526Syongari		sf_setperf(sc, i, dummy);
465175526Syongari	for (i = SF_RXFILT_HASH_BASE; i < (SF_RXFILT_HASH_MAX + 1);
466175526Syongari	    i += sizeof(uint32_t))
46749076Swpaul		csr_write_4(sc, i, 0);
46849076Swpaul
469175526Syongari	rxfilt = csr_read_4(sc, SF_RXFILT);
470175526Syongari	rxfilt &= ~(SF_RXFILT_PROMISC | SF_RXFILT_ALLMULTI | SF_RXFILT_BROAD);
471175526Syongari	if ((ifp->if_flags & IFF_BROADCAST) != 0)
472175526Syongari		rxfilt |= SF_RXFILT_BROAD;
473175526Syongari	if ((ifp->if_flags & IFF_ALLMULTI) != 0 ||
474175526Syongari	    (ifp->if_flags & IFF_PROMISC) != 0) {
475175526Syongari		if ((ifp->if_flags & IFF_PROMISC) != 0)
476175526Syongari			rxfilt |= SF_RXFILT_PROMISC;
477175526Syongari		if ((ifp->if_flags & IFF_ALLMULTI) != 0)
478175526Syongari			rxfilt |= SF_RXFILT_ALLMULTI;
479175526Syongari		goto done;
480175526Syongari	}
481175526Syongari
48249076Swpaul	/* Now program new ones. */
483175526Syongari	i = 1;
484195049Srwatson	if_maddr_rlock(ifp);
485175526Syongari	TAILQ_FOREACH_REVERSE(ifma, &ifp->if_multiaddrs, ifmultihead,
486175526Syongari	    ifma_link) {
487175526Syongari		if (ifma->ifma_addr->sa_family != AF_LINK)
488175526Syongari			continue;
489175526Syongari		/*
490175526Syongari		 * Program the first 15 multicast groups
491175526Syongari		 * into the perfect filter. For all others,
492175526Syongari		 * use the hash table.
493175526Syongari		 */
494175526Syongari		if (i < SF_RXFILT_PERFECT_CNT) {
495175526Syongari			sf_setperf(sc, i,
496175526Syongari			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
497175526Syongari			i++;
498175526Syongari			continue;
499175526Syongari		}
50049076Swpaul
501175526Syongari		sf_sethash(sc,
502175526Syongari		    LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 0);
50349076Swpaul	}
504195049Srwatson	if_maddr_runlock(ifp);
505175526Syongari
506175526Syongaridone:
507175526Syongari	csr_write_4(sc, SF_RXFILT, rxfilt);
50849076Swpaul}
50949076Swpaul
51049076Swpaul/*
51149076Swpaul * Set media options.
51249076Swpaul */
513102335Salfredstatic int
514175526Syongarisf_ifmedia_upd(struct ifnet *ifp)
51549076Swpaul{
51649076Swpaul	struct sf_softc		*sc;
517175526Syongari	int			error;
518149240Sjhb
519149240Sjhb	sc = ifp->if_softc;
520149240Sjhb	SF_LOCK(sc);
521232025Syongari	error = sf_ifmedia_upd_locked(ifp);
522232025Syongari	SF_UNLOCK(sc);
523232025Syongari	return (error);
524232025Syongari}
525149240Sjhb
526232025Syongaristatic int
527232025Syongarisf_ifmedia_upd_locked(struct ifnet *ifp)
528232025Syongari{
529232025Syongari	struct sf_softc		*sc;
530232025Syongari	struct mii_data		*mii;
531232025Syongari	struct mii_softc        *miisc;
532232025Syongari
533232025Syongari	sc = ifp->if_softc;
53450675Swpaul	mii = device_get_softc(sc->sf_miibus);
535221407Smarius	LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
536221407Smarius		PHY_RESET(miisc);
537232025Syongari	return (mii_mediachg(mii));
53849076Swpaul}
53949076Swpaul
54049076Swpaul/*
54149076Swpaul * Report current media status.
54249076Swpaul */
543102335Salfredstatic void
544175526Syongarisf_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
54549076Swpaul{
54649076Swpaul	struct sf_softc		*sc;
54750675Swpaul	struct mii_data		*mii;
54849076Swpaul
54949076Swpaul	sc = ifp->if_softc;
550149240Sjhb	SF_LOCK(sc);
551232029Syongari	if ((ifp->if_flags & IFF_UP) == 0) {
552232029Syongari		SF_UNLOCK(sc);
553232029Syongari		return;
554232029Syongari	}
555232029Syongari
55650675Swpaul	mii = device_get_softc(sc->sf_miibus);
55750675Swpaul	mii_pollstat(mii);
55850675Swpaul	ifmr->ifm_active = mii->mii_media_active;
55950675Swpaul	ifmr->ifm_status = mii->mii_media_status;
560149240Sjhb	SF_UNLOCK(sc);
56149076Swpaul}
56249076Swpaul
563102335Salfredstatic int
564175526Syongarisf_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
56549076Swpaul{
566175526Syongari	struct sf_softc		*sc;
567175526Syongari	struct ifreq		*ifr;
56850675Swpaul	struct mii_data		*mii;
569175526Syongari	int			error, mask;
57049076Swpaul
571175526Syongari	sc = ifp->if_softc;
572175526Syongari	ifr = (struct ifreq *)data;
573175526Syongari	error = 0;
574175526Syongari
575175526Syongari	switch (command) {
57649076Swpaul	case SIOCSIFFLAGS:
577149240Sjhb		SF_LOCK(sc);
57849076Swpaul		if (ifp->if_flags & IFF_UP) {
579175526Syongari			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
580175526Syongari				if ((ifp->if_flags ^ sc->sf_if_flags) &
581175526Syongari				    (IFF_PROMISC | IFF_ALLMULTI))
582175526Syongari					sf_rxfilter(sc);
583175526Syongari			} else {
584175526Syongari				if (sc->sf_detach == 0)
585175526Syongari					sf_init_locked(sc);
586175526Syongari			}
58749076Swpaul		} else {
588175526Syongari			if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
58949076Swpaul				sf_stop(sc);
59049076Swpaul		}
59154161Swpaul		sc->sf_if_flags = ifp->if_flags;
592149240Sjhb		SF_UNLOCK(sc);
59349076Swpaul		break;
59449076Swpaul	case SIOCADDMULTI:
59549076Swpaul	case SIOCDELMULTI:
596149240Sjhb		SF_LOCK(sc);
597232027Syongari		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
598232027Syongari			sf_rxfilter(sc);
599149240Sjhb		SF_UNLOCK(sc);
60049076Swpaul		break;
60149076Swpaul	case SIOCGIFMEDIA:
60249076Swpaul	case SIOCSIFMEDIA:
60350675Swpaul		mii = device_get_softc(sc->sf_miibus);
60450675Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
60549076Swpaul		break;
606137557Sbrueffer	case SIOCSIFCAP:
607175526Syongari		mask = ifr->ifr_reqcap ^ ifp->if_capenable;
608150789Sglebius#ifdef DEVICE_POLLING
609175526Syongari		if ((mask & IFCAP_POLLING) != 0) {
610175526Syongari			if ((ifr->ifr_reqcap & IFCAP_POLLING) != 0) {
611175526Syongari				error = ether_poll_register(sf_poll, ifp);
612175526Syongari				if (error != 0)
613175526Syongari					break;
614175526Syongari				SF_LOCK(sc);
615175526Syongari				/* Disable interrupts. */
616175526Syongari				csr_write_4(sc, SF_IMR, 0);
617175526Syongari				ifp->if_capenable |= IFCAP_POLLING;
618175526Syongari				SF_UNLOCK(sc);
619175526Syongari			} else {
620175526Syongari				error = ether_poll_deregister(ifp);
621175526Syongari				/* Enable interrupts. */
622175526Syongari				SF_LOCK(sc);
623175526Syongari				csr_write_4(sc, SF_IMR, SF_INTRS);
624175526Syongari				ifp->if_capenable &= ~IFCAP_POLLING;
625175526Syongari				SF_UNLOCK(sc);
626175526Syongari			}
627150789Sglebius		}
628175526Syongari#endif /* DEVICE_POLLING */
629175526Syongari		if ((mask & IFCAP_TXCSUM) != 0) {
630175526Syongari			if ((IFCAP_TXCSUM & ifp->if_capabilities) != 0) {
631175526Syongari				SF_LOCK(sc);
632175526Syongari				ifp->if_capenable ^= IFCAP_TXCSUM;
633175526Syongari				if ((IFCAP_TXCSUM & ifp->if_capenable) != 0) {
634175526Syongari					ifp->if_hwassist |= SF_CSUM_FEATURES;
635175526Syongari					SF_SETBIT(sc, SF_GEN_ETH_CTL,
636175526Syongari					    SF_ETHCTL_TXGFP_ENB);
637175526Syongari				} else {
638175526Syongari					ifp->if_hwassist &= ~SF_CSUM_FEATURES;
639175526Syongari					SF_CLRBIT(sc, SF_GEN_ETH_CTL,
640175526Syongari					    SF_ETHCTL_TXGFP_ENB);
641175526Syongari				}
642175526Syongari				SF_UNLOCK(sc);
643175526Syongari			}
644150789Sglebius		}
645175526Syongari		if ((mask & IFCAP_RXCSUM) != 0) {
646175526Syongari			if ((IFCAP_RXCSUM & ifp->if_capabilities) != 0) {
647175526Syongari				SF_LOCK(sc);
648175526Syongari				ifp->if_capenable ^= IFCAP_RXCSUM;
649175526Syongari				if ((IFCAP_RXCSUM & ifp->if_capenable) != 0)
650175526Syongari					SF_SETBIT(sc, SF_GEN_ETH_CTL,
651175526Syongari					    SF_ETHCTL_RXGFP_ENB);
652175526Syongari				else
653175526Syongari					SF_CLRBIT(sc, SF_GEN_ETH_CTL,
654175526Syongari					    SF_ETHCTL_RXGFP_ENB);
655175526Syongari				SF_UNLOCK(sc);
656175526Syongari			}
657175526Syongari		}
658137557Sbrueffer		break;
65949076Swpaul	default:
660106936Ssam		error = ether_ioctl(ifp, command, data);
66149076Swpaul		break;
66249076Swpaul	}
66349076Swpaul
664175526Syongari	return (error);
66549076Swpaul}
66649076Swpaul
667102335Salfredstatic void
668175526Syongarisf_reset(struct sf_softc *sc)
66949076Swpaul{
670175526Syongari	int		i;
67149076Swpaul
67249076Swpaul	csr_write_4(sc, SF_GEN_ETH_CTL, 0);
67349076Swpaul	SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
67449076Swpaul	DELAY(1000);
67549076Swpaul	SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
67649076Swpaul
67749076Swpaul	SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_RESET);
67849076Swpaul
67949076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
68049076Swpaul		DELAY(10);
68149076Swpaul		if (!(csr_read_4(sc, SF_PCI_DEVCFG) & SF_PCIDEVCFG_RESET))
68249076Swpaul			break;
68349076Swpaul	}
68449076Swpaul
68549076Swpaul	if (i == SF_TIMEOUT)
686162315Sglebius		device_printf(sc->sf_dev, "reset never completed!\n");
68749076Swpaul
68849076Swpaul	/* Wait a little while for the chip to get its brains in order. */
68949076Swpaul	DELAY(1000);
69049076Swpaul}
69149076Swpaul
69249076Swpaul/*
69349076Swpaul * Probe for an Adaptec AIC-6915 chip. Check the PCI vendor and device
69449076Swpaul * IDs against our list and return a device name if we find a match.
69549076Swpaul * We also check the subsystem ID so that we can identify exactly which
69649076Swpaul * NIC has been found, if possible.
69749076Swpaul */
698102335Salfredstatic int
699175526Syongarisf_probe(device_t dev)
70049076Swpaul{
70149076Swpaul	struct sf_type		*t;
702175526Syongari	uint16_t		vid;
703175526Syongari	uint16_t		did;
704175526Syongari	uint16_t		sdid;
705175526Syongari	int			i;
70649076Swpaul
707175526Syongari	vid = pci_get_vendor(dev);
708175526Syongari	did = pci_get_device(dev);
709175526Syongari	sdid = pci_get_subdevice(dev);
710175526Syongari
71149076Swpaul	t = sf_devs;
712175526Syongari	for (i = 0; i < sizeof(sf_devs) / sizeof(sf_devs[0]); i++, t++) {
713175526Syongari		if (vid == t->sf_vid && did == t->sf_did) {
714175526Syongari			if (sdid == t->sf_sdid) {
715175526Syongari				device_set_desc(dev, t->sf_sname);
716142398Simp				return (BUS_PROBE_DEFAULT);
71749076Swpaul			}
71849076Swpaul		}
71949076Swpaul	}
72049076Swpaul
721175526Syongari	if (vid == AD_VENDORID && did == AD_DEVICEID_STARFIRE) {
722175526Syongari		/* unkown subdevice */
723175526Syongari		device_set_desc(dev, sf_devs[0].sf_name);
724175526Syongari		return (BUS_PROBE_DEFAULT);
725175526Syongari	}
726175526Syongari
727175526Syongari	return (ENXIO);
72849076Swpaul}
72949076Swpaul
73049076Swpaul/*
73149076Swpaul * Attach the interface. Allocate softc structures, do ifmedia
73249076Swpaul * setup and ethernet/BPF attach.
73349076Swpaul */
734102335Salfredstatic int
735175526Syongarisf_attach(device_t dev)
73649076Swpaul{
73767087Swpaul	int			i;
73849076Swpaul	struct sf_softc		*sc;
73949076Swpaul	struct ifnet		*ifp;
740175526Syongari	uint32_t		reg;
741148947Sjhb	int			rid, error = 0;
742175526Syongari	uint8_t			eaddr[ETHER_ADDR_LEN];
74349076Swpaul
74449076Swpaul	sc = device_get_softc(dev);
745162315Sglebius	sc->sf_dev = dev;
74649076Swpaul
74793818Sjhb	mtx_init(&sc->sf_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
748149240Sjhb	    MTX_DEF);
749175526Syongari	callout_init_mtx(&sc->sf_co, &sc->sf_mtx, 0);
750175526Syongari
75149076Swpaul	/*
75249076Swpaul	 * Map control/status registers.
75349076Swpaul	 */
75472813Swpaul	pci_enable_busmaster(dev);
75549076Swpaul
756175526Syongari	/*
757175526Syongari	 * Prefer memory space register mapping over I/O space as the
758175526Syongari	 * hardware requires lots of register access to get various
759175526Syongari	 * producer/consumer index during Tx/Rx operation. However this
760175526Syongari	 * requires large memory space(512K) to map the entire register
761175526Syongari	 * space.
762175526Syongari	 */
763175526Syongari	sc->sf_rid = PCIR_BAR(0);
764175526Syongari	sc->sf_restype = SYS_RES_MEMORY;
765175526Syongari	sc->sf_res = bus_alloc_resource_any(dev, sc->sf_restype, &sc->sf_rid,
766175526Syongari	    RF_ACTIVE);
76749076Swpaul	if (sc->sf_res == NULL) {
768175526Syongari		reg = pci_read_config(dev, PCIR_BAR(0), 4);
769175526Syongari		if ((reg & PCIM_BAR_MEM_64) == PCIM_BAR_MEM_64)
770175526Syongari			sc->sf_rid = PCIR_BAR(2);
771175526Syongari		else
772175526Syongari			sc->sf_rid = PCIR_BAR(1);
773175526Syongari		sc->sf_restype = SYS_RES_IOPORT;
774175526Syongari		sc->sf_res = bus_alloc_resource_any(dev, sc->sf_restype,
775175526Syongari		    &sc->sf_rid, RF_ACTIVE);
776175526Syongari		if (sc->sf_res == NULL) {
777175526Syongari			device_printf(dev, "couldn't allocate resources\n");
778175526Syongari			mtx_destroy(&sc->sf_mtx);
779175526Syongari			return (ENXIO);
780175526Syongari		}
78149076Swpaul	}
782175526Syongari	if (bootverbose)
783175526Syongari		device_printf(dev, "using %s space register mapping\n",
784175526Syongari		    sc->sf_restype == SYS_RES_MEMORY ? "memory" : "I/O");
78549076Swpaul
786175526Syongari	reg = pci_read_config(dev, PCIR_CACHELNSZ, 1);
787175526Syongari	if (reg == 0) {
788175526Syongari		/*
789175526Syongari		 * If cache line size is 0, MWI is not used at all, so set
790175526Syongari		 * reasonable default. AIC-6915 supports 0, 4, 8, 16, 32
791175526Syongari		 * and 64.
792175526Syongari		 */
793175526Syongari		reg = 16;
794175526Syongari		device_printf(dev, "setting PCI cache line size to %u\n", reg);
795175526Syongari		pci_write_config(dev, PCIR_CACHELNSZ, reg, 1);
796175526Syongari	} else {
797175526Syongari		if (bootverbose)
798175526Syongari			device_printf(dev, "PCI cache line size : %u\n", reg);
799175526Syongari	}
800175526Syongari	/* Enable MWI. */
801175526Syongari	reg = pci_read_config(dev, PCIR_COMMAND, 2);
802175526Syongari	reg |= PCIM_CMD_MWRICEN;
803175526Syongari	pci_write_config(dev, PCIR_COMMAND, reg, 2);
80449076Swpaul
805175526Syongari	/* Allocate interrupt. */
80649076Swpaul	rid = 0;
807127135Snjl	sc->sf_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
80849076Swpaul	    RF_SHAREABLE | RF_ACTIVE);
80949076Swpaul
81049076Swpaul	if (sc->sf_irq == NULL) {
811148947Sjhb		device_printf(dev, "couldn't map interrupt\n");
81249076Swpaul		error = ENXIO;
81349076Swpaul		goto fail;
81449076Swpaul	}
81549076Swpaul
816175526Syongari	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
817175526Syongari	    SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
818175526Syongari	    OID_AUTO, "stats", CTLTYPE_INT | CTLFLAG_RW, sc, 0,
819175526Syongari	    sf_sysctl_stats, "I", "Statistics");
820149240Sjhb
821175526Syongari	SYSCTL_ADD_PROC(device_get_sysctl_ctx(dev),
822175526Syongari		SYSCTL_CHILDREN(device_get_sysctl_tree(dev)),
823175526Syongari		OID_AUTO, "int_mod", CTLTYPE_INT | CTLFLAG_RW,
824175526Syongari		&sc->sf_int_mod, 0, sysctl_hw_sf_int_mod, "I",
825175526Syongari		"sf interrupt moderation");
826175526Syongari	/* Pull in device tunables. */
827175526Syongari	sc->sf_int_mod = SF_IM_DEFAULT;
828175526Syongari	error = resource_int_value(device_get_name(dev), device_get_unit(dev),
829175526Syongari	    "int_mod", &sc->sf_int_mod);
830175526Syongari	if (error == 0) {
831175526Syongari		if (sc->sf_int_mod < SF_IM_MIN ||
832175526Syongari		    sc->sf_int_mod > SF_IM_MAX) {
833175526Syongari			device_printf(dev, "int_mod value out of range; "
834175526Syongari			    "using default: %d\n", SF_IM_DEFAULT);
835175526Syongari			sc->sf_int_mod = SF_IM_DEFAULT;
836175526Syongari		}
837175526Syongari	}
838175526Syongari
83949076Swpaul	/* Reset the adapter. */
84049076Swpaul	sf_reset(sc);
84149076Swpaul
84249076Swpaul	/*
84349076Swpaul	 * Get station address from the EEPROM.
84449076Swpaul	 */
84549076Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
846147256Sbrooks		eaddr[i] =
84749076Swpaul		    sf_read_eeprom(sc, SF_EE_NODEADDR + ETHER_ADDR_LEN - i);
84849076Swpaul
849175526Syongari	/* Allocate DMA resources. */
850175526Syongari	if (sf_dma_alloc(sc) != 0) {
851175526Syongari		error = ENOSPC;
85249076Swpaul		goto fail;
85349076Swpaul	}
85449076Swpaul
855175526Syongari	sc->sf_txthresh = SF_MIN_TX_THRESHOLD;
85649076Swpaul
857147291Sbrooks	ifp = sc->sf_ifp = if_alloc(IFT_ETHER);
858147291Sbrooks	if (ifp == NULL) {
859175526Syongari		device_printf(dev, "can not allocate ifnet structure\n");
860147291Sbrooks		error = ENOSPC;
861147291Sbrooks		goto fail;
862147291Sbrooks	}
863147291Sbrooks
86450675Swpaul	/* Do MII setup. */
865213894Smarius	error = mii_attach(dev, &sc->sf_miibus, ifp, sf_ifmedia_upd,
866213894Smarius	    sf_ifmedia_sts, BMSR_DEFCAPMASK, MII_PHY_ANY, MII_OFFSET_ANY, 0);
867213894Smarius	if (error != 0) {
868213894Smarius		device_printf(dev, "attaching PHYs failed\n");
86949076Swpaul		goto fail;
87049076Swpaul	}
87149076Swpaul
87249076Swpaul	ifp->if_softc = sc;
873121816Sbrooks	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
874149240Sjhb	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
87549076Swpaul	ifp->if_ioctl = sf_ioctl;
87649076Swpaul	ifp->if_start = sf_start;
87749076Swpaul	ifp->if_init = sf_init;
878137620Sbrueffer	IFQ_SET_MAXLEN(&ifp->if_snd, SF_TX_DLIST_CNT - 1);
879137620Sbrueffer	ifp->if_snd.ifq_drv_maxlen = SF_TX_DLIST_CNT - 1;
880137620Sbrueffer	IFQ_SET_READY(&ifp->if_snd);
881175526Syongari	/*
882175526Syongari	 * With the help of firmware, AIC-6915 supports
883175526Syongari	 * Tx/Rx TCP/UDP checksum offload.
884175526Syongari	 */
885175526Syongari	ifp->if_hwassist = SF_CSUM_FEATURES;
886175526Syongari	ifp->if_capabilities = IFCAP_HWCSUM;
887175526Syongari
888175526Syongari	/*
889175526Syongari	 * Call MI attach routine.
890175526Syongari	 */
891175526Syongari	ether_ifattach(ifp, eaddr);
892175526Syongari
893175526Syongari	/* VLAN capability setup. */
894175526Syongari	ifp->if_capabilities |= IFCAP_VLAN_MTU;
895150789Sglebius	ifp->if_capenable = ifp->if_capabilities;
896137557Sbrueffer#ifdef DEVICE_POLLING
897137557Sbrueffer	ifp->if_capabilities |= IFCAP_POLLING;
898150789Sglebius#endif
89949076Swpaul	/*
900175526Syongari	 * Tell the upper layer(s) we support long frames.
901175526Syongari	 * Must appear after the call to ether_ifattach() because
902175526Syongari	 * ether_ifattach() sets ifi_hdrlen to the default value.
90349076Swpaul	 */
904175526Syongari	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
90549076Swpaul
906113609Snjl	/* Hook interrupt last to avoid having to lock softc */
907149240Sjhb	error = bus_setup_intr(dev, sc->sf_irq, INTR_TYPE_NET | INTR_MPSAFE,
908166901Spiso	    NULL, sf_intr, sc, &sc->sf_intrhand);
909112872Snjl
910112872Snjl	if (error) {
911148947Sjhb		device_printf(dev, "couldn't set up irq\n");
912113609Snjl		ether_ifdetach(ifp);
913112872Snjl		goto fail;
914112872Snjl	}
915112872Snjl
91649076Swpaulfail:
917112872Snjl	if (error)
918112872Snjl		sf_detach(dev);
919112872Snjl
920175526Syongari	return (error);
92149076Swpaul}
92249076Swpaul
923113609Snjl/*
924113609Snjl * Shutdown hardware and free up resources. This can be called any
925113609Snjl * time after the mutex has been initialized. It is called in both
926113609Snjl * the error case in attach and the normal detach case so it needs
927113609Snjl * to be careful about only freeing resources that have actually been
928113609Snjl * allocated.
929113609Snjl */
930102335Salfredstatic int
931175526Syongarisf_detach(device_t dev)
93249076Swpaul{
93349076Swpaul	struct sf_softc		*sc;
93449076Swpaul	struct ifnet		*ifp;
93549076Swpaul
93649076Swpaul	sc = device_get_softc(dev);
937147256Sbrooks	ifp = sc->sf_ifp;
93849076Swpaul
939150789Sglebius#ifdef DEVICE_POLLING
940175526Syongari	if (ifp != NULL && ifp->if_capenable & IFCAP_POLLING)
941150789Sglebius		ether_poll_deregister(ifp);
942150789Sglebius#endif
943175526Syongari
944113609Snjl	/* These should only be active if attach succeeded */
945113812Simp	if (device_is_attached(dev)) {
946149240Sjhb		SF_LOCK(sc);
947175526Syongari		sc->sf_detach = 1;
948113609Snjl		sf_stop(sc);
949149240Sjhb		SF_UNLOCK(sc);
950175526Syongari		callout_drain(&sc->sf_co);
951175526Syongari		if (ifp != NULL)
952175526Syongari			ether_ifdetach(ifp);
953150213Sru	}
954175526Syongari	if (sc->sf_miibus) {
955112872Snjl		device_delete_child(dev, sc->sf_miibus);
956175526Syongari		sc->sf_miibus = NULL;
957175526Syongari	}
958113609Snjl	bus_generic_detach(dev);
95949076Swpaul
960175526Syongari	if (sc->sf_intrhand != NULL)
961112872Snjl		bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
962175526Syongari	if (sc->sf_irq != NULL)
963112872Snjl		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
964175526Syongari	if (sc->sf_res != NULL)
965175526Syongari		bus_release_resource(dev, sc->sf_restype, sc->sf_rid,
966175526Syongari		    sc->sf_res);
96750675Swpaul
968175526Syongari	sf_dma_free(sc);
969175526Syongari	if (ifp != NULL)
970151297Sru		if_free(ifp);
971151297Sru
97267087Swpaul	mtx_destroy(&sc->sf_mtx);
97349076Swpaul
974175526Syongari	return (0);
97549076Swpaul}
97649076Swpaul
977175526Syongaristruct sf_dmamap_arg {
978175526Syongari	bus_addr_t		sf_busaddr;
979175526Syongari};
980175526Syongari
981175526Syongaristatic void
982175526Syongarisf_dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error)
983175526Syongari{
984175526Syongari	struct sf_dmamap_arg	*ctx;
985175526Syongari
986175526Syongari	if (error != 0)
987175526Syongari		return;
988175526Syongari	ctx = arg;
989175526Syongari	ctx->sf_busaddr = segs[0].ds_addr;
990175526Syongari}
991175526Syongari
992102335Salfredstatic int
993175526Syongarisf_dma_alloc(struct sf_softc *sc)
99449076Swpaul{
995175526Syongari	struct sf_dmamap_arg	ctx;
996175526Syongari	struct sf_txdesc	*txd;
997175526Syongari	struct sf_rxdesc	*rxd;
998175526Syongari	bus_addr_t		lowaddr;
999175526Syongari	bus_addr_t		rx_ring_end, rx_cring_end;
1000175526Syongari	bus_addr_t		tx_ring_end, tx_cring_end;
1001175526Syongari	int			error, i;
100249076Swpaul
1003175526Syongari	lowaddr = BUS_SPACE_MAXADDR;
100449076Swpaul
1005175526Syongariagain:
1006175526Syongari	/* Create parent DMA tag. */
1007175526Syongari	error = bus_dma_tag_create(
1008175526Syongari	    bus_get_dma_tag(sc->sf_dev),	/* parent */
1009175526Syongari	    1, 0,			/* alignment, boundary */
1010175526Syongari	    lowaddr,			/* lowaddr */
1011175526Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1012175526Syongari	    NULL, NULL,			/* filter, filterarg */
1013175526Syongari	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsize */
1014175526Syongari	    0,				/* nsegments */
1015175526Syongari	    BUS_SPACE_MAXSIZE_32BIT,	/* maxsegsize */
1016175526Syongari	    0,				/* flags */
1017175526Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1018175526Syongari	    &sc->sf_cdata.sf_parent_tag);
1019175526Syongari	if (error != 0) {
1020175526Syongari		device_printf(sc->sf_dev, "failed to create parent DMA tag\n");
1021175526Syongari		goto fail;
1022175526Syongari	}
1023175526Syongari	/* Create tag for Tx ring. */
1024175526Syongari	error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */
1025175526Syongari	    SF_RING_ALIGN, 0, 		/* alignment, boundary */
1026175526Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
1027175526Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1028175526Syongari	    NULL, NULL,			/* filter, filterarg */
1029175526Syongari	    SF_TX_DLIST_SIZE,		/* maxsize */
1030175526Syongari	    1,				/* nsegments */
1031175526Syongari	    SF_TX_DLIST_SIZE,		/* maxsegsize */
1032175526Syongari	    0,				/* flags */
1033175526Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1034175526Syongari	    &sc->sf_cdata.sf_tx_ring_tag);
1035175526Syongari	if (error != 0) {
1036175526Syongari		device_printf(sc->sf_dev, "failed to create Tx ring DMA tag\n");
1037175526Syongari		goto fail;
1038175526Syongari	}
103949076Swpaul
1040175526Syongari	/* Create tag for Tx completion ring. */
1041175526Syongari	error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */
1042175526Syongari	    SF_RING_ALIGN, 0, 		/* alignment, boundary */
1043175526Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
1044175526Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1045175526Syongari	    NULL, NULL,			/* filter, filterarg */
1046175526Syongari	    SF_TX_CLIST_SIZE,		/* maxsize */
1047175526Syongari	    1,				/* nsegments */
1048175526Syongari	    SF_TX_CLIST_SIZE,		/* maxsegsize */
1049175526Syongari	    0,				/* flags */
1050175526Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1051175526Syongari	    &sc->sf_cdata.sf_tx_cring_tag);
1052175526Syongari	if (error != 0) {
1053175526Syongari		device_printf(sc->sf_dev,
1054175526Syongari		    "failed to create Tx completion ring DMA tag\n");
1055175526Syongari		goto fail;
1056175526Syongari	}
1057175526Syongari
1058175526Syongari	/* Create tag for Rx ring. */
1059175526Syongari	error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */
1060175526Syongari	    SF_RING_ALIGN, 0,		/* alignment, boundary */
1061175526Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
1062175526Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1063175526Syongari	    NULL, NULL,			/* filter, filterarg */
1064175526Syongari	    SF_RX_DLIST_SIZE,		/* maxsize */
1065175526Syongari	    1,				/* nsegments */
1066175526Syongari	    SF_RX_DLIST_SIZE,		/* maxsegsize */
1067175526Syongari	    0,				/* flags */
1068175526Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1069175526Syongari	    &sc->sf_cdata.sf_rx_ring_tag);
1070175526Syongari	if (error != 0) {
1071175526Syongari		device_printf(sc->sf_dev,
1072175526Syongari		    "failed to create Rx ring DMA tag\n");
1073175526Syongari		goto fail;
1074175526Syongari	}
1075175526Syongari
1076175526Syongari	/* Create tag for Rx completion ring. */
1077175526Syongari	error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */
1078175526Syongari	    SF_RING_ALIGN, 0,		/* alignment, boundary */
1079175526Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
1080175526Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1081175526Syongari	    NULL, NULL,			/* filter, filterarg */
1082175526Syongari	    SF_RX_CLIST_SIZE,		/* maxsize */
1083175526Syongari	    1,				/* nsegments */
1084175526Syongari	    SF_RX_CLIST_SIZE,		/* maxsegsize */
1085175526Syongari	    0,				/* flags */
1086175526Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1087175526Syongari	    &sc->sf_cdata.sf_rx_cring_tag);
1088175526Syongari	if (error != 0) {
1089175526Syongari		device_printf(sc->sf_dev,
1090175526Syongari		    "failed to create Rx completion ring DMA tag\n");
1091175526Syongari		goto fail;
1092175526Syongari	}
1093175526Syongari
1094175526Syongari	/* Create tag for Tx buffers. */
1095175526Syongari	error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */
1096175526Syongari	    1, 0,			/* alignment, boundary */
1097175526Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
1098175526Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1099175526Syongari	    NULL, NULL,			/* filter, filterarg */
1100175526Syongari	    MCLBYTES * SF_MAXTXSEGS,	/* maxsize */
1101175526Syongari	    SF_MAXTXSEGS,		/* nsegments */
1102175526Syongari	    MCLBYTES,			/* maxsegsize */
1103175526Syongari	    0,				/* flags */
1104175526Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1105175526Syongari	    &sc->sf_cdata.sf_tx_tag);
1106175526Syongari	if (error != 0) {
1107175526Syongari		device_printf(sc->sf_dev, "failed to create Tx DMA tag\n");
1108175526Syongari		goto fail;
1109175526Syongari	}
1110175526Syongari
1111175526Syongari	/* Create tag for Rx buffers. */
1112175526Syongari	error = bus_dma_tag_create(sc->sf_cdata.sf_parent_tag,/* parent */
1113175526Syongari	    SF_RX_ALIGN, 0,		/* alignment, boundary */
1114175526Syongari	    BUS_SPACE_MAXADDR,		/* lowaddr */
1115175526Syongari	    BUS_SPACE_MAXADDR,		/* highaddr */
1116175526Syongari	    NULL, NULL,			/* filter, filterarg */
1117175526Syongari	    MCLBYTES,			/* maxsize */
1118175526Syongari	    1,				/* nsegments */
1119175526Syongari	    MCLBYTES,			/* maxsegsize */
1120175526Syongari	    0,				/* flags */
1121175526Syongari	    NULL, NULL,			/* lockfunc, lockarg */
1122175526Syongari	    &sc->sf_cdata.sf_rx_tag);
1123175526Syongari	if (error != 0) {
1124175526Syongari		device_printf(sc->sf_dev, "failed to create Rx DMA tag\n");
1125175526Syongari		goto fail;
1126175526Syongari	}
1127175526Syongari
1128175526Syongari	/* Allocate DMA'able memory and load the DMA map for Tx ring. */
1129175526Syongari	error = bus_dmamem_alloc(sc->sf_cdata.sf_tx_ring_tag,
1130175526Syongari	    (void **)&sc->sf_rdata.sf_tx_ring, BUS_DMA_WAITOK |
1131175526Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->sf_cdata.sf_tx_ring_map);
1132175526Syongari	if (error != 0) {
1133175526Syongari		device_printf(sc->sf_dev,
1134175526Syongari		    "failed to allocate DMA'able memory for Tx ring\n");
1135175526Syongari		goto fail;
1136175526Syongari	}
1137175526Syongari
1138175526Syongari	ctx.sf_busaddr = 0;
1139175526Syongari	error = bus_dmamap_load(sc->sf_cdata.sf_tx_ring_tag,
1140175526Syongari	    sc->sf_cdata.sf_tx_ring_map, sc->sf_rdata.sf_tx_ring,
1141175526Syongari	    SF_TX_DLIST_SIZE, sf_dmamap_cb, &ctx, 0);
1142175526Syongari	if (error != 0 || ctx.sf_busaddr == 0) {
1143175526Syongari		device_printf(sc->sf_dev,
1144175526Syongari		    "failed to load DMA'able memory for Tx ring\n");
1145175526Syongari		goto fail;
1146175526Syongari	}
1147175526Syongari	sc->sf_rdata.sf_tx_ring_paddr = ctx.sf_busaddr;
1148175526Syongari
1149175526Syongari	/*
1150175526Syongari	 * Allocate DMA'able memory and load the DMA map for Tx completion ring.
1151175526Syongari	 */
1152175526Syongari	error = bus_dmamem_alloc(sc->sf_cdata.sf_tx_cring_tag,
1153175526Syongari	    (void **)&sc->sf_rdata.sf_tx_cring, BUS_DMA_WAITOK |
1154175526Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->sf_cdata.sf_tx_cring_map);
1155175526Syongari	if (error != 0) {
1156175526Syongari		device_printf(sc->sf_dev,
1157175526Syongari		    "failed to allocate DMA'able memory for "
1158175526Syongari		    "Tx completion ring\n");
1159175526Syongari		goto fail;
1160175526Syongari	}
1161175526Syongari
1162175526Syongari	ctx.sf_busaddr = 0;
1163175526Syongari	error = bus_dmamap_load(sc->sf_cdata.sf_tx_cring_tag,
1164175526Syongari	    sc->sf_cdata.sf_tx_cring_map, sc->sf_rdata.sf_tx_cring,
1165175526Syongari	    SF_TX_CLIST_SIZE, sf_dmamap_cb, &ctx, 0);
1166175526Syongari	if (error != 0 || ctx.sf_busaddr == 0) {
1167175526Syongari		device_printf(sc->sf_dev,
1168175526Syongari		    "failed to load DMA'able memory for Tx completion ring\n");
1169175526Syongari		goto fail;
1170175526Syongari	}
1171175526Syongari	sc->sf_rdata.sf_tx_cring_paddr = ctx.sf_busaddr;
1172175526Syongari
1173175526Syongari	/* Allocate DMA'able memory and load the DMA map for Rx ring. */
1174175526Syongari	error = bus_dmamem_alloc(sc->sf_cdata.sf_rx_ring_tag,
1175175526Syongari	    (void **)&sc->sf_rdata.sf_rx_ring, BUS_DMA_WAITOK |
1176175526Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->sf_cdata.sf_rx_ring_map);
1177175526Syongari	if (error != 0) {
1178175526Syongari		device_printf(sc->sf_dev,
1179175526Syongari		    "failed to allocate DMA'able memory for Rx ring\n");
1180175526Syongari		goto fail;
1181175526Syongari	}
1182175526Syongari
1183175526Syongari	ctx.sf_busaddr = 0;
1184175526Syongari	error = bus_dmamap_load(sc->sf_cdata.sf_rx_ring_tag,
1185175526Syongari	    sc->sf_cdata.sf_rx_ring_map, sc->sf_rdata.sf_rx_ring,
1186175526Syongari	    SF_RX_DLIST_SIZE, sf_dmamap_cb, &ctx, 0);
1187175526Syongari	if (error != 0 || ctx.sf_busaddr == 0) {
1188175526Syongari		device_printf(sc->sf_dev,
1189175526Syongari		    "failed to load DMA'able memory for Rx ring\n");
1190175526Syongari		goto fail;
1191175526Syongari	}
1192175526Syongari	sc->sf_rdata.sf_rx_ring_paddr = ctx.sf_busaddr;
1193175526Syongari
1194175526Syongari	/*
1195175526Syongari	 * Allocate DMA'able memory and load the DMA map for Rx completion ring.
1196175526Syongari	 */
1197175526Syongari	error = bus_dmamem_alloc(sc->sf_cdata.sf_rx_cring_tag,
1198175526Syongari	    (void **)&sc->sf_rdata.sf_rx_cring, BUS_DMA_WAITOK |
1199175526Syongari	    BUS_DMA_COHERENT | BUS_DMA_ZERO, &sc->sf_cdata.sf_rx_cring_map);
1200175526Syongari	if (error != 0) {
1201175526Syongari		device_printf(sc->sf_dev,
1202175526Syongari		    "failed to allocate DMA'able memory for "
1203175526Syongari		    "Rx completion ring\n");
1204175526Syongari		goto fail;
1205175526Syongari	}
1206175526Syongari
1207175526Syongari	ctx.sf_busaddr = 0;
1208175526Syongari	error = bus_dmamap_load(sc->sf_cdata.sf_rx_cring_tag,
1209175526Syongari	    sc->sf_cdata.sf_rx_cring_map, sc->sf_rdata.sf_rx_cring,
1210175526Syongari	    SF_RX_CLIST_SIZE, sf_dmamap_cb, &ctx, 0);
1211175526Syongari	if (error != 0 || ctx.sf_busaddr == 0) {
1212175526Syongari		device_printf(sc->sf_dev,
1213175526Syongari		    "failed to load DMA'able memory for Rx completion ring\n");
1214175526Syongari		goto fail;
1215175526Syongari	}
1216175526Syongari	sc->sf_rdata.sf_rx_cring_paddr = ctx.sf_busaddr;
1217175526Syongari
1218175526Syongari	/*
1219175526Syongari	 * Tx desciptor ring and Tx completion ring should be addressed in
1220175526Syongari	 * the same 4GB space. The same rule applys to Rx ring and Rx
1221175526Syongari	 * completion ring. Unfortunately there is no way to specify this
1222175526Syongari	 * boundary restriction with bus_dma(9). So just try to allocate
1223175526Syongari	 * without the restriction and check the restriction was satisfied.
1224175526Syongari	 * If not, fall back to 32bit dma addressing mode which always
1225175526Syongari	 * guarantees the restriction.
1226175526Syongari	 */
1227175526Syongari	tx_ring_end = sc->sf_rdata.sf_tx_ring_paddr + SF_TX_DLIST_SIZE;
1228175526Syongari	tx_cring_end = sc->sf_rdata.sf_tx_cring_paddr + SF_TX_CLIST_SIZE;
1229175526Syongari	rx_ring_end = sc->sf_rdata.sf_rx_ring_paddr + SF_RX_DLIST_SIZE;
1230175526Syongari	rx_cring_end = sc->sf_rdata.sf_rx_cring_paddr + SF_RX_CLIST_SIZE;
1231175526Syongari	if ((SF_ADDR_HI(sc->sf_rdata.sf_tx_ring_paddr) !=
1232175526Syongari	    SF_ADDR_HI(tx_cring_end)) ||
1233175526Syongari	    (SF_ADDR_HI(sc->sf_rdata.sf_tx_cring_paddr) !=
1234175526Syongari	    SF_ADDR_HI(tx_ring_end)) ||
1235175526Syongari	    (SF_ADDR_HI(sc->sf_rdata.sf_rx_ring_paddr) !=
1236175526Syongari	    SF_ADDR_HI(rx_cring_end)) ||
1237175526Syongari	    (SF_ADDR_HI(sc->sf_rdata.sf_rx_cring_paddr) !=
1238175526Syongari	    SF_ADDR_HI(rx_ring_end))) {
1239175526Syongari		device_printf(sc->sf_dev,
1240175526Syongari		    "switching to 32bit DMA mode\n");
1241175526Syongari		sf_dma_free(sc);
1242175526Syongari		/* Limit DMA address space to 32bit and try again. */
1243175526Syongari		lowaddr = BUS_SPACE_MAXADDR_32BIT;
1244175526Syongari		goto again;
1245175526Syongari	}
1246175526Syongari
1247175526Syongari	/* Create DMA maps for Tx buffers. */
1248175526Syongari	for (i = 0; i < SF_TX_DLIST_CNT; i++) {
1249175526Syongari		txd = &sc->sf_cdata.sf_txdesc[i];
1250175526Syongari		txd->tx_m = NULL;
1251175526Syongari		txd->ndesc = 0;
1252175526Syongari		txd->tx_dmamap = NULL;
1253175526Syongari		error = bus_dmamap_create(sc->sf_cdata.sf_tx_tag, 0,
1254175526Syongari		    &txd->tx_dmamap);
1255175526Syongari		if (error != 0) {
1256175526Syongari			device_printf(sc->sf_dev,
1257175526Syongari			    "failed to create Tx dmamap\n");
1258175526Syongari			goto fail;
1259175526Syongari		}
1260175526Syongari	}
1261175526Syongari	/* Create DMA maps for Rx buffers. */
1262175526Syongari	if ((error = bus_dmamap_create(sc->sf_cdata.sf_rx_tag, 0,
1263175526Syongari	    &sc->sf_cdata.sf_rx_sparemap)) != 0) {
1264175526Syongari		device_printf(sc->sf_dev,
1265175526Syongari		    "failed to create spare Rx dmamap\n");
1266175526Syongari		goto fail;
1267175526Syongari	}
126849076Swpaul	for (i = 0; i < SF_RX_DLIST_CNT; i++) {
1269175526Syongari		rxd = &sc->sf_cdata.sf_rxdesc[i];
1270175526Syongari		rxd->rx_m = NULL;
1271175526Syongari		rxd->rx_dmamap = NULL;
1272175526Syongari		error = bus_dmamap_create(sc->sf_cdata.sf_rx_tag, 0,
1273175526Syongari		    &rxd->rx_dmamap);
1274175526Syongari		if (error != 0) {
1275175526Syongari			device_printf(sc->sf_dev,
1276175526Syongari			    "failed to create Rx dmamap\n");
1277175526Syongari			goto fail;
1278175526Syongari		}
127949076Swpaul	}
128049076Swpaul
1281175526Syongarifail:
1282175526Syongari	return (error);
128349076Swpaul}
128449076Swpaul
1285102335Salfredstatic void
1286175526Syongarisf_dma_free(struct sf_softc *sc)
128749076Swpaul{
1288175526Syongari	struct sf_txdesc	*txd;
1289175526Syongari	struct sf_rxdesc	*rxd;
129049076Swpaul	int			i;
129149076Swpaul
1292175526Syongari	/* Tx ring. */
1293175526Syongari	if (sc->sf_cdata.sf_tx_ring_tag) {
1294175526Syongari		if (sc->sf_cdata.sf_tx_ring_map)
1295175526Syongari			bus_dmamap_unload(sc->sf_cdata.sf_tx_ring_tag,
1296175526Syongari			    sc->sf_cdata.sf_tx_ring_map);
1297175526Syongari		if (sc->sf_cdata.sf_tx_ring_map &&
1298175526Syongari		    sc->sf_rdata.sf_tx_ring)
1299175526Syongari			bus_dmamem_free(sc->sf_cdata.sf_tx_ring_tag,
1300175526Syongari			    sc->sf_rdata.sf_tx_ring,
1301175526Syongari			    sc->sf_cdata.sf_tx_ring_map);
1302175526Syongari		sc->sf_rdata.sf_tx_ring = NULL;
1303175526Syongari		sc->sf_cdata.sf_tx_ring_map = NULL;
1304175526Syongari		bus_dma_tag_destroy(sc->sf_cdata.sf_tx_ring_tag);
1305175526Syongari		sc->sf_cdata.sf_tx_ring_tag = NULL;
1306175526Syongari	}
1307175526Syongari	/* Tx completion ring. */
1308175526Syongari	if (sc->sf_cdata.sf_tx_cring_tag) {
1309175526Syongari		if (sc->sf_cdata.sf_tx_cring_map)
1310175526Syongari			bus_dmamap_unload(sc->sf_cdata.sf_tx_cring_tag,
1311175526Syongari			    sc->sf_cdata.sf_tx_cring_map);
1312175526Syongari		if (sc->sf_cdata.sf_tx_cring_map &&
1313175526Syongari		    sc->sf_rdata.sf_tx_cring)
1314175526Syongari			bus_dmamem_free(sc->sf_cdata.sf_tx_cring_tag,
1315175526Syongari			    sc->sf_rdata.sf_tx_cring,
1316175526Syongari			    sc->sf_cdata.sf_tx_cring_map);
1317175526Syongari		sc->sf_rdata.sf_tx_cring = NULL;
1318175526Syongari		sc->sf_cdata.sf_tx_cring_map = NULL;
1319175526Syongari		bus_dma_tag_destroy(sc->sf_cdata.sf_tx_cring_tag);
1320175526Syongari		sc->sf_cdata.sf_tx_cring_tag = NULL;
1321175526Syongari	}
1322175526Syongari	/* Rx ring. */
1323175526Syongari	if (sc->sf_cdata.sf_rx_ring_tag) {
1324175526Syongari		if (sc->sf_cdata.sf_rx_ring_map)
1325175526Syongari			bus_dmamap_unload(sc->sf_cdata.sf_rx_ring_tag,
1326175526Syongari			    sc->sf_cdata.sf_rx_ring_map);
1327175526Syongari		if (sc->sf_cdata.sf_rx_ring_map &&
1328175526Syongari		    sc->sf_rdata.sf_rx_ring)
1329175526Syongari			bus_dmamem_free(sc->sf_cdata.sf_rx_ring_tag,
1330175526Syongari			    sc->sf_rdata.sf_rx_ring,
1331175526Syongari			    sc->sf_cdata.sf_rx_ring_map);
1332175526Syongari		sc->sf_rdata.sf_rx_ring = NULL;
1333175526Syongari		sc->sf_cdata.sf_rx_ring_map = NULL;
1334175526Syongari		bus_dma_tag_destroy(sc->sf_cdata.sf_rx_ring_tag);
1335175526Syongari		sc->sf_cdata.sf_rx_ring_tag = NULL;
1336175526Syongari	}
1337175526Syongari	/* Rx completion ring. */
1338175526Syongari	if (sc->sf_cdata.sf_rx_cring_tag) {
1339175526Syongari		if (sc->sf_cdata.sf_rx_cring_map)
1340175526Syongari			bus_dmamap_unload(sc->sf_cdata.sf_rx_cring_tag,
1341175526Syongari			    sc->sf_cdata.sf_rx_cring_map);
1342175526Syongari		if (sc->sf_cdata.sf_rx_cring_map &&
1343175526Syongari		    sc->sf_rdata.sf_rx_cring)
1344175526Syongari			bus_dmamem_free(sc->sf_cdata.sf_rx_cring_tag,
1345175526Syongari			    sc->sf_rdata.sf_rx_cring,
1346175526Syongari			    sc->sf_cdata.sf_rx_cring_map);
1347175526Syongari		sc->sf_rdata.sf_rx_cring = NULL;
1348175526Syongari		sc->sf_cdata.sf_rx_cring_map = NULL;
1349175526Syongari		bus_dma_tag_destroy(sc->sf_cdata.sf_rx_cring_tag);
1350175526Syongari		sc->sf_cdata.sf_rx_cring_tag = NULL;
1351175526Syongari	}
1352175526Syongari	/* Tx buffers. */
1353175526Syongari	if (sc->sf_cdata.sf_tx_tag) {
1354175526Syongari		for (i = 0; i < SF_TX_DLIST_CNT; i++) {
1355175526Syongari			txd = &sc->sf_cdata.sf_txdesc[i];
1356175526Syongari			if (txd->tx_dmamap) {
1357175526Syongari				bus_dmamap_destroy(sc->sf_cdata.sf_tx_tag,
1358175526Syongari				    txd->tx_dmamap);
1359175526Syongari				txd->tx_dmamap = NULL;
1360175526Syongari			}
1361175526Syongari		}
1362175526Syongari		bus_dma_tag_destroy(sc->sf_cdata.sf_tx_tag);
1363175526Syongari		sc->sf_cdata.sf_tx_tag = NULL;
1364175526Syongari	}
1365175526Syongari	/* Rx buffers. */
1366175526Syongari	if (sc->sf_cdata.sf_rx_tag) {
1367175526Syongari		for (i = 0; i < SF_RX_DLIST_CNT; i++) {
1368175526Syongari			rxd = &sc->sf_cdata.sf_rxdesc[i];
1369175526Syongari			if (rxd->rx_dmamap) {
1370175526Syongari				bus_dmamap_destroy(sc->sf_cdata.sf_rx_tag,
1371175526Syongari				    rxd->rx_dmamap);
1372175526Syongari				rxd->rx_dmamap = NULL;
1373175526Syongari			}
1374175526Syongari		}
1375175526Syongari		if (sc->sf_cdata.sf_rx_sparemap) {
1376175526Syongari			bus_dmamap_destroy(sc->sf_cdata.sf_rx_tag,
1377175526Syongari			    sc->sf_cdata.sf_rx_sparemap);
1378175526Syongari			sc->sf_cdata.sf_rx_sparemap = 0;
1379175526Syongari		}
1380175526Syongari		bus_dma_tag_destroy(sc->sf_cdata.sf_rx_tag);
1381175526Syongari		sc->sf_cdata.sf_rx_tag = NULL;
1382175526Syongari	}
138349076Swpaul
1384175526Syongari	if (sc->sf_cdata.sf_parent_tag) {
1385175526Syongari		bus_dma_tag_destroy(sc->sf_cdata.sf_parent_tag);
1386175526Syongari		sc->sf_cdata.sf_parent_tag = NULL;
1387175526Syongari	}
1388175526Syongari}
138949076Swpaul
1390175526Syongaristatic int
1391175526Syongarisf_init_rx_ring(struct sf_softc *sc)
1392175526Syongari{
1393175526Syongari	struct sf_ring_data	*rd;
1394175526Syongari	int			i;
139549076Swpaul
1396175526Syongari	sc->sf_cdata.sf_rxc_cons = 0;
1397175526Syongari
1398175526Syongari	rd = &sc->sf_rdata;
1399175526Syongari	bzero(rd->sf_rx_ring, SF_RX_DLIST_SIZE);
1400175526Syongari	bzero(rd->sf_rx_cring, SF_RX_CLIST_SIZE);
1401175526Syongari
1402175526Syongari	for (i = 0; i < SF_RX_DLIST_CNT; i++) {
1403175526Syongari		if (sf_newbuf(sc, i) != 0)
1404175526Syongari			return (ENOBUFS);
1405175526Syongari	}
1406175526Syongari
1407175526Syongari	bus_dmamap_sync(sc->sf_cdata.sf_rx_cring_tag,
1408175526Syongari	    sc->sf_cdata.sf_rx_cring_map,
1409175526Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1410175526Syongari	bus_dmamap_sync(sc->sf_cdata.sf_rx_ring_tag,
1411175526Syongari	    sc->sf_cdata.sf_rx_ring_map,
1412175526Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1413175526Syongari
1414175526Syongari	return (0);
141549076Swpaul}
141649076Swpaul
1417175526Syongaristatic void
1418175526Syongarisf_init_tx_ring(struct sf_softc *sc)
1419175526Syongari{
1420175526Syongari	struct sf_ring_data	*rd;
1421175526Syongari	int			i;
1422175526Syongari
1423175526Syongari	sc->sf_cdata.sf_tx_prod = 0;
1424175526Syongari	sc->sf_cdata.sf_tx_cnt = 0;
1425175526Syongari	sc->sf_cdata.sf_txc_cons = 0;
1426175526Syongari
1427175526Syongari	rd = &sc->sf_rdata;
1428175526Syongari	bzero(rd->sf_tx_ring, SF_TX_DLIST_SIZE);
1429175526Syongari	bzero(rd->sf_tx_cring, SF_TX_CLIST_SIZE);
1430175526Syongari	for (i = 0; i < SF_TX_DLIST_CNT; i++) {
1431175526Syongari		rd->sf_tx_ring[i].sf_tx_ctrl = htole32(SF_TX_DESC_ID);
1432175526Syongari		sc->sf_cdata.sf_txdesc[i].tx_m = NULL;
1433175526Syongari		sc->sf_cdata.sf_txdesc[i].ndesc = 0;
1434175526Syongari	}
1435175526Syongari	rd->sf_tx_ring[i].sf_tx_ctrl |= htole32(SF_TX_DESC_END);
1436175526Syongari
1437175526Syongari	bus_dmamap_sync(sc->sf_cdata.sf_tx_ring_tag,
1438175526Syongari	    sc->sf_cdata.sf_tx_ring_map,
1439175526Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1440175526Syongari	bus_dmamap_sync(sc->sf_cdata.sf_tx_cring_tag,
1441175526Syongari	    sc->sf_cdata.sf_tx_cring_map,
1442175526Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1443175526Syongari}
1444175526Syongari
1445175526Syongari/*
1446175526Syongari * Initialize an RX descriptor and attach an MBUF cluster.
1447175526Syongari */
1448102335Salfredstatic int
1449175526Syongarisf_newbuf(struct sf_softc *sc, int idx)
1450175526Syongari{
1451175526Syongari	struct sf_rx_rdesc	*desc;
1452175526Syongari	struct sf_rxdesc	*rxd;
145349076Swpaul	struct mbuf		*m;
1454175526Syongari	bus_dma_segment_t	segs[1];
1455175526Syongari	bus_dmamap_t		map;
1456175526Syongari	int			nsegs;
145749076Swpaul
1458243857Sglebius	m = m_getcl(M_NOWAIT, MT_DATA, M_PKTHDR);
1459175526Syongari	if (m == NULL)
1460175526Syongari		return (ENOBUFS);
1461175526Syongari	m->m_len = m->m_pkthdr.len = MCLBYTES;
1462175526Syongari	m_adj(m, sizeof(uint32_t));
146349076Swpaul
1464175526Syongari	if (bus_dmamap_load_mbuf_sg(sc->sf_cdata.sf_rx_tag,
1465175526Syongari	    sc->sf_cdata.sf_rx_sparemap, m, segs, &nsegs, 0) != 0) {
1466175526Syongari		m_freem(m);
1467175526Syongari		return (ENOBUFS);
146849076Swpaul	}
1469175526Syongari	KASSERT(nsegs == 1, ("%s: %d segments returned!", __func__, nsegs));
147049076Swpaul
1471175526Syongari	rxd = &sc->sf_cdata.sf_rxdesc[idx];
1472175526Syongari	if (rxd->rx_m != NULL) {
1473175526Syongari		bus_dmamap_sync(sc->sf_cdata.sf_rx_tag, rxd->rx_dmamap,
1474175526Syongari		    BUS_DMASYNC_POSTREAD);
1475175526Syongari		bus_dmamap_unload(sc->sf_cdata.sf_rx_tag, rxd->rx_dmamap);
1476175526Syongari	}
1477175526Syongari	map = rxd->rx_dmamap;
1478175526Syongari	rxd->rx_dmamap = sc->sf_cdata.sf_rx_sparemap;
1479175526Syongari	sc->sf_cdata.sf_rx_sparemap = map;
1480175526Syongari	bus_dmamap_sync(sc->sf_cdata.sf_rx_tag, rxd->rx_dmamap,
1481175526Syongari	    BUS_DMASYNC_PREREAD);
1482175526Syongari	rxd->rx_m = m;
1483175526Syongari	desc = &sc->sf_rdata.sf_rx_ring[idx];
1484175526Syongari	desc->sf_addr = htole64(segs[0].ds_addr);
148549076Swpaul
1486175526Syongari	return (0);
1487175526Syongari}
148849076Swpaul
1489175526Syongari#ifndef __NO_STRICT_ALIGNMENT
1490175526Syongaristatic __inline void
1491175526Syongarisf_fixup_rx(struct mbuf *m)
1492175526Syongari{
1493175526Syongari        int			i;
1494175526Syongari        uint16_t		*src, *dst;
1495175526Syongari
1496175526Syongari	src = mtod(m, uint16_t *);
1497175526Syongari	dst = src - 1;
1498175526Syongari
1499175526Syongari	for (i = 0; i < (m->m_len / sizeof(uint16_t) + 1); i++)
1500175526Syongari		*dst++ = *src++;
1501175526Syongari
1502175526Syongari	m->m_data -= ETHER_ALIGN;
150349076Swpaul}
1504175526Syongari#endif
150549076Swpaul
150649076Swpaul/*
150749076Swpaul * The starfire is programmed to use 'normal' mode for packet reception,
150849076Swpaul * which means we use the consumer/producer model for both the buffer
150949076Swpaul * descriptor queue and the completion descriptor queue. The only problem
151049076Swpaul * with this is that it involves a lot of register accesses: we have to
151149076Swpaul * read the RX completion consumer and producer indexes and the RX buffer
151249076Swpaul * producer index, plus the RX completion consumer and RX buffer producer
151349076Swpaul * indexes have to be updated. It would have been easier if Adaptec had
151449076Swpaul * put each index in a separate register, especially given that the damn
151549076Swpaul * NIC has a 512K register space.
151649076Swpaul *
151749076Swpaul * In spite of all the lovely features that Adaptec crammed into the 6915,
151849076Swpaul * it is marred by one truly stupid design flaw, which is that receive
151949076Swpaul * buffer addresses must be aligned on a longword boundary. This forces
152049076Swpaul * the packet payload to be unaligned, which is suboptimal on the x86 and
152149076Swpaul * completely unuseable on the Alpha. Our only recourse is to copy received
152249076Swpaul * packets into properly aligned buffers before handing them off.
152349076Swpaul */
1524193096Sattiliostatic int
1525175526Syongarisf_rxeof(struct sf_softc *sc)
152649076Swpaul{
152749076Swpaul	struct mbuf		*m;
152849076Swpaul	struct ifnet		*ifp;
1529175526Syongari	struct sf_rxdesc	*rxd;
1530175526Syongari	struct sf_rx_rcdesc	*cur_cmp;
1531193096Sattilio	int			cons, eidx, prog, rx_npkts;
1532175526Syongari	uint32_t		status, status2;
153349076Swpaul
1534122689Ssam	SF_LOCK_ASSERT(sc);
1535122689Ssam
1536147256Sbrooks	ifp = sc->sf_ifp;
1537193096Sattilio	rx_npkts = 0;
153849076Swpaul
1539175526Syongari	bus_dmamap_sync(sc->sf_cdata.sf_rx_ring_tag,
1540175526Syongari	    sc->sf_cdata.sf_rx_ring_map,
1541175526Syongari	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
1542175526Syongari	bus_dmamap_sync(sc->sf_cdata.sf_rx_cring_tag,
1543175526Syongari	    sc->sf_cdata.sf_rx_cring_map,
1544175526Syongari	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
154549076Swpaul
1546175526Syongari	/*
1547175526Syongari	 * To reduce register access, directly read Receive completion
1548175526Syongari	 * queue entry.
1549175526Syongari	 */
1550175526Syongari	eidx = 0;
1551175526Syongari	prog = 0;
1552232040Syongari	for (cons = sc->sf_cdata.sf_rxc_cons;
1553232040Syongari	    (ifp->if_drv_flags & IFF_DRV_RUNNING) != 0;
1554232040Syongari	    SF_INC(cons, SF_RX_CLIST_CNT)) {
1555175526Syongari		cur_cmp = &sc->sf_rdata.sf_rx_cring[cons];
1556175526Syongari		status = le32toh(cur_cmp->sf_rx_status1);
1557175526Syongari		if (status == 0)
1558175526Syongari			break;
1559137557Sbrueffer#ifdef DEVICE_POLLING
1560175526Syongari		if ((ifp->if_capenable & IFCAP_POLLING) != 0) {
1561137557Sbrueffer			if (sc->rxcycles <= 0)
1562137557Sbrueffer				break;
1563137557Sbrueffer			sc->rxcycles--;
1564137557Sbrueffer		}
1565150789Sglebius#endif
1566175526Syongari		prog++;
1567175526Syongari		eidx = (status & SF_RX_CMPDESC_EIDX) >> 16;
1568175526Syongari		rxd = &sc->sf_cdata.sf_rxdesc[eidx];
1569175526Syongari		m = rxd->rx_m;
1570137557Sbrueffer
1571175526Syongari		/*
1572175526Syongari		 * Note, if_ipackets and if_ierrors counters
1573175526Syongari		 * are handled in sf_stats_update().
1574175526Syongari		 */
1575175526Syongari		if ((status & SF_RXSTAT1_OK) == 0) {
1576175526Syongari			cur_cmp->sf_rx_status1 = 0;
157749076Swpaul			continue;
157849076Swpaul		}
157949076Swpaul
1580175526Syongari		if (sf_newbuf(sc, eidx) != 0) {
1581175526Syongari			ifp->if_iqdrops++;
1582175526Syongari			cur_cmp->sf_rx_status1 = 0;
158349076Swpaul			continue;
158449076Swpaul		}
158549076Swpaul
1586175526Syongari		/* AIC-6915 supports TCP/UDP checksum offload. */
1587175526Syongari		if ((ifp->if_capenable & IFCAP_RXCSUM) != 0) {
1588175526Syongari			status2 = le32toh(cur_cmp->sf_rx_status2);
1589175526Syongari			/*
1590175526Syongari			 * Sometimes AIC-6915 generates an interrupt to
1591175526Syongari			 * warn RxGFP stall with bad checksum bit set
1592175526Syongari			 * in status word. I'm not sure what conditioan
1593175526Syongari			 * triggers it but recevied packet's checksum
1594175526Syongari			 * was correct even though AIC-6915 does not
1595175526Syongari			 * agree on this. This may be an indication of
1596175526Syongari			 * firmware bug. To fix the issue, do not rely
1597175526Syongari			 * on bad checksum bit in status word and let
1598175526Syongari			 * upper layer verify integrity of received
1599175526Syongari			 * frame.
1600175526Syongari			 * Another nice feature of AIC-6915 is hardware
1601175526Syongari			 * assistance of checksum calculation by
1602175526Syongari			 * providing partial checksum value for received
1603175526Syongari			 * frame. The partial checksum value can be used
1604175526Syongari			 * to accelerate checksum computation for
1605175526Syongari			 * fragmented TCP/UDP packets. Upper network
1606175526Syongari			 * stack already takes advantage of the partial
1607175526Syongari			 * checksum value in IP reassembly stage. But
1608175526Syongari			 * I'm not sure the correctness of the partial
1609175526Syongari			 * hardware checksum assistance as frequent
1610175526Syongari			 * RxGFP stalls are seen on non-fragmented
1611175526Syongari			 * frames. Due to the nature of the complexity
1612175526Syongari			 * of checksum computation code in firmware it's
1613175526Syongari			 * possible to see another bug in RxGFP so
1614175526Syongari			 * ignore checksum assistance for fragmented
1615175526Syongari			 * frames. This can be changed in future.
1616175526Syongari			 */
1617175526Syongari			if ((status2 & SF_RXSTAT2_FRAG) == 0) {
1618175526Syongari				if ((status2 & (SF_RXSTAT2_TCP |
1619175526Syongari				    SF_RXSTAT2_UDP)) != 0) {
1620175526Syongari					if ((status2 & SF_RXSTAT2_CSUM_OK)) {
1621175526Syongari						m->m_pkthdr.csum_flags =
1622175526Syongari						    CSUM_DATA_VALID |
1623175526Syongari						    CSUM_PSEUDO_HDR;
1624175526Syongari						m->m_pkthdr.csum_data = 0xffff;
1625175526Syongari					}
1626175526Syongari				}
1627175526Syongari			}
1628175526Syongari#ifdef SF_PARTIAL_CSUM_SUPPORT
1629175526Syongari			else if ((status2 & SF_RXSTAT2_FRAG) != 0) {
1630175526Syongari				if ((status2 & (SF_RXSTAT2_TCP |
1631175526Syongari				    SF_RXSTAT2_UDP)) != 0) {
1632175526Syongari					if ((status2 & SF_RXSTAT2_PCSUM_OK)) {
1633175526Syongari						m->m_pkthdr.csum_flags =
1634175526Syongari						    CSUM_DATA_VALID;
1635175526Syongari						m->m_pkthdr.csum_data =
1636175526Syongari						    (status &
1637175526Syongari						    SF_RX_CMPDESC_CSUM2);
1638175526Syongari					}
1639175526Syongari				}
1640175526Syongari			}
1641175526Syongari#endif
1642175526Syongari		}
1643175526Syongari
1644175526Syongari		m->m_pkthdr.len = m->m_len = status & SF_RX_CMPDESC_LEN;
1645175526Syongari#ifndef	__NO_STRICT_ALIGNMENT
1646175526Syongari		sf_fixup_rx(m);
1647175526Syongari#endif
1648175526Syongari		m->m_pkthdr.rcvif = ifp;
1649175526Syongari
1650122689Ssam		SF_UNLOCK(sc);
1651106936Ssam		(*ifp->if_input)(ifp, m);
1652122689Ssam		SF_LOCK(sc);
1653193096Sattilio		rx_npkts++;
1654175526Syongari
1655175526Syongari		/* Clear completion status. */
1656175526Syongari		cur_cmp->sf_rx_status1 = 0;
165749076Swpaul	}
165849076Swpaul
1659175526Syongari	if (prog > 0) {
1660175526Syongari		sc->sf_cdata.sf_rxc_cons = cons;
1661175526Syongari		bus_dmamap_sync(sc->sf_cdata.sf_rx_ring_tag,
1662175526Syongari		    sc->sf_cdata.sf_rx_ring_map,
1663175526Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1664175526Syongari		bus_dmamap_sync(sc->sf_cdata.sf_rx_cring_tag,
1665175526Syongari		    sc->sf_cdata.sf_rx_cring_map,
1666175526Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
1667175526Syongari
1668175526Syongari		/* Update Rx completion Q1 consumer index. */
1669175526Syongari		csr_write_4(sc, SF_CQ_CONSIDX,
1670175526Syongari		    (csr_read_4(sc, SF_CQ_CONSIDX) & ~SF_CQ_CONSIDX_RXQ1) |
1671175526Syongari		    (cons & SF_CQ_CONSIDX_RXQ1));
1672175526Syongari		/* Update Rx descriptor Q1 ptr. */
1673175526Syongari		csr_write_4(sc, SF_RXDQ_PTR_Q1,
1674175526Syongari		    (csr_read_4(sc, SF_RXDQ_PTR_Q1) & ~SF_RXDQ_PRODIDX) |
1675175526Syongari		    (eidx & SF_RXDQ_PRODIDX));
1676175526Syongari	}
1677193096Sattilio	return (rx_npkts);
167849076Swpaul}
167949076Swpaul
168049076Swpaul/*
168149076Swpaul * Read the transmit status from the completion queue and release
168249076Swpaul * mbufs. Note that the buffer descriptor index in the completion
168349076Swpaul * descriptor is an offset from the start of the transmit buffer
168449076Swpaul * descriptor list in bytes. This is important because the manual
168549076Swpaul * gives the impression that it should match the producer/consumer
168649076Swpaul * index, which is the offset in 8 byte blocks.
168749076Swpaul */
1688102335Salfredstatic void
1689175526Syongarisf_txeof(struct sf_softc *sc)
169049076Swpaul{
1691175526Syongari	struct sf_txdesc	*txd;
1692175526Syongari	struct sf_tx_rcdesc	*cur_cmp;
169349076Swpaul	struct ifnet		*ifp;
1694175526Syongari	uint32_t		status;
1695175526Syongari	int			cons, idx, prod;
169649076Swpaul
1697175526Syongari	SF_LOCK_ASSERT(sc);
1698175526Syongari
1699147256Sbrooks	ifp = sc->sf_ifp;
170049076Swpaul
1701175526Syongari	bus_dmamap_sync(sc->sf_cdata.sf_tx_cring_tag,
1702175526Syongari	    sc->sf_cdata.sf_tx_cring_map,
1703175526Syongari	    BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE);
170449076Swpaul
1705175526Syongari	cons = sc->sf_cdata.sf_txc_cons;
1706175526Syongari	prod = (csr_read_4(sc, SF_CQ_PRODIDX) & SF_TXDQ_PRODIDX_HIPRIO) >> 16;
1707175526Syongari	if (prod == cons)
1708175526Syongari		return;
170949076Swpaul
1710175526Syongari	for (; cons != prod; SF_INC(cons, SF_TX_CLIST_CNT)) {
1711175526Syongari		cur_cmp = &sc->sf_rdata.sf_tx_cring[cons];
1712175526Syongari		status = le32toh(cur_cmp->sf_tx_status1);
1713175526Syongari		if (status == 0)
1714175526Syongari			break;
1715175526Syongari		switch (status & SF_TX_CMPDESC_TYPE) {
1716175526Syongari		case SF_TXCMPTYPE_TX:
1717175526Syongari			/* Tx complete entry. */
1718175526Syongari			break;
1719175526Syongari		case SF_TXCMPTYPE_DMA:
1720175526Syongari			/* DMA complete entry. */
1721175526Syongari			idx = status & SF_TX_CMPDESC_IDX;
1722175526Syongari			idx = idx / sizeof(struct sf_tx_rdesc);
1723175526Syongari			/*
1724175526Syongari			 * We don't need to check Tx status here.
1725175526Syongari			 * SF_ISR_TX_LOFIFO intr would handle this.
1726175526Syongari			 * Note, if_opackets, if_collisions and if_oerrors
1727175526Syongari			 * counters are handled in sf_stats_update().
1728175526Syongari			 */
1729175526Syongari			txd = &sc->sf_cdata.sf_txdesc[idx];
1730175526Syongari			if (txd->tx_m != NULL) {
1731175526Syongari				bus_dmamap_sync(sc->sf_cdata.sf_tx_tag,
1732175526Syongari				    txd->tx_dmamap,
1733175526Syongari				    BUS_DMASYNC_POSTWRITE);
1734175526Syongari				bus_dmamap_unload(sc->sf_cdata.sf_tx_tag,
1735175526Syongari				    txd->tx_dmamap);
1736175526Syongari				m_freem(txd->tx_m);
1737175526Syongari				txd->tx_m = NULL;
1738175526Syongari			}
1739175526Syongari			sc->sf_cdata.sf_tx_cnt -= txd->ndesc;
1740175526Syongari			KASSERT(sc->sf_cdata.sf_tx_cnt >= 0,
1741175526Syongari			    ("%s: Active Tx desc counter was garbled\n",
1742175526Syongari			    __func__));
1743175526Syongari			txd->ndesc = 0;
1744175526Syongari			ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
1745175526Syongari			break;
1746175526Syongari		default:
1747175526Syongari			/* It should not happen. */
1748175526Syongari			device_printf(sc->sf_dev,
1749175526Syongari			    "unknown Tx completion type : 0x%08x : %d : %d\n",
1750175526Syongari			    status, cons, prod);
1751175526Syongari			break;
175281737Swpaul		}
1753175526Syongari		cur_cmp->sf_tx_status1 = 0;
175449076Swpaul	}
175549076Swpaul
1756175526Syongari	sc->sf_cdata.sf_txc_cons = cons;
1757175526Syongari	bus_dmamap_sync(sc->sf_cdata.sf_tx_cring_tag,
1758175526Syongari	    sc->sf_cdata.sf_tx_cring_map,
1759175526Syongari	    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
176049076Swpaul
1761175526Syongari	if (sc->sf_cdata.sf_tx_cnt == 0)
1762175526Syongari		sc->sf_watchdog_timer = 0;
1763175526Syongari
1764175526Syongari	/* Update Tx completion consumer index. */
176549076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX,
1766175526Syongari	    (csr_read_4(sc, SF_CQ_CONSIDX) & 0xffff) |
1767175526Syongari	    ((cons << 16) & 0xffff0000));
176849076Swpaul}
176949076Swpaul
1770102335Salfredstatic void
1771175526Syongarisf_txthresh_adjust(struct sf_softc *sc)
177281737Swpaul{
1773175526Syongari	uint32_t		txfctl;
177481737Swpaul
1775175526Syongari	device_printf(sc->sf_dev, "Tx underrun -- ");
1776175526Syongari	if (sc->sf_txthresh < SF_MAX_TX_THRESHOLD) {
1777175526Syongari		txfctl = csr_read_4(sc, SF_TX_FRAMCTL);
1778175526Syongari		/* Increase Tx threshold 256 bytes. */
1779175526Syongari		sc->sf_txthresh += 16;
1780175526Syongari		if (sc->sf_txthresh > SF_MAX_TX_THRESHOLD)
1781175526Syongari			sc->sf_txthresh = SF_MAX_TX_THRESHOLD;
178281737Swpaul		txfctl &= ~SF_TXFRMCTL_TXTHRESH;
1783175526Syongari		txfctl |= sc->sf_txthresh;
1784175526Syongari		printf("increasing Tx threshold to %d bytes\n",
1785175526Syongari		    sc->sf_txthresh * SF_TX_THRESHOLD_UNIT);
178681737Swpaul		csr_write_4(sc, SF_TX_FRAMCTL, txfctl);
1787175526Syongari	} else
1788175526Syongari		printf("\n");
178981737Swpaul}
179081737Swpaul
1791137557Sbrueffer#ifdef DEVICE_POLLING
1792193096Sattiliostatic int
1793137557Sbrueffersf_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1794137557Sbrueffer{
1795175526Syongari	struct sf_softc		*sc;
1796175526Syongari	uint32_t		status;
1797193096Sattilio	int			rx_npkts;
1798137557Sbrueffer
1799175526Syongari	sc = ifp->if_softc;
1800193096Sattilio	rx_npkts = 0;
1801137557Sbrueffer	SF_LOCK(sc);
1802137557Sbrueffer
1803175526Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0) {
1804175526Syongari		SF_UNLOCK(sc);
1805193096Sattilio		return (rx_npkts);
1806175526Syongari	}
1807137557Sbrueffer
1808137557Sbrueffer	sc->rxcycles = count;
1809193096Sattilio	rx_npkts = sf_rxeof(sc);
1810137557Sbrueffer	sf_txeof(sc);
1811137620Sbrueffer	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1812149240Sjhb		sf_start_locked(ifp);
1813137557Sbrueffer
1814137557Sbrueffer	if (cmd == POLL_AND_CHECK_STATUS) {
1815175526Syongari		/* Reading the ISR register clears all interrrupts. */
1816137557Sbrueffer		status = csr_read_4(sc, SF_ISR);
1817137557Sbrueffer
1818175526Syongari		if ((status & SF_ISR_ABNORMALINTR) != 0) {
1819175526Syongari			if ((status & SF_ISR_STATSOFLOW) != 0)
1820137557Sbrueffer				sf_stats_update(sc);
1821175526Syongari			else if ((status & SF_ISR_TX_LOFIFO) != 0)
1822175526Syongari				sf_txthresh_adjust(sc);
1823175526Syongari			else if ((status & SF_ISR_DMAERR) != 0) {
1824175526Syongari				device_printf(sc->sf_dev,
1825175526Syongari				    "DMA error, resetting\n");
1826212971Syongari				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1827149240Sjhb				sf_init_locked(sc);
1828212971Syongari				SF_UNLOCK(sc);
1829212971Syongari				return (rx_npkts);
1830175526Syongari			} else if ((status & SF_ISR_NO_TX_CSUM) != 0) {
1831175531Syongari				sc->sf_statistics.sf_tx_gfp_stall++;
1832175526Syongari#ifdef	SF_GFP_DEBUG
1833175526Syongari				device_printf(sc->sf_dev,
1834175526Syongari				    "TxGFP is not responding!\n");
1835175526Syongari#endif
1836175526Syongari			} else if ((status & SF_ISR_RXGFP_NORESP) != 0) {
1837175531Syongari				sc->sf_statistics.sf_rx_gfp_stall++;
1838175526Syongari#ifdef	SF_GFP_DEBUG
1839175526Syongari				device_printf(sc->sf_dev,
1840175526Syongari				    "RxGFP is not responding!\n");
1841175526Syongari#endif
1842175526Syongari			}
1843137557Sbrueffer		}
1844137557Sbrueffer	}
1845175526Syongari
1846175526Syongari	SF_UNLOCK(sc);
1847193096Sattilio	return (rx_npkts);
1848137557Sbrueffer}
1849137557Sbrueffer#endif /* DEVICE_POLLING */
1850137557Sbrueffer
1851137557Sbruefferstatic void
1852175526Syongarisf_intr(void *arg)
185349076Swpaul{
185449076Swpaul	struct sf_softc		*sc;
185549076Swpaul	struct ifnet		*ifp;
1856175526Syongari	uint32_t		status;
1857232040Syongari	int			cnt;
185849076Swpaul
1859175526Syongari	sc = (struct sf_softc *)arg;
186067087Swpaul	SF_LOCK(sc);
186167087Swpaul
1862175526Syongari	if (sc->sf_suspended != 0)
1863175526Syongari		goto done_locked;
1864175526Syongari
1865175526Syongari	/* Reading the ISR register clears all interrrupts. */
1866175526Syongari	status = csr_read_4(sc, SF_ISR);
1867175526Syongari	if (status == 0 || status == 0xffffffff ||
1868175526Syongari	    (status & SF_ISR_PCIINT_ASSERTED) == 0)
1869175526Syongari		goto done_locked;
1870175526Syongari
1871147256Sbrooks	ifp = sc->sf_ifp;
1872137557Sbrueffer#ifdef DEVICE_POLLING
1873175526Syongari	if ((ifp->if_capenable & IFCAP_POLLING) != 0)
1874175526Syongari		goto done_locked;
1875150789Sglebius#endif
1876137557Sbrueffer
187749076Swpaul	/* Disable interrupts. */
187849076Swpaul	csr_write_4(sc, SF_IMR, 0x00000000);
187949076Swpaul
1880232040Syongari	for (cnt = 32; (status & SF_INTRS) != 0;) {
1881232040Syongari		if ((ifp->if_drv_flags & IFF_DRV_RUNNING) == 0)
1882232040Syongari			break;
1883175526Syongari		if ((status & SF_ISR_RXDQ1_DMADONE) != 0)
188449076Swpaul			sf_rxeof(sc);
188549076Swpaul
1886175526Syongari		if ((status & (SF_ISR_TX_TXDONE | SF_ISR_TX_DMADONE |
1887175526Syongari		    SF_ISR_TX_QUEUEDONE)) != 0)
188849076Swpaul			sf_txeof(sc);
188949076Swpaul
1890175526Syongari		if ((status & SF_ISR_ABNORMALINTR) != 0) {
1891175526Syongari			if ((status & SF_ISR_STATSOFLOW) != 0)
189249076Swpaul				sf_stats_update(sc);
1893175526Syongari			else if ((status & SF_ISR_TX_LOFIFO) != 0)
1894175526Syongari				sf_txthresh_adjust(sc);
1895175526Syongari			else if ((status & SF_ISR_DMAERR) != 0) {
1896175526Syongari				device_printf(sc->sf_dev,
1897175526Syongari				    "DMA error, resetting\n");
1898212971Syongari				ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
1899149240Sjhb				sf_init_locked(sc);
1900212971Syongari				SF_UNLOCK(sc);
1901212971Syongari				return;
1902175526Syongari			} else if ((status & SF_ISR_NO_TX_CSUM) != 0) {
1903175526Syongari				sc->sf_statistics.sf_tx_gfp_stall++;
1904175526Syongari#ifdef	SF_GFP_DEBUG
1905175526Syongari				device_printf(sc->sf_dev,
1906175526Syongari				    "TxGFP is not responding!\n");
1907175526Syongari#endif
1908175526Syongari			}
1909175526Syongari			else if ((status & SF_ISR_RXGFP_NORESP) != 0) {
1910175526Syongari				sc->sf_statistics.sf_rx_gfp_stall++;
1911175526Syongari#ifdef	SF_GFP_DEBUG
1912175526Syongari				device_printf(sc->sf_dev,
1913175526Syongari				    "RxGFP is not responding!\n");
1914175526Syongari#endif
1915175526Syongari			}
191649076Swpaul		}
1917232040Syongari		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1918232040Syongari			sf_start_locked(ifp);
1919232040Syongari		if (--cnt <= 0)
1920232040Syongari			break;
1921175526Syongari		/* Reading the ISR register clears all interrrupts. */
1922175526Syongari		status = csr_read_4(sc, SF_ISR);
192349076Swpaul	}
192449076Swpaul
1925232040Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0) {
1926232040Syongari		/* Re-enable interrupts. */
1927232040Syongari		csr_write_4(sc, SF_IMR, SF_INTRS);
1928232040Syongari	}
192949076Swpaul
1930175526Syongaridone_locked:
193167087Swpaul	SF_UNLOCK(sc);
193249076Swpaul}
193349076Swpaul
1934102335Salfredstatic void
1935175526Syongarisf_download_fw(struct sf_softc *sc)
193649076Swpaul{
1937175526Syongari	uint32_t gfpinst;
1938175526Syongari	int i, ndx;
1939175526Syongari	uint8_t *p;
1940175526Syongari
1941175526Syongari	/*
1942175526Syongari	 * A FP instruction is composed of 48bits so we have to
1943175526Syongari	 * write it with two parts.
1944175526Syongari	 */
1945175526Syongari	p = txfwdata;
1946175526Syongari	ndx = 0;
1947175526Syongari	for (i = 0; i < sizeof(txfwdata) / SF_GFP_INST_BYTES; i++) {
1948175526Syongari		gfpinst = p[2] << 24 | p[3] << 16 | p[4] << 8 | p[5];
1949175526Syongari		csr_write_4(sc, SF_TXGFP_MEM_BASE + ndx * 4, gfpinst);
1950175526Syongari		gfpinst = p[0] << 8 | p[1];
1951175526Syongari		csr_write_4(sc, SF_TXGFP_MEM_BASE + (ndx + 1) * 4, gfpinst);
1952175526Syongari		p += SF_GFP_INST_BYTES;
1953175526Syongari		ndx += 2;
1954175526Syongari	}
1955175526Syongari	if (bootverbose)
1956175526Syongari		device_printf(sc->sf_dev, "%d Tx instructions downloaded\n", i);
1957175526Syongari
1958175526Syongari	p = rxfwdata;
1959175526Syongari	ndx = 0;
1960175526Syongari	for (i = 0; i < sizeof(rxfwdata) / SF_GFP_INST_BYTES; i++) {
1961175526Syongari		gfpinst = p[2] << 24 | p[3] << 16 | p[4] << 8 | p[5];
1962175526Syongari		csr_write_4(sc, SF_RXGFP_MEM_BASE + (ndx * 4), gfpinst);
1963175526Syongari		gfpinst = p[0] << 8 | p[1];
1964175526Syongari		csr_write_4(sc, SF_RXGFP_MEM_BASE + (ndx + 1) * 4, gfpinst);
1965175526Syongari		p += SF_GFP_INST_BYTES;
1966175526Syongari		ndx += 2;
1967175526Syongari	}
1968175526Syongari	if (bootverbose)
1969175526Syongari		device_printf(sc->sf_dev, "%d Rx instructions downloaded\n", i);
1970175526Syongari}
1971175526Syongari
1972175526Syongaristatic void
1973175526Syongarisf_init(void *xsc)
1974175526Syongari{
197549076Swpaul	struct sf_softc		*sc;
1976149240Sjhb
1977175526Syongari	sc = (struct sf_softc *)xsc;
1978149240Sjhb	SF_LOCK(sc);
1979149240Sjhb	sf_init_locked(sc);
1980149240Sjhb	SF_UNLOCK(sc);
1981149240Sjhb}
1982149240Sjhb
1983149240Sjhbstatic void
1984175526Syongarisf_init_locked(struct sf_softc *sc)
1985149240Sjhb{
198649076Swpaul	struct ifnet		*ifp;
1987175526Syongari	uint8_t			eaddr[ETHER_ADDR_LEN];
1988175526Syongari	bus_addr_t		addr;
198967087Swpaul	int			i;
199049076Swpaul
1991149240Sjhb	SF_LOCK_ASSERT(sc);
1992147256Sbrooks	ifp = sc->sf_ifp;
1993212971Syongari	if ((ifp->if_drv_flags & IFF_DRV_RUNNING) != 0)
1994212971Syongari		return;
199549076Swpaul
199649076Swpaul	sf_stop(sc);
1997175526Syongari	/* Reset the hardware to a known state. */
199849076Swpaul	sf_reset(sc);
199949076Swpaul
200049076Swpaul	/* Init all the receive filter registers */
200149076Swpaul	for (i = SF_RXFILT_PERFECT_BASE;
2002175526Syongari	    i < (SF_RXFILT_HASH_MAX + 1); i += sizeof(uint32_t))
200349076Swpaul		csr_write_4(sc, i, 0);
200449076Swpaul
200549076Swpaul	/* Empty stats counter registers. */
2006175526Syongari	for (i = SF_STATS_BASE; i < (SF_STATS_END + 1); i += sizeof(uint32_t))
2007175526Syongari		csr_write_4(sc, i, 0);
200849076Swpaul
2009175526Syongari	/* Init our MAC address. */
2010175526Syongari	bcopy(IF_LLADDR(sc->sf_ifp), eaddr, sizeof(eaddr));
2011175526Syongari	csr_write_4(sc, SF_PAR0,
2012175526Syongari	    eaddr[2] << 24 | eaddr[3] << 16 | eaddr[4] << 8 | eaddr[5]);
2013175526Syongari	csr_write_4(sc, SF_PAR1, eaddr[0] << 8 | eaddr[1]);
2014175526Syongari	sf_setperf(sc, 0, eaddr);
201549076Swpaul
201649076Swpaul	if (sf_init_rx_ring(sc) == ENOBUFS) {
2017162315Sglebius		device_printf(sc->sf_dev,
2018148947Sjhb		    "initialization failed: no memory for rx buffers\n");
2019232021Syongari		sf_stop(sc);
202049076Swpaul		return;
202149076Swpaul	}
202249076Swpaul
202349076Swpaul	sf_init_tx_ring(sc);
202449076Swpaul
2025175526Syongari	/*
2026175526Syongari	 * 16 perfect address filtering.
2027175526Syongari	 * Hash only multicast destination address, Accept matching
2028175526Syongari	 * frames regardless of VLAN ID.
2029175526Syongari	 */
2030175526Syongari	csr_write_4(sc, SF_RXFILT, SF_PERFMODE_NORMAL | SF_HASHMODE_ANYVLAN);
203149076Swpaul
203263166Swpaul	/*
2033175526Syongari	 * Set Rx filter.
203463166Swpaul	 */
2035175526Syongari	sf_rxfilter(sc);
203663166Swpaul
2037175526Syongari	/* Init the completion queue indexes. */
203849076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX, 0);
203949076Swpaul	csr_write_4(sc, SF_CQ_PRODIDX, 0);
204049076Swpaul
2041175526Syongari	/* Init the RX completion queue. */
2042175526Syongari	addr = sc->sf_rdata.sf_rx_cring_paddr;
2043175526Syongari	csr_write_4(sc, SF_CQ_ADDR_HI, SF_ADDR_HI(addr));
2044175526Syongari	csr_write_4(sc, SF_RXCQ_CTL_1, SF_ADDR_LO(addr) & SF_RXCQ_ADDR);
2045175526Syongari	if (SF_ADDR_HI(addr) != 0)
2046175526Syongari		SF_SETBIT(sc, SF_RXCQ_CTL_1, SF_RXCQ_USE_64BIT);
2047175526Syongari	/* Set RX completion queue type 2. */
2048175526Syongari	SF_SETBIT(sc, SF_RXCQ_CTL_1, SF_RXCQTYPE_2);
2049175526Syongari	csr_write_4(sc, SF_RXCQ_CTL_2, 0);
205049076Swpaul
2051175526Syongari	/*
2052175526Syongari	 * Init RX DMA control.
2053175526Syongari	 * default RxHighPriority Threshold,
2054175526Syongari	 * default RxBurstSize, 128bytes.
2055175526Syongari	 */
2056175526Syongari	SF_SETBIT(sc, SF_RXDMA_CTL,
2057175526Syongari	    SF_RXDMA_REPORTBADPKTS |
2058175526Syongari	    (SF_RXDMA_HIGHPRIO_THRESH << 8) |
2059175526Syongari	    SF_RXDMA_BURST);
206049076Swpaul
206149076Swpaul	/* Init the RX buffer descriptor queue. */
2062175526Syongari	addr = sc->sf_rdata.sf_rx_ring_paddr;
2063175526Syongari	csr_write_4(sc, SF_RXDQ_ADDR_HI, SF_ADDR_HI(addr));
2064175526Syongari	csr_write_4(sc, SF_RXDQ_ADDR_Q1, SF_ADDR_LO(addr));
2065175526Syongari
2066175526Syongari	/* Set RX queue buffer length. */
2067175526Syongari	csr_write_4(sc, SF_RXDQ_CTL_1,
2068175526Syongari	    ((MCLBYTES  - sizeof(uint32_t)) << 16) |
2069175526Syongari	    SF_RXDQCTL_64BITBADDR | SF_RXDQCTL_VARIABLE);
2070175526Syongari
2071175526Syongari	if (SF_ADDR_HI(addr) != 0)
2072175526Syongari		SF_SETBIT(sc, SF_RXDQ_CTL_1, SF_RXDQCTL_64BITDADDR);
207349076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1, SF_RX_DLIST_CNT - 1);
2074175526Syongari	csr_write_4(sc, SF_RXDQ_CTL_2, 0);
207549076Swpaul
207649076Swpaul	/* Init the TX completion queue */
2077175526Syongari	addr = sc->sf_rdata.sf_tx_cring_paddr;
2078175526Syongari	csr_write_4(sc, SF_TXCQ_CTL, SF_ADDR_LO(addr) & SF_TXCQ_ADDR);
2079175526Syongari	if (SF_ADDR_HI(addr) != 0)
2080175526Syongari		SF_SETBIT(sc, SF_TXCQ_CTL, SF_TXCQ_USE_64BIT);
208149076Swpaul
208249076Swpaul	/* Init the TX buffer descriptor queue. */
2083175526Syongari	addr = sc->sf_rdata.sf_tx_ring_paddr;
2084175526Syongari	csr_write_4(sc, SF_TXDQ_ADDR_HI, SF_ADDR_HI(addr));
2085175526Syongari	csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO, 0);
2086175526Syongari	csr_write_4(sc, SF_TXDQ_ADDR_LOPRIO, SF_ADDR_LO(addr));
2087175526Syongari	csr_write_4(sc, SF_TX_FRAMCTL,
2088175526Syongari	    SF_TXFRMCTL_CPLAFTERTX | sc->sf_txthresh);
208949076Swpaul	csr_write_4(sc, SF_TXDQ_CTL,
2090175526Syongari	    SF_TXDMA_HIPRIO_THRESH << 24 |
2091175526Syongari	    SF_TXSKIPLEN_0BYTES << 16 |
2092175526Syongari	    SF_TXDDMA_BURST << 8 |
2093175526Syongari	    SF_TXBUFDESC_TYPE2 | SF_TXMINSPACE_UNLIMIT);
2094175526Syongari	if (SF_ADDR_HI(addr) != 0)
2095175526Syongari		SF_SETBIT(sc, SF_TXDQ_CTL, SF_TXDQCTL_64BITADDR);
209649076Swpaul
2097175526Syongari	/* Set VLAN Type register. */
2098175526Syongari	csr_write_4(sc, SF_VLANTYPE, ETHERTYPE_VLAN);
2099175526Syongari
2100175526Syongari	/* Set TxPause Timer. */
2101175526Syongari	csr_write_4(sc, SF_TXPAUSETIMER, 0xffff);
2102175526Syongari
210349076Swpaul	/* Enable autopadding of short TX frames. */
210449076Swpaul	SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_AUTOPAD);
2105175526Syongari	SF_SETBIT(sc, SF_MACCFG_2, SF_MACCFG2_AUTOVLANPAD);
2106175526Syongari	/* Make sure to reset MAC to take changes effect. */
2107175526Syongari	SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
2108175526Syongari	DELAY(1000);
2109175526Syongari	SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
211049076Swpaul
2111175526Syongari	/* Enable PCI bus master. */
2112175526Syongari	SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_PCIMEN);
2113175526Syongari
2114175526Syongari	/* Load StarFire firmware. */
2115175526Syongari	sf_download_fw(sc);
2116175526Syongari
2117175526Syongari	/* Intialize interrupt moderation. */
2118175526Syongari	csr_write_4(sc, SF_TIMER_CTL, SF_TIMER_IMASK_MODE | SF_TIMER_TIMES_TEN |
2119175526Syongari	    (sc->sf_int_mod & SF_TIMER_IMASK_INTERVAL));
2120175526Syongari
2121137557Sbrueffer#ifdef DEVICE_POLLING
2122137557Sbrueffer	/* Disable interrupts if we are polling. */
2123175526Syongari	if ((ifp->if_capenable & IFCAP_POLLING) != 0)
2124137557Sbrueffer		csr_write_4(sc, SF_IMR, 0x00000000);
2125137557Sbrueffer	else
2126150789Sglebius#endif
212749076Swpaul	/* Enable interrupts. */
212849076Swpaul	csr_write_4(sc, SF_IMR, SF_INTRS);
212949076Swpaul	SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_INTR_ENB);
213049076Swpaul
213149076Swpaul	/* Enable the RX and TX engines. */
2132175526Syongari	csr_write_4(sc, SF_GEN_ETH_CTL,
2133175526Syongari	    SF_ETHCTL_RX_ENB | SF_ETHCTL_RXDMA_ENB |
2134175526Syongari	    SF_ETHCTL_TX_ENB | SF_ETHCTL_TXDMA_ENB);
213549076Swpaul
2136175526Syongari	if ((ifp->if_capenable & IFCAP_TXCSUM) != 0)
2137175526Syongari		SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_TXGFP_ENB);
2138175526Syongari	else
2139175526Syongari		SF_CLRBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_TXGFP_ENB);
2140175526Syongari	if ((ifp->if_capenable & IFCAP_RXCSUM) != 0)
2141175526Syongari		SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_RXGFP_ENB);
2142175526Syongari	else
2143175526Syongari		SF_CLRBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_RXGFP_ENB);
214450675Swpaul
2145148887Srwatson	ifp->if_drv_flags |= IFF_DRV_RUNNING;
2146148887Srwatson	ifp->if_drv_flags &= ~IFF_DRV_OACTIVE;
214749076Swpaul
2148232025Syongari	sc->sf_link = 0;
2149232025Syongari	sf_ifmedia_upd_locked(ifp);
2150232025Syongari
2151175526Syongari	callout_reset(&sc->sf_co, hz, sf_tick, sc);
215249076Swpaul}
215349076Swpaul
2154102335Salfredstatic int
2155175526Syongarisf_encap(struct sf_softc *sc, struct mbuf **m_head)
215649076Swpaul{
2157175526Syongari	struct sf_txdesc	*txd;
2158175526Syongari	struct sf_tx_rdesc	*desc;
215949076Swpaul	struct mbuf		*m;
2160175526Syongari	bus_dmamap_t		map;
2161175526Syongari	bus_dma_segment_t	txsegs[SF_MAXTXSEGS];
2162175526Syongari	int			error, i, nsegs, prod, si;
2163175526Syongari	int			avail, nskip;
216449076Swpaul
2165175526Syongari	SF_LOCK_ASSERT(sc);
216649076Swpaul
2167175526Syongari	m = *m_head;
2168175526Syongari	prod = sc->sf_cdata.sf_tx_prod;
2169175526Syongari	txd = &sc->sf_cdata.sf_txdesc[prod];
2170175526Syongari	map = txd->tx_dmamap;
2171175526Syongari	error = bus_dmamap_load_mbuf_sg(sc->sf_cdata.sf_tx_tag, map,
2172175526Syongari	    *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
2173175526Syongari	if (error == EFBIG) {
2174243857Sglebius		m = m_collapse(*m_head, M_NOWAIT, SF_MAXTXSEGS);
2175175526Syongari		if (m == NULL) {
2176175526Syongari			m_freem(*m_head);
2177175526Syongari			*m_head = NULL;
2178175526Syongari			return (ENOBUFS);
217949076Swpaul		}
2180175526Syongari		*m_head = m;
2181175526Syongari		error = bus_dmamap_load_mbuf_sg(sc->sf_cdata.sf_tx_tag,
2182175526Syongari		    map, *m_head, txsegs, &nsegs, BUS_DMA_NOWAIT);
2183175526Syongari		if (error != 0) {
2184175526Syongari			m_freem(*m_head);
2185175526Syongari			*m_head = NULL;
2186175526Syongari			return (error);
2187175526Syongari		}
2188175526Syongari	} else if (error != 0)
2189175526Syongari		return (error);
2190175526Syongari	if (nsegs == 0) {
2191175526Syongari		m_freem(*m_head);
2192175526Syongari		*m_head = NULL;
2193175526Syongari		return (EIO);
219449076Swpaul	}
219549076Swpaul
2196175526Syongari	/* Check number of available descriptors. */
2197175526Syongari	avail = (SF_TX_DLIST_CNT - 1) - sc->sf_cdata.sf_tx_cnt;
2198175526Syongari	if (avail < nsegs) {
2199175526Syongari		bus_dmamap_unload(sc->sf_cdata.sf_tx_tag, map);
2200175526Syongari		return (ENOBUFS);
2201175526Syongari	}
2202175526Syongari	nskip = 0;
2203175526Syongari	if (prod + nsegs >= SF_TX_DLIST_CNT) {
2204175526Syongari		nskip = SF_TX_DLIST_CNT - prod - 1;
2205175526Syongari		if (avail < nsegs + nskip) {
2206175526Syongari			bus_dmamap_unload(sc->sf_cdata.sf_tx_tag, map);
2207175526Syongari			return (ENOBUFS);
220849076Swpaul		}
2209175526Syongari	}
221049076Swpaul
2211175526Syongari	bus_dmamap_sync(sc->sf_cdata.sf_tx_tag, map, BUS_DMASYNC_PREWRITE);
2212175526Syongari
2213175526Syongari	si = prod;
2214175526Syongari	for (i = 0; i < nsegs; i++) {
2215175526Syongari		desc = &sc->sf_rdata.sf_tx_ring[prod];
2216175526Syongari		desc->sf_tx_ctrl = htole32(SF_TX_DESC_ID |
2217175526Syongari		    (txsegs[i].ds_len & SF_TX_DESC_FRAGLEN));
2218175526Syongari		desc->sf_tx_reserved = 0;
2219175526Syongari		desc->sf_addr = htole64(txsegs[i].ds_addr);
2220175526Syongari		if (i == 0 && prod + nsegs >= SF_TX_DLIST_CNT) {
2221175526Syongari			/* Queue wraps! */
2222175526Syongari			desc->sf_tx_ctrl |= htole32(SF_TX_DESC_END);
2223175526Syongari			prod = 0;
2224175526Syongari		} else
2225175526Syongari			SF_INC(prod, SF_TX_DLIST_CNT);
222649076Swpaul	}
2227175526Syongari	/* Update producer index. */
2228175526Syongari	sc->sf_cdata.sf_tx_prod = prod;
2229175526Syongari	sc->sf_cdata.sf_tx_cnt += nsegs + nskip;
223049076Swpaul
2231175526Syongari	desc = &sc->sf_rdata.sf_tx_ring[si];
2232175526Syongari	/* Check TDP/UDP checksum offload request. */
2233175526Syongari	if ((m->m_pkthdr.csum_flags & SF_CSUM_FEATURES) != 0)
2234175526Syongari		desc->sf_tx_ctrl |= htole32(SF_TX_DESC_CALTCP);
2235175526Syongari	desc->sf_tx_ctrl |=
2236175526Syongari	    htole32(SF_TX_DESC_CRCEN | SF_TX_DESC_INTR | (nsegs << 16));
223749076Swpaul
2238175526Syongari	txd->tx_dmamap = map;
2239175526Syongari	txd->tx_m = m;
2240175526Syongari	txd->ndesc = nsegs + nskip;
2241175526Syongari
2242175526Syongari	return (0);
224349076Swpaul}
224449076Swpaul
2245102335Salfredstatic void
2246175526Syongarisf_start(struct ifnet *ifp)
224749076Swpaul{
224849076Swpaul	struct sf_softc		*sc;
2249149240Sjhb
2250149240Sjhb	sc = ifp->if_softc;
2251149240Sjhb	SF_LOCK(sc);
2252149240Sjhb	sf_start_locked(ifp);
2253149240Sjhb	SF_UNLOCK(sc);
2254149240Sjhb}
2255149240Sjhb
2256149240Sjhbstatic void
2257175526Syongarisf_start_locked(struct ifnet *ifp)
2258149240Sjhb{
2259149240Sjhb	struct sf_softc		*sc;
2260175526Syongari	struct mbuf		*m_head;
2261175526Syongari	int			enq;
226249076Swpaul
226349076Swpaul	sc = ifp->if_softc;
2264149240Sjhb	SF_LOCK_ASSERT(sc);
226549076Swpaul
2266175526Syongari	if ((ifp->if_drv_flags & (IFF_DRV_RUNNING | IFF_DRV_OACTIVE)) !=
2267175526Syongari	    IFF_DRV_RUNNING || sc->sf_link == 0)
226854161Swpaul		return;
226954161Swpaul
2270175526Syongari	/*
2271175526Syongari	 * Since we don't know when descriptor wrap occurrs in advance
2272175526Syongari	 * limit available number of active Tx descriptor counter to be
2273175526Syongari	 * higher than maximum number of DMA segments allowed in driver.
2274175526Syongari	 */
2275175526Syongari	for (enq = 0; !IFQ_DRV_IS_EMPTY(&ifp->if_snd) &&
2276175526Syongari	    sc->sf_cdata.sf_tx_cnt < SF_TX_DLIST_CNT - SF_MAXTXSEGS; ) {
2277137620Sbrueffer		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
227849076Swpaul		if (m_head == NULL)
227949076Swpaul			break;
2280175526Syongari		/*
2281175526Syongari		 * Pack the data into the transmit ring. If we
2282175526Syongari		 * don't have room, set the OACTIVE flag and wait
2283175526Syongari		 * for the NIC to drain the ring.
2284175526Syongari		 */
2285175526Syongari		if (sf_encap(sc, &m_head)) {
2286175526Syongari			if (m_head == NULL)
2287175526Syongari				break;
2288137620Sbrueffer			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
2289148887Srwatson			ifp->if_drv_flags |= IFF_DRV_OACTIVE;
229071276Swpaul			break;
229171276Swpaul		}
229249076Swpaul
2293175526Syongari		enq++;
229449076Swpaul		/*
229549076Swpaul		 * If there's a BPF listener, bounce a copy of this frame
229649076Swpaul		 * to him.
229749076Swpaul		 */
2298175526Syongari		ETHER_BPF_MTAP(ifp, m_head);
229949076Swpaul	}
230049076Swpaul
2301175526Syongari	if (enq > 0) {
2302175526Syongari		bus_dmamap_sync(sc->sf_cdata.sf_tx_ring_tag,
2303175526Syongari		    sc->sf_cdata.sf_tx_ring_map,
2304175526Syongari		    BUS_DMASYNC_PREREAD | BUS_DMASYNC_PREWRITE);
2305175526Syongari		/* Kick transmit. */
2306175526Syongari		csr_write_4(sc, SF_TXDQ_PRODIDX,
2307175526Syongari		    sc->sf_cdata.sf_tx_prod * (sizeof(struct sf_tx_rdesc) / 8));
230849076Swpaul
2309175526Syongari		/* Set a timeout in case the chip goes out to lunch. */
2310175526Syongari		sc->sf_watchdog_timer = 5;
2311175526Syongari	}
231249076Swpaul}
231349076Swpaul
2314102335Salfredstatic void
2315175526Syongarisf_stop(struct sf_softc *sc)
231649076Swpaul{
2317175526Syongari	struct sf_txdesc	*txd;
2318175526Syongari	struct sf_rxdesc	*rxd;
2319175526Syongari	struct ifnet		*ifp;
232049076Swpaul	int			i;
232149076Swpaul
2322149240Sjhb	SF_LOCK_ASSERT(sc);
232367087Swpaul
2324147256Sbrooks	ifp = sc->sf_ifp;
232549077Swpaul
2326175526Syongari	ifp->if_drv_flags &= ~(IFF_DRV_RUNNING | IFF_DRV_OACTIVE);
2327175526Syongari	sc->sf_link = 0;
2328175526Syongari	callout_stop(&sc->sf_co);
2329175526Syongari	sc->sf_watchdog_timer = 0;
233049076Swpaul
2331175526Syongari	/* Reading the ISR register clears all interrrupts. */
2332175526Syongari	csr_read_4(sc, SF_ISR);
2333175526Syongari	/* Disable further interrupts. */
2334175526Syongari	csr_write_4(sc, SF_IMR, 0);
2335175526Syongari
2336175526Syongari	/* Disable Tx/Rx egine. */
233749076Swpaul	csr_write_4(sc, SF_GEN_ETH_CTL, 0);
2338175526Syongari
2339232019Syongari	/* Give hardware chance to drain active DMA cycles. */
2340232019Syongari	DELAY(1000);
2341232019Syongari
234249076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX, 0);
234349076Swpaul	csr_write_4(sc, SF_CQ_PRODIDX, 0);
234449076Swpaul	csr_write_4(sc, SF_RXDQ_ADDR_Q1, 0);
234549076Swpaul	csr_write_4(sc, SF_RXDQ_CTL_1, 0);
234649076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1, 0);
234749076Swpaul	csr_write_4(sc, SF_TXCQ_CTL, 0);
234849076Swpaul	csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO, 0);
234949076Swpaul	csr_write_4(sc, SF_TXDQ_CTL, 0);
235049076Swpaul
2351175526Syongari	/*
2352175526Syongari	 * Free RX and TX mbufs still in the queues.
2353175526Syongari	 */
235449076Swpaul	for (i = 0; i < SF_RX_DLIST_CNT; i++) {
2355175526Syongari		rxd = &sc->sf_cdata.sf_rxdesc[i];
2356175526Syongari		if (rxd->rx_m != NULL) {
2357175526Syongari			bus_dmamap_sync(sc->sf_cdata.sf_rx_tag,
2358175526Syongari			    rxd->rx_dmamap, BUS_DMASYNC_POSTREAD);
2359175526Syongari			bus_dmamap_unload(sc->sf_cdata.sf_rx_tag,
2360175526Syongari			    rxd->rx_dmamap);
2361175526Syongari			m_freem(rxd->rx_m);
2362175526Syongari			rxd->rx_m = NULL;
236349076Swpaul		}
2364175526Syongari        }
236549076Swpaul	for (i = 0; i < SF_TX_DLIST_CNT; i++) {
2366175526Syongari		txd = &sc->sf_cdata.sf_txdesc[i];
2367175526Syongari		if (txd->tx_m != NULL) {
2368175526Syongari			bus_dmamap_sync(sc->sf_cdata.sf_tx_tag,
2369175526Syongari			    txd->tx_dmamap, BUS_DMASYNC_POSTWRITE);
2370175526Syongari			bus_dmamap_unload(sc->sf_cdata.sf_tx_tag,
2371175526Syongari			    txd->tx_dmamap);
2372175526Syongari			m_freem(txd->tx_m);
2373175526Syongari			txd->tx_m = NULL;
2374175526Syongari			txd->ndesc = 0;
237549076Swpaul		}
2376175526Syongari        }
2377175526Syongari}
237849076Swpaul
2379175526Syongaristatic void
2380175526Syongarisf_tick(void *xsc)
2381175526Syongari{
2382175526Syongari	struct sf_softc		*sc;
2383175526Syongari	struct mii_data		*mii;
2384175526Syongari
2385175526Syongari	sc = xsc;
2386175526Syongari	SF_LOCK_ASSERT(sc);
2387175526Syongari	mii = device_get_softc(sc->sf_miibus);
2388175526Syongari	mii_tick(mii);
2389175526Syongari	sf_stats_update(sc);
2390175526Syongari	sf_watchdog(sc);
2391175526Syongari	callout_reset(&sc->sf_co, hz, sf_tick, sc);
239249076Swpaul}
239349076Swpaul
239449076Swpaul/*
239549076Swpaul * Note: it is important that this function not be interrupted. We
239649076Swpaul * use a two-stage register access scheme: if we are interrupted in
239749076Swpaul * between setting the indirect address register and reading from the
239849076Swpaul * indirect data register, the contents of the address register could
239949076Swpaul * be changed out from under us.
2400131657Sbms */
2401102335Salfredstatic void
2402175526Syongarisf_stats_update(struct sf_softc *sc)
240349076Swpaul{
240449076Swpaul	struct ifnet		*ifp;
2405175526Syongari	struct sf_stats		now, *stats, *nstats;
240667087Swpaul	int			i;
240749076Swpaul
2408149240Sjhb	SF_LOCK_ASSERT(sc);
2409175526Syongari
2410147256Sbrooks	ifp = sc->sf_ifp;
2411175526Syongari	stats = &now;
241249076Swpaul
2413175526Syongari	stats->sf_tx_frames =
2414175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_FRAMES);
2415175526Syongari	stats->sf_tx_single_colls =
2416175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_SINGLE_COL);
2417175526Syongari	stats->sf_tx_multi_colls =
2418175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_MULTI_COL);
2419175526Syongari	stats->sf_tx_crcerrs =
2420175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_CRC_ERRS);
2421175526Syongari	stats->sf_tx_bytes =
2422175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_BYTES);
2423175526Syongari	stats->sf_tx_deferred =
2424175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_DEFERRED);
2425175526Syongari	stats->sf_tx_late_colls =
2426175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_LATE_COL);
2427175526Syongari	stats->sf_tx_pause_frames =
2428175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_PAUSE);
2429175526Syongari	stats->sf_tx_control_frames =
2430175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_CTL_FRAME);
2431175526Syongari	stats->sf_tx_excess_colls =
2432175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_EXCESS_COL);
2433175526Syongari	stats->sf_tx_excess_defer =
2434175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_EXCESS_DEF);
2435175526Syongari	stats->sf_tx_mcast_frames =
2436175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_MULTI);
2437175526Syongari	stats->sf_tx_bcast_frames =
2438175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_BCAST);
2439175526Syongari	stats->sf_tx_frames_lost =
2440175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_FRAME_LOST);
2441175526Syongari	stats->sf_rx_frames =
2442175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_FRAMES);
2443175526Syongari	stats->sf_rx_crcerrs =
2444175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_CRC_ERRS);
2445175526Syongari	stats->sf_rx_alignerrs =
2446175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_ALIGN_ERRS);
2447175526Syongari	stats->sf_rx_bytes =
2448175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_BYTES);
2449175526Syongari	stats->sf_rx_pause_frames =
2450175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_PAUSE);
2451175526Syongari	stats->sf_rx_control_frames =
2452175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_CTL_FRAME);
2453175526Syongari	stats->sf_rx_unsup_control_frames =
2454175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_UNSUP_FRAME);
2455175526Syongari	stats->sf_rx_giants =
2456175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_GIANTS);
2457175526Syongari	stats->sf_rx_runts =
2458175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_RUNTS);
2459175526Syongari	stats->sf_rx_jabbererrs =
2460175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_JABBER);
2461175526Syongari	stats->sf_rx_fragments =
2462175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_FRAGMENTS);
2463175526Syongari	stats->sf_rx_pkts_64 =
2464175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_64);
2465175526Syongari	stats->sf_rx_pkts_65_127 =
2466175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_65_127);
2467175526Syongari	stats->sf_rx_pkts_128_255 =
2468175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_128_255);
2469175526Syongari	stats->sf_rx_pkts_256_511 =
2470175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_256_511);
2471175526Syongari	stats->sf_rx_pkts_512_1023 =
2472175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_512_1023);
2473175526Syongari	stats->sf_rx_pkts_1024_1518 =
2474175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_1024_1518);
2475175526Syongari	stats->sf_rx_frames_lost =
2476175526Syongari	    csr_read_4(sc, SF_STATS_BASE + SF_STATS_RX_FRAME_LOST);
2477175526Syongari	/* Lower 16bits are valid. */
2478175526Syongari	stats->sf_tx_underruns =
2479175526Syongari	    (csr_read_4(sc, SF_STATS_BASE + SF_STATS_TX_UNDERRUN) & 0xffff);
248049076Swpaul
2481175526Syongari	/* Empty stats counter registers. */
2482175526Syongari	for (i = SF_STATS_BASE; i < (SF_STATS_END + 1); i += sizeof(uint32_t))
2483175526Syongari		csr_write_4(sc, i, 0);
248449076Swpaul
2485175526Syongari	ifp->if_opackets += (u_long)stats->sf_tx_frames;
248649076Swpaul
2487175526Syongari	ifp->if_collisions += (u_long)stats->sf_tx_single_colls +
2488175526Syongari	    (u_long)stats->sf_tx_multi_colls;
248984147Sjlemon
2490175526Syongari	ifp->if_oerrors += (u_long)stats->sf_tx_excess_colls +
2491175526Syongari	    (u_long)stats->sf_tx_excess_defer +
2492175526Syongari	    (u_long)stats->sf_tx_frames_lost;
249350675Swpaul
2494175526Syongari	ifp->if_ipackets += (u_long)stats->sf_rx_frames;
2495175526Syongari
2496175526Syongari	ifp->if_ierrors += (u_long)stats->sf_rx_crcerrs +
2497175526Syongari	    (u_long)stats->sf_rx_alignerrs +
2498175526Syongari	    (u_long)stats->sf_rx_giants +
2499175526Syongari	    (u_long)stats->sf_rx_runts +
2500175526Syongari	    (u_long)stats->sf_rx_jabbererrs +
2501175526Syongari	    (u_long)stats->sf_rx_frames_lost;
2502175526Syongari
2503175526Syongari	nstats = &sc->sf_statistics;
2504175526Syongari
2505175526Syongari	nstats->sf_tx_frames += stats->sf_tx_frames;
2506175526Syongari	nstats->sf_tx_single_colls += stats->sf_tx_single_colls;
2507175526Syongari	nstats->sf_tx_multi_colls += stats->sf_tx_multi_colls;
2508175526Syongari	nstats->sf_tx_crcerrs += stats->sf_tx_crcerrs;
2509175526Syongari	nstats->sf_tx_bytes += stats->sf_tx_bytes;
2510175526Syongari	nstats->sf_tx_deferred += stats->sf_tx_deferred;
2511175526Syongari	nstats->sf_tx_late_colls += stats->sf_tx_late_colls;
2512175526Syongari	nstats->sf_tx_pause_frames += stats->sf_tx_pause_frames;
2513175526Syongari	nstats->sf_tx_control_frames += stats->sf_tx_control_frames;
2514175526Syongari	nstats->sf_tx_excess_colls += stats->sf_tx_excess_colls;
2515175526Syongari	nstats->sf_tx_excess_defer += stats->sf_tx_excess_defer;
2516175526Syongari	nstats->sf_tx_mcast_frames += stats->sf_tx_mcast_frames;
2517175526Syongari	nstats->sf_tx_bcast_frames += stats->sf_tx_bcast_frames;
2518175526Syongari	nstats->sf_tx_frames_lost += stats->sf_tx_frames_lost;
2519175526Syongari	nstats->sf_rx_frames += stats->sf_rx_frames;
2520175526Syongari	nstats->sf_rx_crcerrs += stats->sf_rx_crcerrs;
2521175526Syongari	nstats->sf_rx_alignerrs += stats->sf_rx_alignerrs;
2522175526Syongari	nstats->sf_rx_bytes += stats->sf_rx_bytes;
2523175526Syongari	nstats->sf_rx_pause_frames += stats->sf_rx_pause_frames;
2524175526Syongari	nstats->sf_rx_control_frames += stats->sf_rx_control_frames;
2525175526Syongari	nstats->sf_rx_unsup_control_frames += stats->sf_rx_unsup_control_frames;
2526175526Syongari	nstats->sf_rx_giants += stats->sf_rx_giants;
2527175526Syongari	nstats->sf_rx_runts += stats->sf_rx_runts;
2528175526Syongari	nstats->sf_rx_jabbererrs += stats->sf_rx_jabbererrs;
2529175526Syongari	nstats->sf_rx_fragments += stats->sf_rx_fragments;
2530175526Syongari	nstats->sf_rx_pkts_64 += stats->sf_rx_pkts_64;
2531175526Syongari	nstats->sf_rx_pkts_65_127 += stats->sf_rx_pkts_65_127;
2532175526Syongari	nstats->sf_rx_pkts_128_255 += stats->sf_rx_pkts_128_255;
2533175526Syongari	nstats->sf_rx_pkts_256_511 += stats->sf_rx_pkts_256_511;
2534175526Syongari	nstats->sf_rx_pkts_512_1023 += stats->sf_rx_pkts_512_1023;
2535175526Syongari	nstats->sf_rx_pkts_1024_1518 += stats->sf_rx_pkts_1024_1518;
2536175526Syongari	nstats->sf_rx_frames_lost += stats->sf_rx_frames_lost;
2537175526Syongari	nstats->sf_tx_underruns += stats->sf_tx_underruns;
253849076Swpaul}
253949076Swpaul
2540102335Salfredstatic void
2541175526Syongarisf_watchdog(struct sf_softc *sc)
2542175526Syongari{
254349076Swpaul	struct ifnet		*ifp;
254449076Swpaul
2545175526Syongari	SF_LOCK_ASSERT(sc);
254649076Swpaul
2547175526Syongari	if (sc->sf_watchdog_timer == 0 || --sc->sf_watchdog_timer)
2548175526Syongari		return;
254967087Swpaul
2550175526Syongari	ifp = sc->sf_ifp;
2551175526Syongari
255249076Swpaul	ifp->if_oerrors++;
2553175526Syongari	if (sc->sf_link == 0) {
2554175526Syongari		if (bootverbose)
2555175526Syongari			if_printf(sc->sf_ifp, "watchdog timeout "
2556175526Syongari			   "(missed link)\n");
2557175526Syongari	} else
2558175526Syongari		if_printf(ifp, "watchdog timeout, %d Tx descs are active\n",
2559175526Syongari		    sc->sf_cdata.sf_tx_cnt);
256049076Swpaul
2561212971Syongari	ifp->if_drv_flags &= ~IFF_DRV_RUNNING;
2562149240Sjhb	sf_init_locked(sc);
256349076Swpaul
2564137620Sbrueffer	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
2565149240Sjhb		sf_start_locked(ifp);
2566175526Syongari}
256749076Swpaul
2568175526Syongaristatic int
2569175526Syongarisf_shutdown(device_t dev)
2570175526Syongari{
2571175526Syongari	struct sf_softc		*sc;
2572175526Syongari
2573175526Syongari	sc = device_get_softc(dev);
2574175526Syongari
2575175526Syongari	SF_LOCK(sc);
2576175526Syongari	sf_stop(sc);
257767087Swpaul	SF_UNLOCK(sc);
2578175526Syongari
2579175526Syongari	return (0);
258049076Swpaul}
258149076Swpaul
2582173839Syongaristatic int
2583175526Syongarisf_suspend(device_t dev)
258449076Swpaul{
258549076Swpaul	struct sf_softc		*sc;
258649076Swpaul
258749076Swpaul	sc = device_get_softc(dev);
258849076Swpaul
2589149240Sjhb	SF_LOCK(sc);
259049076Swpaul	sf_stop(sc);
2591175526Syongari	sc->sf_suspended = 1;
2592175526Syongari	bus_generic_suspend(dev);
2593149240Sjhb	SF_UNLOCK(sc);
2594173839Syongari
2595173839Syongari	return (0);
259649076Swpaul}
2597175526Syongari
2598175526Syongaristatic int
2599175526Syongarisf_resume(device_t dev)
2600175526Syongari{
2601175526Syongari	struct sf_softc		*sc;
2602175526Syongari	struct ifnet		*ifp;
2603175526Syongari
2604175526Syongari	sc = device_get_softc(dev);
2605175526Syongari
2606175526Syongari	SF_LOCK(sc);
2607175526Syongari	bus_generic_resume(dev);
2608175526Syongari	ifp = sc->sf_ifp;
2609175526Syongari	if ((ifp->if_flags & IFF_UP) != 0)
2610175526Syongari		sf_init_locked(sc);
2611175526Syongari
2612175526Syongari	sc->sf_suspended = 0;
2613175526Syongari	SF_UNLOCK(sc);
2614175526Syongari
2615175526Syongari	return (0);
2616175526Syongari}
2617175526Syongari
2618175526Syongaristatic int
2619175526Syongarisf_sysctl_stats(SYSCTL_HANDLER_ARGS)
2620175526Syongari{
2621175526Syongari	struct sf_softc		*sc;
2622175526Syongari	struct sf_stats		*stats;
2623175526Syongari	int			error;
2624175526Syongari	int			result;
2625175526Syongari
2626175526Syongari	result = -1;
2627175526Syongari	error = sysctl_handle_int(oidp, &result, 0, req);
2628175526Syongari
2629175526Syongari	if (error != 0 || req->newptr == NULL)
2630175526Syongari		return (error);
2631175526Syongari
2632175526Syongari	if (result != 1)
2633175526Syongari		return (error);
2634175526Syongari
2635175526Syongari	sc = (struct sf_softc *)arg1;
2636175526Syongari	stats = &sc->sf_statistics;
2637175526Syongari
2638175526Syongari	printf("%s statistics:\n", device_get_nameunit(sc->sf_dev));
2639175526Syongari	printf("Transmit good frames : %ju\n",
2640175526Syongari	    (uintmax_t)stats->sf_tx_frames);
2641175526Syongari	printf("Transmit good octets : %ju\n",
2642175526Syongari	    (uintmax_t)stats->sf_tx_bytes);
2643175526Syongari	printf("Transmit single collisions : %u\n",
2644175526Syongari	    stats->sf_tx_single_colls);
2645175526Syongari	printf("Transmit multiple collisions : %u\n",
2646175526Syongari	    stats->sf_tx_multi_colls);
2647175526Syongari	printf("Transmit late collisions : %u\n",
2648175526Syongari	    stats->sf_tx_late_colls);
2649175526Syongari	printf("Transmit abort due to excessive collisions : %u\n",
2650175526Syongari	    stats->sf_tx_excess_colls);
2651175526Syongari	printf("Transmit CRC errors : %u\n",
2652175526Syongari	    stats->sf_tx_crcerrs);
2653175526Syongari	printf("Transmit deferrals : %u\n",
2654175526Syongari	    stats->sf_tx_deferred);
2655175526Syongari	printf("Transmit abort due to excessive deferrals : %u\n",
2656175526Syongari	    stats->sf_tx_excess_defer);
2657175526Syongari	printf("Transmit pause control frames : %u\n",
2658175526Syongari	    stats->sf_tx_pause_frames);
2659175526Syongari	printf("Transmit control frames : %u\n",
2660175526Syongari	    stats->sf_tx_control_frames);
2661175526Syongari	printf("Transmit good multicast frames : %u\n",
2662175526Syongari	    stats->sf_tx_mcast_frames);
2663175526Syongari	printf("Transmit good broadcast frames : %u\n",
2664175526Syongari	    stats->sf_tx_bcast_frames);
2665175526Syongari	printf("Transmit frames lost due to internal transmit errors : %u\n",
2666175526Syongari	    stats->sf_tx_frames_lost);
2667175526Syongari	printf("Transmit FIFO underflows : %u\n",
2668175526Syongari	    stats->sf_tx_underruns);
2669175526Syongari	printf("Transmit GFP stalls : %u\n", stats->sf_tx_gfp_stall);
2670175526Syongari	printf("Receive good frames : %ju\n",
2671175526Syongari	    (uint64_t)stats->sf_rx_frames);
2672175526Syongari	printf("Receive good octets : %ju\n",
2673175526Syongari	    (uint64_t)stats->sf_rx_bytes);
2674175526Syongari	printf("Receive CRC errors : %u\n",
2675175526Syongari	    stats->sf_rx_crcerrs);
2676175526Syongari	printf("Receive alignment errors : %u\n",
2677175526Syongari	    stats->sf_rx_alignerrs);
2678175526Syongari	printf("Receive pause frames : %u\n",
2679175526Syongari	    stats->sf_rx_pause_frames);
2680175526Syongari	printf("Receive control frames : %u\n",
2681175526Syongari	    stats->sf_rx_control_frames);
2682175526Syongari	printf("Receive control frames with unsupported opcode : %u\n",
2683175526Syongari	    stats->sf_rx_unsup_control_frames);
2684175526Syongari	printf("Receive frames too long : %u\n",
2685175526Syongari	    stats->sf_rx_giants);
2686175526Syongari	printf("Receive frames too short : %u\n",
2687175526Syongari	    stats->sf_rx_runts);
2688175526Syongari	printf("Receive frames jabber errors : %u\n",
2689175526Syongari	    stats->sf_rx_jabbererrs);
2690175526Syongari	printf("Receive frames fragments : %u\n",
2691175526Syongari	    stats->sf_rx_fragments);
2692175526Syongari	printf("Receive packets 64 bytes : %ju\n",
2693175526Syongari	    (uint64_t)stats->sf_rx_pkts_64);
2694175526Syongari	printf("Receive packets 65 to 127 bytes : %ju\n",
2695175526Syongari	    (uint64_t)stats->sf_rx_pkts_65_127);
2696175526Syongari	printf("Receive packets 128 to 255 bytes : %ju\n",
2697175526Syongari	    (uint64_t)stats->sf_rx_pkts_128_255);
2698175526Syongari	printf("Receive packets 256 to 511 bytes : %ju\n",
2699175526Syongari	    (uint64_t)stats->sf_rx_pkts_256_511);
2700175526Syongari	printf("Receive packets 512 to 1023 bytes : %ju\n",
2701175526Syongari	    (uint64_t)stats->sf_rx_pkts_512_1023);
2702175526Syongari	printf("Receive packets 1024 to 1518 bytes : %ju\n",
2703175526Syongari	    (uint64_t)stats->sf_rx_pkts_1024_1518);
2704175526Syongari	printf("Receive frames lost due to internal receive errors : %u\n",
2705175526Syongari	    stats->sf_rx_frames_lost);
2706175526Syongari	printf("Receive GFP stalls : %u\n", stats->sf_rx_gfp_stall);
2707175526Syongari
2708175526Syongari	return (error);
2709175526Syongari}
2710175526Syongari
2711175526Syongaristatic int
2712175526Syongarisysctl_int_range(SYSCTL_HANDLER_ARGS, int low, int high)
2713175526Syongari{
2714175526Syongari	int error, value;
2715175526Syongari
2716175526Syongari	if (!arg1)
2717175526Syongari		return (EINVAL);
2718175526Syongari	value = *(int *)arg1;
2719175526Syongari	error = sysctl_handle_int(oidp, &value, 0, req);
2720175526Syongari	if (error || !req->newptr)
2721175526Syongari		return (error);
2722175526Syongari	if (value < low || value > high)
2723175526Syongari		return (EINVAL);
2724175526Syongari	*(int *)arg1 = value;
2725175526Syongari
2726175526Syongari	return (0);
2727175526Syongari}
2728175526Syongari
2729175526Syongaristatic int
2730175526Syongarisysctl_hw_sf_int_mod(SYSCTL_HANDLER_ARGS)
2731175526Syongari{
2732175526Syongari
2733175526Syongari	return (sysctl_int_range(oidp, arg1, arg2, req, SF_IM_MIN, SF_IM_MAX));
2734175526Syongari}
2735