if_sf.c revision 111119
149076Swpaul/*
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 *
3250477Speter * $FreeBSD: head/sys/dev/sf/if_sf.c 111119 2003-02-19 05:47:46Z imp $
3349076Swpaul */
3449076Swpaul
3549076Swpaul/*
3649076Swpaul * Adaptec AIC-6915 "Starfire" PCI fast ethernet driver for FreeBSD.
3751682Swpaul * Programming manual is available from:
3851682Swpaul * ftp.adaptec.com:/pub/BBS/userguides/aic6915_pg.pdf.
3949076Swpaul *
4049076Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu>
4149076Swpaul * Department of Electical Engineering
4249076Swpaul * Columbia University, New York City
4349076Swpaul */
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>
8849076Swpaul#include <sys/socket.h>
8949076Swpaul
9049076Swpaul#include <net/if.h>
9149076Swpaul#include <net/if_arp.h>
9249076Swpaul#include <net/ethernet.h>
9349076Swpaul#include <net/if_dl.h>
9449076Swpaul#include <net/if_media.h>
9549076Swpaul
9649076Swpaul#include <net/bpf.h>
9749076Swpaul
9849076Swpaul#include <vm/vm.h>              /* for vtophys */
9949076Swpaul#include <vm/pmap.h>            /* for vtophys */
10049076Swpaul#include <machine/bus_pio.h>
10149076Swpaul#include <machine/bus_memio.h>
10249076Swpaul#include <machine/bus.h>
10349076Swpaul#include <machine/resource.h>
10449076Swpaul#include <sys/bus.h>
10549076Swpaul#include <sys/rman.h>
10649076Swpaul
10750675Swpaul#include <dev/mii/mii.h>
10850675Swpaul#include <dev/mii/miivar.h>
10950675Swpaul
11051089Speter/* "controller miibus0" required.  See GENERIC if you get errors here. */
11150675Swpaul#include "miibus_if.h"
11250675Swpaul
11349076Swpaul#include <pci/pcireg.h>
11449076Swpaul#include <pci/pcivar.h>
11549076Swpaul
11649076Swpaul#define SF_USEIOSPACE
11749076Swpaul
11849076Swpaul#include <pci/if_sfreg.h>
11949076Swpaul
12059758SpeterMODULE_DEPEND(sf, miibus, 1, 1, 1);
12159758Speter
12249076Swpaul#ifndef lint
12349076Swpaulstatic const char rcsid[] =
12450477Speter  "$FreeBSD: head/sys/dev/sf/if_sf.c 111119 2003-02-19 05:47:46Z imp $";
12549076Swpaul#endif
12649076Swpaul
12749076Swpaulstatic struct sf_type sf_devs[] = {
12849076Swpaul	{ AD_VENDORID, AD_DEVICEID_STARFIRE,
12949076Swpaul		"Adaptec AIC-6915 10/100BaseTX" },
13049076Swpaul	{ 0, 0, NULL }
13149076Swpaul};
13249076Swpaul
13392739Salfredstatic int sf_probe		(device_t);
13492739Salfredstatic int sf_attach		(device_t);
13592739Salfredstatic int sf_detach		(device_t);
13692739Salfredstatic void sf_intr		(void *);
13792739Salfredstatic void sf_stats_update	(void *);
13892739Salfredstatic void sf_rxeof		(struct sf_softc *);
13992739Salfredstatic void sf_txeof		(struct sf_softc *);
14092739Salfredstatic int sf_encap		(struct sf_softc *,
14149076Swpaul					struct sf_tx_bufdesc_type0 *,
14292739Salfred					struct mbuf *);
14392739Salfredstatic void sf_start		(struct ifnet *);
14492739Salfredstatic int sf_ioctl		(struct ifnet *, u_long, caddr_t);
14592739Salfredstatic void sf_init		(void *);
14692739Salfredstatic void sf_stop		(struct sf_softc *);
14792739Salfredstatic void sf_watchdog		(struct ifnet *);
14892739Salfredstatic void sf_shutdown		(device_t);
14992739Salfredstatic int sf_ifmedia_upd	(struct ifnet *);
15092739Salfredstatic void sf_ifmedia_sts	(struct ifnet *, struct ifmediareq *);
15192739Salfredstatic void sf_reset		(struct sf_softc *);
15292739Salfredstatic int sf_init_rx_ring	(struct sf_softc *);
15392739Salfredstatic void sf_init_tx_ring	(struct sf_softc *);
15492739Salfredstatic int sf_newbuf		(struct sf_softc *,
15549076Swpaul					struct sf_rx_bufdesc_type0 *,
15692739Salfred					struct mbuf *);
15792739Salfredstatic void sf_setmulti		(struct sf_softc *);
15892739Salfredstatic int sf_setperf		(struct sf_softc *, int, caddr_t);
15992739Salfredstatic int sf_sethash		(struct sf_softc *, caddr_t, int);
16049076Swpaul#ifdef notdef
16192739Salfredstatic int sf_setvlan		(struct sf_softc *, int, u_int32_t);
16249076Swpaul#endif
16349076Swpaul
16492739Salfredstatic u_int8_t sf_read_eeprom	(struct sf_softc *, int);
16592739Salfredstatic u_int32_t sf_calchash	(caddr_t);
16649076Swpaul
16792739Salfredstatic int sf_miibus_readreg	(device_t, int, int);
16892739Salfredstatic int sf_miibus_writereg	(device_t, int, int, int);
16992739Salfredstatic void sf_miibus_statchg	(device_t);
17049076Swpaul
17192739Salfredstatic u_int32_t csr_read_4	(struct sf_softc *, int);
17292739Salfredstatic void csr_write_4		(struct sf_softc *, int, u_int32_t);
17392739Salfredstatic void sf_txthresh_adjust	(struct sf_softc *);
17449076Swpaul
17549076Swpaul#ifdef SF_USEIOSPACE
17649076Swpaul#define SF_RES			SYS_RES_IOPORT
17749076Swpaul#define SF_RID			SF_PCI_LOIO
17849076Swpaul#else
17949076Swpaul#define SF_RES			SYS_RES_MEMORY
18049076Swpaul#define SF_RID			SF_PCI_LOMEM
18149076Swpaul#endif
18249076Swpaul
18349076Swpaulstatic device_method_t sf_methods[] = {
18449076Swpaul	/* Device interface */
18549076Swpaul	DEVMETHOD(device_probe,		sf_probe),
18649076Swpaul	DEVMETHOD(device_attach,	sf_attach),
18749076Swpaul	DEVMETHOD(device_detach,	sf_detach),
18849076Swpaul	DEVMETHOD(device_shutdown,	sf_shutdown),
18950675Swpaul
19050675Swpaul	/* bus interface */
19150675Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
19250675Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
19350675Swpaul
19450675Swpaul	/* MII interface */
19550675Swpaul	DEVMETHOD(miibus_readreg,	sf_miibus_readreg),
19650675Swpaul	DEVMETHOD(miibus_writereg,	sf_miibus_writereg),
19750675Swpaul	DEVMETHOD(miibus_statchg,	sf_miibus_statchg),
19850675Swpaul
19949076Swpaul	{ 0, 0 }
20049076Swpaul};
20149076Swpaul
20249076Swpaulstatic driver_t sf_driver = {
20351455Swpaul	"sf",
20449076Swpaul	sf_methods,
20549076Swpaul	sizeof(struct sf_softc),
20649076Swpaul};
20749076Swpaul
20849076Swpaulstatic devclass_t sf_devclass;
20949076Swpaul
21051533SwpaulDRIVER_MODULE(if_sf, pci, sf_driver, sf_devclass, 0, 0);
21151473SwpaulDRIVER_MODULE(miibus, sf, miibus_driver, miibus_devclass, 0, 0);
21249076Swpaul
21349076Swpaul#define SF_SETBIT(sc, reg, x)	\
214105221Sphk	csr_write_4(sc, reg, csr_read_4(sc, reg) | (x))
21549076Swpaul
21649076Swpaul#define SF_CLRBIT(sc, reg, x)				\
217105221Sphk	csr_write_4(sc, reg, csr_read_4(sc, reg) & ~(x))
21849076Swpaul
219102335Salfredstatic u_int32_t
220102335Salfredcsr_read_4(sc, reg)
22149076Swpaul	struct sf_softc		*sc;
22249076Swpaul	int			reg;
22349076Swpaul{
22449076Swpaul	u_int32_t		val;
22549076Swpaul
22649076Swpaul#ifdef SF_USEIOSPACE
22749076Swpaul	CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE);
22849076Swpaul	val = CSR_READ_4(sc, SF_INDIRECTIO_DATA);
22949076Swpaul#else
23049076Swpaul	val = CSR_READ_4(sc, (reg + SF_RMAP_INTREG_BASE));
23149076Swpaul#endif
23249076Swpaul
23349076Swpaul	return(val);
23449076Swpaul}
23549076Swpaul
236102335Salfredstatic u_int8_t
237102335Salfredsf_read_eeprom(sc, reg)
23849076Swpaul	struct sf_softc		*sc;
23949076Swpaul	int			reg;
24049076Swpaul{
24149076Swpaul	u_int8_t		val;
24249076Swpaul
24349076Swpaul	val = (csr_read_4(sc, SF_EEADDR_BASE +
24449076Swpaul	    (reg & 0xFFFFFFFC)) >> (8 * (reg & 3))) & 0xFF;
24549076Swpaul
24649076Swpaul	return(val);
24749076Swpaul}
24849076Swpaul
249102335Salfredstatic void
250102335Salfredcsr_write_4(sc, reg, val)
25149076Swpaul	struct sf_softc		*sc;
25249076Swpaul	int			reg;
25349076Swpaul	u_int32_t		val;
25449076Swpaul{
25549076Swpaul#ifdef SF_USEIOSPACE
25649076Swpaul	CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE);
25749076Swpaul	CSR_WRITE_4(sc, SF_INDIRECTIO_DATA, val);
25849076Swpaul#else
25949076Swpaul	CSR_WRITE_4(sc, (reg + SF_RMAP_INTREG_BASE), val);
26049076Swpaul#endif
26149076Swpaul	return;
26249076Swpaul}
26349076Swpaul
264102335Salfredstatic u_int32_t
265102335Salfredsf_calchash(addr)
26649076Swpaul	caddr_t			addr;
26749076Swpaul{
26849076Swpaul	u_int32_t		crc, carry;
26949076Swpaul	int			i, j;
27049076Swpaul	u_int8_t		c;
27149076Swpaul
27249076Swpaul	/* Compute CRC for the address value. */
27349076Swpaul	crc = 0xFFFFFFFF; /* initial value */
27449076Swpaul
27549076Swpaul	for (i = 0; i < 6; i++) {
27649076Swpaul		c = *(addr + i);
27749076Swpaul		for (j = 0; j < 8; j++) {
27849076Swpaul			carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
27949076Swpaul			crc <<= 1;
28049076Swpaul			c >>= 1;
28149076Swpaul			if (carry)
28249076Swpaul				crc = (crc ^ 0x04c11db6) | carry;
28349076Swpaul		}
28449076Swpaul	}
28549076Swpaul
28649076Swpaul	/* return the filter bit position */
28749076Swpaul	return(crc >> 23 & 0x1FF);
28849076Swpaul}
28949076Swpaul
29049076Swpaul/*
29149076Swpaul * Copy the address 'mac' into the perfect RX filter entry at
29249076Swpaul * offset 'idx.' The perfect filter only has 16 entries so do
29349076Swpaul * some sanity tests.
29449076Swpaul */
295102335Salfredstatic int
296102335Salfredsf_setperf(sc, idx, mac)
29749076Swpaul	struct sf_softc		*sc;
29849076Swpaul	int			idx;
29949076Swpaul	caddr_t			mac;
30049076Swpaul{
30149076Swpaul	u_int16_t		*p;
30249076Swpaul
30349076Swpaul	if (idx < 0 || idx > SF_RXFILT_PERFECT_CNT)
30449076Swpaul		return(EINVAL);
30549076Swpaul
30649076Swpaul	if (mac == NULL)
30749076Swpaul		return(EINVAL);
30849076Swpaul
30949076Swpaul	p = (u_int16_t *)mac;
31049076Swpaul
31149076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
31249076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP), htons(p[2]));
31349076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
31449076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP) + 4, htons(p[1]));
31549076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
31649076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP) + 8, htons(p[0]));
31749076Swpaul
31849076Swpaul	return(0);
31949076Swpaul}
32049076Swpaul
32149076Swpaul/*
32249076Swpaul * Set the bit in the 512-bit hash table that corresponds to the
32349076Swpaul * specified mac address 'mac.' If 'prio' is nonzero, update the
32449076Swpaul * priority hash table instead of the filter hash table.
32549076Swpaul */
326102335Salfredstatic int
327102335Salfredsf_sethash(sc, mac, prio)
32849076Swpaul	struct sf_softc		*sc;
32949076Swpaul	caddr_t			mac;
33049076Swpaul	int			prio;
33149076Swpaul{
33249076Swpaul	u_int32_t		h = 0;
33349076Swpaul
33449076Swpaul	if (mac == NULL)
33549076Swpaul		return(EINVAL);
33649076Swpaul
33749076Swpaul	h = sf_calchash(mac);
33849076Swpaul
33949076Swpaul	if (prio) {
34049076Swpaul		SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_PRIOOFF +
34149076Swpaul		    (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF)));
34249076Swpaul	} else {
34349076Swpaul		SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_ADDROFF +
34449076Swpaul		    (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF)));
34549076Swpaul	}
34649076Swpaul
34749076Swpaul	return(0);
34849076Swpaul}
34949076Swpaul
35049076Swpaul#ifdef notdef
35149076Swpaul/*
35249076Swpaul * Set a VLAN tag in the receive filter.
35349076Swpaul */
354102335Salfredstatic int
355102335Salfredsf_setvlan(sc, idx, vlan)
35649076Swpaul	struct sf_softc		*sc;
35749076Swpaul	int			idx;
35849076Swpaul	u_int32_t		vlan;
35949076Swpaul{
36049076Swpaul	if (idx < 0 || idx >> SF_RXFILT_HASH_CNT)
36149076Swpaul		return(EINVAL);
36249076Swpaul
36349076Swpaul	csr_write_4(sc, SF_RXFILT_HASH_BASE +
36449076Swpaul	    (idx * SF_RXFILT_HASH_SKIP) + SF_RXFILT_HASH_VLANOFF, vlan);
36549076Swpaul
36649076Swpaul	return(0);
36749076Swpaul}
36849076Swpaul#endif
36949076Swpaul
370102335Salfredstatic int
371102335Salfredsf_miibus_readreg(dev, phy, reg)
37250675Swpaul	device_t		dev;
37350675Swpaul	int			phy, reg;
37450675Swpaul{
37549076Swpaul	struct sf_softc		*sc;
37649076Swpaul	int			i;
37749076Swpaul	u_int32_t		val = 0;
37849076Swpaul
37950675Swpaul	sc = device_get_softc(dev);
38050675Swpaul
38149076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
38250675Swpaul		val = csr_read_4(sc, SF_PHY_REG(phy, reg));
38349076Swpaul		if (val & SF_MII_DATAVALID)
38449076Swpaul			break;
38549076Swpaul	}
38649076Swpaul
38749076Swpaul	if (i == SF_TIMEOUT)
38849076Swpaul		return(0);
38949076Swpaul
39049076Swpaul	if ((val & 0x0000FFFF) == 0xFFFF)
39149076Swpaul		return(0);
39249076Swpaul
39349076Swpaul	return(val & 0x0000FFFF);
39449076Swpaul}
39549076Swpaul
396102335Salfredstatic int
397102335Salfredsf_miibus_writereg(dev, phy, reg, val)
39850675Swpaul	device_t		dev;
39950675Swpaul	int			phy, reg, val;
40050675Swpaul{
40149076Swpaul	struct sf_softc		*sc;
40249076Swpaul	int			i;
40349076Swpaul	int			busy;
40449076Swpaul
40550675Swpaul	sc = device_get_softc(dev);
40649076Swpaul
40750675Swpaul	csr_write_4(sc, SF_PHY_REG(phy, reg), val);
40850675Swpaul
40949076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
41050675Swpaul		busy = csr_read_4(sc, SF_PHY_REG(phy, reg));
41149076Swpaul		if (!(busy & SF_MII_BUSY))
41249076Swpaul			break;
41349076Swpaul	}
41449076Swpaul
41550675Swpaul	return(0);
41650675Swpaul}
41750675Swpaul
418102335Salfredstatic void
419102335Salfredsf_miibus_statchg(dev)
42050675Swpaul	device_t		dev;
42150675Swpaul{
42250675Swpaul	struct sf_softc		*sc;
42350675Swpaul	struct mii_data		*mii;
42450675Swpaul
42550675Swpaul	sc = device_get_softc(dev);
42650675Swpaul	mii = device_get_softc(sc->sf_miibus);
42750675Swpaul
42850675Swpaul	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
42950675Swpaul		SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX);
43054161Swpaul		csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_FDX);
43150675Swpaul	} else {
43250675Swpaul		SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX);
43354161Swpaul		csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_HDX);
43450675Swpaul	}
43550675Swpaul
43649076Swpaul	return;
43749076Swpaul}
43849076Swpaul
439102335Salfredstatic void
440102335Salfredsf_setmulti(sc)
44149076Swpaul	struct sf_softc		*sc;
44249076Swpaul{
44349076Swpaul	struct ifnet		*ifp;
44449076Swpaul	int			i;
44549076Swpaul	struct ifmultiaddr	*ifma;
44649076Swpaul	u_int8_t		dummy[] = { 0, 0, 0, 0, 0, 0 };
44749076Swpaul
44849076Swpaul	ifp = &sc->arpcom.ac_if;
44949076Swpaul
45049076Swpaul	/* First zot all the existing filters. */
45149076Swpaul	for (i = 1; i < SF_RXFILT_PERFECT_CNT; i++)
45249076Swpaul		sf_setperf(sc, i, (char *)&dummy);
45349076Swpaul	for (i = SF_RXFILT_HASH_BASE;
45449076Swpaul	    i < (SF_RXFILT_HASH_MAX + 1); i += 4)
45549076Swpaul		csr_write_4(sc, i, 0);
45649076Swpaul	SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_ALLMULTI);
45749076Swpaul
45849076Swpaul	/* Now program new ones. */
45949076Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
46049076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_ALLMULTI);
46149076Swpaul	} else {
46249076Swpaul		i = 1;
46372084Sphk		TAILQ_FOREACH_REVERSE(ifma, &ifp->if_multiaddrs, ifmultihead, ifma_link) {
46449076Swpaul			if (ifma->ifma_addr->sa_family != AF_LINK)
46549076Swpaul				continue;
46649076Swpaul			/*
46749076Swpaul			 * Program the first 15 multicast groups
46849076Swpaul			 * into the perfect filter. For all others,
46949076Swpaul			 * use the hash table.
47049076Swpaul			 */
47149076Swpaul			if (i < SF_RXFILT_PERFECT_CNT) {
47249076Swpaul				sf_setperf(sc, i,
47349076Swpaul			LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
47449076Swpaul				i++;
47549076Swpaul				continue;
47649076Swpaul			}
47749076Swpaul
47849076Swpaul			sf_sethash(sc,
47949076Swpaul			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 0);
48049076Swpaul		}
48149076Swpaul	}
48249076Swpaul
48349076Swpaul	return;
48449076Swpaul}
48549076Swpaul
48649076Swpaul/*
48749076Swpaul * Set media options.
48849076Swpaul */
489102335Salfredstatic int
490102335Salfredsf_ifmedia_upd(ifp)
49149076Swpaul	struct ifnet		*ifp;
49249076Swpaul{
49349076Swpaul	struct sf_softc		*sc;
49450675Swpaul	struct mii_data		*mii;
49549076Swpaul
49649076Swpaul	sc = ifp->if_softc;
49750675Swpaul	mii = device_get_softc(sc->sf_miibus);
49854161Swpaul	sc->sf_link = 0;
49954161Swpaul	if (mii->mii_instance) {
50054161Swpaul		struct mii_softc        *miisc;
50172012Sphk		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
50254161Swpaul			mii_phy_reset(miisc);
50354161Swpaul	}
50450675Swpaul	mii_mediachg(mii);
50549076Swpaul
50649076Swpaul	return(0);
50749076Swpaul}
50849076Swpaul
50949076Swpaul/*
51049076Swpaul * Report current media status.
51149076Swpaul */
512102335Salfredstatic void
513102335Salfredsf_ifmedia_sts(ifp, ifmr)
51449076Swpaul	struct ifnet		*ifp;
51549076Swpaul	struct ifmediareq	*ifmr;
51649076Swpaul{
51749076Swpaul	struct sf_softc		*sc;
51850675Swpaul	struct mii_data		*mii;
51949076Swpaul
52049076Swpaul	sc = ifp->if_softc;
52150675Swpaul	mii = device_get_softc(sc->sf_miibus);
52249076Swpaul
52350675Swpaul	mii_pollstat(mii);
52450675Swpaul	ifmr->ifm_active = mii->mii_media_active;
52550675Swpaul	ifmr->ifm_status = mii->mii_media_status;
52649076Swpaul
52749076Swpaul	return;
52849076Swpaul}
52949076Swpaul
530102335Salfredstatic int
531102335Salfredsf_ioctl(ifp, command, data)
53249076Swpaul	struct ifnet		*ifp;
53349076Swpaul	u_long			command;
53449076Swpaul	caddr_t			data;
53549076Swpaul{
53649076Swpaul	struct sf_softc		*sc = ifp->if_softc;
53749076Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
53850675Swpaul	struct mii_data		*mii;
53967087Swpaul	int			error = 0;
54049076Swpaul
54167087Swpaul	SF_LOCK(sc);
54249076Swpaul
54349076Swpaul	switch(command) {
54449076Swpaul	case SIOCSIFFLAGS:
54549076Swpaul		if (ifp->if_flags & IFF_UP) {
54654161Swpaul			if (ifp->if_flags & IFF_RUNNING &&
54754161Swpaul			    ifp->if_flags & IFF_PROMISC &&
54854161Swpaul			    !(sc->sf_if_flags & IFF_PROMISC)) {
54954161Swpaul				SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
55054161Swpaul			} else if (ifp->if_flags & IFF_RUNNING &&
55154161Swpaul			    !(ifp->if_flags & IFF_PROMISC) &&
55254161Swpaul			    sc->sf_if_flags & IFF_PROMISC) {
55354161Swpaul				SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
55454161Swpaul			} else if (!(ifp->if_flags & IFF_RUNNING))
55554161Swpaul				sf_init(sc);
55649076Swpaul		} else {
55749076Swpaul			if (ifp->if_flags & IFF_RUNNING)
55849076Swpaul				sf_stop(sc);
55949076Swpaul		}
56054161Swpaul		sc->sf_if_flags = ifp->if_flags;
56149076Swpaul		error = 0;
56249076Swpaul		break;
56349076Swpaul	case SIOCADDMULTI:
56449076Swpaul	case SIOCDELMULTI:
56549076Swpaul		sf_setmulti(sc);
56649076Swpaul		error = 0;
56749076Swpaul		break;
56849076Swpaul	case SIOCGIFMEDIA:
56949076Swpaul	case SIOCSIFMEDIA:
57050675Swpaul		mii = device_get_softc(sc->sf_miibus);
57150675Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
57249076Swpaul		break;
57349076Swpaul	default:
574106936Ssam		error = ether_ioctl(ifp, command, data);
57549076Swpaul		break;
57649076Swpaul	}
57749076Swpaul
57867087Swpaul	SF_UNLOCK(sc);
57949076Swpaul
58049076Swpaul	return(error);
58149076Swpaul}
58249076Swpaul
583102335Salfredstatic void
584102335Salfredsf_reset(sc)
58549076Swpaul	struct sf_softc		*sc;
58649076Swpaul{
58749076Swpaul	register int		i;
58849076Swpaul
58949076Swpaul	csr_write_4(sc, SF_GEN_ETH_CTL, 0);
59049076Swpaul	SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
59149076Swpaul	DELAY(1000);
59249076Swpaul	SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
59349076Swpaul
59449076Swpaul	SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_RESET);
59549076Swpaul
59649076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
59749076Swpaul		DELAY(10);
59849076Swpaul		if (!(csr_read_4(sc, SF_PCI_DEVCFG) & SF_PCIDEVCFG_RESET))
59949076Swpaul			break;
60049076Swpaul	}
60149076Swpaul
60249076Swpaul	if (i == SF_TIMEOUT)
60349076Swpaul		printf("sf%d: reset never completed!\n", sc->sf_unit);
60449076Swpaul
60549076Swpaul	/* Wait a little while for the chip to get its brains in order. */
60649076Swpaul	DELAY(1000);
60749076Swpaul	return;
60849076Swpaul}
60949076Swpaul
61049076Swpaul/*
61149076Swpaul * Probe for an Adaptec AIC-6915 chip. Check the PCI vendor and device
61249076Swpaul * IDs against our list and return a device name if we find a match.
61349076Swpaul * We also check the subsystem ID so that we can identify exactly which
61449076Swpaul * NIC has been found, if possible.
61549076Swpaul */
616102335Salfredstatic int
617102335Salfredsf_probe(dev)
61849076Swpaul	device_t		dev;
61949076Swpaul{
62049076Swpaul	struct sf_type		*t;
62149076Swpaul
62249076Swpaul	t = sf_devs;
62349076Swpaul
62449076Swpaul	while(t->sf_name != NULL) {
62549076Swpaul		if ((pci_get_vendor(dev) == t->sf_vid) &&
62649076Swpaul		    (pci_get_device(dev) == t->sf_did)) {
62751336Swpaul			switch((pci_read_config(dev,
62851336Swpaul			    SF_PCI_SUBVEN_ID, 4) >> 16) & 0xFFFF) {
62949076Swpaul			case AD_SUBSYSID_62011_REV0:
63049076Swpaul			case AD_SUBSYSID_62011_REV1:
63149076Swpaul				device_set_desc(dev,
63249076Swpaul				    "Adaptec ANA-62011 10/100BaseTX");
63349076Swpaul				return(0);
63449076Swpaul				break;
63549076Swpaul			case AD_SUBSYSID_62022:
63649076Swpaul				device_set_desc(dev,
63749076Swpaul				    "Adaptec ANA-62022 10/100BaseTX");
63849076Swpaul				return(0);
63949076Swpaul				break;
64053468Swpaul			case AD_SUBSYSID_62044_REV0:
64153468Swpaul			case AD_SUBSYSID_62044_REV1:
64249076Swpaul				device_set_desc(dev,
64349076Swpaul				    "Adaptec ANA-62044 10/100BaseTX");
64449076Swpaul				return(0);
64549076Swpaul				break;
64649076Swpaul			case AD_SUBSYSID_62020:
64749076Swpaul				device_set_desc(dev,
64849076Swpaul				    "Adaptec ANA-62020 10/100BaseFX");
64949076Swpaul				return(0);
65049076Swpaul				break;
65149076Swpaul			case AD_SUBSYSID_69011:
65249076Swpaul				device_set_desc(dev,
65349076Swpaul				    "Adaptec ANA-69011 10/100BaseTX");
65449076Swpaul				return(0);
65549076Swpaul				break;
65649076Swpaul			default:
65749076Swpaul				device_set_desc(dev, t->sf_name);
65849076Swpaul				return(0);
65949076Swpaul				break;
66049076Swpaul			}
66149076Swpaul		}
66249076Swpaul		t++;
66349076Swpaul	}
66449076Swpaul
66549076Swpaul	return(ENXIO);
66649076Swpaul}
66749076Swpaul
66849076Swpaul/*
66949076Swpaul * Attach the interface. Allocate softc structures, do ifmedia
67049076Swpaul * setup and ethernet/BPF attach.
67149076Swpaul */
672102335Salfredstatic int
673102335Salfredsf_attach(dev)
67449076Swpaul	device_t		dev;
67549076Swpaul{
67667087Swpaul	int			i;
67749076Swpaul	u_int32_t		command;
67849076Swpaul	struct sf_softc		*sc;
67949076Swpaul	struct ifnet		*ifp;
68049076Swpaul	int			unit, rid, error = 0;
68149076Swpaul
68249076Swpaul	sc = device_get_softc(dev);
68349076Swpaul	unit = device_get_unit(dev);
68449076Swpaul	bzero(sc, sizeof(struct sf_softc));
68549076Swpaul
68693818Sjhb	mtx_init(&sc->sf_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
68793818Sjhb	    MTX_DEF | MTX_RECURSE);
68869583Swpaul	SF_LOCK(sc);
68949076Swpaul	/*
69049076Swpaul	 * Handle power management nonsense.
69149076Swpaul	 */
69272813Swpaul	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
69372813Swpaul		u_int32_t		iobase, membase, irq;
69449076Swpaul
69572813Swpaul		/* Save important PCI config data. */
69672813Swpaul		iobase = pci_read_config(dev, SF_PCI_LOIO, 4);
69772813Swpaul		membase = pci_read_config(dev, SF_PCI_LOMEM, 4);
69872813Swpaul		irq = pci_read_config(dev, SF_PCI_INTLINE, 4);
69949076Swpaul
70072813Swpaul		/* Reset the power state. */
70172813Swpaul		printf("sf%d: chip is in D%d power mode "
70272813Swpaul		    "-- setting to D0\n", unit,
70372813Swpaul		    pci_get_powerstate(dev));
70472813Swpaul		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
70549076Swpaul
70672813Swpaul		/* Restore PCI config data. */
70772813Swpaul		pci_write_config(dev, SF_PCI_LOIO, iobase, 4);
70872813Swpaul		pci_write_config(dev, SF_PCI_LOMEM, membase, 4);
70972813Swpaul		pci_write_config(dev, SF_PCI_INTLINE, irq, 4);
71049076Swpaul	}
71149076Swpaul
71249076Swpaul	/*
71349076Swpaul	 * Map control/status registers.
71449076Swpaul	 */
71572813Swpaul	pci_enable_busmaster(dev);
71679472Swpaul	pci_enable_io(dev, SYS_RES_IOPORT);
71779472Swpaul	pci_enable_io(dev, SYS_RES_MEMORY);
71861041Speter	command = pci_read_config(dev, PCIR_COMMAND, 4);
71949076Swpaul
72049076Swpaul#ifdef SF_USEIOSPACE
72149076Swpaul	if (!(command & PCIM_CMD_PORTEN)) {
72249076Swpaul		printf("sf%d: failed to enable I/O ports!\n", unit);
72349076Swpaul		error = ENXIO;
72449076Swpaul		goto fail;
72549076Swpaul	}
72649076Swpaul#else
72749076Swpaul	if (!(command & PCIM_CMD_MEMEN)) {
72849076Swpaul		printf("sf%d: failed to enable memory mapping!\n", unit);
72949076Swpaul		error = ENXIO;
73049076Swpaul		goto fail;
73149076Swpaul	}
73249076Swpaul#endif
73349076Swpaul
73449076Swpaul	rid = SF_RID;
73549076Swpaul	sc->sf_res = bus_alloc_resource(dev, SF_RES, &rid,
73649076Swpaul	    0, ~0, 1, RF_ACTIVE);
73749076Swpaul
73849076Swpaul	if (sc->sf_res == NULL) {
73949076Swpaul		printf ("sf%d: couldn't map ports\n", unit);
74049076Swpaul		error = ENXIO;
74149076Swpaul		goto fail;
74249076Swpaul	}
74349076Swpaul
74449076Swpaul	sc->sf_btag = rman_get_bustag(sc->sf_res);
74549076Swpaul	sc->sf_bhandle = rman_get_bushandle(sc->sf_res);
74649076Swpaul
74749076Swpaul	/* Allocate interrupt */
74849076Swpaul	rid = 0;
74949076Swpaul	sc->sf_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
75049076Swpaul	    RF_SHAREABLE | RF_ACTIVE);
75149076Swpaul
75249076Swpaul	if (sc->sf_irq == NULL) {
75349076Swpaul		printf("sf%d: couldn't map interrupt\n", unit);
75449076Swpaul		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
75549076Swpaul		error = ENXIO;
75649076Swpaul		goto fail;
75749076Swpaul	}
75849076Swpaul
75949076Swpaul	error = bus_setup_intr(dev, sc->sf_irq, INTR_TYPE_NET,
76049076Swpaul	    sf_intr, sc, &sc->sf_intrhand);
76149076Swpaul
76249076Swpaul	if (error) {
76349076Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_res);
76449076Swpaul		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
76549076Swpaul		printf("sf%d: couldn't set up irq\n", unit);
76649076Swpaul		goto fail;
76749076Swpaul	}
76849076Swpaul
76949076Swpaul	callout_handle_init(&sc->sf_stat_ch);
77049076Swpaul	/* Reset the adapter. */
77149076Swpaul	sf_reset(sc);
77249076Swpaul
77349076Swpaul	/*
77449076Swpaul	 * Get station address from the EEPROM.
77549076Swpaul	 */
77649076Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
77749076Swpaul		sc->arpcom.ac_enaddr[i] =
77849076Swpaul		    sf_read_eeprom(sc, SF_EE_NODEADDR + ETHER_ADDR_LEN - i);
77949076Swpaul
78049076Swpaul	/*
78149076Swpaul	 * An Adaptec chip was detected. Inform the world.
78249076Swpaul	 */
78349076Swpaul	printf("sf%d: Ethernet address: %6D\n", unit,
78449076Swpaul	    sc->arpcom.ac_enaddr, ":");
78549076Swpaul
78649076Swpaul	sc->sf_unit = unit;
78749076Swpaul
78849076Swpaul	/* Allocate the descriptor queues. */
78949076Swpaul	sc->sf_ldata = contigmalloc(sizeof(struct sf_list_data), M_DEVBUF,
79051657Swpaul	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
79149076Swpaul
79249076Swpaul	if (sc->sf_ldata == NULL) {
79349076Swpaul		printf("sf%d: no memory for list buffers!\n", unit);
79449076Swpaul		bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
79549076Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
79649076Swpaul		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
79749076Swpaul		error = ENXIO;
79849076Swpaul		goto fail;
79949076Swpaul	}
80049076Swpaul
80149076Swpaul	bzero(sc->sf_ldata, sizeof(struct sf_list_data));
80249076Swpaul
80350675Swpaul	/* Do MII setup. */
80450675Swpaul	if (mii_phy_probe(dev, &sc->sf_miibus,
80550675Swpaul	    sf_ifmedia_upd, sf_ifmedia_sts)) {
80649076Swpaul		printf("sf%d: MII without any phy!\n", sc->sf_unit);
80754161Swpaul		contigfree(sc->sf_ldata,sizeof(struct sf_list_data),M_DEVBUF);
80849076Swpaul		bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
80949076Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
81049076Swpaul		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
81149076Swpaul		error = ENXIO;
81249076Swpaul		goto fail;
81349076Swpaul	}
81449076Swpaul
81549076Swpaul	ifp = &sc->arpcom.ac_if;
81649076Swpaul	ifp->if_softc = sc;
81749076Swpaul	ifp->if_unit = unit;
81849076Swpaul	ifp->if_name = "sf";
81949076Swpaul	ifp->if_mtu = ETHERMTU;
82049076Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
82149076Swpaul	ifp->if_ioctl = sf_ioctl;
82249076Swpaul	ifp->if_output = ether_output;
82349076Swpaul	ifp->if_start = sf_start;
82449076Swpaul	ifp->if_watchdog = sf_watchdog;
82549076Swpaul	ifp->if_init = sf_init;
82649076Swpaul	ifp->if_baudrate = 10000000;
82749076Swpaul	ifp->if_snd.ifq_maxlen = SF_TX_DLIST_CNT - 1;
82849076Swpaul
82949076Swpaul	/*
83063090Sarchie	 * Call MI attach routine.
83149076Swpaul	 */
832106936Ssam	ether_ifattach(ifp, sc->arpcom.ac_enaddr);
83367087Swpaul	SF_UNLOCK(sc);
83467087Swpaul	return(0);
83549076Swpaul
83649076Swpaulfail:
83767087Swpaul	SF_UNLOCK(sc);
83867087Swpaul	mtx_destroy(&sc->sf_mtx);
83949076Swpaul	return(error);
84049076Swpaul}
84149076Swpaul
842102335Salfredstatic int
843102335Salfredsf_detach(dev)
84449076Swpaul	device_t		dev;
84549076Swpaul{
84649076Swpaul	struct sf_softc		*sc;
84749076Swpaul	struct ifnet		*ifp;
84849076Swpaul
84949076Swpaul	sc = device_get_softc(dev);
85067087Swpaul	SF_LOCK(sc);
85149076Swpaul	ifp = &sc->arpcom.ac_if;
85249076Swpaul
853106936Ssam	ether_ifdetach(ifp);
85449076Swpaul	sf_stop(sc);
85549076Swpaul
85650675Swpaul	bus_generic_detach(dev);
85750675Swpaul	device_delete_child(dev, sc->sf_miibus);
85850675Swpaul
85949076Swpaul	bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
86049076Swpaul	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
86149076Swpaul	bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
86249076Swpaul
86354161Swpaul	contigfree(sc->sf_ldata, sizeof(struct sf_list_data), M_DEVBUF);
86449076Swpaul
86567087Swpaul	SF_UNLOCK(sc);
86667087Swpaul	mtx_destroy(&sc->sf_mtx);
86749076Swpaul
86849076Swpaul	return(0);
86949076Swpaul}
87049076Swpaul
871102335Salfredstatic int
872102335Salfredsf_init_rx_ring(sc)
87349076Swpaul	struct sf_softc		*sc;
87449076Swpaul{
87549076Swpaul	struct sf_list_data	*ld;
87649076Swpaul	int			i;
87749076Swpaul
87849076Swpaul	ld = sc->sf_ldata;
87949076Swpaul
88049076Swpaul	bzero((char *)ld->sf_rx_dlist_big,
88149076Swpaul	    sizeof(struct sf_rx_bufdesc_type0) * SF_RX_DLIST_CNT);
88249076Swpaul	bzero((char *)ld->sf_rx_clist,
88349076Swpaul	    sizeof(struct sf_rx_cmpdesc_type3) * SF_RX_CLIST_CNT);
88449076Swpaul
88549076Swpaul	for (i = 0; i < SF_RX_DLIST_CNT; i++) {
88649076Swpaul		if (sf_newbuf(sc, &ld->sf_rx_dlist_big[i], NULL) == ENOBUFS)
88749076Swpaul			return(ENOBUFS);
88849076Swpaul	}
88949076Swpaul
89049076Swpaul	return(0);
89149076Swpaul}
89249076Swpaul
893102335Salfredstatic void
894102335Salfredsf_init_tx_ring(sc)
89549076Swpaul	struct sf_softc		*sc;
89649076Swpaul{
89749076Swpaul	struct sf_list_data	*ld;
89849076Swpaul	int			i;
89949076Swpaul
90049076Swpaul	ld = sc->sf_ldata;
90149076Swpaul
90249076Swpaul	bzero((char *)ld->sf_tx_dlist,
90349076Swpaul	    sizeof(struct sf_tx_bufdesc_type0) * SF_TX_DLIST_CNT);
90449076Swpaul	bzero((char *)ld->sf_tx_clist,
90549076Swpaul	    sizeof(struct sf_tx_cmpdesc_type0) * SF_TX_CLIST_CNT);
90649076Swpaul
90749076Swpaul	for (i = 0; i < SF_TX_DLIST_CNT; i++)
90849076Swpaul		ld->sf_tx_dlist[i].sf_id = SF_TX_BUFDESC_ID;
90949076Swpaul	for (i = 0; i < SF_TX_CLIST_CNT; i++)
91049076Swpaul		ld->sf_tx_clist[i].sf_type = SF_TXCMPTYPE_TX;
91149076Swpaul
91249076Swpaul	ld->sf_tx_dlist[SF_TX_DLIST_CNT - 1].sf_end = 1;
91349076Swpaul	sc->sf_tx_cnt = 0;
91449076Swpaul
91549076Swpaul	return;
91649076Swpaul}
91749076Swpaul
918102335Salfredstatic int
919102335Salfredsf_newbuf(sc, c, m)
92049076Swpaul	struct sf_softc		*sc;
92149076Swpaul	struct sf_rx_bufdesc_type0	*c;
92249076Swpaul	struct mbuf		*m;
92349076Swpaul{
92449076Swpaul	struct mbuf		*m_new = NULL;
92549076Swpaul
92649076Swpaul	if (m == NULL) {
927111119Simp		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
92887846Sluigi		if (m_new == NULL)
92949076Swpaul			return(ENOBUFS);
93049076Swpaul
931111119Simp		MCLGET(m_new, M_DONTWAIT);
93249076Swpaul		if (!(m_new->m_flags & M_EXT)) {
93349076Swpaul			m_freem(m_new);
93449076Swpaul			return(ENOBUFS);
93549076Swpaul		}
93649076Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
93749076Swpaul	} else {
93849076Swpaul		m_new = m;
93949076Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
94049076Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
94149076Swpaul	}
94249076Swpaul
94349076Swpaul	m_adj(m_new, sizeof(u_int64_t));
94449076Swpaul
94549076Swpaul	c->sf_mbuf = m_new;
94649076Swpaul	c->sf_addrlo = SF_RX_HOSTADDR(vtophys(mtod(m_new, caddr_t)));
94749076Swpaul	c->sf_valid = 1;
94849076Swpaul
94949076Swpaul	return(0);
95049076Swpaul}
95149076Swpaul
95249076Swpaul/*
95349076Swpaul * The starfire is programmed to use 'normal' mode for packet reception,
95449076Swpaul * which means we use the consumer/producer model for both the buffer
95549076Swpaul * descriptor queue and the completion descriptor queue. The only problem
95649076Swpaul * with this is that it involves a lot of register accesses: we have to
95749076Swpaul * read the RX completion consumer and producer indexes and the RX buffer
95849076Swpaul * producer index, plus the RX completion consumer and RX buffer producer
95949076Swpaul * indexes have to be updated. It would have been easier if Adaptec had
96049076Swpaul * put each index in a separate register, especially given that the damn
96149076Swpaul * NIC has a 512K register space.
96249076Swpaul *
96349076Swpaul * In spite of all the lovely features that Adaptec crammed into the 6915,
96449076Swpaul * it is marred by one truly stupid design flaw, which is that receive
96549076Swpaul * buffer addresses must be aligned on a longword boundary. This forces
96649076Swpaul * the packet payload to be unaligned, which is suboptimal on the x86 and
96749076Swpaul * completely unuseable on the Alpha. Our only recourse is to copy received
96849076Swpaul * packets into properly aligned buffers before handing them off.
96949076Swpaul */
97049076Swpaul
971102335Salfredstatic void
972102335Salfredsf_rxeof(sc)
97349076Swpaul	struct sf_softc		*sc;
97449076Swpaul{
97549076Swpaul	struct mbuf		*m;
97649076Swpaul	struct ifnet		*ifp;
97749076Swpaul	struct sf_rx_bufdesc_type0	*desc;
97849076Swpaul	struct sf_rx_cmpdesc_type3	*cur_rx;
97949076Swpaul	u_int32_t		rxcons, rxprod;
98049076Swpaul	int			cmpprodidx, cmpconsidx, bufprodidx;
98149076Swpaul
98249076Swpaul	ifp = &sc->arpcom.ac_if;
98349076Swpaul
98449076Swpaul	rxcons = csr_read_4(sc, SF_CQ_CONSIDX);
98549076Swpaul	rxprod = csr_read_4(sc, SF_RXDQ_PTR_Q1);
98649076Swpaul	cmpprodidx = SF_IDX_LO(csr_read_4(sc, SF_CQ_PRODIDX));
98749076Swpaul	cmpconsidx = SF_IDX_LO(rxcons);
98849076Swpaul	bufprodidx = SF_IDX_LO(rxprod);
98949076Swpaul
99049076Swpaul	while (cmpconsidx != cmpprodidx) {
99149076Swpaul		struct mbuf		*m0;
99249076Swpaul
99349076Swpaul		cur_rx = &sc->sf_ldata->sf_rx_clist[cmpconsidx];
99449076Swpaul		desc = &sc->sf_ldata->sf_rx_dlist_big[cur_rx->sf_endidx];
99549076Swpaul		m = desc->sf_mbuf;
99649076Swpaul		SF_INC(cmpconsidx, SF_RX_CLIST_CNT);
99749076Swpaul		SF_INC(bufprodidx, SF_RX_DLIST_CNT);
99849076Swpaul
99949076Swpaul		if (!(cur_rx->sf_status1 & SF_RXSTAT1_OK)) {
100049076Swpaul			ifp->if_ierrors++;
100149076Swpaul			sf_newbuf(sc, desc, m);
100249076Swpaul			continue;
100349076Swpaul		}
100449076Swpaul
100578508Sbmilekic		m0 = m_devget(mtod(m, char *), cur_rx->sf_len, ETHER_ALIGN,
100678508Sbmilekic		    ifp, NULL);
100749076Swpaul		sf_newbuf(sc, desc, m);
100849076Swpaul		if (m0 == NULL) {
100949076Swpaul			ifp->if_ierrors++;
101049076Swpaul			continue;
101149076Swpaul		}
101249076Swpaul		m = m0;
101349076Swpaul
101449076Swpaul		ifp->if_ipackets++;
1015106936Ssam		(*ifp->if_input)(ifp, m);
101649076Swpaul	}
101749076Swpaul
101849076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX,
101949076Swpaul	    (rxcons & ~SF_CQ_CONSIDX_RXQ1) | cmpconsidx);
102049076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1,
102149076Swpaul	    (rxprod & ~SF_RXDQ_PRODIDX) | bufprodidx);
102249076Swpaul
102349076Swpaul	return;
102449076Swpaul}
102549076Swpaul
102649076Swpaul/*
102749076Swpaul * Read the transmit status from the completion queue and release
102849076Swpaul * mbufs. Note that the buffer descriptor index in the completion
102949076Swpaul * descriptor is an offset from the start of the transmit buffer
103049076Swpaul * descriptor list in bytes. This is important because the manual
103149076Swpaul * gives the impression that it should match the producer/consumer
103249076Swpaul * index, which is the offset in 8 byte blocks.
103349076Swpaul */
1034102335Salfredstatic void
1035102335Salfredsf_txeof(sc)
103649076Swpaul	struct sf_softc		*sc;
103749076Swpaul{
103849076Swpaul	int			txcons, cmpprodidx, cmpconsidx;
103949076Swpaul	struct sf_tx_cmpdesc_type1 *cur_cmp;
104049076Swpaul	struct sf_tx_bufdesc_type0 *cur_tx;
104149076Swpaul	struct ifnet		*ifp;
104249076Swpaul
104349076Swpaul	ifp = &sc->arpcom.ac_if;
104449076Swpaul
104549076Swpaul	txcons = csr_read_4(sc, SF_CQ_CONSIDX);
104649076Swpaul	cmpprodidx = SF_IDX_HI(csr_read_4(sc, SF_CQ_PRODIDX));
104749076Swpaul	cmpconsidx = SF_IDX_HI(txcons);
104849076Swpaul
104949076Swpaul	while (cmpconsidx != cmpprodidx) {
105049076Swpaul		cur_cmp = &sc->sf_ldata->sf_tx_clist[cmpconsidx];
105149076Swpaul		cur_tx = &sc->sf_ldata->sf_tx_dlist[cur_cmp->sf_index >> 7];
105249076Swpaul
105349076Swpaul		if (cur_cmp->sf_txstat & SF_TXSTAT_TX_OK)
105449076Swpaul			ifp->if_opackets++;
105581737Swpaul		else {
105681737Swpaul			if (cur_cmp->sf_txstat & SF_TXSTAT_TX_UNDERRUN)
105781737Swpaul				sf_txthresh_adjust(sc);
105849076Swpaul			ifp->if_oerrors++;
105981737Swpaul		}
106049076Swpaul
106149076Swpaul		sc->sf_tx_cnt--;
106249076Swpaul		if (cur_tx->sf_mbuf != NULL) {
106349076Swpaul			m_freem(cur_tx->sf_mbuf);
106449076Swpaul			cur_tx->sf_mbuf = NULL;
106581737Swpaul		} else
106681737Swpaul			break;
106781737Swpaul		SF_INC(cmpconsidx, SF_TX_CLIST_CNT);
106849076Swpaul	}
106949076Swpaul
107049076Swpaul	ifp->if_timer = 0;
107149076Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
107249076Swpaul
107349076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX,
107449076Swpaul	    (txcons & ~SF_CQ_CONSIDX_TXQ) |
107549076Swpaul	    ((cmpconsidx << 16) & 0xFFFF0000));
107649076Swpaul
107749076Swpaul	return;
107849076Swpaul}
107949076Swpaul
1080102335Salfredstatic void
1081102335Salfredsf_txthresh_adjust(sc)
108281737Swpaul	struct sf_softc		*sc;
108381737Swpaul{
108481737Swpaul	u_int32_t		txfctl;
108581737Swpaul	u_int8_t		txthresh;
108681737Swpaul
108781737Swpaul	txfctl = csr_read_4(sc, SF_TX_FRAMCTL);
108881737Swpaul	txthresh = txfctl & SF_TXFRMCTL_TXTHRESH;
108981737Swpaul	if (txthresh < 0xFF) {
109081737Swpaul		txthresh++;
109181737Swpaul		txfctl &= ~SF_TXFRMCTL_TXTHRESH;
109281737Swpaul		txfctl |= txthresh;
109381737Swpaul#ifdef DIAGNOSTIC
109481737Swpaul		printf("sf%d: tx underrun, increasing "
109581737Swpaul		    "tx threshold to %d bytes\n",
109681737Swpaul		    sc->sf_unit, txthresh * 4);
109781737Swpaul#endif
109881737Swpaul		csr_write_4(sc, SF_TX_FRAMCTL, txfctl);
109981737Swpaul	}
110081737Swpaul
110181737Swpaul	return;
110281737Swpaul}
110381737Swpaul
1104102335Salfredstatic void
1105102335Salfredsf_intr(arg)
110649076Swpaul	void			*arg;
110749076Swpaul{
110849076Swpaul	struct sf_softc		*sc;
110949076Swpaul	struct ifnet		*ifp;
111049076Swpaul	u_int32_t		status;
111149076Swpaul
111249076Swpaul	sc = arg;
111367087Swpaul	SF_LOCK(sc);
111467087Swpaul
111549076Swpaul	ifp = &sc->arpcom.ac_if;
111649076Swpaul
111767087Swpaul	if (!(csr_read_4(sc, SF_ISR_SHADOW) & SF_ISR_PCIINT_ASSERTED)) {
111867087Swpaul		SF_UNLOCK(sc);
111949076Swpaul		return;
112067087Swpaul	}
112149076Swpaul
112249076Swpaul	/* Disable interrupts. */
112349076Swpaul	csr_write_4(sc, SF_IMR, 0x00000000);
112449076Swpaul
112549076Swpaul	for (;;) {
112649076Swpaul		status = csr_read_4(sc, SF_ISR);
112749076Swpaul		if (status)
112849076Swpaul			csr_write_4(sc, SF_ISR, status);
112949076Swpaul
113049076Swpaul		if (!(status & SF_INTRS))
113149076Swpaul			break;
113249076Swpaul
113349076Swpaul		if (status & SF_ISR_RXDQ1_DMADONE)
113449076Swpaul			sf_rxeof(sc);
113549076Swpaul
113681714Swpaul		if (status & SF_ISR_TX_TXDONE ||
113781714Swpaul		    status & SF_ISR_TX_DMADONE ||
113881737Swpaul		    status & SF_ISR_TX_QUEUEDONE)
113949076Swpaul			sf_txeof(sc);
114049076Swpaul
114181737Swpaul		if (status & SF_ISR_TX_LOFIFO)
114281737Swpaul			sf_txthresh_adjust(sc);
114381737Swpaul
114449076Swpaul		if (status & SF_ISR_ABNORMALINTR) {
114549076Swpaul			if (status & SF_ISR_STATSOFLOW) {
114649076Swpaul				untimeout(sf_stats_update, sc,
114749076Swpaul				    sc->sf_stat_ch);
114849076Swpaul				sf_stats_update(sc);
114949076Swpaul			} else
115049076Swpaul				sf_init(sc);
115149076Swpaul		}
115249076Swpaul	}
115349076Swpaul
115449076Swpaul	/* Re-enable interrupts. */
115549076Swpaul	csr_write_4(sc, SF_IMR, SF_INTRS);
115649076Swpaul
115749076Swpaul	if (ifp->if_snd.ifq_head != NULL)
115849076Swpaul		sf_start(ifp);
115949076Swpaul
116067087Swpaul	SF_UNLOCK(sc);
116149076Swpaul	return;
116249076Swpaul}
116349076Swpaul
1164102335Salfredstatic void
1165102335Salfredsf_init(xsc)
116649076Swpaul	void			*xsc;
116749076Swpaul{
116849076Swpaul	struct sf_softc		*sc;
116949076Swpaul	struct ifnet		*ifp;
117050675Swpaul	struct mii_data		*mii;
117167087Swpaul	int			i;
117249076Swpaul
117349076Swpaul	sc = xsc;
117467087Swpaul	SF_LOCK(sc);
117549076Swpaul	ifp = &sc->arpcom.ac_if;
117650675Swpaul	mii = device_get_softc(sc->sf_miibus);
117749076Swpaul
117849076Swpaul	sf_stop(sc);
117949076Swpaul	sf_reset(sc);
118049076Swpaul
118149076Swpaul	/* Init all the receive filter registers */
118249076Swpaul	for (i = SF_RXFILT_PERFECT_BASE;
118349076Swpaul	    i < (SF_RXFILT_HASH_MAX + 1); i += 4)
118449076Swpaul		csr_write_4(sc, i, 0);
118549076Swpaul
118649076Swpaul	/* Empty stats counter registers. */
118749076Swpaul	for (i = 0; i < sizeof(struct sf_stats)/sizeof(u_int32_t); i++)
118849076Swpaul		csr_write_4(sc, SF_STATS_BASE +
118949076Swpaul		    (i + sizeof(u_int32_t)), 0);
119049076Swpaul
119149076Swpaul	/* Init our MAC address */
119249076Swpaul	csr_write_4(sc, SF_PAR0, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0]));
119349076Swpaul	csr_write_4(sc, SF_PAR1, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4]));
119449076Swpaul	sf_setperf(sc, 0, (caddr_t)&sc->arpcom.ac_enaddr);
119549076Swpaul
119649076Swpaul	if (sf_init_rx_ring(sc) == ENOBUFS) {
119749076Swpaul		printf("sf%d: initialization failed: no "
119849076Swpaul		    "memory for rx buffers\n", sc->sf_unit);
119967087Swpaul		SF_UNLOCK(sc);
120049076Swpaul		return;
120149076Swpaul	}
120249076Swpaul
120349076Swpaul	sf_init_tx_ring(sc);
120449076Swpaul
120549076Swpaul	csr_write_4(sc, SF_RXFILT, SF_PERFMODE_NORMAL|SF_HASHMODE_WITHVLAN);
120649076Swpaul
120749076Swpaul	/* If we want promiscuous mode, set the allframes bit. */
120849076Swpaul	if (ifp->if_flags & IFF_PROMISC) {
120949076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
121049076Swpaul	} else {
121149076Swpaul		SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
121249076Swpaul	}
121349076Swpaul
121449076Swpaul	if (ifp->if_flags & IFF_BROADCAST) {
121549076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_BROAD);
121649076Swpaul	} else {
121749076Swpaul		SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_BROAD);
121849076Swpaul	}
121949076Swpaul
122063166Swpaul	/*
122163166Swpaul	 * Load the multicast filter.
122263166Swpaul	 */
122363166Swpaul	sf_setmulti(sc);
122463166Swpaul
122549076Swpaul	/* Init the completion queue indexes */
122649076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX, 0);
122749076Swpaul	csr_write_4(sc, SF_CQ_PRODIDX, 0);
122849076Swpaul
122949076Swpaul	/* Init the RX completion queue */
123049076Swpaul	csr_write_4(sc, SF_RXCQ_CTL_1,
123149076Swpaul	    vtophys(sc->sf_ldata->sf_rx_clist) & SF_RXCQ_ADDR);
123249076Swpaul	SF_SETBIT(sc, SF_RXCQ_CTL_1, SF_RXCQTYPE_3);
123349076Swpaul
123449076Swpaul	/* Init RX DMA control. */
123549076Swpaul	SF_SETBIT(sc, SF_RXDMA_CTL, SF_RXDMA_REPORTBADPKTS);
123649076Swpaul
123749076Swpaul	/* Init the RX buffer descriptor queue. */
123849076Swpaul	csr_write_4(sc, SF_RXDQ_ADDR_Q1,
123949076Swpaul	    vtophys(sc->sf_ldata->sf_rx_dlist_big));
124049076Swpaul	csr_write_4(sc, SF_RXDQ_CTL_1, (MCLBYTES << 16) | SF_DESCSPACE_16BYTES);
124149076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1, SF_RX_DLIST_CNT - 1);
124249076Swpaul
124349076Swpaul	/* Init the TX completion queue */
124449076Swpaul	csr_write_4(sc, SF_TXCQ_CTL,
124549076Swpaul	    vtophys(sc->sf_ldata->sf_tx_clist) & SF_RXCQ_ADDR);
124649076Swpaul
124749076Swpaul	/* Init the TX buffer descriptor queue. */
124849076Swpaul	csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO,
124949076Swpaul		vtophys(sc->sf_ldata->sf_tx_dlist));
125049076Swpaul	SF_SETBIT(sc, SF_TX_FRAMCTL, SF_TXFRMCTL_CPLAFTERTX);
125149076Swpaul	csr_write_4(sc, SF_TXDQ_CTL,
125249076Swpaul	    SF_TXBUFDESC_TYPE0|SF_TXMINSPACE_128BYTES|SF_TXSKIPLEN_8BYTES);
125349076Swpaul	SF_SETBIT(sc, SF_TXDQ_CTL, SF_TXDQCTL_NODMACMP);
125449076Swpaul
125549076Swpaul	/* Enable autopadding of short TX frames. */
125649076Swpaul	SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_AUTOPAD);
125749076Swpaul
125849076Swpaul	/* Enable interrupts. */
125949076Swpaul	csr_write_4(sc, SF_IMR, SF_INTRS);
126049076Swpaul	SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_INTR_ENB);
126149076Swpaul
126249076Swpaul	/* Enable the RX and TX engines. */
126349076Swpaul	SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_RX_ENB|SF_ETHCTL_RXDMA_ENB);
126449076Swpaul	SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_TX_ENB|SF_ETHCTL_TXDMA_ENB);
126549076Swpaul
126654161Swpaul	/*mii_mediachg(mii);*/
126754161Swpaul	sf_ifmedia_upd(ifp);
126850675Swpaul
126949076Swpaul	ifp->if_flags |= IFF_RUNNING;
127049076Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
127149076Swpaul
127249076Swpaul	sc->sf_stat_ch = timeout(sf_stats_update, sc, hz);
127349076Swpaul
127467087Swpaul	SF_UNLOCK(sc);
127549076Swpaul
127649076Swpaul	return;
127749076Swpaul}
127849076Swpaul
1279102335Salfredstatic int
1280102335Salfredsf_encap(sc, c, m_head)
128149076Swpaul	struct sf_softc		*sc;
128249076Swpaul	struct sf_tx_bufdesc_type0 *c;
128349076Swpaul	struct mbuf		*m_head;
128449076Swpaul{
128549076Swpaul	int			frag = 0;
128649076Swpaul	struct sf_frag		*f = NULL;
128749076Swpaul	struct mbuf		*m;
128849076Swpaul
128949076Swpaul	m = m_head;
129049076Swpaul
129149076Swpaul	for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
129249076Swpaul		if (m->m_len != 0) {
129349076Swpaul			if (frag == SF_MAXFRAGS)
129449076Swpaul				break;
129549076Swpaul			f = &c->sf_frags[frag];
129649076Swpaul			if (frag == 0)
129749076Swpaul				f->sf_pktlen = m_head->m_pkthdr.len;
129849076Swpaul			f->sf_fraglen = m->m_len;
129949076Swpaul			f->sf_addr = vtophys(mtod(m, vm_offset_t));
130049076Swpaul			frag++;
130149076Swpaul		}
130249076Swpaul	}
130349076Swpaul
130449076Swpaul	if (m != NULL) {
130549076Swpaul		struct mbuf		*m_new = NULL;
130649076Swpaul
1307111119Simp		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
130849076Swpaul		if (m_new == NULL) {
1309103139Sticso			printf("sf%d: no memory for tx list\n", sc->sf_unit);
131049076Swpaul			return(1);
131149076Swpaul		}
131249076Swpaul
131349076Swpaul		if (m_head->m_pkthdr.len > MHLEN) {
1314111119Simp			MCLGET(m_new, M_DONTWAIT);
131549076Swpaul			if (!(m_new->m_flags & M_EXT)) {
131649076Swpaul				m_freem(m_new);
1317103139Sticso				printf("sf%d: no memory for tx list\n",
131849076Swpaul				    sc->sf_unit);
131949076Swpaul				return(1);
132049076Swpaul			}
132149076Swpaul		}
132249076Swpaul		m_copydata(m_head, 0, m_head->m_pkthdr.len,
132349076Swpaul		    mtod(m_new, caddr_t));
132449076Swpaul		m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
132549076Swpaul		m_freem(m_head);
132649076Swpaul		m_head = m_new;
132749076Swpaul		f = &c->sf_frags[0];
132849076Swpaul		f->sf_fraglen = f->sf_pktlen = m_head->m_pkthdr.len;
132949076Swpaul		f->sf_addr = vtophys(mtod(m_head, caddr_t));
133049076Swpaul		frag = 1;
133149076Swpaul	}
133249076Swpaul
133349076Swpaul	c->sf_mbuf = m_head;
133449076Swpaul	c->sf_id = SF_TX_BUFDESC_ID;
133549076Swpaul	c->sf_fragcnt = frag;
133649076Swpaul	c->sf_intr = 1;
133749076Swpaul	c->sf_caltcp = 0;
133849076Swpaul	c->sf_crcen = 1;
133949076Swpaul
134049076Swpaul	return(0);
134149076Swpaul}
134249076Swpaul
1343102335Salfredstatic void
1344102335Salfredsf_start(ifp)
134549076Swpaul	struct ifnet		*ifp;
134649076Swpaul{
134749076Swpaul	struct sf_softc		*sc;
134849076Swpaul	struct sf_tx_bufdesc_type0 *cur_tx = NULL;
134949076Swpaul	struct mbuf		*m_head = NULL;
135049076Swpaul	int			i, txprod;
135149076Swpaul
135249076Swpaul	sc = ifp->if_softc;
135367087Swpaul	SF_LOCK(sc);
135449076Swpaul
135581714Swpaul	if (!sc->sf_link && ifp->if_snd.ifq_len < 10) {
135667087Swpaul		SF_UNLOCK(sc);
135754161Swpaul		return;
135867087Swpaul	}
135954161Swpaul
136067087Swpaul	if (ifp->if_flags & IFF_OACTIVE) {
136167087Swpaul		SF_UNLOCK(sc);
136249076Swpaul		return;
136367087Swpaul	}
136449076Swpaul
136549076Swpaul	txprod = csr_read_4(sc, SF_TXDQ_PRODIDX);
136649076Swpaul	i = SF_IDX_HI(txprod) >> 4;
136749076Swpaul
136881737Swpaul	if (sc->sf_ldata->sf_tx_dlist[i].sf_mbuf != NULL) {
136981737Swpaul		printf("sf%d: TX ring full, resetting\n", sc->sf_unit);
137081737Swpaul		sf_init(sc);
137181737Swpaul		txprod = csr_read_4(sc, SF_TXDQ_PRODIDX);
137281737Swpaul		i = SF_IDX_HI(txprod) >> 4;
137381737Swpaul	}
137481737Swpaul
137549076Swpaul	while(sc->sf_ldata->sf_tx_dlist[i].sf_mbuf == NULL) {
137681737Swpaul		if (sc->sf_tx_cnt >= (SF_TX_DLIST_CNT - 5)) {
137771276Swpaul			ifp->if_flags |= IFF_OACTIVE;
137871276Swpaul			cur_tx = NULL;
137971276Swpaul			break;
138071276Swpaul		}
138149076Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
138249076Swpaul		if (m_head == NULL)
138349076Swpaul			break;
138449076Swpaul
138549076Swpaul		cur_tx = &sc->sf_ldata->sf_tx_dlist[i];
138671276Swpaul		if (sf_encap(sc, cur_tx, m_head)) {
138771276Swpaul			IF_PREPEND(&ifp->if_snd, m_head);
138871276Swpaul			ifp->if_flags |= IFF_OACTIVE;
138971276Swpaul			cur_tx = NULL;
139071276Swpaul			break;
139171276Swpaul		}
139249076Swpaul
139349076Swpaul		/*
139449076Swpaul		 * If there's a BPF listener, bounce a copy of this frame
139549076Swpaul		 * to him.
139649076Swpaul		 */
1397106936Ssam		BPF_MTAP(ifp, m_head);
139851583Swpaul
139949076Swpaul		SF_INC(i, SF_TX_DLIST_CNT);
140049076Swpaul		sc->sf_tx_cnt++;
140181798Swpaul		/*
140281798Swpaul		 * Don't get the TX DMA queue get too full.
140381798Swpaul		 */
140481798Swpaul		if (sc->sf_tx_cnt > 64)
140581798Swpaul			break;
140649076Swpaul	}
140749076Swpaul
140867087Swpaul	if (cur_tx == NULL) {
140967087Swpaul		SF_UNLOCK(sc);
141049076Swpaul		return;
141167087Swpaul	}
141249076Swpaul
141349076Swpaul	/* Transmit */
141449076Swpaul	csr_write_4(sc, SF_TXDQ_PRODIDX,
141549076Swpaul	    (txprod & ~SF_TXDQ_PRODIDX_HIPRIO) |
141649076Swpaul	    ((i << 20) & 0xFFFF0000));
141749076Swpaul
141849076Swpaul	ifp->if_timer = 5;
141949076Swpaul
142067087Swpaul	SF_UNLOCK(sc);
142167087Swpaul
142249076Swpaul	return;
142349076Swpaul}
142449076Swpaul
1425102335Salfredstatic void
1426102335Salfredsf_stop(sc)
142749076Swpaul	struct sf_softc		*sc;
142849076Swpaul{
142949076Swpaul	int			i;
143049077Swpaul	struct ifnet		*ifp;
143149076Swpaul
143267087Swpaul	SF_LOCK(sc);
143367087Swpaul
143449077Swpaul	ifp = &sc->arpcom.ac_if;
143549077Swpaul
143649076Swpaul	untimeout(sf_stats_update, sc, sc->sf_stat_ch);
143749076Swpaul
143849076Swpaul	csr_write_4(sc, SF_GEN_ETH_CTL, 0);
143949076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX, 0);
144049076Swpaul	csr_write_4(sc, SF_CQ_PRODIDX, 0);
144149076Swpaul	csr_write_4(sc, SF_RXDQ_ADDR_Q1, 0);
144249076Swpaul	csr_write_4(sc, SF_RXDQ_CTL_1, 0);
144349076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1, 0);
144449076Swpaul	csr_write_4(sc, SF_TXCQ_CTL, 0);
144549076Swpaul	csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO, 0);
144649076Swpaul	csr_write_4(sc, SF_TXDQ_CTL, 0);
144749076Swpaul	sf_reset(sc);
144849076Swpaul
144954161Swpaul	sc->sf_link = 0;
145054161Swpaul
145149076Swpaul	for (i = 0; i < SF_RX_DLIST_CNT; i++) {
145249076Swpaul		if (sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf != NULL) {
145349076Swpaul			m_freem(sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf);
145449076Swpaul			sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf = NULL;
145549076Swpaul		}
145649076Swpaul	}
145749076Swpaul
145849076Swpaul	for (i = 0; i < SF_TX_DLIST_CNT; i++) {
145949076Swpaul		if (sc->sf_ldata->sf_tx_dlist[i].sf_mbuf != NULL) {
146049076Swpaul			m_freem(sc->sf_ldata->sf_tx_dlist[i].sf_mbuf);
146149076Swpaul			sc->sf_ldata->sf_tx_dlist[i].sf_mbuf = NULL;
146249076Swpaul		}
146349076Swpaul	}
146449076Swpaul
146549077Swpaul	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
146667087Swpaul	SF_UNLOCK(sc);
146749077Swpaul
146849076Swpaul	return;
146949076Swpaul}
147049076Swpaul
147149076Swpaul/*
147249076Swpaul * Note: it is important that this function not be interrupted. We
147349076Swpaul * use a two-stage register access scheme: if we are interrupted in
147449076Swpaul * between setting the indirect address register and reading from the
147549076Swpaul * indirect data register, the contents of the address register could
147649076Swpaul * be changed out from under us.
147749076Swpaul */
1478102335Salfredstatic void
1479102335Salfredsf_stats_update(xsc)
148049076Swpaul	void			*xsc;
148149076Swpaul{
148249076Swpaul	struct sf_softc		*sc;
148349076Swpaul	struct ifnet		*ifp;
148450675Swpaul	struct mii_data		*mii;
148549076Swpaul	struct sf_stats		stats;
148649076Swpaul	u_int32_t		*ptr;
148767087Swpaul	int			i;
148849076Swpaul
148949076Swpaul	sc = xsc;
149067087Swpaul	SF_LOCK(sc);
149149076Swpaul	ifp = &sc->arpcom.ac_if;
149250675Swpaul	mii = device_get_softc(sc->sf_miibus);
149349076Swpaul
149449076Swpaul	ptr = (u_int32_t *)&stats;
149549076Swpaul	for (i = 0; i < sizeof(stats)/sizeof(u_int32_t); i++)
149649076Swpaul		ptr[i] = csr_read_4(sc, SF_STATS_BASE +
149749076Swpaul		    (i + sizeof(u_int32_t)));
149849076Swpaul
149949076Swpaul	for (i = 0; i < sizeof(stats)/sizeof(u_int32_t); i++)
150049076Swpaul		csr_write_4(sc, SF_STATS_BASE +
150149076Swpaul		    (i + sizeof(u_int32_t)), 0);
150249076Swpaul
150349076Swpaul	ifp->if_collisions += stats.sf_tx_single_colls +
150449076Swpaul	    stats.sf_tx_multi_colls + stats.sf_tx_excess_colls;
150549076Swpaul
150650675Swpaul	mii_tick(mii);
150784147Sjlemon
150884147Sjlemon	if (!sc->sf_link && mii->mii_media_status & IFM_ACTIVE &&
150984147Sjlemon	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
151084147Sjlemon		sc->sf_link++;
151184147Sjlemon		if (ifp->if_snd.ifq_head != NULL)
151284147Sjlemon			sf_start(ifp);
151354161Swpaul	}
151450675Swpaul
151549076Swpaul	sc->sf_stat_ch = timeout(sf_stats_update, sc, hz);
151649076Swpaul
151767087Swpaul	SF_UNLOCK(sc);
151849076Swpaul
151949076Swpaul	return;
152049076Swpaul}
152149076Swpaul
1522102335Salfredstatic void
1523102335Salfredsf_watchdog(ifp)
152449076Swpaul	struct ifnet		*ifp;
152549076Swpaul{
152649076Swpaul	struct sf_softc		*sc;
152749076Swpaul
152849076Swpaul	sc = ifp->if_softc;
152949076Swpaul
153067087Swpaul	SF_LOCK(sc);
153167087Swpaul
153249076Swpaul	ifp->if_oerrors++;
153349076Swpaul	printf("sf%d: watchdog timeout\n", sc->sf_unit);
153449076Swpaul
153549076Swpaul	sf_stop(sc);
153649076Swpaul	sf_reset(sc);
153749076Swpaul	sf_init(sc);
153849076Swpaul
153949076Swpaul	if (ifp->if_snd.ifq_head != NULL)
154049076Swpaul		sf_start(ifp);
154149076Swpaul
154267087Swpaul	SF_UNLOCK(sc);
154367087Swpaul
154449076Swpaul	return;
154549076Swpaul}
154649076Swpaul
1547102335Salfredstatic void
1548102335Salfredsf_shutdown(dev)
154949076Swpaul	device_t		dev;
155049076Swpaul{
155149076Swpaul	struct sf_softc		*sc;
155249076Swpaul
155349076Swpaul	sc = device_get_softc(dev);
155449076Swpaul
155549076Swpaul	sf_stop(sc);
155649076Swpaul
155749076Swpaul	return;
155849076Swpaul}
1559