if_sf.c revision 139825
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: head/sys/dev/sf/if_sf.c 139825 2005-01-07 02:29:27Z imp $");
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
5249076Swpaul * OS requirements. This driver makes use of type0 transmit frame
5349076Swpaul * descriptors (since BSD fragments packets across an mbuf chain)
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
6249076Swpaul * causes problems on the Alpha platform, where the packet payload
6349076Swpaul * should be longword aligned. There is no simple way around this.
6449076Swpaul *
6549076Swpaul * For receive filtering, the Starfire offers 16 perfect filter slots
6649076Swpaul * and a 512-bit hash table.
6749076Swpaul *
6849076Swpaul * The Starfire has no internal transceiver, relying instead on an
6949076Swpaul * external MII-based transceiver. Accessing registers on external
7049076Swpaul * PHYs is done through a special register map rather than with the
7149076Swpaul * usual bitbang MDIO method.
7249076Swpaul *
7349076Swpaul * Acesssing the registers on the Starfire is a little tricky. The
7449076Swpaul * Starfire has a 512K internal register space. When programmed for
7549076Swpaul * PCI memory mapped mode, the entire register space can be accessed
7649076Swpaul * directly. However in I/O space mode, only 256 bytes are directly
7749076Swpaul * mapped into PCI I/O space. The other registers can be accessed
7849076Swpaul * indirectly using the SF_INDIRECTIO_ADDR and SF_INDIRECTIO_DATA
7949076Swpaul * registers inside the 256-byte I/O window.
8049076Swpaul */
8149076Swpaul
8249076Swpaul#include <sys/param.h>
8349076Swpaul#include <sys/systm.h>
8449076Swpaul#include <sys/sockio.h>
8549076Swpaul#include <sys/mbuf.h>
8649076Swpaul#include <sys/malloc.h>
8749076Swpaul#include <sys/kernel.h>
88129878Sphk#include <sys/module.h>
8949076Swpaul#include <sys/socket.h>
9049076Swpaul
9149076Swpaul#include <net/if.h>
9249076Swpaul#include <net/if_arp.h>
9349076Swpaul#include <net/ethernet.h>
9449076Swpaul#include <net/if_dl.h>
9549076Swpaul#include <net/if_media.h>
9649076Swpaul
9749076Swpaul#include <net/bpf.h>
9849076Swpaul
9949076Swpaul#include <vm/vm.h>              /* for vtophys */
10049076Swpaul#include <vm/pmap.h>            /* for vtophys */
10149076Swpaul#include <machine/bus_pio.h>
10249076Swpaul#include <machine/bus_memio.h>
10349076Swpaul#include <machine/bus.h>
10449076Swpaul#include <machine/resource.h>
10549076Swpaul#include <sys/bus.h>
10649076Swpaul#include <sys/rman.h>
10749076Swpaul
10850675Swpaul#include <dev/mii/mii.h>
10950675Swpaul#include <dev/mii/miivar.h>
11050675Swpaul
11151089Speter/* "controller miibus0" required.  See GENERIC if you get errors here. */
11250675Swpaul#include "miibus_if.h"
11350675Swpaul
114119288Simp#include <dev/pci/pcireg.h>
115119288Simp#include <dev/pci/pcivar.h>
11649076Swpaul
11749076Swpaul#define SF_USEIOSPACE
11849076Swpaul
11949076Swpaul#include <pci/if_sfreg.h>
12049076Swpaul
121113506SmdoddMODULE_DEPEND(sf, pci, 1, 1, 1);
122113506SmdoddMODULE_DEPEND(sf, ether, 1, 1, 1);
12359758SpeterMODULE_DEPEND(sf, miibus, 1, 1, 1);
12459758Speter
12549076Swpaulstatic struct sf_type sf_devs[] = {
12649076Swpaul	{ AD_VENDORID, AD_DEVICEID_STARFIRE,
12749076Swpaul		"Adaptec AIC-6915 10/100BaseTX" },
12849076Swpaul	{ 0, 0, NULL }
12949076Swpaul};
13049076Swpaul
13192739Salfredstatic int sf_probe		(device_t);
13292739Salfredstatic int sf_attach		(device_t);
13392739Salfredstatic int sf_detach		(device_t);
13492739Salfredstatic void sf_intr		(void *);
13592739Salfredstatic void sf_stats_update	(void *);
13692739Salfredstatic void sf_rxeof		(struct sf_softc *);
13792739Salfredstatic void sf_txeof		(struct sf_softc *);
13892739Salfredstatic int sf_encap		(struct sf_softc *,
13949076Swpaul					struct sf_tx_bufdesc_type0 *,
14092739Salfred					struct mbuf *);
14192739Salfredstatic void sf_start		(struct ifnet *);
14292739Salfredstatic int sf_ioctl		(struct ifnet *, u_long, caddr_t);
14392739Salfredstatic void sf_init		(void *);
14492739Salfredstatic void sf_stop		(struct sf_softc *);
14592739Salfredstatic void sf_watchdog		(struct ifnet *);
14692739Salfredstatic void sf_shutdown		(device_t);
14792739Salfredstatic int sf_ifmedia_upd	(struct ifnet *);
14892739Salfredstatic void sf_ifmedia_sts	(struct ifnet *, struct ifmediareq *);
14992739Salfredstatic void sf_reset		(struct sf_softc *);
15092739Salfredstatic int sf_init_rx_ring	(struct sf_softc *);
15192739Salfredstatic void sf_init_tx_ring	(struct sf_softc *);
15292739Salfredstatic int sf_newbuf		(struct sf_softc *,
15349076Swpaul					struct sf_rx_bufdesc_type0 *,
15492739Salfred					struct mbuf *);
15592739Salfredstatic void sf_setmulti		(struct sf_softc *);
15692739Salfredstatic int sf_setperf		(struct sf_softc *, int, caddr_t);
15792739Salfredstatic int sf_sethash		(struct sf_softc *, caddr_t, int);
15849076Swpaul#ifdef notdef
15992739Salfredstatic int sf_setvlan		(struct sf_softc *, int, u_int32_t);
16049076Swpaul#endif
16149076Swpaul
16292739Salfredstatic u_int8_t sf_read_eeprom	(struct sf_softc *, int);
16349076Swpaul
16492739Salfredstatic int sf_miibus_readreg	(device_t, int, int);
16592739Salfredstatic int sf_miibus_writereg	(device_t, int, int, int);
16692739Salfredstatic void sf_miibus_statchg	(device_t);
167137557Sbrueffer#ifdef DEVICE_POLLING
168137557Sbruefferstatic void sf_poll		(struct ifnet *ifp, enum poll_cmd cmd,
169137557Sbrueffer				 int count);
170137557Sbruefferstatic void sf_poll_locked	(struct ifnet *ifp, enum poll_cmd cmd,
171137557Sbrueffer				 int count);
172137557Sbrueffer#endif /* DEVICE_POLLING */
17349076Swpaul
17492739Salfredstatic u_int32_t csr_read_4	(struct sf_softc *, int);
17592739Salfredstatic void csr_write_4		(struct sf_softc *, int, u_int32_t);
17692739Salfredstatic void sf_txthresh_adjust	(struct sf_softc *);
17749076Swpaul
17849076Swpaul#ifdef SF_USEIOSPACE
17949076Swpaul#define SF_RES			SYS_RES_IOPORT
18049076Swpaul#define SF_RID			SF_PCI_LOIO
18149076Swpaul#else
18249076Swpaul#define SF_RES			SYS_RES_MEMORY
18349076Swpaul#define SF_RID			SF_PCI_LOMEM
18449076Swpaul#endif
18549076Swpaul
18649076Swpaulstatic device_method_t sf_methods[] = {
18749076Swpaul	/* Device interface */
18849076Swpaul	DEVMETHOD(device_probe,		sf_probe),
18949076Swpaul	DEVMETHOD(device_attach,	sf_attach),
19049076Swpaul	DEVMETHOD(device_detach,	sf_detach),
19149076Swpaul	DEVMETHOD(device_shutdown,	sf_shutdown),
19250675Swpaul
19350675Swpaul	/* bus interface */
19450675Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
19550675Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
19650675Swpaul
19750675Swpaul	/* MII interface */
19850675Swpaul	DEVMETHOD(miibus_readreg,	sf_miibus_readreg),
19950675Swpaul	DEVMETHOD(miibus_writereg,	sf_miibus_writereg),
20050675Swpaul	DEVMETHOD(miibus_statchg,	sf_miibus_statchg),
20150675Swpaul
20249076Swpaul	{ 0, 0 }
20349076Swpaul};
20449076Swpaul
20549076Swpaulstatic driver_t sf_driver = {
20651455Swpaul	"sf",
20749076Swpaul	sf_methods,
20849076Swpaul	sizeof(struct sf_softc),
20949076Swpaul};
21049076Swpaul
21149076Swpaulstatic devclass_t sf_devclass;
21249076Swpaul
213113506SmdoddDRIVER_MODULE(sf, pci, sf_driver, sf_devclass, 0, 0);
21451473SwpaulDRIVER_MODULE(miibus, sf, miibus_driver, miibus_devclass, 0, 0);
21549076Swpaul
21649076Swpaul#define SF_SETBIT(sc, reg, x)	\
217105221Sphk	csr_write_4(sc, reg, csr_read_4(sc, reg) | (x))
21849076Swpaul
21949076Swpaul#define SF_CLRBIT(sc, reg, x)				\
220105221Sphk	csr_write_4(sc, reg, csr_read_4(sc, reg) & ~(x))
22149076Swpaul
222102335Salfredstatic u_int32_t
223102335Salfredcsr_read_4(sc, reg)
22449076Swpaul	struct sf_softc		*sc;
22549076Swpaul	int			reg;
22649076Swpaul{
22749076Swpaul	u_int32_t		val;
22849076Swpaul
22949076Swpaul#ifdef SF_USEIOSPACE
23049076Swpaul	CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE);
23149076Swpaul	val = CSR_READ_4(sc, SF_INDIRECTIO_DATA);
23249076Swpaul#else
23349076Swpaul	val = CSR_READ_4(sc, (reg + SF_RMAP_INTREG_BASE));
23449076Swpaul#endif
23549076Swpaul
23649076Swpaul	return(val);
23749076Swpaul}
23849076Swpaul
239102335Salfredstatic u_int8_t
240102335Salfredsf_read_eeprom(sc, reg)
24149076Swpaul	struct sf_softc		*sc;
24249076Swpaul	int			reg;
24349076Swpaul{
24449076Swpaul	u_int8_t		val;
24549076Swpaul
24649076Swpaul	val = (csr_read_4(sc, SF_EEADDR_BASE +
24749076Swpaul	    (reg & 0xFFFFFFFC)) >> (8 * (reg & 3))) & 0xFF;
24849076Swpaul
24949076Swpaul	return(val);
25049076Swpaul}
25149076Swpaul
252102335Salfredstatic void
253102335Salfredcsr_write_4(sc, reg, val)
25449076Swpaul	struct sf_softc		*sc;
25549076Swpaul	int			reg;
25649076Swpaul	u_int32_t		val;
25749076Swpaul{
25849076Swpaul#ifdef SF_USEIOSPACE
25949076Swpaul	CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE);
26049076Swpaul	CSR_WRITE_4(sc, SF_INDIRECTIO_DATA, val);
26149076Swpaul#else
26249076Swpaul	CSR_WRITE_4(sc, (reg + SF_RMAP_INTREG_BASE), val);
26349076Swpaul#endif
26449076Swpaul}
26549076Swpaul
26649076Swpaul/*
26749076Swpaul * Copy the address 'mac' into the perfect RX filter entry at
26849076Swpaul * offset 'idx.' The perfect filter only has 16 entries so do
26949076Swpaul * some sanity tests.
27049076Swpaul */
271102335Salfredstatic int
272102335Salfredsf_setperf(sc, idx, mac)
27349076Swpaul	struct sf_softc		*sc;
27449076Swpaul	int			idx;
27549076Swpaul	caddr_t			mac;
27649076Swpaul{
27749076Swpaul	u_int16_t		*p;
27849076Swpaul
27949076Swpaul	if (idx < 0 || idx > SF_RXFILT_PERFECT_CNT)
28049076Swpaul		return(EINVAL);
28149076Swpaul
28249076Swpaul	if (mac == NULL)
28349076Swpaul		return(EINVAL);
28449076Swpaul
28549076Swpaul	p = (u_int16_t *)mac;
28649076Swpaul
28749076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
28849076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP), htons(p[2]));
28949076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
29049076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP) + 4, htons(p[1]));
29149076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
29249076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP) + 8, htons(p[0]));
29349076Swpaul
29449076Swpaul	return(0);
29549076Swpaul}
29649076Swpaul
29749076Swpaul/*
29849076Swpaul * Set the bit in the 512-bit hash table that corresponds to the
29949076Swpaul * specified mac address 'mac.' If 'prio' is nonzero, update the
30049076Swpaul * priority hash table instead of the filter hash table.
30149076Swpaul */
302102335Salfredstatic int
303102335Salfredsf_sethash(sc, mac, prio)
30449076Swpaul	struct sf_softc		*sc;
30549076Swpaul	caddr_t			mac;
30649076Swpaul	int			prio;
30749076Swpaul{
308130270Snaddy	u_int32_t		h;
30949076Swpaul
31049076Swpaul	if (mac == NULL)
31149076Swpaul		return(EINVAL);
31249076Swpaul
313130270Snaddy	h = ether_crc32_be(mac, ETHER_ADDR_LEN) >> 23;
31449076Swpaul
31549076Swpaul	if (prio) {
31649076Swpaul		SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_PRIOOFF +
31749076Swpaul		    (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF)));
31849076Swpaul	} else {
31949076Swpaul		SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_ADDROFF +
32049076Swpaul		    (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF)));
32149076Swpaul	}
32249076Swpaul
32349076Swpaul	return(0);
32449076Swpaul}
32549076Swpaul
32649076Swpaul#ifdef notdef
32749076Swpaul/*
32849076Swpaul * Set a VLAN tag in the receive filter.
32949076Swpaul */
330102335Salfredstatic int
331102335Salfredsf_setvlan(sc, idx, vlan)
33249076Swpaul	struct sf_softc		*sc;
33349076Swpaul	int			idx;
33449076Swpaul	u_int32_t		vlan;
33549076Swpaul{
33649076Swpaul	if (idx < 0 || idx >> SF_RXFILT_HASH_CNT)
33749076Swpaul		return(EINVAL);
33849076Swpaul
33949076Swpaul	csr_write_4(sc, SF_RXFILT_HASH_BASE +
34049076Swpaul	    (idx * SF_RXFILT_HASH_SKIP) + SF_RXFILT_HASH_VLANOFF, vlan);
34149076Swpaul
34249076Swpaul	return(0);
34349076Swpaul}
34449076Swpaul#endif
34549076Swpaul
346102335Salfredstatic int
347102335Salfredsf_miibus_readreg(dev, phy, reg)
34850675Swpaul	device_t		dev;
34950675Swpaul	int			phy, reg;
35050675Swpaul{
35149076Swpaul	struct sf_softc		*sc;
35249076Swpaul	int			i;
35349076Swpaul	u_int32_t		val = 0;
35449076Swpaul
35550675Swpaul	sc = device_get_softc(dev);
35650675Swpaul
35749076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
35850675Swpaul		val = csr_read_4(sc, SF_PHY_REG(phy, reg));
35949076Swpaul		if (val & SF_MII_DATAVALID)
36049076Swpaul			break;
36149076Swpaul	}
36249076Swpaul
36349076Swpaul	if (i == SF_TIMEOUT)
36449076Swpaul		return(0);
36549076Swpaul
36649076Swpaul	if ((val & 0x0000FFFF) == 0xFFFF)
36749076Swpaul		return(0);
36849076Swpaul
36949076Swpaul	return(val & 0x0000FFFF);
37049076Swpaul}
37149076Swpaul
372102335Salfredstatic int
373102335Salfredsf_miibus_writereg(dev, phy, reg, val)
37450675Swpaul	device_t		dev;
37550675Swpaul	int			phy, reg, val;
37650675Swpaul{
37749076Swpaul	struct sf_softc		*sc;
37849076Swpaul	int			i;
37949076Swpaul	int			busy;
38049076Swpaul
38150675Swpaul	sc = device_get_softc(dev);
38249076Swpaul
38350675Swpaul	csr_write_4(sc, SF_PHY_REG(phy, reg), val);
38450675Swpaul
38549076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
38650675Swpaul		busy = csr_read_4(sc, SF_PHY_REG(phy, reg));
38749076Swpaul		if (!(busy & SF_MII_BUSY))
38849076Swpaul			break;
38949076Swpaul	}
39049076Swpaul
39150675Swpaul	return(0);
39250675Swpaul}
39350675Swpaul
394102335Salfredstatic void
395102335Salfredsf_miibus_statchg(dev)
39650675Swpaul	device_t		dev;
39750675Swpaul{
39850675Swpaul	struct sf_softc		*sc;
39950675Swpaul	struct mii_data		*mii;
40050675Swpaul
40150675Swpaul	sc = device_get_softc(dev);
40250675Swpaul	mii = device_get_softc(sc->sf_miibus);
40350675Swpaul
40450675Swpaul	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
40550675Swpaul		SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX);
40654161Swpaul		csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_FDX);
40750675Swpaul	} else {
40850675Swpaul		SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX);
40954161Swpaul		csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_HDX);
41050675Swpaul	}
41149076Swpaul}
41249076Swpaul
413102335Salfredstatic void
414102335Salfredsf_setmulti(sc)
41549076Swpaul	struct sf_softc		*sc;
41649076Swpaul{
41749076Swpaul	struct ifnet		*ifp;
41849076Swpaul	int			i;
41949076Swpaul	struct ifmultiaddr	*ifma;
42049076Swpaul	u_int8_t		dummy[] = { 0, 0, 0, 0, 0, 0 };
42149076Swpaul
42249076Swpaul	ifp = &sc->arpcom.ac_if;
42349076Swpaul
42449076Swpaul	/* First zot all the existing filters. */
42549076Swpaul	for (i = 1; i < SF_RXFILT_PERFECT_CNT; i++)
42649076Swpaul		sf_setperf(sc, i, (char *)&dummy);
42749076Swpaul	for (i = SF_RXFILT_HASH_BASE;
42849076Swpaul	    i < (SF_RXFILT_HASH_MAX + 1); i += 4)
42949076Swpaul		csr_write_4(sc, i, 0);
43049076Swpaul	SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_ALLMULTI);
43149076Swpaul
43249076Swpaul	/* Now program new ones. */
43349076Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
43449076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_ALLMULTI);
43549076Swpaul	} else {
43649076Swpaul		i = 1;
43772084Sphk		TAILQ_FOREACH_REVERSE(ifma, &ifp->if_multiaddrs, ifmultihead, ifma_link) {
43849076Swpaul			if (ifma->ifma_addr->sa_family != AF_LINK)
43949076Swpaul				continue;
44049076Swpaul			/*
44149076Swpaul			 * Program the first 15 multicast groups
44249076Swpaul			 * into the perfect filter. For all others,
44349076Swpaul			 * use the hash table.
44449076Swpaul			 */
44549076Swpaul			if (i < SF_RXFILT_PERFECT_CNT) {
44649076Swpaul				sf_setperf(sc, i,
44749076Swpaul			LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
44849076Swpaul				i++;
44949076Swpaul				continue;
45049076Swpaul			}
45149076Swpaul
45249076Swpaul			sf_sethash(sc,
45349076Swpaul			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 0);
45449076Swpaul		}
45549076Swpaul	}
45649076Swpaul}
45749076Swpaul
45849076Swpaul/*
45949076Swpaul * Set media options.
46049076Swpaul */
461102335Salfredstatic int
462102335Salfredsf_ifmedia_upd(ifp)
46349076Swpaul	struct ifnet		*ifp;
46449076Swpaul{
46549076Swpaul	struct sf_softc		*sc;
46650675Swpaul	struct mii_data		*mii;
46749076Swpaul
46849076Swpaul	sc = ifp->if_softc;
46950675Swpaul	mii = device_get_softc(sc->sf_miibus);
47054161Swpaul	sc->sf_link = 0;
47154161Swpaul	if (mii->mii_instance) {
47254161Swpaul		struct mii_softc        *miisc;
47372012Sphk		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
47454161Swpaul			mii_phy_reset(miisc);
47554161Swpaul	}
47650675Swpaul	mii_mediachg(mii);
47749076Swpaul
47849076Swpaul	return(0);
47949076Swpaul}
48049076Swpaul
48149076Swpaul/*
48249076Swpaul * Report current media status.
48349076Swpaul */
484102335Salfredstatic void
485102335Salfredsf_ifmedia_sts(ifp, ifmr)
48649076Swpaul	struct ifnet		*ifp;
48749076Swpaul	struct ifmediareq	*ifmr;
48849076Swpaul{
48949076Swpaul	struct sf_softc		*sc;
49050675Swpaul	struct mii_data		*mii;
49149076Swpaul
49249076Swpaul	sc = ifp->if_softc;
49350675Swpaul	mii = device_get_softc(sc->sf_miibus);
49449076Swpaul
49550675Swpaul	mii_pollstat(mii);
49650675Swpaul	ifmr->ifm_active = mii->mii_media_active;
49750675Swpaul	ifmr->ifm_status = mii->mii_media_status;
49849076Swpaul}
49949076Swpaul
500102335Salfredstatic int
501102335Salfredsf_ioctl(ifp, command, data)
50249076Swpaul	struct ifnet		*ifp;
50349076Swpaul	u_long			command;
50449076Swpaul	caddr_t			data;
50549076Swpaul{
50649076Swpaul	struct sf_softc		*sc = ifp->if_softc;
50749076Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
50850675Swpaul	struct mii_data		*mii;
50967087Swpaul	int			error = 0;
51049076Swpaul
51167087Swpaul	SF_LOCK(sc);
51249076Swpaul
51349076Swpaul	switch(command) {
51449076Swpaul	case SIOCSIFFLAGS:
51549076Swpaul		if (ifp->if_flags & IFF_UP) {
51654161Swpaul			if (ifp->if_flags & IFF_RUNNING &&
51754161Swpaul			    ifp->if_flags & IFF_PROMISC &&
51854161Swpaul			    !(sc->sf_if_flags & IFF_PROMISC)) {
51954161Swpaul				SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
52054161Swpaul			} else if (ifp->if_flags & IFF_RUNNING &&
52154161Swpaul			    !(ifp->if_flags & IFF_PROMISC) &&
52254161Swpaul			    sc->sf_if_flags & IFF_PROMISC) {
52354161Swpaul				SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
52454161Swpaul			} else if (!(ifp->if_flags & IFF_RUNNING))
52554161Swpaul				sf_init(sc);
52649076Swpaul		} else {
52749076Swpaul			if (ifp->if_flags & IFF_RUNNING)
52849076Swpaul				sf_stop(sc);
52949076Swpaul		}
53054161Swpaul		sc->sf_if_flags = ifp->if_flags;
53149076Swpaul		error = 0;
53249076Swpaul		break;
53349076Swpaul	case SIOCADDMULTI:
53449076Swpaul	case SIOCDELMULTI:
53549076Swpaul		sf_setmulti(sc);
53649076Swpaul		error = 0;
53749076Swpaul		break;
53849076Swpaul	case SIOCGIFMEDIA:
53949076Swpaul	case SIOCSIFMEDIA:
54050675Swpaul		mii = device_get_softc(sc->sf_miibus);
54150675Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
54249076Swpaul		break;
543137557Sbrueffer	case SIOCSIFCAP:
544137557Sbrueffer		ifp->if_capenable &= ~IFCAP_POLLING;
545137557Sbrueffer		ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING;
546137557Sbrueffer		break;
54749076Swpaul	default:
548106936Ssam		error = ether_ioctl(ifp, command, data);
54949076Swpaul		break;
55049076Swpaul	}
55149076Swpaul
55267087Swpaul	SF_UNLOCK(sc);
55349076Swpaul
55449076Swpaul	return(error);
55549076Swpaul}
55649076Swpaul
557102335Salfredstatic void
558102335Salfredsf_reset(sc)
55949076Swpaul	struct sf_softc		*sc;
56049076Swpaul{
56149076Swpaul	register int		i;
56249076Swpaul
56349076Swpaul	csr_write_4(sc, SF_GEN_ETH_CTL, 0);
56449076Swpaul	SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
56549076Swpaul	DELAY(1000);
56649076Swpaul	SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
56749076Swpaul
56849076Swpaul	SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_RESET);
56949076Swpaul
57049076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
57149076Swpaul		DELAY(10);
57249076Swpaul		if (!(csr_read_4(sc, SF_PCI_DEVCFG) & SF_PCIDEVCFG_RESET))
57349076Swpaul			break;
57449076Swpaul	}
57549076Swpaul
57649076Swpaul	if (i == SF_TIMEOUT)
57749076Swpaul		printf("sf%d: reset never completed!\n", sc->sf_unit);
57849076Swpaul
57949076Swpaul	/* Wait a little while for the chip to get its brains in order. */
58049076Swpaul	DELAY(1000);
58149076Swpaul}
58249076Swpaul
58349076Swpaul/*
58449076Swpaul * Probe for an Adaptec AIC-6915 chip. Check the PCI vendor and device
58549076Swpaul * IDs against our list and return a device name if we find a match.
58649076Swpaul * We also check the subsystem ID so that we can identify exactly which
58749076Swpaul * NIC has been found, if possible.
58849076Swpaul */
589102335Salfredstatic int
590102335Salfredsf_probe(dev)
59149076Swpaul	device_t		dev;
59249076Swpaul{
59349076Swpaul	struct sf_type		*t;
59449076Swpaul
59549076Swpaul	t = sf_devs;
59649076Swpaul
59749076Swpaul	while(t->sf_name != NULL) {
59849076Swpaul		if ((pci_get_vendor(dev) == t->sf_vid) &&
59949076Swpaul		    (pci_get_device(dev) == t->sf_did)) {
60051336Swpaul			switch((pci_read_config(dev,
60151336Swpaul			    SF_PCI_SUBVEN_ID, 4) >> 16) & 0xFFFF) {
60249076Swpaul			case AD_SUBSYSID_62011_REV0:
60349076Swpaul			case AD_SUBSYSID_62011_REV1:
60449076Swpaul				device_set_desc(dev,
60549076Swpaul				    "Adaptec ANA-62011 10/100BaseTX");
60649076Swpaul				return(0);
60749076Swpaul			case AD_SUBSYSID_62022:
60849076Swpaul				device_set_desc(dev,
60949076Swpaul				    "Adaptec ANA-62022 10/100BaseTX");
61049076Swpaul				return(0);
61153468Swpaul			case AD_SUBSYSID_62044_REV0:
61253468Swpaul			case AD_SUBSYSID_62044_REV1:
61349076Swpaul				device_set_desc(dev,
61449076Swpaul				    "Adaptec ANA-62044 10/100BaseTX");
61549076Swpaul				return(0);
61649076Swpaul			case AD_SUBSYSID_62020:
61749076Swpaul				device_set_desc(dev,
61849076Swpaul				    "Adaptec ANA-62020 10/100BaseFX");
61949076Swpaul				return(0);
62049076Swpaul			case AD_SUBSYSID_69011:
62149076Swpaul				device_set_desc(dev,
62249076Swpaul				    "Adaptec ANA-69011 10/100BaseTX");
62349076Swpaul				return(0);
62449076Swpaul			default:
62549076Swpaul				device_set_desc(dev, t->sf_name);
62649076Swpaul				return(0);
62749076Swpaul				break;
62849076Swpaul			}
62949076Swpaul		}
63049076Swpaul		t++;
63149076Swpaul	}
63249076Swpaul
63349076Swpaul	return(ENXIO);
63449076Swpaul}
63549076Swpaul
63649076Swpaul/*
63749076Swpaul * Attach the interface. Allocate softc structures, do ifmedia
63849076Swpaul * setup and ethernet/BPF attach.
63949076Swpaul */
640102335Salfredstatic int
641102335Salfredsf_attach(dev)
64249076Swpaul	device_t		dev;
64349076Swpaul{
64467087Swpaul	int			i;
64549076Swpaul	struct sf_softc		*sc;
64649076Swpaul	struct ifnet		*ifp;
64749076Swpaul	int			unit, rid, error = 0;
64849076Swpaul
64949076Swpaul	sc = device_get_softc(dev);
65049076Swpaul	unit = device_get_unit(dev);
65149076Swpaul
65293818Sjhb	mtx_init(&sc->sf_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
65393818Sjhb	    MTX_DEF | MTX_RECURSE);
65449076Swpaul	/*
65549076Swpaul	 * Map control/status registers.
65649076Swpaul	 */
65772813Swpaul	pci_enable_busmaster(dev);
65849076Swpaul
65949076Swpaul	rid = SF_RID;
660127135Snjl	sc->sf_res = bus_alloc_resource_any(dev, SF_RES, &rid, RF_ACTIVE);
66149076Swpaul
66249076Swpaul	if (sc->sf_res == NULL) {
66349076Swpaul		printf ("sf%d: couldn't map ports\n", unit);
66449076Swpaul		error = ENXIO;
66549076Swpaul		goto fail;
66649076Swpaul	}
66749076Swpaul
66849076Swpaul	sc->sf_btag = rman_get_bustag(sc->sf_res);
66949076Swpaul	sc->sf_bhandle = rman_get_bushandle(sc->sf_res);
67049076Swpaul
67149076Swpaul	/* Allocate interrupt */
67249076Swpaul	rid = 0;
673127135Snjl	sc->sf_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
67449076Swpaul	    RF_SHAREABLE | RF_ACTIVE);
67549076Swpaul
67649076Swpaul	if (sc->sf_irq == NULL) {
67749076Swpaul		printf("sf%d: couldn't map interrupt\n", unit);
67849076Swpaul		error = ENXIO;
67949076Swpaul		goto fail;
68049076Swpaul	}
68149076Swpaul
68249076Swpaul	callout_handle_init(&sc->sf_stat_ch);
68349076Swpaul	/* Reset the adapter. */
68449076Swpaul	sf_reset(sc);
68549076Swpaul
68649076Swpaul	/*
68749076Swpaul	 * Get station address from the EEPROM.
68849076Swpaul	 */
68949076Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
69049076Swpaul		sc->arpcom.ac_enaddr[i] =
69149076Swpaul		    sf_read_eeprom(sc, SF_EE_NODEADDR + ETHER_ADDR_LEN - i);
69249076Swpaul
69349076Swpaul	sc->sf_unit = unit;
69449076Swpaul
69549076Swpaul	/* Allocate the descriptor queues. */
69649076Swpaul	sc->sf_ldata = contigmalloc(sizeof(struct sf_list_data), M_DEVBUF,
69751657Swpaul	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
69849076Swpaul
69949076Swpaul	if (sc->sf_ldata == NULL) {
70049076Swpaul		printf("sf%d: no memory for list buffers!\n", unit);
70149076Swpaul		error = ENXIO;
70249076Swpaul		goto fail;
70349076Swpaul	}
70449076Swpaul
70549076Swpaul	bzero(sc->sf_ldata, sizeof(struct sf_list_data));
70649076Swpaul
70750675Swpaul	/* Do MII setup. */
70850675Swpaul	if (mii_phy_probe(dev, &sc->sf_miibus,
70950675Swpaul	    sf_ifmedia_upd, sf_ifmedia_sts)) {
71049076Swpaul		printf("sf%d: MII without any phy!\n", sc->sf_unit);
71149076Swpaul		error = ENXIO;
71249076Swpaul		goto fail;
71349076Swpaul	}
71449076Swpaul
71549076Swpaul	ifp = &sc->arpcom.ac_if;
71649076Swpaul	ifp->if_softc = sc;
717121816Sbrooks	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
71849076Swpaul	ifp->if_mtu = ETHERMTU;
719134442Srwatson	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST |
720134442Srwatson	    IFF_NEEDSGIANT;
72149076Swpaul	ifp->if_ioctl = sf_ioctl;
72249076Swpaul	ifp->if_start = sf_start;
72349076Swpaul	ifp->if_watchdog = sf_watchdog;
72449076Swpaul	ifp->if_init = sf_init;
72549076Swpaul	ifp->if_baudrate = 10000000;
726137620Sbrueffer	IFQ_SET_MAXLEN(&ifp->if_snd, SF_TX_DLIST_CNT - 1);
727137620Sbrueffer	ifp->if_snd.ifq_drv_maxlen = SF_TX_DLIST_CNT - 1;
728137620Sbrueffer	IFQ_SET_READY(&ifp->if_snd);
729137557Sbrueffer#ifdef DEVICE_POLLING
730137557Sbrueffer	ifp->if_capabilities |= IFCAP_POLLING;
731137557Sbrueffer#endif /* DEVICE_POLLING */
732137557Sbrueffer	ifp->if_capenable = ifp->if_capabilities;
73349076Swpaul
73449076Swpaul	/*
73563090Sarchie	 * Call MI attach routine.
73649076Swpaul	 */
737106936Ssam	ether_ifattach(ifp, sc->arpcom.ac_enaddr);
73849076Swpaul
739113609Snjl	/* Hook interrupt last to avoid having to lock softc */
740112872Snjl	error = bus_setup_intr(dev, sc->sf_irq, INTR_TYPE_NET,
741112872Snjl	    sf_intr, sc, &sc->sf_intrhand);
742112872Snjl
743112872Snjl	if (error) {
744112872Snjl		printf("sf%d: couldn't set up irq\n", unit);
745113609Snjl		ether_ifdetach(ifp);
746112872Snjl		goto fail;
747112872Snjl	}
748112872Snjl
74949076Swpaulfail:
750112872Snjl	if (error)
751112872Snjl		sf_detach(dev);
752112872Snjl
75349076Swpaul	return(error);
75449076Swpaul}
75549076Swpaul
756113609Snjl/*
757113609Snjl * Shutdown hardware and free up resources. This can be called any
758113609Snjl * time after the mutex has been initialized. It is called in both
759113609Snjl * the error case in attach and the normal detach case so it needs
760113609Snjl * to be careful about only freeing resources that have actually been
761113609Snjl * allocated.
762113609Snjl */
763102335Salfredstatic int
764102335Salfredsf_detach(dev)
76549076Swpaul	device_t		dev;
76649076Swpaul{
76749076Swpaul	struct sf_softc		*sc;
76849076Swpaul	struct ifnet		*ifp;
76949076Swpaul
77049076Swpaul	sc = device_get_softc(dev);
771112880Sjhb	KASSERT(mtx_initialized(&sc->sf_mtx), ("sf mutex not initialized"));
77267087Swpaul	SF_LOCK(sc);
77349076Swpaul	ifp = &sc->arpcom.ac_if;
77449076Swpaul
775113609Snjl	/* These should only be active if attach succeeded */
776113812Simp	if (device_is_attached(dev)) {
777113609Snjl		sf_stop(sc);
778112872Snjl		ether_ifdetach(ifp);
779113609Snjl	}
780113609Snjl	if (sc->sf_miibus)
781112872Snjl		device_delete_child(dev, sc->sf_miibus);
782113609Snjl	bus_generic_detach(dev);
78349076Swpaul
784112872Snjl	if (sc->sf_intrhand)
785112872Snjl		bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
786112872Snjl	if (sc->sf_irq)
787112872Snjl		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
788112872Snjl	if (sc->sf_res)
789112872Snjl		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
79050675Swpaul
791112872Snjl	if (sc->sf_ldata)
792112872Snjl		contigfree(sc->sf_ldata, sizeof(struct sf_list_data), M_DEVBUF);
79349076Swpaul
79467087Swpaul	SF_UNLOCK(sc);
79567087Swpaul	mtx_destroy(&sc->sf_mtx);
79649076Swpaul
79749076Swpaul	return(0);
79849076Swpaul}
79949076Swpaul
800102335Salfredstatic int
801102335Salfredsf_init_rx_ring(sc)
80249076Swpaul	struct sf_softc		*sc;
80349076Swpaul{
80449076Swpaul	struct sf_list_data	*ld;
80549076Swpaul	int			i;
80649076Swpaul
80749076Swpaul	ld = sc->sf_ldata;
80849076Swpaul
80949076Swpaul	bzero((char *)ld->sf_rx_dlist_big,
81049076Swpaul	    sizeof(struct sf_rx_bufdesc_type0) * SF_RX_DLIST_CNT);
81149076Swpaul	bzero((char *)ld->sf_rx_clist,
81249076Swpaul	    sizeof(struct sf_rx_cmpdesc_type3) * SF_RX_CLIST_CNT);
81349076Swpaul
81449076Swpaul	for (i = 0; i < SF_RX_DLIST_CNT; i++) {
81549076Swpaul		if (sf_newbuf(sc, &ld->sf_rx_dlist_big[i], NULL) == ENOBUFS)
81649076Swpaul			return(ENOBUFS);
81749076Swpaul	}
81849076Swpaul
81949076Swpaul	return(0);
82049076Swpaul}
82149076Swpaul
822102335Salfredstatic void
823102335Salfredsf_init_tx_ring(sc)
82449076Swpaul	struct sf_softc		*sc;
82549076Swpaul{
82649076Swpaul	struct sf_list_data	*ld;
82749076Swpaul	int			i;
82849076Swpaul
82949076Swpaul	ld = sc->sf_ldata;
83049076Swpaul
83149076Swpaul	bzero((char *)ld->sf_tx_dlist,
83249076Swpaul	    sizeof(struct sf_tx_bufdesc_type0) * SF_TX_DLIST_CNT);
83349076Swpaul	bzero((char *)ld->sf_tx_clist,
83449076Swpaul	    sizeof(struct sf_tx_cmpdesc_type0) * SF_TX_CLIST_CNT);
83549076Swpaul
83649076Swpaul	for (i = 0; i < SF_TX_DLIST_CNT; i++)
83749076Swpaul		ld->sf_tx_dlist[i].sf_id = SF_TX_BUFDESC_ID;
83849076Swpaul	for (i = 0; i < SF_TX_CLIST_CNT; i++)
83949076Swpaul		ld->sf_tx_clist[i].sf_type = SF_TXCMPTYPE_TX;
84049076Swpaul
84149076Swpaul	ld->sf_tx_dlist[SF_TX_DLIST_CNT - 1].sf_end = 1;
84249076Swpaul	sc->sf_tx_cnt = 0;
84349076Swpaul}
84449076Swpaul
845102335Salfredstatic int
846102335Salfredsf_newbuf(sc, c, m)
84749076Swpaul	struct sf_softc		*sc;
84849076Swpaul	struct sf_rx_bufdesc_type0	*c;
84949076Swpaul	struct mbuf		*m;
85049076Swpaul{
85149076Swpaul	struct mbuf		*m_new = NULL;
85249076Swpaul
85349076Swpaul	if (m == NULL) {
854111119Simp		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
85587846Sluigi		if (m_new == NULL)
85649076Swpaul			return(ENOBUFS);
85749076Swpaul
858111119Simp		MCLGET(m_new, M_DONTWAIT);
85949076Swpaul		if (!(m_new->m_flags & M_EXT)) {
86049076Swpaul			m_freem(m_new);
86149076Swpaul			return(ENOBUFS);
86249076Swpaul		}
86349076Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
86449076Swpaul	} else {
86549076Swpaul		m_new = m;
86649076Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
86749076Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
86849076Swpaul	}
86949076Swpaul
87049076Swpaul	m_adj(m_new, sizeof(u_int64_t));
87149076Swpaul
87249076Swpaul	c->sf_mbuf = m_new;
87349076Swpaul	c->sf_addrlo = SF_RX_HOSTADDR(vtophys(mtod(m_new, caddr_t)));
87449076Swpaul	c->sf_valid = 1;
87549076Swpaul
87649076Swpaul	return(0);
87749076Swpaul}
87849076Swpaul
87949076Swpaul/*
88049076Swpaul * The starfire is programmed to use 'normal' mode for packet reception,
88149076Swpaul * which means we use the consumer/producer model for both the buffer
88249076Swpaul * descriptor queue and the completion descriptor queue. The only problem
88349076Swpaul * with this is that it involves a lot of register accesses: we have to
88449076Swpaul * read the RX completion consumer and producer indexes and the RX buffer
88549076Swpaul * producer index, plus the RX completion consumer and RX buffer producer
88649076Swpaul * indexes have to be updated. It would have been easier if Adaptec had
88749076Swpaul * put each index in a separate register, especially given that the damn
88849076Swpaul * NIC has a 512K register space.
88949076Swpaul *
89049076Swpaul * In spite of all the lovely features that Adaptec crammed into the 6915,
89149076Swpaul * it is marred by one truly stupid design flaw, which is that receive
89249076Swpaul * buffer addresses must be aligned on a longword boundary. This forces
89349076Swpaul * the packet payload to be unaligned, which is suboptimal on the x86 and
89449076Swpaul * completely unuseable on the Alpha. Our only recourse is to copy received
89549076Swpaul * packets into properly aligned buffers before handing them off.
89649076Swpaul */
89749076Swpaul
898102335Salfredstatic void
899102335Salfredsf_rxeof(sc)
90049076Swpaul	struct sf_softc		*sc;
90149076Swpaul{
90249076Swpaul	struct mbuf		*m;
90349076Swpaul	struct ifnet		*ifp;
90449076Swpaul	struct sf_rx_bufdesc_type0	*desc;
90549076Swpaul	struct sf_rx_cmpdesc_type3	*cur_rx;
90649076Swpaul	u_int32_t		rxcons, rxprod;
90749076Swpaul	int			cmpprodidx, cmpconsidx, bufprodidx;
90849076Swpaul
909122689Ssam	SF_LOCK_ASSERT(sc);
910122689Ssam
91149076Swpaul	ifp = &sc->arpcom.ac_if;
91249076Swpaul
91349076Swpaul	rxcons = csr_read_4(sc, SF_CQ_CONSIDX);
91449076Swpaul	rxprod = csr_read_4(sc, SF_RXDQ_PTR_Q1);
91549076Swpaul	cmpprodidx = SF_IDX_LO(csr_read_4(sc, SF_CQ_PRODIDX));
91649076Swpaul	cmpconsidx = SF_IDX_LO(rxcons);
91749076Swpaul	bufprodidx = SF_IDX_LO(rxprod);
91849076Swpaul
91949076Swpaul	while (cmpconsidx != cmpprodidx) {
92049076Swpaul		struct mbuf		*m0;
92149076Swpaul
922137557Sbrueffer#ifdef DEVICE_POLLING
923137557Sbrueffer		if (ifp->if_flags & IFF_POLLING) {
924137557Sbrueffer			if (sc->rxcycles <= 0)
925137557Sbrueffer				break;
926137557Sbrueffer			sc->rxcycles--;
927137557Sbrueffer		}
928137557Sbrueffer#endif /* DEVICE_POLLING */
929137557Sbrueffer
93049076Swpaul		cur_rx = &sc->sf_ldata->sf_rx_clist[cmpconsidx];
93149076Swpaul		desc = &sc->sf_ldata->sf_rx_dlist_big[cur_rx->sf_endidx];
93249076Swpaul		m = desc->sf_mbuf;
93349076Swpaul		SF_INC(cmpconsidx, SF_RX_CLIST_CNT);
93449076Swpaul		SF_INC(bufprodidx, SF_RX_DLIST_CNT);
93549076Swpaul
93649076Swpaul		if (!(cur_rx->sf_status1 & SF_RXSTAT1_OK)) {
93749076Swpaul			ifp->if_ierrors++;
93849076Swpaul			sf_newbuf(sc, desc, m);
93949076Swpaul			continue;
94049076Swpaul		}
94149076Swpaul
94278508Sbmilekic		m0 = m_devget(mtod(m, char *), cur_rx->sf_len, ETHER_ALIGN,
94378508Sbmilekic		    ifp, NULL);
94449076Swpaul		sf_newbuf(sc, desc, m);
94549076Swpaul		if (m0 == NULL) {
94649076Swpaul			ifp->if_ierrors++;
94749076Swpaul			continue;
94849076Swpaul		}
94949076Swpaul		m = m0;
95049076Swpaul
95149076Swpaul		ifp->if_ipackets++;
952122689Ssam		SF_UNLOCK(sc);
953106936Ssam		(*ifp->if_input)(ifp, m);
954122689Ssam		SF_LOCK(sc);
95549076Swpaul	}
95649076Swpaul
95749076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX,
95849076Swpaul	    (rxcons & ~SF_CQ_CONSIDX_RXQ1) | cmpconsidx);
95949076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1,
96049076Swpaul	    (rxprod & ~SF_RXDQ_PRODIDX) | bufprodidx);
96149076Swpaul}
96249076Swpaul
96349076Swpaul/*
96449076Swpaul * Read the transmit status from the completion queue and release
96549076Swpaul * mbufs. Note that the buffer descriptor index in the completion
96649076Swpaul * descriptor is an offset from the start of the transmit buffer
96749076Swpaul * descriptor list in bytes. This is important because the manual
96849076Swpaul * gives the impression that it should match the producer/consumer
96949076Swpaul * index, which is the offset in 8 byte blocks.
97049076Swpaul */
971102335Salfredstatic void
972102335Salfredsf_txeof(sc)
97349076Swpaul	struct sf_softc		*sc;
97449076Swpaul{
97549076Swpaul	int			txcons, cmpprodidx, cmpconsidx;
97649076Swpaul	struct sf_tx_cmpdesc_type1 *cur_cmp;
97749076Swpaul	struct sf_tx_bufdesc_type0 *cur_tx;
97849076Swpaul	struct ifnet		*ifp;
97949076Swpaul
98049076Swpaul	ifp = &sc->arpcom.ac_if;
98149076Swpaul
98249076Swpaul	txcons = csr_read_4(sc, SF_CQ_CONSIDX);
98349076Swpaul	cmpprodidx = SF_IDX_HI(csr_read_4(sc, SF_CQ_PRODIDX));
98449076Swpaul	cmpconsidx = SF_IDX_HI(txcons);
98549076Swpaul
98649076Swpaul	while (cmpconsidx != cmpprodidx) {
98749076Swpaul		cur_cmp = &sc->sf_ldata->sf_tx_clist[cmpconsidx];
98849076Swpaul		cur_tx = &sc->sf_ldata->sf_tx_dlist[cur_cmp->sf_index >> 7];
98949076Swpaul
99049076Swpaul		if (cur_cmp->sf_txstat & SF_TXSTAT_TX_OK)
99149076Swpaul			ifp->if_opackets++;
99281737Swpaul		else {
99381737Swpaul			if (cur_cmp->sf_txstat & SF_TXSTAT_TX_UNDERRUN)
99481737Swpaul				sf_txthresh_adjust(sc);
99549076Swpaul			ifp->if_oerrors++;
99681737Swpaul		}
99749076Swpaul
99849076Swpaul		sc->sf_tx_cnt--;
99949076Swpaul		if (cur_tx->sf_mbuf != NULL) {
100049076Swpaul			m_freem(cur_tx->sf_mbuf);
100149076Swpaul			cur_tx->sf_mbuf = NULL;
100281737Swpaul		} else
100381737Swpaul			break;
100481737Swpaul		SF_INC(cmpconsidx, SF_TX_CLIST_CNT);
100549076Swpaul	}
100649076Swpaul
100749076Swpaul	ifp->if_timer = 0;
100849076Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
100949076Swpaul
101049076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX,
101149076Swpaul	    (txcons & ~SF_CQ_CONSIDX_TXQ) |
101249076Swpaul	    ((cmpconsidx << 16) & 0xFFFF0000));
101349076Swpaul}
101449076Swpaul
1015102335Salfredstatic void
1016102335Salfredsf_txthresh_adjust(sc)
101781737Swpaul	struct sf_softc		*sc;
101881737Swpaul{
101981737Swpaul	u_int32_t		txfctl;
102081737Swpaul	u_int8_t		txthresh;
102181737Swpaul
102281737Swpaul	txfctl = csr_read_4(sc, SF_TX_FRAMCTL);
102381737Swpaul	txthresh = txfctl & SF_TXFRMCTL_TXTHRESH;
102481737Swpaul	if (txthresh < 0xFF) {
102581737Swpaul		txthresh++;
102681737Swpaul		txfctl &= ~SF_TXFRMCTL_TXTHRESH;
102781737Swpaul		txfctl |= txthresh;
102881737Swpaul#ifdef DIAGNOSTIC
102981737Swpaul		printf("sf%d: tx underrun, increasing "
103081737Swpaul		    "tx threshold to %d bytes\n",
103181737Swpaul		    sc->sf_unit, txthresh * 4);
103281737Swpaul#endif
103381737Swpaul		csr_write_4(sc, SF_TX_FRAMCTL, txfctl);
103481737Swpaul	}
103581737Swpaul}
103681737Swpaul
1037137557Sbrueffer#ifdef DEVICE_POLLING
1038102335Salfredstatic void
1039137557Sbrueffersf_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
1040137557Sbrueffer{
1041137557Sbrueffer	struct sf_softc *sc = ifp->if_softc;
1042137557Sbrueffer
1043137557Sbrueffer	SF_LOCK(sc);
1044137557Sbrueffer	sf_poll_locked(ifp, cmd, count);
1045137557Sbrueffer	SF_UNLOCK(sc);
1046137557Sbrueffer}
1047137557Sbrueffer
1048137557Sbruefferstatic void
1049137557Sbrueffersf_poll_locked(struct ifnet *ifp, enum poll_cmd cmd, int count)
1050137557Sbrueffer{
1051137557Sbrueffer	struct sf_softc *sc = ifp->if_softc;
1052137557Sbrueffer
1053137557Sbrueffer	SF_LOCK_ASSERT(sc);
1054137557Sbrueffer
1055137557Sbrueffer	if (!(ifp->if_capenable & IFCAP_POLLING)) {
1056137557Sbrueffer		ether_poll_deregister(ifp);
1057137557Sbrueffer		cmd = POLL_DEREGISTER;
1058137557Sbrueffer	}
1059137557Sbrueffer
1060137557Sbrueffer	if (cmd == POLL_DEREGISTER) {
1061137557Sbrueffer		/* Final call, enable interrupts. */
1062137557Sbrueffer		csr_write_4(sc, SF_IMR, SF_INTRS);
1063137557Sbrueffer		return;
1064137557Sbrueffer	}
1065137557Sbrueffer
1066137557Sbrueffer	sc->rxcycles = count;
1067137557Sbrueffer	sf_rxeof(sc);
1068137557Sbrueffer	sf_txeof(sc);
1069137620Sbrueffer	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1070137557Sbrueffer		sf_start(ifp);
1071137557Sbrueffer
1072137557Sbrueffer	if (cmd == POLL_AND_CHECK_STATUS) {
1073137557Sbrueffer		u_int32_t status;
1074137557Sbrueffer
1075137557Sbrueffer		status = csr_read_4(sc, SF_ISR);
1076137557Sbrueffer		if (status)
1077137557Sbrueffer			csr_write_4(sc, SF_ISR, status);
1078137557Sbrueffer
1079137557Sbrueffer		if (status & SF_ISR_TX_LOFIFO)
1080137557Sbrueffer			sf_txthresh_adjust(sc);
1081137557Sbrueffer
1082137557Sbrueffer		if (status & SF_ISR_ABNORMALINTR) {
1083137557Sbrueffer			if (status & SF_ISR_STATSOFLOW) {
1084137557Sbrueffer				untimeout(sf_stats_update, sc,
1085137557Sbrueffer				    sc->sf_stat_ch);
1086137557Sbrueffer				sf_stats_update(sc);
1087137557Sbrueffer			} else
1088137557Sbrueffer				sf_init(sc);
1089137557Sbrueffer		}
1090137557Sbrueffer	}
1091137557Sbrueffer}
1092137557Sbrueffer#endif /* DEVICE_POLLING */
1093137557Sbrueffer
1094137557Sbruefferstatic void
1095102335Salfredsf_intr(arg)
109649076Swpaul	void			*arg;
109749076Swpaul{
109849076Swpaul	struct sf_softc		*sc;
109949076Swpaul	struct ifnet		*ifp;
110049076Swpaul	u_int32_t		status;
110149076Swpaul
110249076Swpaul	sc = arg;
110367087Swpaul	SF_LOCK(sc);
110467087Swpaul
110549076Swpaul	ifp = &sc->arpcom.ac_if;
110649076Swpaul
1107137557Sbrueffer#ifdef DEVICE_POLLING
1108137557Sbrueffer	if (ifp->if_flags & IFF_POLLING)
1109137557Sbrueffer		goto done_locked;
1110137557Sbrueffer
1111137557Sbrueffer	if ((ifp->if_capenable & IFCAP_POLLING) &&
1112137557Sbrueffer	    ether_poll_register(sf_poll, ifp)) {
1113137557Sbrueffer		/* OK, disable interrupts. */
1114137557Sbrueffer		csr_write_4(sc, SF_IMR, 0x00000000);
1115137557Sbrueffer		sf_poll_locked(ifp, 0, 1);
1116137557Sbrueffer		goto done_locked;
1117137557Sbrueffer	}
1118137557Sbrueffer#endif /* DEVICE_POLLING */
1119137557Sbrueffer
112067087Swpaul	if (!(csr_read_4(sc, SF_ISR_SHADOW) & SF_ISR_PCIINT_ASSERTED)) {
112167087Swpaul		SF_UNLOCK(sc);
112249076Swpaul		return;
112367087Swpaul	}
112449076Swpaul
112549076Swpaul	/* Disable interrupts. */
112649076Swpaul	csr_write_4(sc, SF_IMR, 0x00000000);
112749076Swpaul
112849076Swpaul	for (;;) {
112949076Swpaul		status = csr_read_4(sc, SF_ISR);
113049076Swpaul		if (status)
113149076Swpaul			csr_write_4(sc, SF_ISR, status);
113249076Swpaul
113349076Swpaul		if (!(status & SF_INTRS))
113449076Swpaul			break;
113549076Swpaul
113649076Swpaul		if (status & SF_ISR_RXDQ1_DMADONE)
113749076Swpaul			sf_rxeof(sc);
113849076Swpaul
113981714Swpaul		if (status & SF_ISR_TX_TXDONE ||
114081714Swpaul		    status & SF_ISR_TX_DMADONE ||
114181737Swpaul		    status & SF_ISR_TX_QUEUEDONE)
114249076Swpaul			sf_txeof(sc);
114349076Swpaul
114481737Swpaul		if (status & SF_ISR_TX_LOFIFO)
114581737Swpaul			sf_txthresh_adjust(sc);
114681737Swpaul
114749076Swpaul		if (status & SF_ISR_ABNORMALINTR) {
114849076Swpaul			if (status & SF_ISR_STATSOFLOW) {
114949076Swpaul				untimeout(sf_stats_update, sc,
115049076Swpaul				    sc->sf_stat_ch);
115149076Swpaul				sf_stats_update(sc);
115249076Swpaul			} else
115349076Swpaul				sf_init(sc);
115449076Swpaul		}
115549076Swpaul	}
115649076Swpaul
115749076Swpaul	/* Re-enable interrupts. */
115849076Swpaul	csr_write_4(sc, SF_IMR, SF_INTRS);
115949076Swpaul
1160137620Sbrueffer	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
116149076Swpaul		sf_start(ifp);
116249076Swpaul
1163137557Sbrueffer#ifdef DEVICE_POLLING
1164137557Sbruefferdone_locked:
1165137557Sbrueffer#endif /* DEVICE_POLLING */
116667087Swpaul	SF_UNLOCK(sc);
116749076Swpaul}
116849076Swpaul
1169102335Salfredstatic void
1170102335Salfredsf_init(xsc)
117149076Swpaul	void			*xsc;
117249076Swpaul{
117349076Swpaul	struct sf_softc		*sc;
117449076Swpaul	struct ifnet		*ifp;
117550675Swpaul	struct mii_data		*mii;
117667087Swpaul	int			i;
117749076Swpaul
117849076Swpaul	sc = xsc;
117967087Swpaul	SF_LOCK(sc);
118049076Swpaul	ifp = &sc->arpcom.ac_if;
118150675Swpaul	mii = device_get_softc(sc->sf_miibus);
118249076Swpaul
118349076Swpaul	sf_stop(sc);
118449076Swpaul	sf_reset(sc);
118549076Swpaul
118649076Swpaul	/* Init all the receive filter registers */
118749076Swpaul	for (i = SF_RXFILT_PERFECT_BASE;
118849076Swpaul	    i < (SF_RXFILT_HASH_MAX + 1); i += 4)
118949076Swpaul		csr_write_4(sc, i, 0);
119049076Swpaul
119149076Swpaul	/* Empty stats counter registers. */
119249076Swpaul	for (i = 0; i < sizeof(struct sf_stats)/sizeof(u_int32_t); i++)
119349076Swpaul		csr_write_4(sc, SF_STATS_BASE +
119449076Swpaul		    (i + sizeof(u_int32_t)), 0);
119549076Swpaul
119649076Swpaul	/* Init our MAC address */
119749076Swpaul	csr_write_4(sc, SF_PAR0, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0]));
119849076Swpaul	csr_write_4(sc, SF_PAR1, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4]));
119949076Swpaul	sf_setperf(sc, 0, (caddr_t)&sc->arpcom.ac_enaddr);
120049076Swpaul
120149076Swpaul	if (sf_init_rx_ring(sc) == ENOBUFS) {
120249076Swpaul		printf("sf%d: initialization failed: no "
120349076Swpaul		    "memory for rx buffers\n", sc->sf_unit);
120467087Swpaul		SF_UNLOCK(sc);
120549076Swpaul		return;
120649076Swpaul	}
120749076Swpaul
120849076Swpaul	sf_init_tx_ring(sc);
120949076Swpaul
121049076Swpaul	csr_write_4(sc, SF_RXFILT, SF_PERFMODE_NORMAL|SF_HASHMODE_WITHVLAN);
121149076Swpaul
121249076Swpaul	/* If we want promiscuous mode, set the allframes bit. */
121349076Swpaul	if (ifp->if_flags & IFF_PROMISC) {
121449076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
121549076Swpaul	} else {
121649076Swpaul		SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
121749076Swpaul	}
121849076Swpaul
121949076Swpaul	if (ifp->if_flags & IFF_BROADCAST) {
122049076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_BROAD);
122149076Swpaul	} else {
122249076Swpaul		SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_BROAD);
122349076Swpaul	}
122449076Swpaul
122563166Swpaul	/*
122663166Swpaul	 * Load the multicast filter.
122763166Swpaul	 */
122863166Swpaul	sf_setmulti(sc);
122963166Swpaul
123049076Swpaul	/* Init the completion queue indexes */
123149076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX, 0);
123249076Swpaul	csr_write_4(sc, SF_CQ_PRODIDX, 0);
123349076Swpaul
123449076Swpaul	/* Init the RX completion queue */
123549076Swpaul	csr_write_4(sc, SF_RXCQ_CTL_1,
123649076Swpaul	    vtophys(sc->sf_ldata->sf_rx_clist) & SF_RXCQ_ADDR);
123749076Swpaul	SF_SETBIT(sc, SF_RXCQ_CTL_1, SF_RXCQTYPE_3);
123849076Swpaul
123949076Swpaul	/* Init RX DMA control. */
124049076Swpaul	SF_SETBIT(sc, SF_RXDMA_CTL, SF_RXDMA_REPORTBADPKTS);
124149076Swpaul
124249076Swpaul	/* Init the RX buffer descriptor queue. */
124349076Swpaul	csr_write_4(sc, SF_RXDQ_ADDR_Q1,
124449076Swpaul	    vtophys(sc->sf_ldata->sf_rx_dlist_big));
124549076Swpaul	csr_write_4(sc, SF_RXDQ_CTL_1, (MCLBYTES << 16) | SF_DESCSPACE_16BYTES);
124649076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1, SF_RX_DLIST_CNT - 1);
124749076Swpaul
124849076Swpaul	/* Init the TX completion queue */
124949076Swpaul	csr_write_4(sc, SF_TXCQ_CTL,
125049076Swpaul	    vtophys(sc->sf_ldata->sf_tx_clist) & SF_RXCQ_ADDR);
125149076Swpaul
125249076Swpaul	/* Init the TX buffer descriptor queue. */
125349076Swpaul	csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO,
125449076Swpaul		vtophys(sc->sf_ldata->sf_tx_dlist));
125549076Swpaul	SF_SETBIT(sc, SF_TX_FRAMCTL, SF_TXFRMCTL_CPLAFTERTX);
125649076Swpaul	csr_write_4(sc, SF_TXDQ_CTL,
125749076Swpaul	    SF_TXBUFDESC_TYPE0|SF_TXMINSPACE_128BYTES|SF_TXSKIPLEN_8BYTES);
125849076Swpaul	SF_SETBIT(sc, SF_TXDQ_CTL, SF_TXDQCTL_NODMACMP);
125949076Swpaul
126049076Swpaul	/* Enable autopadding of short TX frames. */
126149076Swpaul	SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_AUTOPAD);
126249076Swpaul
1263137557Sbrueffer#ifdef DEVICE_POLLING
1264137557Sbrueffer	/* Disable interrupts if we are polling. */
1265137557Sbrueffer	if (ifp->if_flags & IFF_POLLING)
1266137557Sbrueffer		csr_write_4(sc, SF_IMR, 0x00000000);
1267137557Sbrueffer	else
1268137557Sbrueffer#endif /* DEVICE_POLLING */
1269137557Sbrueffer
127049076Swpaul	/* Enable interrupts. */
127149076Swpaul	csr_write_4(sc, SF_IMR, SF_INTRS);
127249076Swpaul	SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_INTR_ENB);
127349076Swpaul
127449076Swpaul	/* Enable the RX and TX engines. */
127549076Swpaul	SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_RX_ENB|SF_ETHCTL_RXDMA_ENB);
127649076Swpaul	SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_TX_ENB|SF_ETHCTL_TXDMA_ENB);
127749076Swpaul
127854161Swpaul	/*mii_mediachg(mii);*/
127954161Swpaul	sf_ifmedia_upd(ifp);
128050675Swpaul
128149076Swpaul	ifp->if_flags |= IFF_RUNNING;
128249076Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
128349076Swpaul
128449076Swpaul	sc->sf_stat_ch = timeout(sf_stats_update, sc, hz);
128549076Swpaul
128667087Swpaul	SF_UNLOCK(sc);
128749076Swpaul}
128849076Swpaul
1289102335Salfredstatic int
1290102335Salfredsf_encap(sc, c, m_head)
129149076Swpaul	struct sf_softc		*sc;
129249076Swpaul	struct sf_tx_bufdesc_type0 *c;
129349076Swpaul	struct mbuf		*m_head;
129449076Swpaul{
129549076Swpaul	int			frag = 0;
129649076Swpaul	struct sf_frag		*f = NULL;
129749076Swpaul	struct mbuf		*m;
129849076Swpaul
129949076Swpaul	m = m_head;
130049076Swpaul
130149076Swpaul	for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
130249076Swpaul		if (m->m_len != 0) {
130349076Swpaul			if (frag == SF_MAXFRAGS)
130449076Swpaul				break;
130549076Swpaul			f = &c->sf_frags[frag];
130649076Swpaul			if (frag == 0)
130749076Swpaul				f->sf_pktlen = m_head->m_pkthdr.len;
130849076Swpaul			f->sf_fraglen = m->m_len;
130949076Swpaul			f->sf_addr = vtophys(mtod(m, vm_offset_t));
131049076Swpaul			frag++;
131149076Swpaul		}
131249076Swpaul	}
131349076Swpaul
131449076Swpaul	if (m != NULL) {
131549076Swpaul		struct mbuf		*m_new = NULL;
131649076Swpaul
1317111119Simp		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
131849076Swpaul		if (m_new == NULL) {
1319103139Sticso			printf("sf%d: no memory for tx list\n", sc->sf_unit);
132049076Swpaul			return(1);
132149076Swpaul		}
132249076Swpaul
132349076Swpaul		if (m_head->m_pkthdr.len > MHLEN) {
1324111119Simp			MCLGET(m_new, M_DONTWAIT);
132549076Swpaul			if (!(m_new->m_flags & M_EXT)) {
132649076Swpaul				m_freem(m_new);
1327103139Sticso				printf("sf%d: no memory for tx list\n",
132849076Swpaul				    sc->sf_unit);
132949076Swpaul				return(1);
133049076Swpaul			}
133149076Swpaul		}
133249076Swpaul		m_copydata(m_head, 0, m_head->m_pkthdr.len,
133349076Swpaul		    mtod(m_new, caddr_t));
133449076Swpaul		m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
133549076Swpaul		m_freem(m_head);
133649076Swpaul		m_head = m_new;
133749076Swpaul		f = &c->sf_frags[0];
133849076Swpaul		f->sf_fraglen = f->sf_pktlen = m_head->m_pkthdr.len;
133949076Swpaul		f->sf_addr = vtophys(mtod(m_head, caddr_t));
134049076Swpaul		frag = 1;
134149076Swpaul	}
134249076Swpaul
134349076Swpaul	c->sf_mbuf = m_head;
134449076Swpaul	c->sf_id = SF_TX_BUFDESC_ID;
134549076Swpaul	c->sf_fragcnt = frag;
134649076Swpaul	c->sf_intr = 1;
134749076Swpaul	c->sf_caltcp = 0;
134849076Swpaul	c->sf_crcen = 1;
134949076Swpaul
135049076Swpaul	return(0);
135149076Swpaul}
135249076Swpaul
1353102335Salfredstatic void
1354102335Salfredsf_start(ifp)
135549076Swpaul	struct ifnet		*ifp;
135649076Swpaul{
135749076Swpaul	struct sf_softc		*sc;
135849076Swpaul	struct sf_tx_bufdesc_type0 *cur_tx = NULL;
135949076Swpaul	struct mbuf		*m_head = NULL;
136049076Swpaul	int			i, txprod;
136149076Swpaul
136249076Swpaul	sc = ifp->if_softc;
136367087Swpaul	SF_LOCK(sc);
136449076Swpaul
136581714Swpaul	if (!sc->sf_link && ifp->if_snd.ifq_len < 10) {
136667087Swpaul		SF_UNLOCK(sc);
136754161Swpaul		return;
136867087Swpaul	}
136954161Swpaul
137067087Swpaul	if (ifp->if_flags & IFF_OACTIVE) {
137167087Swpaul		SF_UNLOCK(sc);
137249076Swpaul		return;
137367087Swpaul	}
137449076Swpaul
137549076Swpaul	txprod = csr_read_4(sc, SF_TXDQ_PRODIDX);
137649076Swpaul	i = SF_IDX_HI(txprod) >> 4;
137749076Swpaul
137881737Swpaul	if (sc->sf_ldata->sf_tx_dlist[i].sf_mbuf != NULL) {
137981737Swpaul		printf("sf%d: TX ring full, resetting\n", sc->sf_unit);
138081737Swpaul		sf_init(sc);
138181737Swpaul		txprod = csr_read_4(sc, SF_TXDQ_PRODIDX);
138281737Swpaul		i = SF_IDX_HI(txprod) >> 4;
138381737Swpaul	}
138481737Swpaul
138549076Swpaul	while(sc->sf_ldata->sf_tx_dlist[i].sf_mbuf == NULL) {
138681737Swpaul		if (sc->sf_tx_cnt >= (SF_TX_DLIST_CNT - 5)) {
138771276Swpaul			ifp->if_flags |= IFF_OACTIVE;
138871276Swpaul			cur_tx = NULL;
138971276Swpaul			break;
139071276Swpaul		}
1391137620Sbrueffer		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
139249076Swpaul		if (m_head == NULL)
139349076Swpaul			break;
139449076Swpaul
139549076Swpaul		cur_tx = &sc->sf_ldata->sf_tx_dlist[i];
139671276Swpaul		if (sf_encap(sc, cur_tx, m_head)) {
1397137620Sbrueffer			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
139871276Swpaul			ifp->if_flags |= IFF_OACTIVE;
139971276Swpaul			cur_tx = NULL;
140071276Swpaul			break;
140171276Swpaul		}
140249076Swpaul
140349076Swpaul		/*
140449076Swpaul		 * If there's a BPF listener, bounce a copy of this frame
140549076Swpaul		 * to him.
140649076Swpaul		 */
1407106936Ssam		BPF_MTAP(ifp, m_head);
140851583Swpaul
140949076Swpaul		SF_INC(i, SF_TX_DLIST_CNT);
141049076Swpaul		sc->sf_tx_cnt++;
141181798Swpaul		/*
141281798Swpaul		 * Don't get the TX DMA queue get too full.
141381798Swpaul		 */
141481798Swpaul		if (sc->sf_tx_cnt > 64)
141581798Swpaul			break;
141649076Swpaul	}
141749076Swpaul
141867087Swpaul	if (cur_tx == NULL) {
141967087Swpaul		SF_UNLOCK(sc);
142049076Swpaul		return;
142167087Swpaul	}
142249076Swpaul
142349076Swpaul	/* Transmit */
142449076Swpaul	csr_write_4(sc, SF_TXDQ_PRODIDX,
142549076Swpaul	    (txprod & ~SF_TXDQ_PRODIDX_HIPRIO) |
142649076Swpaul	    ((i << 20) & 0xFFFF0000));
142749076Swpaul
142849076Swpaul	ifp->if_timer = 5;
142949076Swpaul
143067087Swpaul	SF_UNLOCK(sc);
143149076Swpaul}
143249076Swpaul
1433102335Salfredstatic void
1434102335Salfredsf_stop(sc)
143549076Swpaul	struct sf_softc		*sc;
143649076Swpaul{
143749076Swpaul	int			i;
143849077Swpaul	struct ifnet		*ifp;
143949076Swpaul
144067087Swpaul	SF_LOCK(sc);
144167087Swpaul
144249077Swpaul	ifp = &sc->arpcom.ac_if;
144349077Swpaul
144449076Swpaul	untimeout(sf_stats_update, sc, sc->sf_stat_ch);
144549076Swpaul
1446137557Sbrueffer#ifdef DEVICE_POLLING
1447137557Sbrueffer	ether_poll_deregister(ifp);
1448137557Sbrueffer#endif /* DEVICE_POLLING */
1449137557Sbrueffer
145049076Swpaul	csr_write_4(sc, SF_GEN_ETH_CTL, 0);
145149076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX, 0);
145249076Swpaul	csr_write_4(sc, SF_CQ_PRODIDX, 0);
145349076Swpaul	csr_write_4(sc, SF_RXDQ_ADDR_Q1, 0);
145449076Swpaul	csr_write_4(sc, SF_RXDQ_CTL_1, 0);
145549076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1, 0);
145649076Swpaul	csr_write_4(sc, SF_TXCQ_CTL, 0);
145749076Swpaul	csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO, 0);
145849076Swpaul	csr_write_4(sc, SF_TXDQ_CTL, 0);
145949076Swpaul	sf_reset(sc);
146049076Swpaul
146154161Swpaul	sc->sf_link = 0;
146254161Swpaul
146349076Swpaul	for (i = 0; i < SF_RX_DLIST_CNT; i++) {
146449076Swpaul		if (sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf != NULL) {
146549076Swpaul			m_freem(sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf);
146649076Swpaul			sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf = NULL;
146749076Swpaul		}
146849076Swpaul	}
146949076Swpaul
147049076Swpaul	for (i = 0; i < SF_TX_DLIST_CNT; i++) {
147149076Swpaul		if (sc->sf_ldata->sf_tx_dlist[i].sf_mbuf != NULL) {
147249076Swpaul			m_freem(sc->sf_ldata->sf_tx_dlist[i].sf_mbuf);
147349076Swpaul			sc->sf_ldata->sf_tx_dlist[i].sf_mbuf = NULL;
147449076Swpaul		}
147549076Swpaul	}
147649076Swpaul
147749077Swpaul	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
147867087Swpaul	SF_UNLOCK(sc);
147949076Swpaul}
148049076Swpaul
148149076Swpaul/*
148249076Swpaul * Note: it is important that this function not be interrupted. We
148349076Swpaul * use a two-stage register access scheme: if we are interrupted in
148449076Swpaul * between setting the indirect address register and reading from the
148549076Swpaul * indirect data register, the contents of the address register could
148649076Swpaul * be changed out from under us.
1487131657Sbms */
1488102335Salfredstatic void
1489102335Salfredsf_stats_update(xsc)
149049076Swpaul	void			*xsc;
149149076Swpaul{
149249076Swpaul	struct sf_softc		*sc;
149349076Swpaul	struct ifnet		*ifp;
149450675Swpaul	struct mii_data		*mii;
149549076Swpaul	struct sf_stats		stats;
149649076Swpaul	u_int32_t		*ptr;
149767087Swpaul	int			i;
149849076Swpaul
149949076Swpaul	sc = xsc;
150067087Swpaul	SF_LOCK(sc);
150149076Swpaul	ifp = &sc->arpcom.ac_if;
150250675Swpaul	mii = device_get_softc(sc->sf_miibus);
150349076Swpaul
150449076Swpaul	ptr = (u_int32_t *)&stats;
150549076Swpaul	for (i = 0; i < sizeof(stats)/sizeof(u_int32_t); i++)
150649076Swpaul		ptr[i] = csr_read_4(sc, SF_STATS_BASE +
150749076Swpaul		    (i + sizeof(u_int32_t)));
150849076Swpaul
150949076Swpaul	for (i = 0; i < sizeof(stats)/sizeof(u_int32_t); i++)
151049076Swpaul		csr_write_4(sc, SF_STATS_BASE +
151149076Swpaul		    (i + sizeof(u_int32_t)), 0);
151249076Swpaul
151349076Swpaul	ifp->if_collisions += stats.sf_tx_single_colls +
151449076Swpaul	    stats.sf_tx_multi_colls + stats.sf_tx_excess_colls;
151549076Swpaul
151650675Swpaul	mii_tick(mii);
151784147Sjlemon
151884147Sjlemon	if (!sc->sf_link && mii->mii_media_status & IFM_ACTIVE &&
151984147Sjlemon	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
152084147Sjlemon		sc->sf_link++;
1521137620Sbrueffer		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
152284147Sjlemon			sf_start(ifp);
152354161Swpaul	}
152450675Swpaul
152549076Swpaul	sc->sf_stat_ch = timeout(sf_stats_update, sc, hz);
152649076Swpaul
152767087Swpaul	SF_UNLOCK(sc);
152849076Swpaul}
152949076Swpaul
1530102335Salfredstatic void
1531102335Salfredsf_watchdog(ifp)
153249076Swpaul	struct ifnet		*ifp;
153349076Swpaul{
153449076Swpaul	struct sf_softc		*sc;
153549076Swpaul
153649076Swpaul	sc = ifp->if_softc;
153749076Swpaul
153867087Swpaul	SF_LOCK(sc);
153967087Swpaul
154049076Swpaul	ifp->if_oerrors++;
154149076Swpaul	printf("sf%d: watchdog timeout\n", sc->sf_unit);
154249076Swpaul
154349076Swpaul	sf_stop(sc);
154449076Swpaul	sf_reset(sc);
154549076Swpaul	sf_init(sc);
154649076Swpaul
1547137620Sbrueffer	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
154849076Swpaul		sf_start(ifp);
154949076Swpaul
155067087Swpaul	SF_UNLOCK(sc);
155149076Swpaul}
155249076Swpaul
1553102335Salfredstatic void
1554102335Salfredsf_shutdown(dev)
155549076Swpaul	device_t		dev;
155649076Swpaul{
155749076Swpaul	struct sf_softc		*sc;
155849076Swpaul
155949076Swpaul	sc = device_get_softc(dev);
156049076Swpaul
156149076Swpaul	sf_stop(sc);
156249076Swpaul}
1563