if_sf.c revision 134442
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 */
3249076Swpaul
33122678Sobrien#include <sys/cdefs.h>
34122678Sobrien__FBSDID("$FreeBSD: head/sys/dev/sf/if_sf.c 134442 2004-08-28 15:10:35Z rwatson $");
35122678Sobrien
3649076Swpaul/*
3749076Swpaul * Adaptec AIC-6915 "Starfire" PCI fast ethernet driver for FreeBSD.
3851682Swpaul * Programming manual is available from:
3951682Swpaul * ftp.adaptec.com:/pub/BBS/userguides/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);
16749076Swpaul
16892739Salfredstatic u_int32_t csr_read_4	(struct sf_softc *, int);
16992739Salfredstatic void csr_write_4		(struct sf_softc *, int, u_int32_t);
17092739Salfredstatic void sf_txthresh_adjust	(struct sf_softc *);
17149076Swpaul
17249076Swpaul#ifdef SF_USEIOSPACE
17349076Swpaul#define SF_RES			SYS_RES_IOPORT
17449076Swpaul#define SF_RID			SF_PCI_LOIO
17549076Swpaul#else
17649076Swpaul#define SF_RES			SYS_RES_MEMORY
17749076Swpaul#define SF_RID			SF_PCI_LOMEM
17849076Swpaul#endif
17949076Swpaul
18049076Swpaulstatic device_method_t sf_methods[] = {
18149076Swpaul	/* Device interface */
18249076Swpaul	DEVMETHOD(device_probe,		sf_probe),
18349076Swpaul	DEVMETHOD(device_attach,	sf_attach),
18449076Swpaul	DEVMETHOD(device_detach,	sf_detach),
18549076Swpaul	DEVMETHOD(device_shutdown,	sf_shutdown),
18650675Swpaul
18750675Swpaul	/* bus interface */
18850675Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
18950675Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
19050675Swpaul
19150675Swpaul	/* MII interface */
19250675Swpaul	DEVMETHOD(miibus_readreg,	sf_miibus_readreg),
19350675Swpaul	DEVMETHOD(miibus_writereg,	sf_miibus_writereg),
19450675Swpaul	DEVMETHOD(miibus_statchg,	sf_miibus_statchg),
19550675Swpaul
19649076Swpaul	{ 0, 0 }
19749076Swpaul};
19849076Swpaul
19949076Swpaulstatic driver_t sf_driver = {
20051455Swpaul	"sf",
20149076Swpaul	sf_methods,
20249076Swpaul	sizeof(struct sf_softc),
20349076Swpaul};
20449076Swpaul
20549076Swpaulstatic devclass_t sf_devclass;
20649076Swpaul
207113506SmdoddDRIVER_MODULE(sf, pci, sf_driver, sf_devclass, 0, 0);
20851473SwpaulDRIVER_MODULE(miibus, sf, miibus_driver, miibus_devclass, 0, 0);
20949076Swpaul
21049076Swpaul#define SF_SETBIT(sc, reg, x)	\
211105221Sphk	csr_write_4(sc, reg, csr_read_4(sc, reg) | (x))
21249076Swpaul
21349076Swpaul#define SF_CLRBIT(sc, reg, x)				\
214105221Sphk	csr_write_4(sc, reg, csr_read_4(sc, reg) & ~(x))
21549076Swpaul
216102335Salfredstatic u_int32_t
217102335Salfredcsr_read_4(sc, reg)
21849076Swpaul	struct sf_softc		*sc;
21949076Swpaul	int			reg;
22049076Swpaul{
22149076Swpaul	u_int32_t		val;
22249076Swpaul
22349076Swpaul#ifdef SF_USEIOSPACE
22449076Swpaul	CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE);
22549076Swpaul	val = CSR_READ_4(sc, SF_INDIRECTIO_DATA);
22649076Swpaul#else
22749076Swpaul	val = CSR_READ_4(sc, (reg + SF_RMAP_INTREG_BASE));
22849076Swpaul#endif
22949076Swpaul
23049076Swpaul	return(val);
23149076Swpaul}
23249076Swpaul
233102335Salfredstatic u_int8_t
234102335Salfredsf_read_eeprom(sc, reg)
23549076Swpaul	struct sf_softc		*sc;
23649076Swpaul	int			reg;
23749076Swpaul{
23849076Swpaul	u_int8_t		val;
23949076Swpaul
24049076Swpaul	val = (csr_read_4(sc, SF_EEADDR_BASE +
24149076Swpaul	    (reg & 0xFFFFFFFC)) >> (8 * (reg & 3))) & 0xFF;
24249076Swpaul
24349076Swpaul	return(val);
24449076Swpaul}
24549076Swpaul
246102335Salfredstatic void
247102335Salfredcsr_write_4(sc, reg, val)
24849076Swpaul	struct sf_softc		*sc;
24949076Swpaul	int			reg;
25049076Swpaul	u_int32_t		val;
25149076Swpaul{
25249076Swpaul#ifdef SF_USEIOSPACE
25349076Swpaul	CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE);
25449076Swpaul	CSR_WRITE_4(sc, SF_INDIRECTIO_DATA, val);
25549076Swpaul#else
25649076Swpaul	CSR_WRITE_4(sc, (reg + SF_RMAP_INTREG_BASE), val);
25749076Swpaul#endif
25849076Swpaul}
25949076Swpaul
26049076Swpaul/*
26149076Swpaul * Copy the address 'mac' into the perfect RX filter entry at
26249076Swpaul * offset 'idx.' The perfect filter only has 16 entries so do
26349076Swpaul * some sanity tests.
26449076Swpaul */
265102335Salfredstatic int
266102335Salfredsf_setperf(sc, idx, mac)
26749076Swpaul	struct sf_softc		*sc;
26849076Swpaul	int			idx;
26949076Swpaul	caddr_t			mac;
27049076Swpaul{
27149076Swpaul	u_int16_t		*p;
27249076Swpaul
27349076Swpaul	if (idx < 0 || idx > SF_RXFILT_PERFECT_CNT)
27449076Swpaul		return(EINVAL);
27549076Swpaul
27649076Swpaul	if (mac == NULL)
27749076Swpaul		return(EINVAL);
27849076Swpaul
27949076Swpaul	p = (u_int16_t *)mac;
28049076Swpaul
28149076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
28249076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP), htons(p[2]));
28349076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
28449076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP) + 4, htons(p[1]));
28549076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
28649076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP) + 8, htons(p[0]));
28749076Swpaul
28849076Swpaul	return(0);
28949076Swpaul}
29049076Swpaul
29149076Swpaul/*
29249076Swpaul * Set the bit in the 512-bit hash table that corresponds to the
29349076Swpaul * specified mac address 'mac.' If 'prio' is nonzero, update the
29449076Swpaul * priority hash table instead of the filter hash table.
29549076Swpaul */
296102335Salfredstatic int
297102335Salfredsf_sethash(sc, mac, prio)
29849076Swpaul	struct sf_softc		*sc;
29949076Swpaul	caddr_t			mac;
30049076Swpaul	int			prio;
30149076Swpaul{
302130270Snaddy	u_int32_t		h;
30349076Swpaul
30449076Swpaul	if (mac == NULL)
30549076Swpaul		return(EINVAL);
30649076Swpaul
307130270Snaddy	h = ether_crc32_be(mac, ETHER_ADDR_LEN) >> 23;
30849076Swpaul
30949076Swpaul	if (prio) {
31049076Swpaul		SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_PRIOOFF +
31149076Swpaul		    (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF)));
31249076Swpaul	} else {
31349076Swpaul		SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_ADDROFF +
31449076Swpaul		    (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF)));
31549076Swpaul	}
31649076Swpaul
31749076Swpaul	return(0);
31849076Swpaul}
31949076Swpaul
32049076Swpaul#ifdef notdef
32149076Swpaul/*
32249076Swpaul * Set a VLAN tag in the receive filter.
32349076Swpaul */
324102335Salfredstatic int
325102335Salfredsf_setvlan(sc, idx, vlan)
32649076Swpaul	struct sf_softc		*sc;
32749076Swpaul	int			idx;
32849076Swpaul	u_int32_t		vlan;
32949076Swpaul{
33049076Swpaul	if (idx < 0 || idx >> SF_RXFILT_HASH_CNT)
33149076Swpaul		return(EINVAL);
33249076Swpaul
33349076Swpaul	csr_write_4(sc, SF_RXFILT_HASH_BASE +
33449076Swpaul	    (idx * SF_RXFILT_HASH_SKIP) + SF_RXFILT_HASH_VLANOFF, vlan);
33549076Swpaul
33649076Swpaul	return(0);
33749076Swpaul}
33849076Swpaul#endif
33949076Swpaul
340102335Salfredstatic int
341102335Salfredsf_miibus_readreg(dev, phy, reg)
34250675Swpaul	device_t		dev;
34350675Swpaul	int			phy, reg;
34450675Swpaul{
34549076Swpaul	struct sf_softc		*sc;
34649076Swpaul	int			i;
34749076Swpaul	u_int32_t		val = 0;
34849076Swpaul
34950675Swpaul	sc = device_get_softc(dev);
35050675Swpaul
35149076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
35250675Swpaul		val = csr_read_4(sc, SF_PHY_REG(phy, reg));
35349076Swpaul		if (val & SF_MII_DATAVALID)
35449076Swpaul			break;
35549076Swpaul	}
35649076Swpaul
35749076Swpaul	if (i == SF_TIMEOUT)
35849076Swpaul		return(0);
35949076Swpaul
36049076Swpaul	if ((val & 0x0000FFFF) == 0xFFFF)
36149076Swpaul		return(0);
36249076Swpaul
36349076Swpaul	return(val & 0x0000FFFF);
36449076Swpaul}
36549076Swpaul
366102335Salfredstatic int
367102335Salfredsf_miibus_writereg(dev, phy, reg, val)
36850675Swpaul	device_t		dev;
36950675Swpaul	int			phy, reg, val;
37050675Swpaul{
37149076Swpaul	struct sf_softc		*sc;
37249076Swpaul	int			i;
37349076Swpaul	int			busy;
37449076Swpaul
37550675Swpaul	sc = device_get_softc(dev);
37649076Swpaul
37750675Swpaul	csr_write_4(sc, SF_PHY_REG(phy, reg), val);
37850675Swpaul
37949076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
38050675Swpaul		busy = csr_read_4(sc, SF_PHY_REG(phy, reg));
38149076Swpaul		if (!(busy & SF_MII_BUSY))
38249076Swpaul			break;
38349076Swpaul	}
38449076Swpaul
38550675Swpaul	return(0);
38650675Swpaul}
38750675Swpaul
388102335Salfredstatic void
389102335Salfredsf_miibus_statchg(dev)
39050675Swpaul	device_t		dev;
39150675Swpaul{
39250675Swpaul	struct sf_softc		*sc;
39350675Swpaul	struct mii_data		*mii;
39450675Swpaul
39550675Swpaul	sc = device_get_softc(dev);
39650675Swpaul	mii = device_get_softc(sc->sf_miibus);
39750675Swpaul
39850675Swpaul	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
39950675Swpaul		SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX);
40054161Swpaul		csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_FDX);
40150675Swpaul	} else {
40250675Swpaul		SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX);
40354161Swpaul		csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_HDX);
40450675Swpaul	}
40549076Swpaul}
40649076Swpaul
407102335Salfredstatic void
408102335Salfredsf_setmulti(sc)
40949076Swpaul	struct sf_softc		*sc;
41049076Swpaul{
41149076Swpaul	struct ifnet		*ifp;
41249076Swpaul	int			i;
41349076Swpaul	struct ifmultiaddr	*ifma;
41449076Swpaul	u_int8_t		dummy[] = { 0, 0, 0, 0, 0, 0 };
41549076Swpaul
41649076Swpaul	ifp = &sc->arpcom.ac_if;
41749076Swpaul
41849076Swpaul	/* First zot all the existing filters. */
41949076Swpaul	for (i = 1; i < SF_RXFILT_PERFECT_CNT; i++)
42049076Swpaul		sf_setperf(sc, i, (char *)&dummy);
42149076Swpaul	for (i = SF_RXFILT_HASH_BASE;
42249076Swpaul	    i < (SF_RXFILT_HASH_MAX + 1); i += 4)
42349076Swpaul		csr_write_4(sc, i, 0);
42449076Swpaul	SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_ALLMULTI);
42549076Swpaul
42649076Swpaul	/* Now program new ones. */
42749076Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
42849076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_ALLMULTI);
42949076Swpaul	} else {
43049076Swpaul		i = 1;
43172084Sphk		TAILQ_FOREACH_REVERSE(ifma, &ifp->if_multiaddrs, ifmultihead, ifma_link) {
43249076Swpaul			if (ifma->ifma_addr->sa_family != AF_LINK)
43349076Swpaul				continue;
43449076Swpaul			/*
43549076Swpaul			 * Program the first 15 multicast groups
43649076Swpaul			 * into the perfect filter. For all others,
43749076Swpaul			 * use the hash table.
43849076Swpaul			 */
43949076Swpaul			if (i < SF_RXFILT_PERFECT_CNT) {
44049076Swpaul				sf_setperf(sc, i,
44149076Swpaul			LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
44249076Swpaul				i++;
44349076Swpaul				continue;
44449076Swpaul			}
44549076Swpaul
44649076Swpaul			sf_sethash(sc,
44749076Swpaul			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 0);
44849076Swpaul		}
44949076Swpaul	}
45049076Swpaul}
45149076Swpaul
45249076Swpaul/*
45349076Swpaul * Set media options.
45449076Swpaul */
455102335Salfredstatic int
456102335Salfredsf_ifmedia_upd(ifp)
45749076Swpaul	struct ifnet		*ifp;
45849076Swpaul{
45949076Swpaul	struct sf_softc		*sc;
46050675Swpaul	struct mii_data		*mii;
46149076Swpaul
46249076Swpaul	sc = ifp->if_softc;
46350675Swpaul	mii = device_get_softc(sc->sf_miibus);
46454161Swpaul	sc->sf_link = 0;
46554161Swpaul	if (mii->mii_instance) {
46654161Swpaul		struct mii_softc        *miisc;
46772012Sphk		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
46854161Swpaul			mii_phy_reset(miisc);
46954161Swpaul	}
47050675Swpaul	mii_mediachg(mii);
47149076Swpaul
47249076Swpaul	return(0);
47349076Swpaul}
47449076Swpaul
47549076Swpaul/*
47649076Swpaul * Report current media status.
47749076Swpaul */
478102335Salfredstatic void
479102335Salfredsf_ifmedia_sts(ifp, ifmr)
48049076Swpaul	struct ifnet		*ifp;
48149076Swpaul	struct ifmediareq	*ifmr;
48249076Swpaul{
48349076Swpaul	struct sf_softc		*sc;
48450675Swpaul	struct mii_data		*mii;
48549076Swpaul
48649076Swpaul	sc = ifp->if_softc;
48750675Swpaul	mii = device_get_softc(sc->sf_miibus);
48849076Swpaul
48950675Swpaul	mii_pollstat(mii);
49050675Swpaul	ifmr->ifm_active = mii->mii_media_active;
49150675Swpaul	ifmr->ifm_status = mii->mii_media_status;
49249076Swpaul}
49349076Swpaul
494102335Salfredstatic int
495102335Salfredsf_ioctl(ifp, command, data)
49649076Swpaul	struct ifnet		*ifp;
49749076Swpaul	u_long			command;
49849076Swpaul	caddr_t			data;
49949076Swpaul{
50049076Swpaul	struct sf_softc		*sc = ifp->if_softc;
50149076Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
50250675Swpaul	struct mii_data		*mii;
50367087Swpaul	int			error = 0;
50449076Swpaul
50567087Swpaul	SF_LOCK(sc);
50649076Swpaul
50749076Swpaul	switch(command) {
50849076Swpaul	case SIOCSIFFLAGS:
50949076Swpaul		if (ifp->if_flags & IFF_UP) {
51054161Swpaul			if (ifp->if_flags & IFF_RUNNING &&
51154161Swpaul			    ifp->if_flags & IFF_PROMISC &&
51254161Swpaul			    !(sc->sf_if_flags & IFF_PROMISC)) {
51354161Swpaul				SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
51454161Swpaul			} else if (ifp->if_flags & IFF_RUNNING &&
51554161Swpaul			    !(ifp->if_flags & IFF_PROMISC) &&
51654161Swpaul			    sc->sf_if_flags & IFF_PROMISC) {
51754161Swpaul				SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
51854161Swpaul			} else if (!(ifp->if_flags & IFF_RUNNING))
51954161Swpaul				sf_init(sc);
52049076Swpaul		} else {
52149076Swpaul			if (ifp->if_flags & IFF_RUNNING)
52249076Swpaul				sf_stop(sc);
52349076Swpaul		}
52454161Swpaul		sc->sf_if_flags = ifp->if_flags;
52549076Swpaul		error = 0;
52649076Swpaul		break;
52749076Swpaul	case SIOCADDMULTI:
52849076Swpaul	case SIOCDELMULTI:
52949076Swpaul		sf_setmulti(sc);
53049076Swpaul		error = 0;
53149076Swpaul		break;
53249076Swpaul	case SIOCGIFMEDIA:
53349076Swpaul	case SIOCSIFMEDIA:
53450675Swpaul		mii = device_get_softc(sc->sf_miibus);
53550675Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
53649076Swpaul		break;
53749076Swpaul	default:
538106936Ssam		error = ether_ioctl(ifp, command, data);
53949076Swpaul		break;
54049076Swpaul	}
54149076Swpaul
54267087Swpaul	SF_UNLOCK(sc);
54349076Swpaul
54449076Swpaul	return(error);
54549076Swpaul}
54649076Swpaul
547102335Salfredstatic void
548102335Salfredsf_reset(sc)
54949076Swpaul	struct sf_softc		*sc;
55049076Swpaul{
55149076Swpaul	register int		i;
55249076Swpaul
55349076Swpaul	csr_write_4(sc, SF_GEN_ETH_CTL, 0);
55449076Swpaul	SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
55549076Swpaul	DELAY(1000);
55649076Swpaul	SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
55749076Swpaul
55849076Swpaul	SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_RESET);
55949076Swpaul
56049076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
56149076Swpaul		DELAY(10);
56249076Swpaul		if (!(csr_read_4(sc, SF_PCI_DEVCFG) & SF_PCIDEVCFG_RESET))
56349076Swpaul			break;
56449076Swpaul	}
56549076Swpaul
56649076Swpaul	if (i == SF_TIMEOUT)
56749076Swpaul		printf("sf%d: reset never completed!\n", sc->sf_unit);
56849076Swpaul
56949076Swpaul	/* Wait a little while for the chip to get its brains in order. */
57049076Swpaul	DELAY(1000);
57149076Swpaul}
57249076Swpaul
57349076Swpaul/*
57449076Swpaul * Probe for an Adaptec AIC-6915 chip. Check the PCI vendor and device
57549076Swpaul * IDs against our list and return a device name if we find a match.
57649076Swpaul * We also check the subsystem ID so that we can identify exactly which
57749076Swpaul * NIC has been found, if possible.
57849076Swpaul */
579102335Salfredstatic int
580102335Salfredsf_probe(dev)
58149076Swpaul	device_t		dev;
58249076Swpaul{
58349076Swpaul	struct sf_type		*t;
58449076Swpaul
58549076Swpaul	t = sf_devs;
58649076Swpaul
58749076Swpaul	while(t->sf_name != NULL) {
58849076Swpaul		if ((pci_get_vendor(dev) == t->sf_vid) &&
58949076Swpaul		    (pci_get_device(dev) == t->sf_did)) {
59051336Swpaul			switch((pci_read_config(dev,
59151336Swpaul			    SF_PCI_SUBVEN_ID, 4) >> 16) & 0xFFFF) {
59249076Swpaul			case AD_SUBSYSID_62011_REV0:
59349076Swpaul			case AD_SUBSYSID_62011_REV1:
59449076Swpaul				device_set_desc(dev,
59549076Swpaul				    "Adaptec ANA-62011 10/100BaseTX");
59649076Swpaul				return(0);
59749076Swpaul			case AD_SUBSYSID_62022:
59849076Swpaul				device_set_desc(dev,
59949076Swpaul				    "Adaptec ANA-62022 10/100BaseTX");
60049076Swpaul				return(0);
60153468Swpaul			case AD_SUBSYSID_62044_REV0:
60253468Swpaul			case AD_SUBSYSID_62044_REV1:
60349076Swpaul				device_set_desc(dev,
60449076Swpaul				    "Adaptec ANA-62044 10/100BaseTX");
60549076Swpaul				return(0);
60649076Swpaul			case AD_SUBSYSID_62020:
60749076Swpaul				device_set_desc(dev,
60849076Swpaul				    "Adaptec ANA-62020 10/100BaseFX");
60949076Swpaul				return(0);
61049076Swpaul			case AD_SUBSYSID_69011:
61149076Swpaul				device_set_desc(dev,
61249076Swpaul				    "Adaptec ANA-69011 10/100BaseTX");
61349076Swpaul				return(0);
61449076Swpaul			default:
61549076Swpaul				device_set_desc(dev, t->sf_name);
61649076Swpaul				return(0);
61749076Swpaul				break;
61849076Swpaul			}
61949076Swpaul		}
62049076Swpaul		t++;
62149076Swpaul	}
62249076Swpaul
62349076Swpaul	return(ENXIO);
62449076Swpaul}
62549076Swpaul
62649076Swpaul/*
62749076Swpaul * Attach the interface. Allocate softc structures, do ifmedia
62849076Swpaul * setup and ethernet/BPF attach.
62949076Swpaul */
630102335Salfredstatic int
631102335Salfredsf_attach(dev)
63249076Swpaul	device_t		dev;
63349076Swpaul{
63467087Swpaul	int			i;
63549076Swpaul	struct sf_softc		*sc;
63649076Swpaul	struct ifnet		*ifp;
63749076Swpaul	int			unit, rid, error = 0;
63849076Swpaul
63949076Swpaul	sc = device_get_softc(dev);
64049076Swpaul	unit = device_get_unit(dev);
64149076Swpaul
64293818Sjhb	mtx_init(&sc->sf_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
64393818Sjhb	    MTX_DEF | MTX_RECURSE);
64449076Swpaul	/*
64549076Swpaul	 * Map control/status registers.
64649076Swpaul	 */
64772813Swpaul	pci_enable_busmaster(dev);
64849076Swpaul
64949076Swpaul	rid = SF_RID;
650127135Snjl	sc->sf_res = bus_alloc_resource_any(dev, SF_RES, &rid, RF_ACTIVE);
65149076Swpaul
65249076Swpaul	if (sc->sf_res == NULL) {
65349076Swpaul		printf ("sf%d: couldn't map ports\n", unit);
65449076Swpaul		error = ENXIO;
65549076Swpaul		goto fail;
65649076Swpaul	}
65749076Swpaul
65849076Swpaul	sc->sf_btag = rman_get_bustag(sc->sf_res);
65949076Swpaul	sc->sf_bhandle = rman_get_bushandle(sc->sf_res);
66049076Swpaul
66149076Swpaul	/* Allocate interrupt */
66249076Swpaul	rid = 0;
663127135Snjl	sc->sf_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
66449076Swpaul	    RF_SHAREABLE | RF_ACTIVE);
66549076Swpaul
66649076Swpaul	if (sc->sf_irq == NULL) {
66749076Swpaul		printf("sf%d: couldn't map interrupt\n", unit);
66849076Swpaul		error = ENXIO;
66949076Swpaul		goto fail;
67049076Swpaul	}
67149076Swpaul
67249076Swpaul	callout_handle_init(&sc->sf_stat_ch);
67349076Swpaul	/* Reset the adapter. */
67449076Swpaul	sf_reset(sc);
67549076Swpaul
67649076Swpaul	/*
67749076Swpaul	 * Get station address from the EEPROM.
67849076Swpaul	 */
67949076Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
68049076Swpaul		sc->arpcom.ac_enaddr[i] =
68149076Swpaul		    sf_read_eeprom(sc, SF_EE_NODEADDR + ETHER_ADDR_LEN - i);
68249076Swpaul
68349076Swpaul	sc->sf_unit = unit;
68449076Swpaul
68549076Swpaul	/* Allocate the descriptor queues. */
68649076Swpaul	sc->sf_ldata = contigmalloc(sizeof(struct sf_list_data), M_DEVBUF,
68751657Swpaul	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
68849076Swpaul
68949076Swpaul	if (sc->sf_ldata == NULL) {
69049076Swpaul		printf("sf%d: no memory for list buffers!\n", unit);
69149076Swpaul		error = ENXIO;
69249076Swpaul		goto fail;
69349076Swpaul	}
69449076Swpaul
69549076Swpaul	bzero(sc->sf_ldata, sizeof(struct sf_list_data));
69649076Swpaul
69750675Swpaul	/* Do MII setup. */
69850675Swpaul	if (mii_phy_probe(dev, &sc->sf_miibus,
69950675Swpaul	    sf_ifmedia_upd, sf_ifmedia_sts)) {
70049076Swpaul		printf("sf%d: MII without any phy!\n", sc->sf_unit);
70149076Swpaul		error = ENXIO;
70249076Swpaul		goto fail;
70349076Swpaul	}
70449076Swpaul
70549076Swpaul	ifp = &sc->arpcom.ac_if;
70649076Swpaul	ifp->if_softc = sc;
707121816Sbrooks	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
70849076Swpaul	ifp->if_mtu = ETHERMTU;
709134442Srwatson	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST |
710134442Srwatson	    IFF_NEEDSGIANT;
71149076Swpaul	ifp->if_ioctl = sf_ioctl;
71249076Swpaul	ifp->if_start = sf_start;
71349076Swpaul	ifp->if_watchdog = sf_watchdog;
71449076Swpaul	ifp->if_init = sf_init;
71549076Swpaul	ifp->if_baudrate = 10000000;
71649076Swpaul	ifp->if_snd.ifq_maxlen = SF_TX_DLIST_CNT - 1;
71749076Swpaul
71849076Swpaul	/*
71963090Sarchie	 * Call MI attach routine.
72049076Swpaul	 */
721106936Ssam	ether_ifattach(ifp, sc->arpcom.ac_enaddr);
72249076Swpaul
723113609Snjl	/* Hook interrupt last to avoid having to lock softc */
724112872Snjl	error = bus_setup_intr(dev, sc->sf_irq, INTR_TYPE_NET,
725112872Snjl	    sf_intr, sc, &sc->sf_intrhand);
726112872Snjl
727112872Snjl	if (error) {
728112872Snjl		printf("sf%d: couldn't set up irq\n", unit);
729113609Snjl		ether_ifdetach(ifp);
730112872Snjl		goto fail;
731112872Snjl	}
732112872Snjl
73349076Swpaulfail:
734112872Snjl	if (error)
735112872Snjl		sf_detach(dev);
736112872Snjl
73749076Swpaul	return(error);
73849076Swpaul}
73949076Swpaul
740113609Snjl/*
741113609Snjl * Shutdown hardware and free up resources. This can be called any
742113609Snjl * time after the mutex has been initialized. It is called in both
743113609Snjl * the error case in attach and the normal detach case so it needs
744113609Snjl * to be careful about only freeing resources that have actually been
745113609Snjl * allocated.
746113609Snjl */
747102335Salfredstatic int
748102335Salfredsf_detach(dev)
74949076Swpaul	device_t		dev;
75049076Swpaul{
75149076Swpaul	struct sf_softc		*sc;
75249076Swpaul	struct ifnet		*ifp;
75349076Swpaul
75449076Swpaul	sc = device_get_softc(dev);
755112880Sjhb	KASSERT(mtx_initialized(&sc->sf_mtx), ("sf mutex not initialized"));
75667087Swpaul	SF_LOCK(sc);
75749076Swpaul	ifp = &sc->arpcom.ac_if;
75849076Swpaul
759113609Snjl	/* These should only be active if attach succeeded */
760113812Simp	if (device_is_attached(dev)) {
761113609Snjl		sf_stop(sc);
762112872Snjl		ether_ifdetach(ifp);
763113609Snjl	}
764113609Snjl	if (sc->sf_miibus)
765112872Snjl		device_delete_child(dev, sc->sf_miibus);
766113609Snjl	bus_generic_detach(dev);
76749076Swpaul
768112872Snjl	if (sc->sf_intrhand)
769112872Snjl		bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
770112872Snjl	if (sc->sf_irq)
771112872Snjl		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
772112872Snjl	if (sc->sf_res)
773112872Snjl		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
77450675Swpaul
775112872Snjl	if (sc->sf_ldata)
776112872Snjl		contigfree(sc->sf_ldata, sizeof(struct sf_list_data), M_DEVBUF);
77749076Swpaul
77867087Swpaul	SF_UNLOCK(sc);
77967087Swpaul	mtx_destroy(&sc->sf_mtx);
78049076Swpaul
78149076Swpaul	return(0);
78249076Swpaul}
78349076Swpaul
784102335Salfredstatic int
785102335Salfredsf_init_rx_ring(sc)
78649076Swpaul	struct sf_softc		*sc;
78749076Swpaul{
78849076Swpaul	struct sf_list_data	*ld;
78949076Swpaul	int			i;
79049076Swpaul
79149076Swpaul	ld = sc->sf_ldata;
79249076Swpaul
79349076Swpaul	bzero((char *)ld->sf_rx_dlist_big,
79449076Swpaul	    sizeof(struct sf_rx_bufdesc_type0) * SF_RX_DLIST_CNT);
79549076Swpaul	bzero((char *)ld->sf_rx_clist,
79649076Swpaul	    sizeof(struct sf_rx_cmpdesc_type3) * SF_RX_CLIST_CNT);
79749076Swpaul
79849076Swpaul	for (i = 0; i < SF_RX_DLIST_CNT; i++) {
79949076Swpaul		if (sf_newbuf(sc, &ld->sf_rx_dlist_big[i], NULL) == ENOBUFS)
80049076Swpaul			return(ENOBUFS);
80149076Swpaul	}
80249076Swpaul
80349076Swpaul	return(0);
80449076Swpaul}
80549076Swpaul
806102335Salfredstatic void
807102335Salfredsf_init_tx_ring(sc)
80849076Swpaul	struct sf_softc		*sc;
80949076Swpaul{
81049076Swpaul	struct sf_list_data	*ld;
81149076Swpaul	int			i;
81249076Swpaul
81349076Swpaul	ld = sc->sf_ldata;
81449076Swpaul
81549076Swpaul	bzero((char *)ld->sf_tx_dlist,
81649076Swpaul	    sizeof(struct sf_tx_bufdesc_type0) * SF_TX_DLIST_CNT);
81749076Swpaul	bzero((char *)ld->sf_tx_clist,
81849076Swpaul	    sizeof(struct sf_tx_cmpdesc_type0) * SF_TX_CLIST_CNT);
81949076Swpaul
82049076Swpaul	for (i = 0; i < SF_TX_DLIST_CNT; i++)
82149076Swpaul		ld->sf_tx_dlist[i].sf_id = SF_TX_BUFDESC_ID;
82249076Swpaul	for (i = 0; i < SF_TX_CLIST_CNT; i++)
82349076Swpaul		ld->sf_tx_clist[i].sf_type = SF_TXCMPTYPE_TX;
82449076Swpaul
82549076Swpaul	ld->sf_tx_dlist[SF_TX_DLIST_CNT - 1].sf_end = 1;
82649076Swpaul	sc->sf_tx_cnt = 0;
82749076Swpaul}
82849076Swpaul
829102335Salfredstatic int
830102335Salfredsf_newbuf(sc, c, m)
83149076Swpaul	struct sf_softc		*sc;
83249076Swpaul	struct sf_rx_bufdesc_type0	*c;
83349076Swpaul	struct mbuf		*m;
83449076Swpaul{
83549076Swpaul	struct mbuf		*m_new = NULL;
83649076Swpaul
83749076Swpaul	if (m == NULL) {
838111119Simp		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
83987846Sluigi		if (m_new == NULL)
84049076Swpaul			return(ENOBUFS);
84149076Swpaul
842111119Simp		MCLGET(m_new, M_DONTWAIT);
84349076Swpaul		if (!(m_new->m_flags & M_EXT)) {
84449076Swpaul			m_freem(m_new);
84549076Swpaul			return(ENOBUFS);
84649076Swpaul		}
84749076Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
84849076Swpaul	} else {
84949076Swpaul		m_new = m;
85049076Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
85149076Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
85249076Swpaul	}
85349076Swpaul
85449076Swpaul	m_adj(m_new, sizeof(u_int64_t));
85549076Swpaul
85649076Swpaul	c->sf_mbuf = m_new;
85749076Swpaul	c->sf_addrlo = SF_RX_HOSTADDR(vtophys(mtod(m_new, caddr_t)));
85849076Swpaul	c->sf_valid = 1;
85949076Swpaul
86049076Swpaul	return(0);
86149076Swpaul}
86249076Swpaul
86349076Swpaul/*
86449076Swpaul * The starfire is programmed to use 'normal' mode for packet reception,
86549076Swpaul * which means we use the consumer/producer model for both the buffer
86649076Swpaul * descriptor queue and the completion descriptor queue. The only problem
86749076Swpaul * with this is that it involves a lot of register accesses: we have to
86849076Swpaul * read the RX completion consumer and producer indexes and the RX buffer
86949076Swpaul * producer index, plus the RX completion consumer and RX buffer producer
87049076Swpaul * indexes have to be updated. It would have been easier if Adaptec had
87149076Swpaul * put each index in a separate register, especially given that the damn
87249076Swpaul * NIC has a 512K register space.
87349076Swpaul *
87449076Swpaul * In spite of all the lovely features that Adaptec crammed into the 6915,
87549076Swpaul * it is marred by one truly stupid design flaw, which is that receive
87649076Swpaul * buffer addresses must be aligned on a longword boundary. This forces
87749076Swpaul * the packet payload to be unaligned, which is suboptimal on the x86 and
87849076Swpaul * completely unuseable on the Alpha. Our only recourse is to copy received
87949076Swpaul * packets into properly aligned buffers before handing them off.
88049076Swpaul */
88149076Swpaul
882102335Salfredstatic void
883102335Salfredsf_rxeof(sc)
88449076Swpaul	struct sf_softc		*sc;
88549076Swpaul{
88649076Swpaul	struct mbuf		*m;
88749076Swpaul	struct ifnet		*ifp;
88849076Swpaul	struct sf_rx_bufdesc_type0	*desc;
88949076Swpaul	struct sf_rx_cmpdesc_type3	*cur_rx;
89049076Swpaul	u_int32_t		rxcons, rxprod;
89149076Swpaul	int			cmpprodidx, cmpconsidx, bufprodidx;
89249076Swpaul
893122689Ssam	SF_LOCK_ASSERT(sc);
894122689Ssam
89549076Swpaul	ifp = &sc->arpcom.ac_if;
89649076Swpaul
89749076Swpaul	rxcons = csr_read_4(sc, SF_CQ_CONSIDX);
89849076Swpaul	rxprod = csr_read_4(sc, SF_RXDQ_PTR_Q1);
89949076Swpaul	cmpprodidx = SF_IDX_LO(csr_read_4(sc, SF_CQ_PRODIDX));
90049076Swpaul	cmpconsidx = SF_IDX_LO(rxcons);
90149076Swpaul	bufprodidx = SF_IDX_LO(rxprod);
90249076Swpaul
90349076Swpaul	while (cmpconsidx != cmpprodidx) {
90449076Swpaul		struct mbuf		*m0;
90549076Swpaul
90649076Swpaul		cur_rx = &sc->sf_ldata->sf_rx_clist[cmpconsidx];
90749076Swpaul		desc = &sc->sf_ldata->sf_rx_dlist_big[cur_rx->sf_endidx];
90849076Swpaul		m = desc->sf_mbuf;
90949076Swpaul		SF_INC(cmpconsidx, SF_RX_CLIST_CNT);
91049076Swpaul		SF_INC(bufprodidx, SF_RX_DLIST_CNT);
91149076Swpaul
91249076Swpaul		if (!(cur_rx->sf_status1 & SF_RXSTAT1_OK)) {
91349076Swpaul			ifp->if_ierrors++;
91449076Swpaul			sf_newbuf(sc, desc, m);
91549076Swpaul			continue;
91649076Swpaul		}
91749076Swpaul
91878508Sbmilekic		m0 = m_devget(mtod(m, char *), cur_rx->sf_len, ETHER_ALIGN,
91978508Sbmilekic		    ifp, NULL);
92049076Swpaul		sf_newbuf(sc, desc, m);
92149076Swpaul		if (m0 == NULL) {
92249076Swpaul			ifp->if_ierrors++;
92349076Swpaul			continue;
92449076Swpaul		}
92549076Swpaul		m = m0;
92649076Swpaul
92749076Swpaul		ifp->if_ipackets++;
928122689Ssam		SF_UNLOCK(sc);
929106936Ssam		(*ifp->if_input)(ifp, m);
930122689Ssam		SF_LOCK(sc);
93149076Swpaul	}
93249076Swpaul
93349076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX,
93449076Swpaul	    (rxcons & ~SF_CQ_CONSIDX_RXQ1) | cmpconsidx);
93549076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1,
93649076Swpaul	    (rxprod & ~SF_RXDQ_PRODIDX) | bufprodidx);
93749076Swpaul}
93849076Swpaul
93949076Swpaul/*
94049076Swpaul * Read the transmit status from the completion queue and release
94149076Swpaul * mbufs. Note that the buffer descriptor index in the completion
94249076Swpaul * descriptor is an offset from the start of the transmit buffer
94349076Swpaul * descriptor list in bytes. This is important because the manual
94449076Swpaul * gives the impression that it should match the producer/consumer
94549076Swpaul * index, which is the offset in 8 byte blocks.
94649076Swpaul */
947102335Salfredstatic void
948102335Salfredsf_txeof(sc)
94949076Swpaul	struct sf_softc		*sc;
95049076Swpaul{
95149076Swpaul	int			txcons, cmpprodidx, cmpconsidx;
95249076Swpaul	struct sf_tx_cmpdesc_type1 *cur_cmp;
95349076Swpaul	struct sf_tx_bufdesc_type0 *cur_tx;
95449076Swpaul	struct ifnet		*ifp;
95549076Swpaul
95649076Swpaul	ifp = &sc->arpcom.ac_if;
95749076Swpaul
95849076Swpaul	txcons = csr_read_4(sc, SF_CQ_CONSIDX);
95949076Swpaul	cmpprodidx = SF_IDX_HI(csr_read_4(sc, SF_CQ_PRODIDX));
96049076Swpaul	cmpconsidx = SF_IDX_HI(txcons);
96149076Swpaul
96249076Swpaul	while (cmpconsidx != cmpprodidx) {
96349076Swpaul		cur_cmp = &sc->sf_ldata->sf_tx_clist[cmpconsidx];
96449076Swpaul		cur_tx = &sc->sf_ldata->sf_tx_dlist[cur_cmp->sf_index >> 7];
96549076Swpaul
96649076Swpaul		if (cur_cmp->sf_txstat & SF_TXSTAT_TX_OK)
96749076Swpaul			ifp->if_opackets++;
96881737Swpaul		else {
96981737Swpaul			if (cur_cmp->sf_txstat & SF_TXSTAT_TX_UNDERRUN)
97081737Swpaul				sf_txthresh_adjust(sc);
97149076Swpaul			ifp->if_oerrors++;
97281737Swpaul		}
97349076Swpaul
97449076Swpaul		sc->sf_tx_cnt--;
97549076Swpaul		if (cur_tx->sf_mbuf != NULL) {
97649076Swpaul			m_freem(cur_tx->sf_mbuf);
97749076Swpaul			cur_tx->sf_mbuf = NULL;
97881737Swpaul		} else
97981737Swpaul			break;
98081737Swpaul		SF_INC(cmpconsidx, SF_TX_CLIST_CNT);
98149076Swpaul	}
98249076Swpaul
98349076Swpaul	ifp->if_timer = 0;
98449076Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
98549076Swpaul
98649076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX,
98749076Swpaul	    (txcons & ~SF_CQ_CONSIDX_TXQ) |
98849076Swpaul	    ((cmpconsidx << 16) & 0xFFFF0000));
98949076Swpaul}
99049076Swpaul
991102335Salfredstatic void
992102335Salfredsf_txthresh_adjust(sc)
99381737Swpaul	struct sf_softc		*sc;
99481737Swpaul{
99581737Swpaul	u_int32_t		txfctl;
99681737Swpaul	u_int8_t		txthresh;
99781737Swpaul
99881737Swpaul	txfctl = csr_read_4(sc, SF_TX_FRAMCTL);
99981737Swpaul	txthresh = txfctl & SF_TXFRMCTL_TXTHRESH;
100081737Swpaul	if (txthresh < 0xFF) {
100181737Swpaul		txthresh++;
100281737Swpaul		txfctl &= ~SF_TXFRMCTL_TXTHRESH;
100381737Swpaul		txfctl |= txthresh;
100481737Swpaul#ifdef DIAGNOSTIC
100581737Swpaul		printf("sf%d: tx underrun, increasing "
100681737Swpaul		    "tx threshold to %d bytes\n",
100781737Swpaul		    sc->sf_unit, txthresh * 4);
100881737Swpaul#endif
100981737Swpaul		csr_write_4(sc, SF_TX_FRAMCTL, txfctl);
101081737Swpaul	}
101181737Swpaul}
101281737Swpaul
1013102335Salfredstatic void
1014102335Salfredsf_intr(arg)
101549076Swpaul	void			*arg;
101649076Swpaul{
101749076Swpaul	struct sf_softc		*sc;
101849076Swpaul	struct ifnet		*ifp;
101949076Swpaul	u_int32_t		status;
102049076Swpaul
102149076Swpaul	sc = arg;
102267087Swpaul	SF_LOCK(sc);
102367087Swpaul
102449076Swpaul	ifp = &sc->arpcom.ac_if;
102549076Swpaul
102667087Swpaul	if (!(csr_read_4(sc, SF_ISR_SHADOW) & SF_ISR_PCIINT_ASSERTED)) {
102767087Swpaul		SF_UNLOCK(sc);
102849076Swpaul		return;
102967087Swpaul	}
103049076Swpaul
103149076Swpaul	/* Disable interrupts. */
103249076Swpaul	csr_write_4(sc, SF_IMR, 0x00000000);
103349076Swpaul
103449076Swpaul	for (;;) {
103549076Swpaul		status = csr_read_4(sc, SF_ISR);
103649076Swpaul		if (status)
103749076Swpaul			csr_write_4(sc, SF_ISR, status);
103849076Swpaul
103949076Swpaul		if (!(status & SF_INTRS))
104049076Swpaul			break;
104149076Swpaul
104249076Swpaul		if (status & SF_ISR_RXDQ1_DMADONE)
104349076Swpaul			sf_rxeof(sc);
104449076Swpaul
104581714Swpaul		if (status & SF_ISR_TX_TXDONE ||
104681714Swpaul		    status & SF_ISR_TX_DMADONE ||
104781737Swpaul		    status & SF_ISR_TX_QUEUEDONE)
104849076Swpaul			sf_txeof(sc);
104949076Swpaul
105081737Swpaul		if (status & SF_ISR_TX_LOFIFO)
105181737Swpaul			sf_txthresh_adjust(sc);
105281737Swpaul
105349076Swpaul		if (status & SF_ISR_ABNORMALINTR) {
105449076Swpaul			if (status & SF_ISR_STATSOFLOW) {
105549076Swpaul				untimeout(sf_stats_update, sc,
105649076Swpaul				    sc->sf_stat_ch);
105749076Swpaul				sf_stats_update(sc);
105849076Swpaul			} else
105949076Swpaul				sf_init(sc);
106049076Swpaul		}
106149076Swpaul	}
106249076Swpaul
106349076Swpaul	/* Re-enable interrupts. */
106449076Swpaul	csr_write_4(sc, SF_IMR, SF_INTRS);
106549076Swpaul
106649076Swpaul	if (ifp->if_snd.ifq_head != NULL)
106749076Swpaul		sf_start(ifp);
106849076Swpaul
106967087Swpaul	SF_UNLOCK(sc);
107049076Swpaul}
107149076Swpaul
1072102335Salfredstatic void
1073102335Salfredsf_init(xsc)
107449076Swpaul	void			*xsc;
107549076Swpaul{
107649076Swpaul	struct sf_softc		*sc;
107749076Swpaul	struct ifnet		*ifp;
107850675Swpaul	struct mii_data		*mii;
107967087Swpaul	int			i;
108049076Swpaul
108149076Swpaul	sc = xsc;
108267087Swpaul	SF_LOCK(sc);
108349076Swpaul	ifp = &sc->arpcom.ac_if;
108450675Swpaul	mii = device_get_softc(sc->sf_miibus);
108549076Swpaul
108649076Swpaul	sf_stop(sc);
108749076Swpaul	sf_reset(sc);
108849076Swpaul
108949076Swpaul	/* Init all the receive filter registers */
109049076Swpaul	for (i = SF_RXFILT_PERFECT_BASE;
109149076Swpaul	    i < (SF_RXFILT_HASH_MAX + 1); i += 4)
109249076Swpaul		csr_write_4(sc, i, 0);
109349076Swpaul
109449076Swpaul	/* Empty stats counter registers. */
109549076Swpaul	for (i = 0; i < sizeof(struct sf_stats)/sizeof(u_int32_t); i++)
109649076Swpaul		csr_write_4(sc, SF_STATS_BASE +
109749076Swpaul		    (i + sizeof(u_int32_t)), 0);
109849076Swpaul
109949076Swpaul	/* Init our MAC address */
110049076Swpaul	csr_write_4(sc, SF_PAR0, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0]));
110149076Swpaul	csr_write_4(sc, SF_PAR1, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4]));
110249076Swpaul	sf_setperf(sc, 0, (caddr_t)&sc->arpcom.ac_enaddr);
110349076Swpaul
110449076Swpaul	if (sf_init_rx_ring(sc) == ENOBUFS) {
110549076Swpaul		printf("sf%d: initialization failed: no "
110649076Swpaul		    "memory for rx buffers\n", sc->sf_unit);
110767087Swpaul		SF_UNLOCK(sc);
110849076Swpaul		return;
110949076Swpaul	}
111049076Swpaul
111149076Swpaul	sf_init_tx_ring(sc);
111249076Swpaul
111349076Swpaul	csr_write_4(sc, SF_RXFILT, SF_PERFMODE_NORMAL|SF_HASHMODE_WITHVLAN);
111449076Swpaul
111549076Swpaul	/* If we want promiscuous mode, set the allframes bit. */
111649076Swpaul	if (ifp->if_flags & IFF_PROMISC) {
111749076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
111849076Swpaul	} else {
111949076Swpaul		SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
112049076Swpaul	}
112149076Swpaul
112249076Swpaul	if (ifp->if_flags & IFF_BROADCAST) {
112349076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_BROAD);
112449076Swpaul	} else {
112549076Swpaul		SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_BROAD);
112649076Swpaul	}
112749076Swpaul
112863166Swpaul	/*
112963166Swpaul	 * Load the multicast filter.
113063166Swpaul	 */
113163166Swpaul	sf_setmulti(sc);
113263166Swpaul
113349076Swpaul	/* Init the completion queue indexes */
113449076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX, 0);
113549076Swpaul	csr_write_4(sc, SF_CQ_PRODIDX, 0);
113649076Swpaul
113749076Swpaul	/* Init the RX completion queue */
113849076Swpaul	csr_write_4(sc, SF_RXCQ_CTL_1,
113949076Swpaul	    vtophys(sc->sf_ldata->sf_rx_clist) & SF_RXCQ_ADDR);
114049076Swpaul	SF_SETBIT(sc, SF_RXCQ_CTL_1, SF_RXCQTYPE_3);
114149076Swpaul
114249076Swpaul	/* Init RX DMA control. */
114349076Swpaul	SF_SETBIT(sc, SF_RXDMA_CTL, SF_RXDMA_REPORTBADPKTS);
114449076Swpaul
114549076Swpaul	/* Init the RX buffer descriptor queue. */
114649076Swpaul	csr_write_4(sc, SF_RXDQ_ADDR_Q1,
114749076Swpaul	    vtophys(sc->sf_ldata->sf_rx_dlist_big));
114849076Swpaul	csr_write_4(sc, SF_RXDQ_CTL_1, (MCLBYTES << 16) | SF_DESCSPACE_16BYTES);
114949076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1, SF_RX_DLIST_CNT - 1);
115049076Swpaul
115149076Swpaul	/* Init the TX completion queue */
115249076Swpaul	csr_write_4(sc, SF_TXCQ_CTL,
115349076Swpaul	    vtophys(sc->sf_ldata->sf_tx_clist) & SF_RXCQ_ADDR);
115449076Swpaul
115549076Swpaul	/* Init the TX buffer descriptor queue. */
115649076Swpaul	csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO,
115749076Swpaul		vtophys(sc->sf_ldata->sf_tx_dlist));
115849076Swpaul	SF_SETBIT(sc, SF_TX_FRAMCTL, SF_TXFRMCTL_CPLAFTERTX);
115949076Swpaul	csr_write_4(sc, SF_TXDQ_CTL,
116049076Swpaul	    SF_TXBUFDESC_TYPE0|SF_TXMINSPACE_128BYTES|SF_TXSKIPLEN_8BYTES);
116149076Swpaul	SF_SETBIT(sc, SF_TXDQ_CTL, SF_TXDQCTL_NODMACMP);
116249076Swpaul
116349076Swpaul	/* Enable autopadding of short TX frames. */
116449076Swpaul	SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_AUTOPAD);
116549076Swpaul
116649076Swpaul	/* Enable interrupts. */
116749076Swpaul	csr_write_4(sc, SF_IMR, SF_INTRS);
116849076Swpaul	SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_INTR_ENB);
116949076Swpaul
117049076Swpaul	/* Enable the RX and TX engines. */
117149076Swpaul	SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_RX_ENB|SF_ETHCTL_RXDMA_ENB);
117249076Swpaul	SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_TX_ENB|SF_ETHCTL_TXDMA_ENB);
117349076Swpaul
117454161Swpaul	/*mii_mediachg(mii);*/
117554161Swpaul	sf_ifmedia_upd(ifp);
117650675Swpaul
117749076Swpaul	ifp->if_flags |= IFF_RUNNING;
117849076Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
117949076Swpaul
118049076Swpaul	sc->sf_stat_ch = timeout(sf_stats_update, sc, hz);
118149076Swpaul
118267087Swpaul	SF_UNLOCK(sc);
118349076Swpaul}
118449076Swpaul
1185102335Salfredstatic int
1186102335Salfredsf_encap(sc, c, m_head)
118749076Swpaul	struct sf_softc		*sc;
118849076Swpaul	struct sf_tx_bufdesc_type0 *c;
118949076Swpaul	struct mbuf		*m_head;
119049076Swpaul{
119149076Swpaul	int			frag = 0;
119249076Swpaul	struct sf_frag		*f = NULL;
119349076Swpaul	struct mbuf		*m;
119449076Swpaul
119549076Swpaul	m = m_head;
119649076Swpaul
119749076Swpaul	for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
119849076Swpaul		if (m->m_len != 0) {
119949076Swpaul			if (frag == SF_MAXFRAGS)
120049076Swpaul				break;
120149076Swpaul			f = &c->sf_frags[frag];
120249076Swpaul			if (frag == 0)
120349076Swpaul				f->sf_pktlen = m_head->m_pkthdr.len;
120449076Swpaul			f->sf_fraglen = m->m_len;
120549076Swpaul			f->sf_addr = vtophys(mtod(m, vm_offset_t));
120649076Swpaul			frag++;
120749076Swpaul		}
120849076Swpaul	}
120949076Swpaul
121049076Swpaul	if (m != NULL) {
121149076Swpaul		struct mbuf		*m_new = NULL;
121249076Swpaul
1213111119Simp		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
121449076Swpaul		if (m_new == NULL) {
1215103139Sticso			printf("sf%d: no memory for tx list\n", sc->sf_unit);
121649076Swpaul			return(1);
121749076Swpaul		}
121849076Swpaul
121949076Swpaul		if (m_head->m_pkthdr.len > MHLEN) {
1220111119Simp			MCLGET(m_new, M_DONTWAIT);
122149076Swpaul			if (!(m_new->m_flags & M_EXT)) {
122249076Swpaul				m_freem(m_new);
1223103139Sticso				printf("sf%d: no memory for tx list\n",
122449076Swpaul				    sc->sf_unit);
122549076Swpaul				return(1);
122649076Swpaul			}
122749076Swpaul		}
122849076Swpaul		m_copydata(m_head, 0, m_head->m_pkthdr.len,
122949076Swpaul		    mtod(m_new, caddr_t));
123049076Swpaul		m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
123149076Swpaul		m_freem(m_head);
123249076Swpaul		m_head = m_new;
123349076Swpaul		f = &c->sf_frags[0];
123449076Swpaul		f->sf_fraglen = f->sf_pktlen = m_head->m_pkthdr.len;
123549076Swpaul		f->sf_addr = vtophys(mtod(m_head, caddr_t));
123649076Swpaul		frag = 1;
123749076Swpaul	}
123849076Swpaul
123949076Swpaul	c->sf_mbuf = m_head;
124049076Swpaul	c->sf_id = SF_TX_BUFDESC_ID;
124149076Swpaul	c->sf_fragcnt = frag;
124249076Swpaul	c->sf_intr = 1;
124349076Swpaul	c->sf_caltcp = 0;
124449076Swpaul	c->sf_crcen = 1;
124549076Swpaul
124649076Swpaul	return(0);
124749076Swpaul}
124849076Swpaul
1249102335Salfredstatic void
1250102335Salfredsf_start(ifp)
125149076Swpaul	struct ifnet		*ifp;
125249076Swpaul{
125349076Swpaul	struct sf_softc		*sc;
125449076Swpaul	struct sf_tx_bufdesc_type0 *cur_tx = NULL;
125549076Swpaul	struct mbuf		*m_head = NULL;
125649076Swpaul	int			i, txprod;
125749076Swpaul
125849076Swpaul	sc = ifp->if_softc;
125967087Swpaul	SF_LOCK(sc);
126049076Swpaul
126181714Swpaul	if (!sc->sf_link && ifp->if_snd.ifq_len < 10) {
126267087Swpaul		SF_UNLOCK(sc);
126354161Swpaul		return;
126467087Swpaul	}
126554161Swpaul
126667087Swpaul	if (ifp->if_flags & IFF_OACTIVE) {
126767087Swpaul		SF_UNLOCK(sc);
126849076Swpaul		return;
126967087Swpaul	}
127049076Swpaul
127149076Swpaul	txprod = csr_read_4(sc, SF_TXDQ_PRODIDX);
127249076Swpaul	i = SF_IDX_HI(txprod) >> 4;
127349076Swpaul
127481737Swpaul	if (sc->sf_ldata->sf_tx_dlist[i].sf_mbuf != NULL) {
127581737Swpaul		printf("sf%d: TX ring full, resetting\n", sc->sf_unit);
127681737Swpaul		sf_init(sc);
127781737Swpaul		txprod = csr_read_4(sc, SF_TXDQ_PRODIDX);
127881737Swpaul		i = SF_IDX_HI(txprod) >> 4;
127981737Swpaul	}
128081737Swpaul
128149076Swpaul	while(sc->sf_ldata->sf_tx_dlist[i].sf_mbuf == NULL) {
128281737Swpaul		if (sc->sf_tx_cnt >= (SF_TX_DLIST_CNT - 5)) {
128371276Swpaul			ifp->if_flags |= IFF_OACTIVE;
128471276Swpaul			cur_tx = NULL;
128571276Swpaul			break;
128671276Swpaul		}
128749076Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
128849076Swpaul		if (m_head == NULL)
128949076Swpaul			break;
129049076Swpaul
129149076Swpaul		cur_tx = &sc->sf_ldata->sf_tx_dlist[i];
129271276Swpaul		if (sf_encap(sc, cur_tx, m_head)) {
129371276Swpaul			IF_PREPEND(&ifp->if_snd, m_head);
129471276Swpaul			ifp->if_flags |= IFF_OACTIVE;
129571276Swpaul			cur_tx = NULL;
129671276Swpaul			break;
129771276Swpaul		}
129849076Swpaul
129949076Swpaul		/*
130049076Swpaul		 * If there's a BPF listener, bounce a copy of this frame
130149076Swpaul		 * to him.
130249076Swpaul		 */
1303106936Ssam		BPF_MTAP(ifp, m_head);
130451583Swpaul
130549076Swpaul		SF_INC(i, SF_TX_DLIST_CNT);
130649076Swpaul		sc->sf_tx_cnt++;
130781798Swpaul		/*
130881798Swpaul		 * Don't get the TX DMA queue get too full.
130981798Swpaul		 */
131081798Swpaul		if (sc->sf_tx_cnt > 64)
131181798Swpaul			break;
131249076Swpaul	}
131349076Swpaul
131467087Swpaul	if (cur_tx == NULL) {
131567087Swpaul		SF_UNLOCK(sc);
131649076Swpaul		return;
131767087Swpaul	}
131849076Swpaul
131949076Swpaul	/* Transmit */
132049076Swpaul	csr_write_4(sc, SF_TXDQ_PRODIDX,
132149076Swpaul	    (txprod & ~SF_TXDQ_PRODIDX_HIPRIO) |
132249076Swpaul	    ((i << 20) & 0xFFFF0000));
132349076Swpaul
132449076Swpaul	ifp->if_timer = 5;
132549076Swpaul
132667087Swpaul	SF_UNLOCK(sc);
132749076Swpaul}
132849076Swpaul
1329102335Salfredstatic void
1330102335Salfredsf_stop(sc)
133149076Swpaul	struct sf_softc		*sc;
133249076Swpaul{
133349076Swpaul	int			i;
133449077Swpaul	struct ifnet		*ifp;
133549076Swpaul
133667087Swpaul	SF_LOCK(sc);
133767087Swpaul
133849077Swpaul	ifp = &sc->arpcom.ac_if;
133949077Swpaul
134049076Swpaul	untimeout(sf_stats_update, sc, sc->sf_stat_ch);
134149076Swpaul
134249076Swpaul	csr_write_4(sc, SF_GEN_ETH_CTL, 0);
134349076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX, 0);
134449076Swpaul	csr_write_4(sc, SF_CQ_PRODIDX, 0);
134549076Swpaul	csr_write_4(sc, SF_RXDQ_ADDR_Q1, 0);
134649076Swpaul	csr_write_4(sc, SF_RXDQ_CTL_1, 0);
134749076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1, 0);
134849076Swpaul	csr_write_4(sc, SF_TXCQ_CTL, 0);
134949076Swpaul	csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO, 0);
135049076Swpaul	csr_write_4(sc, SF_TXDQ_CTL, 0);
135149076Swpaul	sf_reset(sc);
135249076Swpaul
135354161Swpaul	sc->sf_link = 0;
135454161Swpaul
135549076Swpaul	for (i = 0; i < SF_RX_DLIST_CNT; i++) {
135649076Swpaul		if (sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf != NULL) {
135749076Swpaul			m_freem(sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf);
135849076Swpaul			sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf = NULL;
135949076Swpaul		}
136049076Swpaul	}
136149076Swpaul
136249076Swpaul	for (i = 0; i < SF_TX_DLIST_CNT; i++) {
136349076Swpaul		if (sc->sf_ldata->sf_tx_dlist[i].sf_mbuf != NULL) {
136449076Swpaul			m_freem(sc->sf_ldata->sf_tx_dlist[i].sf_mbuf);
136549076Swpaul			sc->sf_ldata->sf_tx_dlist[i].sf_mbuf = NULL;
136649076Swpaul		}
136749076Swpaul	}
136849076Swpaul
136949077Swpaul	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
137067087Swpaul	SF_UNLOCK(sc);
137149076Swpaul}
137249076Swpaul
137349076Swpaul/*
137449076Swpaul * Note: it is important that this function not be interrupted. We
137549076Swpaul * use a two-stage register access scheme: if we are interrupted in
137649076Swpaul * between setting the indirect address register and reading from the
137749076Swpaul * indirect data register, the contents of the address register could
137849076Swpaul * be changed out from under us.
1379131657Sbms */
1380102335Salfredstatic void
1381102335Salfredsf_stats_update(xsc)
138249076Swpaul	void			*xsc;
138349076Swpaul{
138449076Swpaul	struct sf_softc		*sc;
138549076Swpaul	struct ifnet		*ifp;
138650675Swpaul	struct mii_data		*mii;
138749076Swpaul	struct sf_stats		stats;
138849076Swpaul	u_int32_t		*ptr;
138967087Swpaul	int			i;
139049076Swpaul
139149076Swpaul	sc = xsc;
139267087Swpaul	SF_LOCK(sc);
139349076Swpaul	ifp = &sc->arpcom.ac_if;
139450675Swpaul	mii = device_get_softc(sc->sf_miibus);
139549076Swpaul
139649076Swpaul	ptr = (u_int32_t *)&stats;
139749076Swpaul	for (i = 0; i < sizeof(stats)/sizeof(u_int32_t); i++)
139849076Swpaul		ptr[i] = csr_read_4(sc, SF_STATS_BASE +
139949076Swpaul		    (i + sizeof(u_int32_t)));
140049076Swpaul
140149076Swpaul	for (i = 0; i < sizeof(stats)/sizeof(u_int32_t); i++)
140249076Swpaul		csr_write_4(sc, SF_STATS_BASE +
140349076Swpaul		    (i + sizeof(u_int32_t)), 0);
140449076Swpaul
140549076Swpaul	ifp->if_collisions += stats.sf_tx_single_colls +
140649076Swpaul	    stats.sf_tx_multi_colls + stats.sf_tx_excess_colls;
140749076Swpaul
140850675Swpaul	mii_tick(mii);
140984147Sjlemon
141084147Sjlemon	if (!sc->sf_link && mii->mii_media_status & IFM_ACTIVE &&
141184147Sjlemon	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
141284147Sjlemon		sc->sf_link++;
141384147Sjlemon		if (ifp->if_snd.ifq_head != NULL)
141484147Sjlemon			sf_start(ifp);
141554161Swpaul	}
141650675Swpaul
141749076Swpaul	sc->sf_stat_ch = timeout(sf_stats_update, sc, hz);
141849076Swpaul
141967087Swpaul	SF_UNLOCK(sc);
142049076Swpaul}
142149076Swpaul
1422102335Salfredstatic void
1423102335Salfredsf_watchdog(ifp)
142449076Swpaul	struct ifnet		*ifp;
142549076Swpaul{
142649076Swpaul	struct sf_softc		*sc;
142749076Swpaul
142849076Swpaul	sc = ifp->if_softc;
142949076Swpaul
143067087Swpaul	SF_LOCK(sc);
143167087Swpaul
143249076Swpaul	ifp->if_oerrors++;
143349076Swpaul	printf("sf%d: watchdog timeout\n", sc->sf_unit);
143449076Swpaul
143549076Swpaul	sf_stop(sc);
143649076Swpaul	sf_reset(sc);
143749076Swpaul	sf_init(sc);
143849076Swpaul
143949076Swpaul	if (ifp->if_snd.ifq_head != NULL)
144049076Swpaul		sf_start(ifp);
144149076Swpaul
144267087Swpaul	SF_UNLOCK(sc);
144349076Swpaul}
144449076Swpaul
1445102335Salfredstatic void
1446102335Salfredsf_shutdown(dev)
144749076Swpaul	device_t		dev;
144849076Swpaul{
144949076Swpaul	struct sf_softc		*sc;
145049076Swpaul
145149076Swpaul	sc = device_get_softc(dev);
145249076Swpaul
145349076Swpaul	sf_stop(sc);
145449076Swpaul}
1455