if_sf.c revision 81714
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 81714 2001-08-15 17:46:57Z wpaul $
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 81714 2001-08-15 17:46:57Z wpaul $";
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
13349076Swpaulstatic int sf_probe		__P((device_t));
13449076Swpaulstatic int sf_attach		__P((device_t));
13549076Swpaulstatic int sf_detach		__P((device_t));
13649076Swpaulstatic void sf_intr		__P((void *));
13749076Swpaulstatic void sf_stats_update	__P((void *));
13849076Swpaulstatic void sf_rxeof		__P((struct sf_softc *));
13949076Swpaulstatic void sf_txeof		__P((struct sf_softc *));
14049076Swpaulstatic int sf_encap		__P((struct sf_softc *,
14149076Swpaul					struct sf_tx_bufdesc_type0 *,
14249076Swpaul					struct mbuf *));
14349076Swpaulstatic void sf_start		__P((struct ifnet *));
14449076Swpaulstatic int sf_ioctl		__P((struct ifnet *, u_long, caddr_t));
14549076Swpaulstatic void sf_init		__P((void *));
14649076Swpaulstatic void sf_stop		__P((struct sf_softc *));
14749076Swpaulstatic void sf_watchdog		__P((struct ifnet *));
14849076Swpaulstatic void sf_shutdown		__P((device_t));
14949076Swpaulstatic int sf_ifmedia_upd	__P((struct ifnet *));
15049076Swpaulstatic void sf_ifmedia_sts	__P((struct ifnet *, struct ifmediareq *));
15149076Swpaulstatic void sf_reset		__P((struct sf_softc *));
15249076Swpaulstatic int sf_init_rx_ring	__P((struct sf_softc *));
15349076Swpaulstatic void sf_init_tx_ring	__P((struct sf_softc *));
15449076Swpaulstatic int sf_newbuf		__P((struct sf_softc *,
15549076Swpaul					struct sf_rx_bufdesc_type0 *,
15649076Swpaul					struct mbuf *));
15749076Swpaulstatic void sf_setmulti		__P((struct sf_softc *));
15849076Swpaulstatic int sf_setperf		__P((struct sf_softc *, int, caddr_t));
15949076Swpaulstatic int sf_sethash		__P((struct sf_softc *, caddr_t, int));
16049076Swpaul#ifdef notdef
16149076Swpaulstatic int sf_setvlan		__P((struct sf_softc *, int, u_int32_t));
16249076Swpaul#endif
16349076Swpaul
16449076Swpaulstatic u_int8_t sf_read_eeprom	__P((struct sf_softc *, int));
16549076Swpaulstatic u_int32_t sf_calchash	__P((caddr_t));
16649076Swpaul
16750675Swpaulstatic int sf_miibus_readreg	__P((device_t, int, int));
16850675Swpaulstatic int sf_miibus_writereg	__P((device_t, int, int, int));
16950675Swpaulstatic void sf_miibus_statchg	__P((device_t));
17049076Swpaul
17149076Swpaulstatic u_int32_t csr_read_4	__P((struct sf_softc *, int));
17249076Swpaulstatic void csr_write_4		__P((struct sf_softc *, int, u_int32_t));
17349076Swpaul
17449076Swpaul#ifdef SF_USEIOSPACE
17549076Swpaul#define SF_RES			SYS_RES_IOPORT
17649076Swpaul#define SF_RID			SF_PCI_LOIO
17749076Swpaul#else
17849076Swpaul#define SF_RES			SYS_RES_MEMORY
17949076Swpaul#define SF_RID			SF_PCI_LOMEM
18049076Swpaul#endif
18149076Swpaul
18249076Swpaulstatic device_method_t sf_methods[] = {
18349076Swpaul	/* Device interface */
18449076Swpaul	DEVMETHOD(device_probe,		sf_probe),
18549076Swpaul	DEVMETHOD(device_attach,	sf_attach),
18649076Swpaul	DEVMETHOD(device_detach,	sf_detach),
18749076Swpaul	DEVMETHOD(device_shutdown,	sf_shutdown),
18850675Swpaul
18950675Swpaul	/* bus interface */
19050675Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
19150675Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
19250675Swpaul
19350675Swpaul	/* MII interface */
19450675Swpaul	DEVMETHOD(miibus_readreg,	sf_miibus_readreg),
19550675Swpaul	DEVMETHOD(miibus_writereg,	sf_miibus_writereg),
19650675Swpaul	DEVMETHOD(miibus_statchg,	sf_miibus_statchg),
19750675Swpaul
19849076Swpaul	{ 0, 0 }
19949076Swpaul};
20049076Swpaul
20149076Swpaulstatic driver_t sf_driver = {
20251455Swpaul	"sf",
20349076Swpaul	sf_methods,
20449076Swpaul	sizeof(struct sf_softc),
20549076Swpaul};
20649076Swpaul
20749076Swpaulstatic devclass_t sf_devclass;
20849076Swpaul
20951533SwpaulDRIVER_MODULE(if_sf, pci, sf_driver, sf_devclass, 0, 0);
21051473SwpaulDRIVER_MODULE(miibus, sf, miibus_driver, miibus_devclass, 0, 0);
21149076Swpaul
21249076Swpaul#define SF_SETBIT(sc, reg, x)	\
21349076Swpaul	csr_write_4(sc, reg, csr_read_4(sc, reg) | x)
21449076Swpaul
21549076Swpaul#define SF_CLRBIT(sc, reg, x)				\
21649076Swpaul	csr_write_4(sc, reg, csr_read_4(sc, reg) & ~x)
21749076Swpaul
21849076Swpaulstatic u_int32_t csr_read_4(sc, reg)
21949076Swpaul	struct sf_softc		*sc;
22049076Swpaul	int			reg;
22149076Swpaul{
22249076Swpaul	u_int32_t		val;
22349076Swpaul
22449076Swpaul#ifdef SF_USEIOSPACE
22549076Swpaul	CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE);
22649076Swpaul	val = CSR_READ_4(sc, SF_INDIRECTIO_DATA);
22749076Swpaul#else
22849076Swpaul	val = CSR_READ_4(sc, (reg + SF_RMAP_INTREG_BASE));
22949076Swpaul#endif
23049076Swpaul
23149076Swpaul	return(val);
23249076Swpaul}
23349076Swpaul
23449076Swpaulstatic u_int8_t sf_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
24649076Swpaulstatic void csr_write_4(sc, reg, val)
24749076Swpaul	struct sf_softc		*sc;
24849076Swpaul	int			reg;
24949076Swpaul	u_int32_t		val;
25049076Swpaul{
25149076Swpaul#ifdef SF_USEIOSPACE
25249076Swpaul	CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE);
25349076Swpaul	CSR_WRITE_4(sc, SF_INDIRECTIO_DATA, val);
25449076Swpaul#else
25549076Swpaul	CSR_WRITE_4(sc, (reg + SF_RMAP_INTREG_BASE), val);
25649076Swpaul#endif
25749076Swpaul	return;
25849076Swpaul}
25949076Swpaul
26049076Swpaulstatic u_int32_t sf_calchash(addr)
26149076Swpaul	caddr_t			addr;
26249076Swpaul{
26349076Swpaul	u_int32_t		crc, carry;
26449076Swpaul	int			i, j;
26549076Swpaul	u_int8_t		c;
26649076Swpaul
26749076Swpaul	/* Compute CRC for the address value. */
26849076Swpaul	crc = 0xFFFFFFFF; /* initial value */
26949076Swpaul
27049076Swpaul	for (i = 0; i < 6; i++) {
27149076Swpaul		c = *(addr + i);
27249076Swpaul		for (j = 0; j < 8; j++) {
27349076Swpaul			carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
27449076Swpaul			crc <<= 1;
27549076Swpaul			c >>= 1;
27649076Swpaul			if (carry)
27749076Swpaul				crc = (crc ^ 0x04c11db6) | carry;
27849076Swpaul		}
27949076Swpaul	}
28049076Swpaul
28149076Swpaul	/* return the filter bit position */
28249076Swpaul	return(crc >> 23 & 0x1FF);
28349076Swpaul}
28449076Swpaul
28549076Swpaul/*
28649076Swpaul * Copy the address 'mac' into the perfect RX filter entry at
28749076Swpaul * offset 'idx.' The perfect filter only has 16 entries so do
28849076Swpaul * some sanity tests.
28949076Swpaul */
29049076Swpaulstatic int sf_setperf(sc, idx, mac)
29149076Swpaul	struct sf_softc		*sc;
29249076Swpaul	int			idx;
29349076Swpaul	caddr_t			mac;
29449076Swpaul{
29549076Swpaul	u_int16_t		*p;
29649076Swpaul
29749076Swpaul	if (idx < 0 || idx > SF_RXFILT_PERFECT_CNT)
29849076Swpaul		return(EINVAL);
29949076Swpaul
30049076Swpaul	if (mac == NULL)
30149076Swpaul		return(EINVAL);
30249076Swpaul
30349076Swpaul	p = (u_int16_t *)mac;
30449076Swpaul
30549076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
30649076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP), htons(p[2]));
30749076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
30849076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP) + 4, htons(p[1]));
30949076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
31049076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP) + 8, htons(p[0]));
31149076Swpaul
31249076Swpaul	return(0);
31349076Swpaul}
31449076Swpaul
31549076Swpaul/*
31649076Swpaul * Set the bit in the 512-bit hash table that corresponds to the
31749076Swpaul * specified mac address 'mac.' If 'prio' is nonzero, update the
31849076Swpaul * priority hash table instead of the filter hash table.
31949076Swpaul */
32049076Swpaulstatic int sf_sethash(sc, mac, prio)
32149076Swpaul	struct sf_softc		*sc;
32249076Swpaul	caddr_t			mac;
32349076Swpaul	int			prio;
32449076Swpaul{
32549076Swpaul	u_int32_t		h = 0;
32649076Swpaul
32749076Swpaul	if (mac == NULL)
32849076Swpaul		return(EINVAL);
32949076Swpaul
33049076Swpaul	h = sf_calchash(mac);
33149076Swpaul
33249076Swpaul	if (prio) {
33349076Swpaul		SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_PRIOOFF +
33449076Swpaul		    (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF)));
33549076Swpaul	} else {
33649076Swpaul		SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_ADDROFF +
33749076Swpaul		    (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF)));
33849076Swpaul	}
33949076Swpaul
34049076Swpaul	return(0);
34149076Swpaul}
34249076Swpaul
34349076Swpaul#ifdef notdef
34449076Swpaul/*
34549076Swpaul * Set a VLAN tag in the receive filter.
34649076Swpaul */
34749076Swpaulstatic int sf_setvlan(sc, idx, vlan)
34849076Swpaul	struct sf_softc		*sc;
34949076Swpaul	int			idx;
35049076Swpaul	u_int32_t		vlan;
35149076Swpaul{
35249076Swpaul	if (idx < 0 || idx >> SF_RXFILT_HASH_CNT)
35349076Swpaul		return(EINVAL);
35449076Swpaul
35549076Swpaul	csr_write_4(sc, SF_RXFILT_HASH_BASE +
35649076Swpaul	    (idx * SF_RXFILT_HASH_SKIP) + SF_RXFILT_HASH_VLANOFF, vlan);
35749076Swpaul
35849076Swpaul	return(0);
35949076Swpaul}
36049076Swpaul#endif
36149076Swpaul
36250675Swpaulstatic int sf_miibus_readreg(dev, phy, reg)
36350675Swpaul	device_t		dev;
36450675Swpaul	int			phy, reg;
36550675Swpaul{
36649076Swpaul	struct sf_softc		*sc;
36749076Swpaul	int			i;
36849076Swpaul	u_int32_t		val = 0;
36949076Swpaul
37050675Swpaul	sc = device_get_softc(dev);
37150675Swpaul
37249076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
37350675Swpaul		val = csr_read_4(sc, SF_PHY_REG(phy, reg));
37449076Swpaul		if (val & SF_MII_DATAVALID)
37549076Swpaul			break;
37649076Swpaul	}
37749076Swpaul
37849076Swpaul	if (i == SF_TIMEOUT)
37949076Swpaul		return(0);
38049076Swpaul
38149076Swpaul	if ((val & 0x0000FFFF) == 0xFFFF)
38249076Swpaul		return(0);
38349076Swpaul
38449076Swpaul	return(val & 0x0000FFFF);
38549076Swpaul}
38649076Swpaul
38750675Swpaulstatic int sf_miibus_writereg(dev, phy, reg, val)
38850675Swpaul	device_t		dev;
38950675Swpaul	int			phy, reg, val;
39050675Swpaul{
39149076Swpaul	struct sf_softc		*sc;
39249076Swpaul	int			i;
39349076Swpaul	int			busy;
39449076Swpaul
39550675Swpaul	sc = device_get_softc(dev);
39649076Swpaul
39750675Swpaul	csr_write_4(sc, SF_PHY_REG(phy, reg), val);
39850675Swpaul
39949076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
40050675Swpaul		busy = csr_read_4(sc, SF_PHY_REG(phy, reg));
40149076Swpaul		if (!(busy & SF_MII_BUSY))
40249076Swpaul			break;
40349076Swpaul	}
40449076Swpaul
40550675Swpaul	return(0);
40650675Swpaul}
40750675Swpaul
40850675Swpaulstatic void sf_miibus_statchg(dev)
40950675Swpaul	device_t		dev;
41050675Swpaul{
41150675Swpaul	struct sf_softc		*sc;
41250675Swpaul	struct mii_data		*mii;
41350675Swpaul
41450675Swpaul	sc = device_get_softc(dev);
41550675Swpaul	mii = device_get_softc(sc->sf_miibus);
41650675Swpaul
41750675Swpaul	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
41850675Swpaul		SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX);
41954161Swpaul		csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_FDX);
42050675Swpaul	} else {
42150675Swpaul		SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX);
42254161Swpaul		csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_HDX);
42350675Swpaul	}
42450675Swpaul
42549076Swpaul	return;
42649076Swpaul}
42749076Swpaul
42849076Swpaulstatic void sf_setmulti(sc)
42949076Swpaul	struct sf_softc		*sc;
43049076Swpaul{
43149076Swpaul	struct ifnet		*ifp;
43249076Swpaul	int			i;
43349076Swpaul	struct ifmultiaddr	*ifma;
43449076Swpaul	u_int8_t		dummy[] = { 0, 0, 0, 0, 0, 0 };
43549076Swpaul
43649076Swpaul	ifp = &sc->arpcom.ac_if;
43749076Swpaul
43849076Swpaul	/* First zot all the existing filters. */
43949076Swpaul	for (i = 1; i < SF_RXFILT_PERFECT_CNT; i++)
44049076Swpaul		sf_setperf(sc, i, (char *)&dummy);
44149076Swpaul	for (i = SF_RXFILT_HASH_BASE;
44249076Swpaul	    i < (SF_RXFILT_HASH_MAX + 1); i += 4)
44349076Swpaul		csr_write_4(sc, i, 0);
44449076Swpaul	SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_ALLMULTI);
44549076Swpaul
44649076Swpaul	/* Now program new ones. */
44749076Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
44849076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_ALLMULTI);
44949076Swpaul	} else {
45049076Swpaul		i = 1;
45172084Sphk		TAILQ_FOREACH_REVERSE(ifma, &ifp->if_multiaddrs, ifmultihead, ifma_link) {
45249076Swpaul			if (ifma->ifma_addr->sa_family != AF_LINK)
45349076Swpaul				continue;
45449076Swpaul			/*
45549076Swpaul			 * Program the first 15 multicast groups
45649076Swpaul			 * into the perfect filter. For all others,
45749076Swpaul			 * use the hash table.
45849076Swpaul			 */
45949076Swpaul			if (i < SF_RXFILT_PERFECT_CNT) {
46049076Swpaul				sf_setperf(sc, i,
46149076Swpaul			LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
46249076Swpaul				i++;
46349076Swpaul				continue;
46449076Swpaul			}
46549076Swpaul
46649076Swpaul			sf_sethash(sc,
46749076Swpaul			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 0);
46849076Swpaul		}
46949076Swpaul	}
47049076Swpaul
47149076Swpaul	return;
47249076Swpaul}
47349076Swpaul
47449076Swpaul/*
47549076Swpaul * Set media options.
47649076Swpaul */
47749076Swpaulstatic int sf_ifmedia_upd(ifp)
47849076Swpaul	struct ifnet		*ifp;
47949076Swpaul{
48049076Swpaul	struct sf_softc		*sc;
48150675Swpaul	struct mii_data		*mii;
48249076Swpaul
48349076Swpaul	sc = ifp->if_softc;
48450675Swpaul	mii = device_get_softc(sc->sf_miibus);
48554161Swpaul	sc->sf_link = 0;
48654161Swpaul	if (mii->mii_instance) {
48754161Swpaul		struct mii_softc        *miisc;
48872012Sphk		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
48954161Swpaul			mii_phy_reset(miisc);
49054161Swpaul	}
49150675Swpaul	mii_mediachg(mii);
49249076Swpaul
49349076Swpaul	return(0);
49449076Swpaul}
49549076Swpaul
49649076Swpaul/*
49749076Swpaul * Report current media status.
49849076Swpaul */
49949076Swpaulstatic void sf_ifmedia_sts(ifp, ifmr)
50049076Swpaul	struct ifnet		*ifp;
50149076Swpaul	struct ifmediareq	*ifmr;
50249076Swpaul{
50349076Swpaul	struct sf_softc		*sc;
50450675Swpaul	struct mii_data		*mii;
50549076Swpaul
50649076Swpaul	sc = ifp->if_softc;
50750675Swpaul	mii = device_get_softc(sc->sf_miibus);
50849076Swpaul
50950675Swpaul	mii_pollstat(mii);
51050675Swpaul	ifmr->ifm_active = mii->mii_media_active;
51150675Swpaul	ifmr->ifm_status = mii->mii_media_status;
51249076Swpaul
51349076Swpaul	return;
51449076Swpaul}
51549076Swpaul
51649076Swpaulstatic int sf_ioctl(ifp, command, data)
51749076Swpaul	struct ifnet		*ifp;
51849076Swpaul	u_long			command;
51949076Swpaul	caddr_t			data;
52049076Swpaul{
52149076Swpaul	struct sf_softc		*sc = ifp->if_softc;
52249076Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
52350675Swpaul	struct mii_data		*mii;
52467087Swpaul	int			error = 0;
52549076Swpaul
52667087Swpaul	SF_LOCK(sc);
52749076Swpaul
52849076Swpaul	switch(command) {
52949076Swpaul	case SIOCSIFADDR:
53049076Swpaul	case SIOCGIFADDR:
53149076Swpaul	case SIOCSIFMTU:
53249076Swpaul		error = ether_ioctl(ifp, command, data);
53349076Swpaul		break;
53449076Swpaul	case SIOCSIFFLAGS:
53549076Swpaul		if (ifp->if_flags & IFF_UP) {
53654161Swpaul			if (ifp->if_flags & IFF_RUNNING &&
53754161Swpaul			    ifp->if_flags & IFF_PROMISC &&
53854161Swpaul			    !(sc->sf_if_flags & IFF_PROMISC)) {
53954161Swpaul				SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
54054161Swpaul			} else if (ifp->if_flags & IFF_RUNNING &&
54154161Swpaul			    !(ifp->if_flags & IFF_PROMISC) &&
54254161Swpaul			    sc->sf_if_flags & IFF_PROMISC) {
54354161Swpaul				SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
54454161Swpaul			} else if (!(ifp->if_flags & IFF_RUNNING))
54554161Swpaul				sf_init(sc);
54649076Swpaul		} else {
54749076Swpaul			if (ifp->if_flags & IFF_RUNNING)
54849076Swpaul				sf_stop(sc);
54949076Swpaul		}
55054161Swpaul		sc->sf_if_flags = ifp->if_flags;
55149076Swpaul		error = 0;
55249076Swpaul		break;
55349076Swpaul	case SIOCADDMULTI:
55449076Swpaul	case SIOCDELMULTI:
55549076Swpaul		sf_setmulti(sc);
55649076Swpaul		error = 0;
55749076Swpaul		break;
55849076Swpaul	case SIOCGIFMEDIA:
55949076Swpaul	case SIOCSIFMEDIA:
56050675Swpaul		mii = device_get_softc(sc->sf_miibus);
56150675Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
56249076Swpaul		break;
56349076Swpaul	default:
56449076Swpaul		error = EINVAL;
56549076Swpaul		break;
56649076Swpaul	}
56749076Swpaul
56867087Swpaul	SF_UNLOCK(sc);
56949076Swpaul
57049076Swpaul	return(error);
57149076Swpaul}
57249076Swpaul
57349076Swpaulstatic void sf_reset(sc)
57449076Swpaul	struct sf_softc		*sc;
57549076Swpaul{
57649076Swpaul	register int		i;
57749076Swpaul
57849076Swpaul	csr_write_4(sc, SF_GEN_ETH_CTL, 0);
57949076Swpaul	SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
58049076Swpaul	DELAY(1000);
58149076Swpaul	SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
58249076Swpaul
58349076Swpaul	SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_RESET);
58449076Swpaul
58549076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
58649076Swpaul		DELAY(10);
58749076Swpaul		if (!(csr_read_4(sc, SF_PCI_DEVCFG) & SF_PCIDEVCFG_RESET))
58849076Swpaul			break;
58949076Swpaul	}
59049076Swpaul
59149076Swpaul	if (i == SF_TIMEOUT)
59249076Swpaul		printf("sf%d: reset never completed!\n", sc->sf_unit);
59349076Swpaul
59449076Swpaul	/* Wait a little while for the chip to get its brains in order. */
59549076Swpaul	DELAY(1000);
59649076Swpaul	return;
59749076Swpaul}
59849076Swpaul
59949076Swpaul/*
60049076Swpaul * Probe for an Adaptec AIC-6915 chip. Check the PCI vendor and device
60149076Swpaul * IDs against our list and return a device name if we find a match.
60249076Swpaul * We also check the subsystem ID so that we can identify exactly which
60349076Swpaul * NIC has been found, if possible.
60449076Swpaul */
60549076Swpaulstatic int sf_probe(dev)
60649076Swpaul	device_t		dev;
60749076Swpaul{
60849076Swpaul	struct sf_type		*t;
60949076Swpaul
61049076Swpaul	t = sf_devs;
61149076Swpaul
61249076Swpaul	while(t->sf_name != NULL) {
61349076Swpaul		if ((pci_get_vendor(dev) == t->sf_vid) &&
61449076Swpaul		    (pci_get_device(dev) == t->sf_did)) {
61551336Swpaul			switch((pci_read_config(dev,
61651336Swpaul			    SF_PCI_SUBVEN_ID, 4) >> 16) & 0xFFFF) {
61749076Swpaul			case AD_SUBSYSID_62011_REV0:
61849076Swpaul			case AD_SUBSYSID_62011_REV1:
61949076Swpaul				device_set_desc(dev,
62049076Swpaul				    "Adaptec ANA-62011 10/100BaseTX");
62149076Swpaul				return(0);
62249076Swpaul				break;
62349076Swpaul			case AD_SUBSYSID_62022:
62449076Swpaul				device_set_desc(dev,
62549076Swpaul				    "Adaptec ANA-62022 10/100BaseTX");
62649076Swpaul				return(0);
62749076Swpaul				break;
62853468Swpaul			case AD_SUBSYSID_62044_REV0:
62953468Swpaul			case AD_SUBSYSID_62044_REV1:
63049076Swpaul				device_set_desc(dev,
63149076Swpaul				    "Adaptec ANA-62044 10/100BaseTX");
63249076Swpaul				return(0);
63349076Swpaul				break;
63449076Swpaul			case AD_SUBSYSID_62020:
63549076Swpaul				device_set_desc(dev,
63649076Swpaul				    "Adaptec ANA-62020 10/100BaseFX");
63749076Swpaul				return(0);
63849076Swpaul				break;
63949076Swpaul			case AD_SUBSYSID_69011:
64049076Swpaul				device_set_desc(dev,
64149076Swpaul				    "Adaptec ANA-69011 10/100BaseTX");
64249076Swpaul				return(0);
64349076Swpaul				break;
64449076Swpaul			default:
64549076Swpaul				device_set_desc(dev, t->sf_name);
64649076Swpaul				return(0);
64749076Swpaul				break;
64849076Swpaul			}
64949076Swpaul		}
65049076Swpaul		t++;
65149076Swpaul	}
65249076Swpaul
65349076Swpaul	return(ENXIO);
65449076Swpaul}
65549076Swpaul
65649076Swpaul/*
65749076Swpaul * Attach the interface. Allocate softc structures, do ifmedia
65849076Swpaul * setup and ethernet/BPF attach.
65949076Swpaul */
66049076Swpaulstatic int sf_attach(dev)
66149076Swpaul	device_t		dev;
66249076Swpaul{
66367087Swpaul	int			i;
66449076Swpaul	u_int32_t		command;
66549076Swpaul	struct sf_softc		*sc;
66649076Swpaul	struct ifnet		*ifp;
66749076Swpaul	int			unit, rid, error = 0;
66849076Swpaul
66949076Swpaul	sc = device_get_softc(dev);
67049076Swpaul	unit = device_get_unit(dev);
67149076Swpaul	bzero(sc, sizeof(struct sf_softc));
67249076Swpaul
67371228Sbmilekic	mtx_init(&sc->sf_mtx, device_get_nameunit(dev), MTX_DEF | MTX_RECURSE);
67469583Swpaul	SF_LOCK(sc);
67549076Swpaul	/*
67649076Swpaul	 * Handle power management nonsense.
67749076Swpaul	 */
67872813Swpaul	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
67972813Swpaul		u_int32_t		iobase, membase, irq;
68049076Swpaul
68172813Swpaul		/* Save important PCI config data. */
68272813Swpaul		iobase = pci_read_config(dev, SF_PCI_LOIO, 4);
68372813Swpaul		membase = pci_read_config(dev, SF_PCI_LOMEM, 4);
68472813Swpaul		irq = pci_read_config(dev, SF_PCI_INTLINE, 4);
68549076Swpaul
68672813Swpaul		/* Reset the power state. */
68772813Swpaul		printf("sf%d: chip is in D%d power mode "
68872813Swpaul		    "-- setting to D0\n", unit,
68972813Swpaul		    pci_get_powerstate(dev));
69072813Swpaul		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
69149076Swpaul
69272813Swpaul		/* Restore PCI config data. */
69372813Swpaul		pci_write_config(dev, SF_PCI_LOIO, iobase, 4);
69472813Swpaul		pci_write_config(dev, SF_PCI_LOMEM, membase, 4);
69572813Swpaul		pci_write_config(dev, SF_PCI_INTLINE, irq, 4);
69649076Swpaul	}
69749076Swpaul
69849076Swpaul	/*
69949076Swpaul	 * Map control/status registers.
70049076Swpaul	 */
70172813Swpaul	pci_enable_busmaster(dev);
70279472Swpaul	pci_enable_io(dev, SYS_RES_IOPORT);
70379472Swpaul	pci_enable_io(dev, SYS_RES_MEMORY);
70461041Speter	command = pci_read_config(dev, PCIR_COMMAND, 4);
70549076Swpaul
70649076Swpaul#ifdef SF_USEIOSPACE
70749076Swpaul	if (!(command & PCIM_CMD_PORTEN)) {
70849076Swpaul		printf("sf%d: failed to enable I/O ports!\n", unit);
70949076Swpaul		error = ENXIO;
71049076Swpaul		goto fail;
71149076Swpaul	}
71249076Swpaul#else
71349076Swpaul	if (!(command & PCIM_CMD_MEMEN)) {
71449076Swpaul		printf("sf%d: failed to enable memory mapping!\n", unit);
71549076Swpaul		error = ENXIO;
71649076Swpaul		goto fail;
71749076Swpaul	}
71849076Swpaul#endif
71949076Swpaul
72049076Swpaul	rid = SF_RID;
72149076Swpaul	sc->sf_res = bus_alloc_resource(dev, SF_RES, &rid,
72249076Swpaul	    0, ~0, 1, RF_ACTIVE);
72349076Swpaul
72449076Swpaul	if (sc->sf_res == NULL) {
72549076Swpaul		printf ("sf%d: couldn't map ports\n", unit);
72649076Swpaul		error = ENXIO;
72749076Swpaul		goto fail;
72849076Swpaul	}
72949076Swpaul
73049076Swpaul	sc->sf_btag = rman_get_bustag(sc->sf_res);
73149076Swpaul	sc->sf_bhandle = rman_get_bushandle(sc->sf_res);
73249076Swpaul
73349076Swpaul	/* Allocate interrupt */
73449076Swpaul	rid = 0;
73549076Swpaul	sc->sf_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
73649076Swpaul	    RF_SHAREABLE | RF_ACTIVE);
73749076Swpaul
73849076Swpaul	if (sc->sf_irq == NULL) {
73949076Swpaul		printf("sf%d: couldn't map interrupt\n", unit);
74049076Swpaul		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
74149076Swpaul		error = ENXIO;
74249076Swpaul		goto fail;
74349076Swpaul	}
74449076Swpaul
74549076Swpaul	error = bus_setup_intr(dev, sc->sf_irq, INTR_TYPE_NET,
74649076Swpaul	    sf_intr, sc, &sc->sf_intrhand);
74749076Swpaul
74849076Swpaul	if (error) {
74949076Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_res);
75049076Swpaul		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
75149076Swpaul		printf("sf%d: couldn't set up irq\n", unit);
75249076Swpaul		goto fail;
75349076Swpaul	}
75449076Swpaul
75549076Swpaul	callout_handle_init(&sc->sf_stat_ch);
75649076Swpaul	/* Reset the adapter. */
75749076Swpaul	sf_reset(sc);
75849076Swpaul
75949076Swpaul	/*
76049076Swpaul	 * Get station address from the EEPROM.
76149076Swpaul	 */
76249076Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
76349076Swpaul		sc->arpcom.ac_enaddr[i] =
76449076Swpaul		    sf_read_eeprom(sc, SF_EE_NODEADDR + ETHER_ADDR_LEN - i);
76549076Swpaul
76649076Swpaul	/*
76749076Swpaul	 * An Adaptec chip was detected. Inform the world.
76849076Swpaul	 */
76949076Swpaul	printf("sf%d: Ethernet address: %6D\n", unit,
77049076Swpaul	    sc->arpcom.ac_enaddr, ":");
77149076Swpaul
77249076Swpaul	sc->sf_unit = unit;
77349076Swpaul
77449076Swpaul	/* Allocate the descriptor queues. */
77549076Swpaul	sc->sf_ldata = contigmalloc(sizeof(struct sf_list_data), M_DEVBUF,
77651657Swpaul	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
77749076Swpaul
77849076Swpaul	if (sc->sf_ldata == NULL) {
77949076Swpaul		printf("sf%d: no memory for list buffers!\n", unit);
78049076Swpaul		bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
78149076Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
78249076Swpaul		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
78349076Swpaul		error = ENXIO;
78449076Swpaul		goto fail;
78549076Swpaul	}
78649076Swpaul
78749076Swpaul	bzero(sc->sf_ldata, sizeof(struct sf_list_data));
78849076Swpaul
78950675Swpaul	/* Do MII setup. */
79050675Swpaul	if (mii_phy_probe(dev, &sc->sf_miibus,
79150675Swpaul	    sf_ifmedia_upd, sf_ifmedia_sts)) {
79249076Swpaul		printf("sf%d: MII without any phy!\n", sc->sf_unit);
79354161Swpaul		contigfree(sc->sf_ldata,sizeof(struct sf_list_data),M_DEVBUF);
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	ifp = &sc->arpcom.ac_if;
80249076Swpaul	ifp->if_softc = sc;
80349076Swpaul	ifp->if_unit = unit;
80449076Swpaul	ifp->if_name = "sf";
80549076Swpaul	ifp->if_mtu = ETHERMTU;
80649076Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
80749076Swpaul	ifp->if_ioctl = sf_ioctl;
80849076Swpaul	ifp->if_output = ether_output;
80949076Swpaul	ifp->if_start = sf_start;
81049076Swpaul	ifp->if_watchdog = sf_watchdog;
81149076Swpaul	ifp->if_init = sf_init;
81249076Swpaul	ifp->if_baudrate = 10000000;
81349076Swpaul	ifp->if_snd.ifq_maxlen = SF_TX_DLIST_CNT - 1;
81449076Swpaul
81549076Swpaul	/*
81663090Sarchie	 * Call MI attach routine.
81749076Swpaul	 */
81863090Sarchie	ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
81967087Swpaul	SF_UNLOCK(sc);
82067087Swpaul	return(0);
82149076Swpaul
82249076Swpaulfail:
82367087Swpaul	SF_UNLOCK(sc);
82467087Swpaul	mtx_destroy(&sc->sf_mtx);
82549076Swpaul	return(error);
82649076Swpaul}
82749076Swpaul
82849076Swpaulstatic int sf_detach(dev)
82949076Swpaul	device_t		dev;
83049076Swpaul{
83149076Swpaul	struct sf_softc		*sc;
83249076Swpaul	struct ifnet		*ifp;
83349076Swpaul
83449076Swpaul	sc = device_get_softc(dev);
83567087Swpaul	SF_LOCK(sc);
83649076Swpaul	ifp = &sc->arpcom.ac_if;
83749076Swpaul
83863090Sarchie	ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
83949076Swpaul	sf_stop(sc);
84049076Swpaul
84150675Swpaul	bus_generic_detach(dev);
84250675Swpaul	device_delete_child(dev, sc->sf_miibus);
84350675Swpaul
84449076Swpaul	bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
84549076Swpaul	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
84649076Swpaul	bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
84749076Swpaul
84854161Swpaul	contigfree(sc->sf_ldata, sizeof(struct sf_list_data), M_DEVBUF);
84949076Swpaul
85067087Swpaul	SF_UNLOCK(sc);
85167087Swpaul	mtx_destroy(&sc->sf_mtx);
85249076Swpaul
85349076Swpaul	return(0);
85449076Swpaul}
85549076Swpaul
85649076Swpaulstatic int sf_init_rx_ring(sc)
85749076Swpaul	struct sf_softc		*sc;
85849076Swpaul{
85949076Swpaul	struct sf_list_data	*ld;
86049076Swpaul	int			i;
86149076Swpaul
86249076Swpaul	ld = sc->sf_ldata;
86349076Swpaul
86449076Swpaul	bzero((char *)ld->sf_rx_dlist_big,
86549076Swpaul	    sizeof(struct sf_rx_bufdesc_type0) * SF_RX_DLIST_CNT);
86649076Swpaul	bzero((char *)ld->sf_rx_clist,
86749076Swpaul	    sizeof(struct sf_rx_cmpdesc_type3) * SF_RX_CLIST_CNT);
86849076Swpaul
86949076Swpaul	for (i = 0; i < SF_RX_DLIST_CNT; i++) {
87049076Swpaul		if (sf_newbuf(sc, &ld->sf_rx_dlist_big[i], NULL) == ENOBUFS)
87149076Swpaul			return(ENOBUFS);
87249076Swpaul	}
87349076Swpaul
87449076Swpaul	return(0);
87549076Swpaul}
87649076Swpaul
87749076Swpaulstatic void sf_init_tx_ring(sc)
87849076Swpaul	struct sf_softc		*sc;
87949076Swpaul{
88049076Swpaul	struct sf_list_data	*ld;
88149076Swpaul	int			i;
88249076Swpaul
88349076Swpaul	ld = sc->sf_ldata;
88449076Swpaul
88549076Swpaul	bzero((char *)ld->sf_tx_dlist,
88649076Swpaul	    sizeof(struct sf_tx_bufdesc_type0) * SF_TX_DLIST_CNT);
88749076Swpaul	bzero((char *)ld->sf_tx_clist,
88849076Swpaul	    sizeof(struct sf_tx_cmpdesc_type0) * SF_TX_CLIST_CNT);
88949076Swpaul
89049076Swpaul	for (i = 0; i < SF_TX_DLIST_CNT; i++)
89149076Swpaul		ld->sf_tx_dlist[i].sf_id = SF_TX_BUFDESC_ID;
89249076Swpaul	for (i = 0; i < SF_TX_CLIST_CNT; i++)
89349076Swpaul		ld->sf_tx_clist[i].sf_type = SF_TXCMPTYPE_TX;
89449076Swpaul
89549076Swpaul	ld->sf_tx_dlist[SF_TX_DLIST_CNT - 1].sf_end = 1;
89649076Swpaul	sc->sf_tx_cnt = 0;
89749076Swpaul
89849076Swpaul	return;
89949076Swpaul}
90049076Swpaul
90149076Swpaulstatic int sf_newbuf(sc, c, m)
90249076Swpaul	struct sf_softc		*sc;
90349076Swpaul	struct sf_rx_bufdesc_type0	*c;
90449076Swpaul	struct mbuf		*m;
90549076Swpaul{
90649076Swpaul	struct mbuf		*m_new = NULL;
90749076Swpaul
90849076Swpaul	if (m == NULL) {
90949076Swpaul		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
91049076Swpaul		if (m_new == NULL) {
91149076Swpaul			printf("sf%d: no memory for rx list -- "
91249076Swpaul			    "packet dropped!\n", sc->sf_unit);
91349076Swpaul			return(ENOBUFS);
91449076Swpaul		}
91549076Swpaul
91649076Swpaul		MCLGET(m_new, M_DONTWAIT);
91749076Swpaul		if (!(m_new->m_flags & M_EXT)) {
91849076Swpaul			printf("sf%d: no memory for rx list -- "
91949076Swpaul			    "packet dropped!\n", sc->sf_unit);
92049076Swpaul			m_freem(m_new);
92149076Swpaul			return(ENOBUFS);
92249076Swpaul		}
92349076Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
92449076Swpaul	} else {
92549076Swpaul		m_new = m;
92649076Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
92749076Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
92849076Swpaul	}
92949076Swpaul
93049076Swpaul	m_adj(m_new, sizeof(u_int64_t));
93149076Swpaul
93249076Swpaul	c->sf_mbuf = m_new;
93349076Swpaul	c->sf_addrlo = SF_RX_HOSTADDR(vtophys(mtod(m_new, caddr_t)));
93449076Swpaul	c->sf_valid = 1;
93549076Swpaul
93649076Swpaul	return(0);
93749076Swpaul}
93849076Swpaul
93949076Swpaul/*
94049076Swpaul * The starfire is programmed to use 'normal' mode for packet reception,
94149076Swpaul * which means we use the consumer/producer model for both the buffer
94249076Swpaul * descriptor queue and the completion descriptor queue. The only problem
94349076Swpaul * with this is that it involves a lot of register accesses: we have to
94449076Swpaul * read the RX completion consumer and producer indexes and the RX buffer
94549076Swpaul * producer index, plus the RX completion consumer and RX buffer producer
94649076Swpaul * indexes have to be updated. It would have been easier if Adaptec had
94749076Swpaul * put each index in a separate register, especially given that the damn
94849076Swpaul * NIC has a 512K register space.
94949076Swpaul *
95049076Swpaul * In spite of all the lovely features that Adaptec crammed into the 6915,
95149076Swpaul * it is marred by one truly stupid design flaw, which is that receive
95249076Swpaul * buffer addresses must be aligned on a longword boundary. This forces
95349076Swpaul * the packet payload to be unaligned, which is suboptimal on the x86 and
95449076Swpaul * completely unuseable on the Alpha. Our only recourse is to copy received
95549076Swpaul * packets into properly aligned buffers before handing them off.
95649076Swpaul */
95749076Swpaul
95849076Swpaulstatic void sf_rxeof(sc)
95949076Swpaul	struct sf_softc		*sc;
96049076Swpaul{
96149076Swpaul	struct ether_header	*eh;
96249076Swpaul	struct mbuf		*m;
96349076Swpaul	struct ifnet		*ifp;
96449076Swpaul	struct sf_rx_bufdesc_type0	*desc;
96549076Swpaul	struct sf_rx_cmpdesc_type3	*cur_rx;
96649076Swpaul	u_int32_t		rxcons, rxprod;
96749076Swpaul	int			cmpprodidx, cmpconsidx, bufprodidx;
96849076Swpaul
96949076Swpaul	ifp = &sc->arpcom.ac_if;
97049076Swpaul
97149076Swpaul	rxcons = csr_read_4(sc, SF_CQ_CONSIDX);
97249076Swpaul	rxprod = csr_read_4(sc, SF_RXDQ_PTR_Q1);
97349076Swpaul	cmpprodidx = SF_IDX_LO(csr_read_4(sc, SF_CQ_PRODIDX));
97449076Swpaul	cmpconsidx = SF_IDX_LO(rxcons);
97549076Swpaul	bufprodidx = SF_IDX_LO(rxprod);
97649076Swpaul
97749076Swpaul	while (cmpconsidx != cmpprodidx) {
97849076Swpaul		struct mbuf		*m0;
97949076Swpaul
98049076Swpaul		cur_rx = &sc->sf_ldata->sf_rx_clist[cmpconsidx];
98149076Swpaul		desc = &sc->sf_ldata->sf_rx_dlist_big[cur_rx->sf_endidx];
98249076Swpaul		m = desc->sf_mbuf;
98349076Swpaul		SF_INC(cmpconsidx, SF_RX_CLIST_CNT);
98449076Swpaul		SF_INC(bufprodidx, SF_RX_DLIST_CNT);
98549076Swpaul
98649076Swpaul		if (!(cur_rx->sf_status1 & SF_RXSTAT1_OK)) {
98749076Swpaul			ifp->if_ierrors++;
98849076Swpaul			sf_newbuf(sc, desc, m);
98949076Swpaul			continue;
99049076Swpaul		}
99149076Swpaul
99278508Sbmilekic		m0 = m_devget(mtod(m, char *), cur_rx->sf_len, ETHER_ALIGN,
99378508Sbmilekic		    ifp, NULL);
99449076Swpaul		sf_newbuf(sc, desc, m);
99549076Swpaul		if (m0 == NULL) {
99649076Swpaul			ifp->if_ierrors++;
99749076Swpaul			continue;
99849076Swpaul		}
99949076Swpaul		m = m0;
100049076Swpaul
100149076Swpaul		eh = mtod(m, struct ether_header *);
100249076Swpaul		ifp->if_ipackets++;
100349076Swpaul
100449076Swpaul		/* Remove header from mbuf and pass it on. */
100549076Swpaul		m_adj(m, sizeof(struct ether_header));
100649076Swpaul		ether_input(ifp, eh, m);
100749076Swpaul	}
100849076Swpaul
100949076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX,
101049076Swpaul	    (rxcons & ~SF_CQ_CONSIDX_RXQ1) | cmpconsidx);
101149076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1,
101249076Swpaul	    (rxprod & ~SF_RXDQ_PRODIDX) | bufprodidx);
101349076Swpaul
101449076Swpaul	return;
101549076Swpaul}
101649076Swpaul
101749076Swpaul/*
101849076Swpaul * Read the transmit status from the completion queue and release
101949076Swpaul * mbufs. Note that the buffer descriptor index in the completion
102049076Swpaul * descriptor is an offset from the start of the transmit buffer
102149076Swpaul * descriptor list in bytes. This is important because the manual
102249076Swpaul * gives the impression that it should match the producer/consumer
102349076Swpaul * index, which is the offset in 8 byte blocks.
102449076Swpaul */
102549076Swpaulstatic void sf_txeof(sc)
102649076Swpaul	struct sf_softc		*sc;
102749076Swpaul{
102849076Swpaul	int			txcons, cmpprodidx, cmpconsidx;
102949076Swpaul	struct sf_tx_cmpdesc_type1 *cur_cmp;
103049076Swpaul	struct sf_tx_bufdesc_type0 *cur_tx;
103149076Swpaul	struct ifnet		*ifp;
103249076Swpaul
103349076Swpaul	ifp = &sc->arpcom.ac_if;
103449076Swpaul
103549076Swpaul	txcons = csr_read_4(sc, SF_CQ_CONSIDX);
103649076Swpaul	cmpprodidx = SF_IDX_HI(csr_read_4(sc, SF_CQ_PRODIDX));
103749076Swpaul	cmpconsidx = SF_IDX_HI(txcons);
103849076Swpaul
103949076Swpaul	while (cmpconsidx != cmpprodidx) {
104049076Swpaul		cur_cmp = &sc->sf_ldata->sf_tx_clist[cmpconsidx];
104149076Swpaul		cur_tx = &sc->sf_ldata->sf_tx_dlist[cur_cmp->sf_index >> 7];
104249076Swpaul		SF_INC(cmpconsidx, SF_TX_CLIST_CNT);
104349076Swpaul
104449076Swpaul		if (cur_cmp->sf_txstat & SF_TXSTAT_TX_OK)
104549076Swpaul			ifp->if_opackets++;
104649076Swpaul		else
104749076Swpaul			ifp->if_oerrors++;
104849076Swpaul
104949076Swpaul		sc->sf_tx_cnt--;
105049076Swpaul		if (cur_tx->sf_mbuf != NULL) {
105149076Swpaul			m_freem(cur_tx->sf_mbuf);
105249076Swpaul			cur_tx->sf_mbuf = NULL;
105349076Swpaul		}
105449076Swpaul	}
105549076Swpaul
105649076Swpaul	ifp->if_timer = 0;
105749076Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
105849076Swpaul
105949076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX,
106049076Swpaul	    (txcons & ~SF_CQ_CONSIDX_TXQ) |
106149076Swpaul	    ((cmpconsidx << 16) & 0xFFFF0000));
106249076Swpaul
106349076Swpaul	return;
106449076Swpaul}
106549076Swpaul
106649076Swpaulstatic void sf_intr(arg)
106749076Swpaul	void			*arg;
106849076Swpaul{
106949076Swpaul	struct sf_softc		*sc;
107049076Swpaul	struct ifnet		*ifp;
107149076Swpaul	u_int32_t		status;
107249076Swpaul
107349076Swpaul	sc = arg;
107467087Swpaul	SF_LOCK(sc);
107567087Swpaul
107649076Swpaul	ifp = &sc->arpcom.ac_if;
107749076Swpaul
107867087Swpaul	if (!(csr_read_4(sc, SF_ISR_SHADOW) & SF_ISR_PCIINT_ASSERTED)) {
107967087Swpaul		SF_UNLOCK(sc);
108049076Swpaul		return;
108167087Swpaul	}
108249076Swpaul
108349076Swpaul	/* Disable interrupts. */
108449076Swpaul	csr_write_4(sc, SF_IMR, 0x00000000);
108549076Swpaul
108649076Swpaul	for (;;) {
108749076Swpaul		status = csr_read_4(sc, SF_ISR);
108849076Swpaul		if (status)
108949076Swpaul			csr_write_4(sc, SF_ISR, status);
109049076Swpaul
109149076Swpaul		if (!(status & SF_INTRS))
109249076Swpaul			break;
109349076Swpaul
109449076Swpaul		if (status & SF_ISR_RXDQ1_DMADONE)
109549076Swpaul			sf_rxeof(sc);
109649076Swpaul
109781714Swpaul		if (status & SF_ISR_TX_TXDONE ||
109881714Swpaul		    status & SF_ISR_TX_DMADONE ||
109981714Swpaul		    status & SF_ISR_TX_QUEUEDONE ||
110081714Swpaul		    status & SF_ISR_TX_LOFIFO)
110149076Swpaul			sf_txeof(sc);
110249076Swpaul
110349076Swpaul		if (status & SF_ISR_ABNORMALINTR) {
110449076Swpaul			if (status & SF_ISR_STATSOFLOW) {
110549076Swpaul				untimeout(sf_stats_update, sc,
110649076Swpaul				    sc->sf_stat_ch);
110749076Swpaul				sf_stats_update(sc);
110849076Swpaul			} else
110949076Swpaul				sf_init(sc);
111049076Swpaul		}
111149076Swpaul	}
111249076Swpaul
111349076Swpaul	/* Re-enable interrupts. */
111449076Swpaul	csr_write_4(sc, SF_IMR, SF_INTRS);
111549076Swpaul
111649076Swpaul	if (ifp->if_snd.ifq_head != NULL)
111749076Swpaul		sf_start(ifp);
111849076Swpaul
111967087Swpaul	SF_UNLOCK(sc);
112049076Swpaul	return;
112149076Swpaul}
112249076Swpaul
112349076Swpaulstatic void sf_init(xsc)
112449076Swpaul	void			*xsc;
112549076Swpaul{
112649076Swpaul	struct sf_softc		*sc;
112749076Swpaul	struct ifnet		*ifp;
112850675Swpaul	struct mii_data		*mii;
112967087Swpaul	int			i;
113049076Swpaul
113149076Swpaul	sc = xsc;
113267087Swpaul	SF_LOCK(sc);
113349076Swpaul	ifp = &sc->arpcom.ac_if;
113450675Swpaul	mii = device_get_softc(sc->sf_miibus);
113549076Swpaul
113649076Swpaul	sf_stop(sc);
113749076Swpaul	sf_reset(sc);
113849076Swpaul
113949076Swpaul	/* Init all the receive filter registers */
114049076Swpaul	for (i = SF_RXFILT_PERFECT_BASE;
114149076Swpaul	    i < (SF_RXFILT_HASH_MAX + 1); i += 4)
114249076Swpaul		csr_write_4(sc, i, 0);
114349076Swpaul
114449076Swpaul	/* Empty stats counter registers. */
114549076Swpaul	for (i = 0; i < sizeof(struct sf_stats)/sizeof(u_int32_t); i++)
114649076Swpaul		csr_write_4(sc, SF_STATS_BASE +
114749076Swpaul		    (i + sizeof(u_int32_t)), 0);
114849076Swpaul
114949076Swpaul	/* Init our MAC address */
115049076Swpaul	csr_write_4(sc, SF_PAR0, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0]));
115149076Swpaul	csr_write_4(sc, SF_PAR1, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4]));
115249076Swpaul	sf_setperf(sc, 0, (caddr_t)&sc->arpcom.ac_enaddr);
115349076Swpaul
115449076Swpaul	if (sf_init_rx_ring(sc) == ENOBUFS) {
115549076Swpaul		printf("sf%d: initialization failed: no "
115649076Swpaul		    "memory for rx buffers\n", sc->sf_unit);
115767087Swpaul		SF_UNLOCK(sc);
115849076Swpaul		return;
115949076Swpaul	}
116049076Swpaul
116149076Swpaul	sf_init_tx_ring(sc);
116249076Swpaul
116349076Swpaul	csr_write_4(sc, SF_RXFILT, SF_PERFMODE_NORMAL|SF_HASHMODE_WITHVLAN);
116449076Swpaul
116549076Swpaul	/* If we want promiscuous mode, set the allframes bit. */
116649076Swpaul	if (ifp->if_flags & IFF_PROMISC) {
116749076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
116849076Swpaul	} else {
116949076Swpaul		SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
117049076Swpaul	}
117149076Swpaul
117249076Swpaul	if (ifp->if_flags & IFF_BROADCAST) {
117349076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_BROAD);
117449076Swpaul	} else {
117549076Swpaul		SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_BROAD);
117649076Swpaul	}
117749076Swpaul
117863166Swpaul	/*
117963166Swpaul	 * Load the multicast filter.
118063166Swpaul	 */
118163166Swpaul	sf_setmulti(sc);
118263166Swpaul
118349076Swpaul	/* Init the completion queue indexes */
118449076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX, 0);
118549076Swpaul	csr_write_4(sc, SF_CQ_PRODIDX, 0);
118649076Swpaul
118749076Swpaul	/* Init the RX completion queue */
118849076Swpaul	csr_write_4(sc, SF_RXCQ_CTL_1,
118949076Swpaul	    vtophys(sc->sf_ldata->sf_rx_clist) & SF_RXCQ_ADDR);
119049076Swpaul	SF_SETBIT(sc, SF_RXCQ_CTL_1, SF_RXCQTYPE_3);
119149076Swpaul
119249076Swpaul	/* Init RX DMA control. */
119349076Swpaul	SF_SETBIT(sc, SF_RXDMA_CTL, SF_RXDMA_REPORTBADPKTS);
119449076Swpaul
119549076Swpaul	/* Init the RX buffer descriptor queue. */
119649076Swpaul	csr_write_4(sc, SF_RXDQ_ADDR_Q1,
119749076Swpaul	    vtophys(sc->sf_ldata->sf_rx_dlist_big));
119849076Swpaul	csr_write_4(sc, SF_RXDQ_CTL_1, (MCLBYTES << 16) | SF_DESCSPACE_16BYTES);
119949076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1, SF_RX_DLIST_CNT - 1);
120049076Swpaul
120149076Swpaul	/* Init the TX completion queue */
120249076Swpaul	csr_write_4(sc, SF_TXCQ_CTL,
120349076Swpaul	    vtophys(sc->sf_ldata->sf_tx_clist) & SF_RXCQ_ADDR);
120449076Swpaul
120549076Swpaul	/* Init the TX buffer descriptor queue. */
120649076Swpaul	csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO,
120749076Swpaul		vtophys(sc->sf_ldata->sf_tx_dlist));
120849076Swpaul	SF_SETBIT(sc, SF_TX_FRAMCTL, SF_TXFRMCTL_CPLAFTERTX);
120949076Swpaul	csr_write_4(sc, SF_TXDQ_CTL,
121049076Swpaul	    SF_TXBUFDESC_TYPE0|SF_TXMINSPACE_128BYTES|SF_TXSKIPLEN_8BYTES);
121149076Swpaul	SF_SETBIT(sc, SF_TXDQ_CTL, SF_TXDQCTL_NODMACMP);
121249076Swpaul
121349076Swpaul	/* Enable autopadding of short TX frames. */
121449076Swpaul	SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_AUTOPAD);
121549076Swpaul
121649076Swpaul	/* Enable interrupts. */
121749076Swpaul	csr_write_4(sc, SF_IMR, SF_INTRS);
121849076Swpaul	SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_INTR_ENB);
121949076Swpaul
122049076Swpaul	/* Enable the RX and TX engines. */
122149076Swpaul	SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_RX_ENB|SF_ETHCTL_RXDMA_ENB);
122249076Swpaul	SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_TX_ENB|SF_ETHCTL_TXDMA_ENB);
122349076Swpaul
122454161Swpaul	/*mii_mediachg(mii);*/
122554161Swpaul	sf_ifmedia_upd(ifp);
122650675Swpaul
122749076Swpaul	ifp->if_flags |= IFF_RUNNING;
122849076Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
122949076Swpaul
123049076Swpaul	sc->sf_stat_ch = timeout(sf_stats_update, sc, hz);
123149076Swpaul
123267087Swpaul	SF_UNLOCK(sc);
123349076Swpaul
123449076Swpaul	return;
123549076Swpaul}
123649076Swpaul
123749076Swpaulstatic int sf_encap(sc, c, m_head)
123849076Swpaul	struct sf_softc		*sc;
123949076Swpaul	struct sf_tx_bufdesc_type0 *c;
124049076Swpaul	struct mbuf		*m_head;
124149076Swpaul{
124249076Swpaul	int			frag = 0;
124349076Swpaul	struct sf_frag		*f = NULL;
124449076Swpaul	struct mbuf		*m;
124549076Swpaul
124649076Swpaul	m = m_head;
124749076Swpaul
124849076Swpaul	for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
124949076Swpaul		if (m->m_len != 0) {
125049076Swpaul			if (frag == SF_MAXFRAGS)
125149076Swpaul				break;
125249076Swpaul			f = &c->sf_frags[frag];
125349076Swpaul			if (frag == 0)
125449076Swpaul				f->sf_pktlen = m_head->m_pkthdr.len;
125549076Swpaul			f->sf_fraglen = m->m_len;
125649076Swpaul			f->sf_addr = vtophys(mtod(m, vm_offset_t));
125749076Swpaul			frag++;
125849076Swpaul		}
125949076Swpaul	}
126049076Swpaul
126149076Swpaul	if (m != NULL) {
126249076Swpaul		struct mbuf		*m_new = NULL;
126349076Swpaul
126449076Swpaul		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
126549076Swpaul		if (m_new == NULL) {
126649076Swpaul			printf("sf%d: no memory for tx list", sc->sf_unit);
126749076Swpaul			return(1);
126849076Swpaul		}
126949076Swpaul
127049076Swpaul		if (m_head->m_pkthdr.len > MHLEN) {
127149076Swpaul			MCLGET(m_new, M_DONTWAIT);
127249076Swpaul			if (!(m_new->m_flags & M_EXT)) {
127349076Swpaul				m_freem(m_new);
127449076Swpaul				printf("sf%d: no memory for tx list",
127549076Swpaul				    sc->sf_unit);
127649076Swpaul				return(1);
127749076Swpaul			}
127849076Swpaul		}
127949076Swpaul		m_copydata(m_head, 0, m_head->m_pkthdr.len,
128049076Swpaul		    mtod(m_new, caddr_t));
128149076Swpaul		m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
128249076Swpaul		m_freem(m_head);
128349076Swpaul		m_head = m_new;
128449076Swpaul		f = &c->sf_frags[0];
128549076Swpaul		f->sf_fraglen = f->sf_pktlen = m_head->m_pkthdr.len;
128649076Swpaul		f->sf_addr = vtophys(mtod(m_head, caddr_t));
128749076Swpaul		frag = 1;
128849076Swpaul	}
128949076Swpaul
129049076Swpaul	c->sf_mbuf = m_head;
129149076Swpaul	c->sf_id = SF_TX_BUFDESC_ID;
129249076Swpaul	c->sf_fragcnt = frag;
129349076Swpaul	c->sf_intr = 1;
129449076Swpaul	c->sf_caltcp = 0;
129549076Swpaul	c->sf_crcen = 1;
129649076Swpaul
129749076Swpaul	return(0);
129849076Swpaul}
129949076Swpaul
130049076Swpaulstatic void sf_start(ifp)
130149076Swpaul	struct ifnet		*ifp;
130249076Swpaul{
130349076Swpaul	struct sf_softc		*sc;
130449076Swpaul	struct sf_tx_bufdesc_type0 *cur_tx = NULL;
130549076Swpaul	struct mbuf		*m_head = NULL;
130649076Swpaul	int			i, txprod;
130749076Swpaul
130849076Swpaul	sc = ifp->if_softc;
130967087Swpaul	SF_LOCK(sc);
131049076Swpaul
131181714Swpaul	if (!sc->sf_link && ifp->if_snd.ifq_len < 10) {
131267087Swpaul		SF_UNLOCK(sc);
131354161Swpaul		return;
131467087Swpaul	}
131554161Swpaul
131667087Swpaul	if (ifp->if_flags & IFF_OACTIVE) {
131767087Swpaul		SF_UNLOCK(sc);
131849076Swpaul		return;
131967087Swpaul	}
132049076Swpaul
132149076Swpaul	txprod = csr_read_4(sc, SF_TXDQ_PRODIDX);
132249076Swpaul	i = SF_IDX_HI(txprod) >> 4;
132349076Swpaul
132449076Swpaul	while(sc->sf_ldata->sf_tx_dlist[i].sf_mbuf == NULL) {
132571276Swpaul		if (sc->sf_tx_cnt == (SF_TX_DLIST_CNT - 2)) {
132671276Swpaul			ifp->if_flags |= IFF_OACTIVE;
132771276Swpaul			cur_tx = NULL;
132871276Swpaul			break;
132971276Swpaul		}
133049076Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
133149076Swpaul		if (m_head == NULL)
133249076Swpaul			break;
133349076Swpaul
133449076Swpaul		cur_tx = &sc->sf_ldata->sf_tx_dlist[i];
133571276Swpaul		if (sf_encap(sc, cur_tx, m_head)) {
133671276Swpaul			IF_PREPEND(&ifp->if_snd, m_head);
133771276Swpaul			ifp->if_flags |= IFF_OACTIVE;
133871276Swpaul			cur_tx = NULL;
133971276Swpaul			break;
134071276Swpaul		}
134149076Swpaul
134249076Swpaul		/*
134349076Swpaul		 * If there's a BPF listener, bounce a copy of this frame
134449076Swpaul		 * to him.
134549076Swpaul		 */
134649076Swpaul		if (ifp->if_bpf)
134749076Swpaul			bpf_mtap(ifp, m_head);
134851583Swpaul
134949076Swpaul		SF_INC(i, SF_TX_DLIST_CNT);
135049076Swpaul		sc->sf_tx_cnt++;
135149076Swpaul	}
135249076Swpaul
135367087Swpaul	if (cur_tx == NULL) {
135467087Swpaul		SF_UNLOCK(sc);
135549076Swpaul		return;
135667087Swpaul	}
135749076Swpaul
135849076Swpaul	/* Transmit */
135949076Swpaul	csr_write_4(sc, SF_TXDQ_PRODIDX,
136049076Swpaul	    (txprod & ~SF_TXDQ_PRODIDX_HIPRIO) |
136149076Swpaul	    ((i << 20) & 0xFFFF0000));
136249076Swpaul
136349076Swpaul	ifp->if_timer = 5;
136449076Swpaul
136567087Swpaul	SF_UNLOCK(sc);
136667087Swpaul
136749076Swpaul	return;
136849076Swpaul}
136949076Swpaul
137049076Swpaulstatic void sf_stop(sc)
137149076Swpaul	struct sf_softc		*sc;
137249076Swpaul{
137349076Swpaul	int			i;
137449077Swpaul	struct ifnet		*ifp;
137549076Swpaul
137667087Swpaul	SF_LOCK(sc);
137767087Swpaul
137849077Swpaul	ifp = &sc->arpcom.ac_if;
137949077Swpaul
138049076Swpaul	untimeout(sf_stats_update, sc, sc->sf_stat_ch);
138149076Swpaul
138249076Swpaul	csr_write_4(sc, SF_GEN_ETH_CTL, 0);
138349076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX, 0);
138449076Swpaul	csr_write_4(sc, SF_CQ_PRODIDX, 0);
138549076Swpaul	csr_write_4(sc, SF_RXDQ_ADDR_Q1, 0);
138649076Swpaul	csr_write_4(sc, SF_RXDQ_CTL_1, 0);
138749076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1, 0);
138849076Swpaul	csr_write_4(sc, SF_TXCQ_CTL, 0);
138949076Swpaul	csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO, 0);
139049076Swpaul	csr_write_4(sc, SF_TXDQ_CTL, 0);
139149076Swpaul	sf_reset(sc);
139249076Swpaul
139354161Swpaul	sc->sf_link = 0;
139454161Swpaul
139549076Swpaul	for (i = 0; i < SF_RX_DLIST_CNT; i++) {
139649076Swpaul		if (sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf != NULL) {
139749076Swpaul			m_freem(sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf);
139849076Swpaul			sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf = NULL;
139949076Swpaul		}
140049076Swpaul	}
140149076Swpaul
140249076Swpaul	for (i = 0; i < SF_TX_DLIST_CNT; i++) {
140349076Swpaul		if (sc->sf_ldata->sf_tx_dlist[i].sf_mbuf != NULL) {
140449076Swpaul			m_freem(sc->sf_ldata->sf_tx_dlist[i].sf_mbuf);
140549076Swpaul			sc->sf_ldata->sf_tx_dlist[i].sf_mbuf = NULL;
140649076Swpaul		}
140749076Swpaul	}
140849076Swpaul
140949077Swpaul	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
141067087Swpaul	SF_UNLOCK(sc);
141149077Swpaul
141249076Swpaul	return;
141349076Swpaul}
141449076Swpaul
141549076Swpaul/*
141649076Swpaul * Note: it is important that this function not be interrupted. We
141749076Swpaul * use a two-stage register access scheme: if we are interrupted in
141849076Swpaul * between setting the indirect address register and reading from the
141949076Swpaul * indirect data register, the contents of the address register could
142049076Swpaul * be changed out from under us.
142149076Swpaul */
142249076Swpaulstatic void sf_stats_update(xsc)
142349076Swpaul	void			*xsc;
142449076Swpaul{
142549076Swpaul	struct sf_softc		*sc;
142649076Swpaul	struct ifnet		*ifp;
142750675Swpaul	struct mii_data		*mii;
142849076Swpaul	struct sf_stats		stats;
142949076Swpaul	u_int32_t		*ptr;
143067087Swpaul	int			i;
143149076Swpaul
143249076Swpaul	sc = xsc;
143367087Swpaul	SF_LOCK(sc);
143449076Swpaul	ifp = &sc->arpcom.ac_if;
143550675Swpaul	mii = device_get_softc(sc->sf_miibus);
143649076Swpaul
143749076Swpaul	ptr = (u_int32_t *)&stats;
143849076Swpaul	for (i = 0; i < sizeof(stats)/sizeof(u_int32_t); i++)
143949076Swpaul		ptr[i] = csr_read_4(sc, SF_STATS_BASE +
144049076Swpaul		    (i + sizeof(u_int32_t)));
144149076Swpaul
144249076Swpaul	for (i = 0; i < sizeof(stats)/sizeof(u_int32_t); i++)
144349076Swpaul		csr_write_4(sc, SF_STATS_BASE +
144449076Swpaul		    (i + sizeof(u_int32_t)), 0);
144549076Swpaul
144649076Swpaul	ifp->if_collisions += stats.sf_tx_single_colls +
144749076Swpaul	    stats.sf_tx_multi_colls + stats.sf_tx_excess_colls;
144849076Swpaul
144950675Swpaul	mii_tick(mii);
145054161Swpaul	if (!sc->sf_link) {
145154161Swpaul		mii_pollstat(mii);
145254161Swpaul		if (mii->mii_media_status & IFM_ACTIVE &&
145354161Swpaul		    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)
145454161Swpaul			sc->sf_link++;
145554161Swpaul			if (ifp->if_snd.ifq_head != NULL)
145654161Swpaul				sf_start(ifp);
145754161Swpaul	}
145850675Swpaul
145949076Swpaul	sc->sf_stat_ch = timeout(sf_stats_update, sc, hz);
146049076Swpaul
146167087Swpaul	SF_UNLOCK(sc);
146249076Swpaul
146349076Swpaul	return;
146449076Swpaul}
146549076Swpaul
146649076Swpaulstatic void sf_watchdog(ifp)
146749076Swpaul	struct ifnet		*ifp;
146849076Swpaul{
146949076Swpaul	struct sf_softc		*sc;
147049076Swpaul
147149076Swpaul	sc = ifp->if_softc;
147249076Swpaul
147367087Swpaul	SF_LOCK(sc);
147467087Swpaul
147549076Swpaul	ifp->if_oerrors++;
147649076Swpaul	printf("sf%d: watchdog timeout\n", sc->sf_unit);
147749076Swpaul
147849076Swpaul	sf_stop(sc);
147949076Swpaul	sf_reset(sc);
148049076Swpaul	sf_init(sc);
148149076Swpaul
148249076Swpaul	if (ifp->if_snd.ifq_head != NULL)
148349076Swpaul		sf_start(ifp);
148449076Swpaul
148567087Swpaul	SF_UNLOCK(sc);
148667087Swpaul
148749076Swpaul	return;
148849076Swpaul}
148949076Swpaul
149049076Swpaulstatic void sf_shutdown(dev)
149149076Swpaul	device_t		dev;
149249076Swpaul{
149349076Swpaul	struct sf_softc		*sc;
149449076Swpaul
149549076Swpaul	sc = device_get_softc(dev);
149649076Swpaul
149749076Swpaul	sf_stop(sc);
149849076Swpaul
149949076Swpaul	return;
150049076Swpaul}
1501