if_sf.c revision 63090
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 63090 2000-07-13 22:54:34Z archie $
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/clock.h>      /* for DELAY */
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
11449076Swpaul#include <pci/pcireg.h>
11549076Swpaul#include <pci/pcivar.h>
11649076Swpaul
11749076Swpaul#define SF_USEIOSPACE
11849076Swpaul
11949076Swpaul#include <pci/if_sfreg.h>
12049076Swpaul
12159758SpeterMODULE_DEPEND(sf, miibus, 1, 1, 1);
12259758Speter
12349076Swpaul#ifndef lint
12449076Swpaulstatic const char rcsid[] =
12550477Speter  "$FreeBSD: head/sys/dev/sf/if_sf.c 63090 2000-07-13 22:54:34Z archie $";
12649076Swpaul#endif
12749076Swpaul
12849076Swpaulstatic struct sf_type sf_devs[] = {
12949076Swpaul	{ AD_VENDORID, AD_DEVICEID_STARFIRE,
13049076Swpaul		"Adaptec AIC-6915 10/100BaseTX" },
13149076Swpaul	{ 0, 0, NULL }
13249076Swpaul};
13349076Swpaul
13449076Swpaulstatic int sf_probe		__P((device_t));
13549076Swpaulstatic int sf_attach		__P((device_t));
13649076Swpaulstatic int sf_detach		__P((device_t));
13749076Swpaulstatic void sf_intr		__P((void *));
13849076Swpaulstatic void sf_stats_update	__P((void *));
13949076Swpaulstatic void sf_rxeof		__P((struct sf_softc *));
14049076Swpaulstatic void sf_txeof		__P((struct sf_softc *));
14149076Swpaulstatic int sf_encap		__P((struct sf_softc *,
14249076Swpaul					struct sf_tx_bufdesc_type0 *,
14349076Swpaul					struct mbuf *));
14449076Swpaulstatic void sf_start		__P((struct ifnet *));
14549076Swpaulstatic int sf_ioctl		__P((struct ifnet *, u_long, caddr_t));
14649076Swpaulstatic void sf_init		__P((void *));
14749076Swpaulstatic void sf_stop		__P((struct sf_softc *));
14849076Swpaulstatic void sf_watchdog		__P((struct ifnet *));
14949076Swpaulstatic void sf_shutdown		__P((device_t));
15049076Swpaulstatic int sf_ifmedia_upd	__P((struct ifnet *));
15149076Swpaulstatic void sf_ifmedia_sts	__P((struct ifnet *, struct ifmediareq *));
15249076Swpaulstatic void sf_reset		__P((struct sf_softc *));
15349076Swpaulstatic int sf_init_rx_ring	__P((struct sf_softc *));
15449076Swpaulstatic void sf_init_tx_ring	__P((struct sf_softc *));
15549076Swpaulstatic int sf_newbuf		__P((struct sf_softc *,
15649076Swpaul					struct sf_rx_bufdesc_type0 *,
15749076Swpaul					struct mbuf *));
15849076Swpaulstatic void sf_setmulti		__P((struct sf_softc *));
15949076Swpaulstatic int sf_setperf		__P((struct sf_softc *, int, caddr_t));
16049076Swpaulstatic int sf_sethash		__P((struct sf_softc *, caddr_t, int));
16149076Swpaul#ifdef notdef
16249076Swpaulstatic int sf_setvlan		__P((struct sf_softc *, int, u_int32_t));
16349076Swpaul#endif
16449076Swpaul
16549076Swpaulstatic u_int8_t sf_read_eeprom	__P((struct sf_softc *, int));
16649076Swpaulstatic u_int32_t sf_calchash	__P((caddr_t));
16749076Swpaul
16850675Swpaulstatic int sf_miibus_readreg	__P((device_t, int, int));
16950675Swpaulstatic int sf_miibus_writereg	__P((device_t, int, int, int));
17050675Swpaulstatic void sf_miibus_statchg	__P((device_t));
17149076Swpaul
17249076Swpaulstatic u_int32_t csr_read_4	__P((struct sf_softc *, int));
17349076Swpaulstatic void csr_write_4		__P((struct sf_softc *, int, u_int32_t));
17449076Swpaul
17549076Swpaul#ifdef SF_USEIOSPACE
17649076Swpaul#define SF_RES			SYS_RES_IOPORT
17749076Swpaul#define SF_RID			SF_PCI_LOIO
17849076Swpaul#else
17949076Swpaul#define SF_RES			SYS_RES_MEMORY
18049076Swpaul#define SF_RID			SF_PCI_LOMEM
18149076Swpaul#endif
18249076Swpaul
18349076Swpaulstatic device_method_t sf_methods[] = {
18449076Swpaul	/* Device interface */
18549076Swpaul	DEVMETHOD(device_probe,		sf_probe),
18649076Swpaul	DEVMETHOD(device_attach,	sf_attach),
18749076Swpaul	DEVMETHOD(device_detach,	sf_detach),
18849076Swpaul	DEVMETHOD(device_shutdown,	sf_shutdown),
18950675Swpaul
19050675Swpaul	/* bus interface */
19150675Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
19250675Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
19350675Swpaul
19450675Swpaul	/* MII interface */
19550675Swpaul	DEVMETHOD(miibus_readreg,	sf_miibus_readreg),
19650675Swpaul	DEVMETHOD(miibus_writereg,	sf_miibus_writereg),
19750675Swpaul	DEVMETHOD(miibus_statchg,	sf_miibus_statchg),
19850675Swpaul
19949076Swpaul	{ 0, 0 }
20049076Swpaul};
20149076Swpaul
20249076Swpaulstatic driver_t sf_driver = {
20351455Swpaul	"sf",
20449076Swpaul	sf_methods,
20549076Swpaul	sizeof(struct sf_softc),
20649076Swpaul};
20749076Swpaul
20849076Swpaulstatic devclass_t sf_devclass;
20949076Swpaul
21051533SwpaulDRIVER_MODULE(if_sf, pci, sf_driver, sf_devclass, 0, 0);
21151473SwpaulDRIVER_MODULE(miibus, sf, miibus_driver, miibus_devclass, 0, 0);
21249076Swpaul
21349076Swpaul#define SF_SETBIT(sc, reg, x)	\
21449076Swpaul	csr_write_4(sc, reg, csr_read_4(sc, reg) | x)
21549076Swpaul
21649076Swpaul#define SF_CLRBIT(sc, reg, x)				\
21749076Swpaul	csr_write_4(sc, reg, csr_read_4(sc, reg) & ~x)
21849076Swpaul
21949076Swpaulstatic u_int32_t csr_read_4(sc, reg)
22049076Swpaul	struct sf_softc		*sc;
22149076Swpaul	int			reg;
22249076Swpaul{
22349076Swpaul	u_int32_t		val;
22449076Swpaul
22549076Swpaul#ifdef SF_USEIOSPACE
22649076Swpaul	CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE);
22749076Swpaul	val = CSR_READ_4(sc, SF_INDIRECTIO_DATA);
22849076Swpaul#else
22949076Swpaul	val = CSR_READ_4(sc, (reg + SF_RMAP_INTREG_BASE));
23049076Swpaul#endif
23149076Swpaul
23249076Swpaul	return(val);
23349076Swpaul}
23449076Swpaul
23549076Swpaulstatic u_int8_t sf_read_eeprom(sc, reg)
23649076Swpaul	struct sf_softc		*sc;
23749076Swpaul	int			reg;
23849076Swpaul{
23949076Swpaul	u_int8_t		val;
24049076Swpaul
24149076Swpaul	val = (csr_read_4(sc, SF_EEADDR_BASE +
24249076Swpaul	    (reg & 0xFFFFFFFC)) >> (8 * (reg & 3))) & 0xFF;
24349076Swpaul
24449076Swpaul	return(val);
24549076Swpaul}
24649076Swpaul
24749076Swpaulstatic void csr_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	return;
25949076Swpaul}
26049076Swpaul
26149076Swpaulstatic u_int32_t sf_calchash(addr)
26249076Swpaul	caddr_t			addr;
26349076Swpaul{
26449076Swpaul	u_int32_t		crc, carry;
26549076Swpaul	int			i, j;
26649076Swpaul	u_int8_t		c;
26749076Swpaul
26849076Swpaul	/* Compute CRC for the address value. */
26949076Swpaul	crc = 0xFFFFFFFF; /* initial value */
27049076Swpaul
27149076Swpaul	for (i = 0; i < 6; i++) {
27249076Swpaul		c = *(addr + i);
27349076Swpaul		for (j = 0; j < 8; j++) {
27449076Swpaul			carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
27549076Swpaul			crc <<= 1;
27649076Swpaul			c >>= 1;
27749076Swpaul			if (carry)
27849076Swpaul				crc = (crc ^ 0x04c11db6) | carry;
27949076Swpaul		}
28049076Swpaul	}
28149076Swpaul
28249076Swpaul	/* return the filter bit position */
28349076Swpaul	return(crc >> 23 & 0x1FF);
28449076Swpaul}
28549076Swpaul
28649076Swpaul/*
28749076Swpaul * Copy the address 'mac' into the perfect RX filter entry at
28849076Swpaul * offset 'idx.' The perfect filter only has 16 entries so do
28949076Swpaul * some sanity tests.
29049076Swpaul */
29149076Swpaulstatic int sf_setperf(sc, idx, mac)
29249076Swpaul	struct sf_softc		*sc;
29349076Swpaul	int			idx;
29449076Swpaul	caddr_t			mac;
29549076Swpaul{
29649076Swpaul	u_int16_t		*p;
29749076Swpaul
29849076Swpaul	if (idx < 0 || idx > SF_RXFILT_PERFECT_CNT)
29949076Swpaul		return(EINVAL);
30049076Swpaul
30149076Swpaul	if (mac == NULL)
30249076Swpaul		return(EINVAL);
30349076Swpaul
30449076Swpaul	p = (u_int16_t *)mac;
30549076Swpaul
30649076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
30749076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP), htons(p[2]));
30849076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
30949076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP) + 4, htons(p[1]));
31049076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
31149076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP) + 8, htons(p[0]));
31249076Swpaul
31349076Swpaul	return(0);
31449076Swpaul}
31549076Swpaul
31649076Swpaul/*
31749076Swpaul * Set the bit in the 512-bit hash table that corresponds to the
31849076Swpaul * specified mac address 'mac.' If 'prio' is nonzero, update the
31949076Swpaul * priority hash table instead of the filter hash table.
32049076Swpaul */
32149076Swpaulstatic int sf_sethash(sc, mac, prio)
32249076Swpaul	struct sf_softc		*sc;
32349076Swpaul	caddr_t			mac;
32449076Swpaul	int			prio;
32549076Swpaul{
32649076Swpaul	u_int32_t		h = 0;
32749076Swpaul
32849076Swpaul	if (mac == NULL)
32949076Swpaul		return(EINVAL);
33049076Swpaul
33149076Swpaul	h = sf_calchash(mac);
33249076Swpaul
33349076Swpaul	if (prio) {
33449076Swpaul		SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_PRIOOFF +
33549076Swpaul		    (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF)));
33649076Swpaul	} else {
33749076Swpaul		SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_ADDROFF +
33849076Swpaul		    (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF)));
33949076Swpaul	}
34049076Swpaul
34149076Swpaul	return(0);
34249076Swpaul}
34349076Swpaul
34449076Swpaul#ifdef notdef
34549076Swpaul/*
34649076Swpaul * Set a VLAN tag in the receive filter.
34749076Swpaul */
34849076Swpaulstatic int sf_setvlan(sc, idx, vlan)
34949076Swpaul	struct sf_softc		*sc;
35049076Swpaul	int			idx;
35149076Swpaul	u_int32_t		vlan;
35249076Swpaul{
35349076Swpaul	if (idx < 0 || idx >> SF_RXFILT_HASH_CNT)
35449076Swpaul		return(EINVAL);
35549076Swpaul
35649076Swpaul	csr_write_4(sc, SF_RXFILT_HASH_BASE +
35749076Swpaul	    (idx * SF_RXFILT_HASH_SKIP) + SF_RXFILT_HASH_VLANOFF, vlan);
35849076Swpaul
35949076Swpaul	return(0);
36049076Swpaul}
36149076Swpaul#endif
36249076Swpaul
36350675Swpaulstatic int sf_miibus_readreg(dev, phy, reg)
36450675Swpaul	device_t		dev;
36550675Swpaul	int			phy, reg;
36650675Swpaul{
36749076Swpaul	struct sf_softc		*sc;
36849076Swpaul	int			i;
36949076Swpaul	u_int32_t		val = 0;
37049076Swpaul
37150675Swpaul	sc = device_get_softc(dev);
37250675Swpaul
37349076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
37450675Swpaul		val = csr_read_4(sc, SF_PHY_REG(phy, reg));
37549076Swpaul		if (val & SF_MII_DATAVALID)
37649076Swpaul			break;
37749076Swpaul	}
37849076Swpaul
37949076Swpaul	if (i == SF_TIMEOUT)
38049076Swpaul		return(0);
38149076Swpaul
38249076Swpaul	if ((val & 0x0000FFFF) == 0xFFFF)
38349076Swpaul		return(0);
38449076Swpaul
38549076Swpaul	return(val & 0x0000FFFF);
38649076Swpaul}
38749076Swpaul
38850675Swpaulstatic int sf_miibus_writereg(dev, phy, reg, val)
38950675Swpaul	device_t		dev;
39050675Swpaul	int			phy, reg, val;
39150675Swpaul{
39249076Swpaul	struct sf_softc		*sc;
39349076Swpaul	int			i;
39449076Swpaul	int			busy;
39549076Swpaul
39650675Swpaul	sc = device_get_softc(dev);
39749076Swpaul
39850675Swpaul	csr_write_4(sc, SF_PHY_REG(phy, reg), val);
39950675Swpaul
40049076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
40150675Swpaul		busy = csr_read_4(sc, SF_PHY_REG(phy, reg));
40249076Swpaul		if (!(busy & SF_MII_BUSY))
40349076Swpaul			break;
40449076Swpaul	}
40549076Swpaul
40650675Swpaul	return(0);
40750675Swpaul}
40850675Swpaul
40950675Swpaulstatic void sf_miibus_statchg(dev)
41050675Swpaul	device_t		dev;
41150675Swpaul{
41250675Swpaul	struct sf_softc		*sc;
41350675Swpaul	struct mii_data		*mii;
41450675Swpaul
41550675Swpaul	sc = device_get_softc(dev);
41650675Swpaul	mii = device_get_softc(sc->sf_miibus);
41750675Swpaul
41850675Swpaul	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
41950675Swpaul		SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX);
42054161Swpaul		csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_FDX);
42150675Swpaul	} else {
42250675Swpaul		SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX);
42354161Swpaul		csr_write_4(sc, SF_BKTOBKIPG, SF_IPGT_HDX);
42450675Swpaul	}
42550675Swpaul
42649076Swpaul	return;
42749076Swpaul}
42849076Swpaul
42949076Swpaulstatic void sf_setmulti(sc)
43049076Swpaul	struct sf_softc		*sc;
43149076Swpaul{
43249076Swpaul	struct ifnet		*ifp;
43349076Swpaul	int			i;
43449076Swpaul	struct ifmultiaddr	*ifma;
43549076Swpaul	u_int8_t		dummy[] = { 0, 0, 0, 0, 0, 0 };
43649076Swpaul
43749076Swpaul	ifp = &sc->arpcom.ac_if;
43849076Swpaul
43949076Swpaul	/* First zot all the existing filters. */
44049076Swpaul	for (i = 1; i < SF_RXFILT_PERFECT_CNT; i++)
44149076Swpaul		sf_setperf(sc, i, (char *)&dummy);
44249076Swpaul	for (i = SF_RXFILT_HASH_BASE;
44349076Swpaul	    i < (SF_RXFILT_HASH_MAX + 1); i += 4)
44449076Swpaul		csr_write_4(sc, i, 0);
44549076Swpaul	SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_ALLMULTI);
44649076Swpaul
44749076Swpaul	/* Now program new ones. */
44849076Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
44949076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_ALLMULTI);
45049076Swpaul	} else {
45149076Swpaul		i = 1;
45249076Swpaul		/* First find the tail of the list. */
45349076Swpaul		for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
45449076Swpaul					ifma = ifma->ifma_link.le_next) {
45549076Swpaul			if (ifma->ifma_link.le_next == NULL)
45649076Swpaul				break;
45749076Swpaul		}
45849076Swpaul		/* Now traverse the list backwards. */
45949076Swpaul		for (; ifma != NULL && ifma != (void *)&ifp->if_multiaddrs;
46049076Swpaul			ifma = (struct ifmultiaddr *)ifma->ifma_link.le_prev) {
46149076Swpaul			if (ifma->ifma_addr->sa_family != AF_LINK)
46249076Swpaul				continue;
46349076Swpaul			/*
46449076Swpaul			 * Program the first 15 multicast groups
46549076Swpaul			 * into the perfect filter. For all others,
46649076Swpaul			 * use the hash table.
46749076Swpaul			 */
46849076Swpaul			if (i < SF_RXFILT_PERFECT_CNT) {
46949076Swpaul				sf_setperf(sc, i,
47049076Swpaul			LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
47149076Swpaul				i++;
47249076Swpaul				continue;
47349076Swpaul			}
47449076Swpaul
47549076Swpaul			sf_sethash(sc,
47649076Swpaul			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 0);
47749076Swpaul		}
47849076Swpaul	}
47949076Swpaul
48049076Swpaul	return;
48149076Swpaul}
48249076Swpaul
48349076Swpaul/*
48449076Swpaul * Set media options.
48549076Swpaul */
48649076Swpaulstatic int sf_ifmedia_upd(ifp)
48749076Swpaul	struct ifnet		*ifp;
48849076Swpaul{
48949076Swpaul	struct sf_softc		*sc;
49050675Swpaul	struct mii_data		*mii;
49149076Swpaul
49249076Swpaul	sc = ifp->if_softc;
49350675Swpaul	mii = device_get_softc(sc->sf_miibus);
49454161Swpaul	sc->sf_link = 0;
49554161Swpaul	if (mii->mii_instance) {
49654161Swpaul		struct mii_softc        *miisc;
49754161Swpaul		for (miisc = LIST_FIRST(&mii->mii_phys); miisc != NULL;
49854161Swpaul		    miisc = LIST_NEXT(miisc, mii_list))
49954161Swpaul			mii_phy_reset(miisc);
50054161Swpaul	}
50150675Swpaul	mii_mediachg(mii);
50249076Swpaul
50349076Swpaul	return(0);
50449076Swpaul}
50549076Swpaul
50649076Swpaul/*
50749076Swpaul * Report current media status.
50849076Swpaul */
50949076Swpaulstatic void sf_ifmedia_sts(ifp, ifmr)
51049076Swpaul	struct ifnet		*ifp;
51149076Swpaul	struct ifmediareq	*ifmr;
51249076Swpaul{
51349076Swpaul	struct sf_softc		*sc;
51450675Swpaul	struct mii_data		*mii;
51549076Swpaul
51649076Swpaul	sc = ifp->if_softc;
51750675Swpaul	mii = device_get_softc(sc->sf_miibus);
51849076Swpaul
51950675Swpaul	mii_pollstat(mii);
52050675Swpaul	ifmr->ifm_active = mii->mii_media_active;
52150675Swpaul	ifmr->ifm_status = mii->mii_media_status;
52249076Swpaul
52349076Swpaul	return;
52449076Swpaul}
52549076Swpaul
52649076Swpaulstatic int sf_ioctl(ifp, command, data)
52749076Swpaul	struct ifnet		*ifp;
52849076Swpaul	u_long			command;
52949076Swpaul	caddr_t			data;
53049076Swpaul{
53149076Swpaul	struct sf_softc		*sc = ifp->if_softc;
53249076Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
53350675Swpaul	struct mii_data		*mii;
53449076Swpaul	int			s, error = 0;
53549076Swpaul
53649076Swpaul	s = splimp();
53749076Swpaul
53849076Swpaul	switch(command) {
53949076Swpaul	case SIOCSIFADDR:
54049076Swpaul	case SIOCGIFADDR:
54149076Swpaul	case SIOCSIFMTU:
54249076Swpaul		error = ether_ioctl(ifp, command, data);
54349076Swpaul		break;
54449076Swpaul	case SIOCSIFFLAGS:
54549076Swpaul		if (ifp->if_flags & IFF_UP) {
54654161Swpaul			if (ifp->if_flags & IFF_RUNNING &&
54754161Swpaul			    ifp->if_flags & IFF_PROMISC &&
54854161Swpaul			    !(sc->sf_if_flags & IFF_PROMISC)) {
54954161Swpaul				SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
55054161Swpaul			} else if (ifp->if_flags & IFF_RUNNING &&
55154161Swpaul			    !(ifp->if_flags & IFF_PROMISC) &&
55254161Swpaul			    sc->sf_if_flags & IFF_PROMISC) {
55354161Swpaul				SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
55454161Swpaul			} else if (!(ifp->if_flags & IFF_RUNNING))
55554161Swpaul				sf_init(sc);
55649076Swpaul		} else {
55749076Swpaul			if (ifp->if_flags & IFF_RUNNING)
55849076Swpaul				sf_stop(sc);
55949076Swpaul		}
56054161Swpaul		sc->sf_if_flags = ifp->if_flags;
56149076Swpaul		error = 0;
56249076Swpaul		break;
56349076Swpaul	case SIOCADDMULTI:
56449076Swpaul	case SIOCDELMULTI:
56549076Swpaul		sf_setmulti(sc);
56649076Swpaul		error = 0;
56749076Swpaul		break;
56849076Swpaul	case SIOCGIFMEDIA:
56949076Swpaul	case SIOCSIFMEDIA:
57050675Swpaul		mii = device_get_softc(sc->sf_miibus);
57150675Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
57249076Swpaul		break;
57349076Swpaul	default:
57449076Swpaul		error = EINVAL;
57549076Swpaul		break;
57649076Swpaul	}
57749076Swpaul
57849076Swpaul	(void)splx(s);
57949076Swpaul
58049076Swpaul	return(error);
58149076Swpaul}
58249076Swpaul
58349076Swpaulstatic void sf_reset(sc)
58449076Swpaul	struct sf_softc		*sc;
58549076Swpaul{
58649076Swpaul	register int		i;
58749076Swpaul
58849076Swpaul	csr_write_4(sc, SF_GEN_ETH_CTL, 0);
58949076Swpaul	SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
59049076Swpaul	DELAY(1000);
59149076Swpaul	SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
59249076Swpaul
59349076Swpaul	SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_RESET);
59449076Swpaul
59549076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
59649076Swpaul		DELAY(10);
59749076Swpaul		if (!(csr_read_4(sc, SF_PCI_DEVCFG) & SF_PCIDEVCFG_RESET))
59849076Swpaul			break;
59949076Swpaul	}
60049076Swpaul
60149076Swpaul	if (i == SF_TIMEOUT)
60249076Swpaul		printf("sf%d: reset never completed!\n", sc->sf_unit);
60349076Swpaul
60449076Swpaul	/* Wait a little while for the chip to get its brains in order. */
60549076Swpaul	DELAY(1000);
60649076Swpaul	return;
60749076Swpaul}
60849076Swpaul
60949076Swpaul/*
61049076Swpaul * Probe for an Adaptec AIC-6915 chip. Check the PCI vendor and device
61149076Swpaul * IDs against our list and return a device name if we find a match.
61249076Swpaul * We also check the subsystem ID so that we can identify exactly which
61349076Swpaul * NIC has been found, if possible.
61449076Swpaul */
61549076Swpaulstatic int sf_probe(dev)
61649076Swpaul	device_t		dev;
61749076Swpaul{
61849076Swpaul	struct sf_type		*t;
61949076Swpaul
62049076Swpaul	t = sf_devs;
62149076Swpaul
62249076Swpaul	while(t->sf_name != NULL) {
62349076Swpaul		if ((pci_get_vendor(dev) == t->sf_vid) &&
62449076Swpaul		    (pci_get_device(dev) == t->sf_did)) {
62551336Swpaul			switch((pci_read_config(dev,
62651336Swpaul			    SF_PCI_SUBVEN_ID, 4) >> 16) & 0xFFFF) {
62749076Swpaul			case AD_SUBSYSID_62011_REV0:
62849076Swpaul			case AD_SUBSYSID_62011_REV1:
62949076Swpaul				device_set_desc(dev,
63049076Swpaul				    "Adaptec ANA-62011 10/100BaseTX");
63149076Swpaul				return(0);
63249076Swpaul				break;
63349076Swpaul			case AD_SUBSYSID_62022:
63449076Swpaul				device_set_desc(dev,
63549076Swpaul				    "Adaptec ANA-62022 10/100BaseTX");
63649076Swpaul				return(0);
63749076Swpaul				break;
63853468Swpaul			case AD_SUBSYSID_62044_REV0:
63953468Swpaul			case AD_SUBSYSID_62044_REV1:
64049076Swpaul				device_set_desc(dev,
64149076Swpaul				    "Adaptec ANA-62044 10/100BaseTX");
64249076Swpaul				return(0);
64349076Swpaul				break;
64449076Swpaul			case AD_SUBSYSID_62020:
64549076Swpaul				device_set_desc(dev,
64649076Swpaul				    "Adaptec ANA-62020 10/100BaseFX");
64749076Swpaul				return(0);
64849076Swpaul				break;
64949076Swpaul			case AD_SUBSYSID_69011:
65049076Swpaul				device_set_desc(dev,
65149076Swpaul				    "Adaptec ANA-69011 10/100BaseTX");
65249076Swpaul				return(0);
65349076Swpaul				break;
65449076Swpaul			default:
65549076Swpaul				device_set_desc(dev, t->sf_name);
65649076Swpaul				return(0);
65749076Swpaul				break;
65849076Swpaul			}
65949076Swpaul		}
66049076Swpaul		t++;
66149076Swpaul	}
66249076Swpaul
66349076Swpaul	return(ENXIO);
66449076Swpaul}
66549076Swpaul
66649076Swpaul/*
66749076Swpaul * Attach the interface. Allocate softc structures, do ifmedia
66849076Swpaul * setup and ethernet/BPF attach.
66949076Swpaul */
67049076Swpaulstatic int sf_attach(dev)
67149076Swpaul	device_t		dev;
67249076Swpaul{
67349076Swpaul	int			s, i;
67449076Swpaul	u_int32_t		command;
67549076Swpaul	struct sf_softc		*sc;
67649076Swpaul	struct ifnet		*ifp;
67749076Swpaul	int			unit, rid, error = 0;
67849076Swpaul
67949076Swpaul	s = splimp();
68049076Swpaul
68149076Swpaul	sc = device_get_softc(dev);
68249076Swpaul	unit = device_get_unit(dev);
68349076Swpaul	bzero(sc, sizeof(struct sf_softc));
68449076Swpaul
68549076Swpaul	/*
68649076Swpaul	 * Handle power management nonsense.
68749076Swpaul	 */
68849076Swpaul	command = pci_read_config(dev, SF_PCI_CAPID, 4) & 0x000000FF;
68949076Swpaul	if (command == 0x01) {
69049076Swpaul
69149076Swpaul		command = pci_read_config(dev, SF_PCI_PWRMGMTCTRL, 4);
69249076Swpaul		if (command & SF_PSTATE_MASK) {
69349076Swpaul			u_int32_t		iobase, membase, irq;
69449076Swpaul
69549076Swpaul			/* Save important PCI config data. */
69649076Swpaul			iobase = pci_read_config(dev, SF_PCI_LOIO, 4);
69749076Swpaul			membase = pci_read_config(dev, SF_PCI_LOMEM, 4);
69849076Swpaul			irq = pci_read_config(dev, SF_PCI_INTLINE, 4);
69949076Swpaul
70049076Swpaul			/* Reset the power state. */
70149076Swpaul			printf("sf%d: chip is in D%d power mode "
70249076Swpaul			"-- setting to D0\n", unit, command & SF_PSTATE_MASK);
70349076Swpaul			command &= 0xFFFFFFFC;
70449076Swpaul			pci_write_config(dev, SF_PCI_PWRMGMTCTRL, command, 4);
70549076Swpaul
70649076Swpaul			/* Restore PCI config data. */
70749076Swpaul			pci_write_config(dev, SF_PCI_LOIO, iobase, 4);
70849076Swpaul			pci_write_config(dev, SF_PCI_LOMEM, membase, 4);
70949076Swpaul			pci_write_config(dev, SF_PCI_INTLINE, irq, 4);
71049076Swpaul		}
71149076Swpaul	}
71249076Swpaul
71349076Swpaul	/*
71449076Swpaul	 * Map control/status registers.
71549076Swpaul	 */
71661041Speter	command = pci_read_config(dev, PCIR_COMMAND, 4);
71749076Swpaul	command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
71861041Speter	pci_write_config(dev, PCIR_COMMAND, command, 4);
71961041Speter	command = pci_read_config(dev, PCIR_COMMAND, 4);
72049076Swpaul
72149076Swpaul#ifdef SF_USEIOSPACE
72249076Swpaul	if (!(command & PCIM_CMD_PORTEN)) {
72349076Swpaul		printf("sf%d: failed to enable I/O ports!\n", unit);
72449076Swpaul		error = ENXIO;
72549076Swpaul		goto fail;
72649076Swpaul	}
72749076Swpaul#else
72849076Swpaul	if (!(command & PCIM_CMD_MEMEN)) {
72949076Swpaul		printf("sf%d: failed to enable memory mapping!\n", unit);
73049076Swpaul		error = ENXIO;
73149076Swpaul		goto fail;
73249076Swpaul	}
73349076Swpaul#endif
73449076Swpaul
73549076Swpaul	rid = SF_RID;
73649076Swpaul	sc->sf_res = bus_alloc_resource(dev, SF_RES, &rid,
73749076Swpaul	    0, ~0, 1, RF_ACTIVE);
73849076Swpaul
73949076Swpaul	if (sc->sf_res == NULL) {
74049076Swpaul		printf ("sf%d: couldn't map ports\n", unit);
74149076Swpaul		error = ENXIO;
74249076Swpaul		goto fail;
74349076Swpaul	}
74449076Swpaul
74549076Swpaul	sc->sf_btag = rman_get_bustag(sc->sf_res);
74649076Swpaul	sc->sf_bhandle = rman_get_bushandle(sc->sf_res);
74749076Swpaul
74849076Swpaul	/* Allocate interrupt */
74949076Swpaul	rid = 0;
75049076Swpaul	sc->sf_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
75149076Swpaul	    RF_SHAREABLE | RF_ACTIVE);
75249076Swpaul
75349076Swpaul	if (sc->sf_irq == NULL) {
75449076Swpaul		printf("sf%d: couldn't map interrupt\n", unit);
75549076Swpaul		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
75649076Swpaul		error = ENXIO;
75749076Swpaul		goto fail;
75849076Swpaul	}
75949076Swpaul
76049076Swpaul	error = bus_setup_intr(dev, sc->sf_irq, INTR_TYPE_NET,
76149076Swpaul	    sf_intr, sc, &sc->sf_intrhand);
76249076Swpaul
76349076Swpaul	if (error) {
76449076Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_res);
76549076Swpaul		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
76649076Swpaul		printf("sf%d: couldn't set up irq\n", unit);
76749076Swpaul		goto fail;
76849076Swpaul	}
76949076Swpaul
77049076Swpaul	callout_handle_init(&sc->sf_stat_ch);
77149076Swpaul
77249076Swpaul	/* Reset the adapter. */
77349076Swpaul	sf_reset(sc);
77449076Swpaul
77549076Swpaul	/*
77649076Swpaul	 * Get station address from the EEPROM.
77749076Swpaul	 */
77849076Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
77949076Swpaul		sc->arpcom.ac_enaddr[i] =
78049076Swpaul		    sf_read_eeprom(sc, SF_EE_NODEADDR + ETHER_ADDR_LEN - i);
78149076Swpaul
78249076Swpaul	/*
78349076Swpaul	 * An Adaptec chip was detected. Inform the world.
78449076Swpaul	 */
78549076Swpaul	printf("sf%d: Ethernet address: %6D\n", unit,
78649076Swpaul	    sc->arpcom.ac_enaddr, ":");
78749076Swpaul
78849076Swpaul	sc->sf_unit = unit;
78949076Swpaul
79049076Swpaul	/* Allocate the descriptor queues. */
79149076Swpaul	sc->sf_ldata = contigmalloc(sizeof(struct sf_list_data), M_DEVBUF,
79251657Swpaul	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
79349076Swpaul
79449076Swpaul	if (sc->sf_ldata == NULL) {
79549076Swpaul		printf("sf%d: no memory for list buffers!\n", unit);
79649076Swpaul		bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
79749076Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
79849076Swpaul		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
79949076Swpaul		error = ENXIO;
80049076Swpaul		goto fail;
80149076Swpaul	}
80249076Swpaul
80349076Swpaul	bzero(sc->sf_ldata, sizeof(struct sf_list_data));
80449076Swpaul
80550675Swpaul	/* Do MII setup. */
80650675Swpaul	if (mii_phy_probe(dev, &sc->sf_miibus,
80750675Swpaul	    sf_ifmedia_upd, sf_ifmedia_sts)) {
80849076Swpaul		printf("sf%d: MII without any phy!\n", sc->sf_unit);
80954161Swpaul		contigfree(sc->sf_ldata,sizeof(struct sf_list_data),M_DEVBUF);
81049076Swpaul		bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
81149076Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
81249076Swpaul		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
81349076Swpaul		error = ENXIO;
81449076Swpaul		goto fail;
81549076Swpaul	}
81649076Swpaul
81749076Swpaul	ifp = &sc->arpcom.ac_if;
81849076Swpaul	ifp->if_softc = sc;
81949076Swpaul	ifp->if_unit = unit;
82049076Swpaul	ifp->if_name = "sf";
82149076Swpaul	ifp->if_mtu = ETHERMTU;
82249076Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
82349076Swpaul	ifp->if_ioctl = sf_ioctl;
82449076Swpaul	ifp->if_output = ether_output;
82549076Swpaul	ifp->if_start = sf_start;
82649076Swpaul	ifp->if_watchdog = sf_watchdog;
82749076Swpaul	ifp->if_init = sf_init;
82849076Swpaul	ifp->if_baudrate = 10000000;
82949076Swpaul	ifp->if_snd.ifq_maxlen = SF_TX_DLIST_CNT - 1;
83049076Swpaul
83149076Swpaul	/*
83263090Sarchie	 * Call MI attach routine.
83349076Swpaul	 */
83463090Sarchie	ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
83549076Swpaul
83649076Swpaulfail:
83749076Swpaul	splx(s);
83849076Swpaul	return(error);
83949076Swpaul}
84049076Swpaul
84149076Swpaulstatic int sf_detach(dev)
84249076Swpaul	device_t		dev;
84349076Swpaul{
84449076Swpaul	struct sf_softc		*sc;
84549076Swpaul	struct ifnet		*ifp;
84649076Swpaul	int			s;
84749076Swpaul
84849076Swpaul	s = splimp();
84949076Swpaul
85049076Swpaul	sc = device_get_softc(dev);
85149076Swpaul	ifp = &sc->arpcom.ac_if;
85249076Swpaul
85363090Sarchie	ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
85449076Swpaul	sf_stop(sc);
85549076Swpaul
85650675Swpaul	bus_generic_detach(dev);
85750675Swpaul	device_delete_child(dev, sc->sf_miibus);
85850675Swpaul
85949076Swpaul	bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
86049076Swpaul	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
86149076Swpaul	bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
86249076Swpaul
86354161Swpaul	contigfree(sc->sf_ldata, sizeof(struct sf_list_data), M_DEVBUF);
86449076Swpaul
86549076Swpaul	splx(s);
86649076Swpaul
86749076Swpaul	return(0);
86849076Swpaul}
86949076Swpaul
87049076Swpaulstatic int sf_init_rx_ring(sc)
87149076Swpaul	struct sf_softc		*sc;
87249076Swpaul{
87349076Swpaul	struct sf_list_data	*ld;
87449076Swpaul	int			i;
87549076Swpaul
87649076Swpaul	ld = sc->sf_ldata;
87749076Swpaul
87849076Swpaul	bzero((char *)ld->sf_rx_dlist_big,
87949076Swpaul	    sizeof(struct sf_rx_bufdesc_type0) * SF_RX_DLIST_CNT);
88049076Swpaul	bzero((char *)ld->sf_rx_clist,
88149076Swpaul	    sizeof(struct sf_rx_cmpdesc_type3) * SF_RX_CLIST_CNT);
88249076Swpaul
88349076Swpaul	for (i = 0; i < SF_RX_DLIST_CNT; i++) {
88449076Swpaul		if (sf_newbuf(sc, &ld->sf_rx_dlist_big[i], NULL) == ENOBUFS)
88549076Swpaul			return(ENOBUFS);
88649076Swpaul	}
88749076Swpaul
88849076Swpaul	return(0);
88949076Swpaul}
89049076Swpaul
89149076Swpaulstatic void sf_init_tx_ring(sc)
89249076Swpaul	struct sf_softc		*sc;
89349076Swpaul{
89449076Swpaul	struct sf_list_data	*ld;
89549076Swpaul	int			i;
89649076Swpaul
89749076Swpaul	ld = sc->sf_ldata;
89849076Swpaul
89949076Swpaul	bzero((char *)ld->sf_tx_dlist,
90049076Swpaul	    sizeof(struct sf_tx_bufdesc_type0) * SF_TX_DLIST_CNT);
90149076Swpaul	bzero((char *)ld->sf_tx_clist,
90249076Swpaul	    sizeof(struct sf_tx_cmpdesc_type0) * SF_TX_CLIST_CNT);
90349076Swpaul
90449076Swpaul	for (i = 0; i < SF_TX_DLIST_CNT; i++)
90549076Swpaul		ld->sf_tx_dlist[i].sf_id = SF_TX_BUFDESC_ID;
90649076Swpaul	for (i = 0; i < SF_TX_CLIST_CNT; i++)
90749076Swpaul		ld->sf_tx_clist[i].sf_type = SF_TXCMPTYPE_TX;
90849076Swpaul
90949076Swpaul	ld->sf_tx_dlist[SF_TX_DLIST_CNT - 1].sf_end = 1;
91049076Swpaul	sc->sf_tx_cnt = 0;
91149076Swpaul
91249076Swpaul	return;
91349076Swpaul}
91449076Swpaul
91549076Swpaulstatic int sf_newbuf(sc, c, m)
91649076Swpaul	struct sf_softc		*sc;
91749076Swpaul	struct sf_rx_bufdesc_type0	*c;
91849076Swpaul	struct mbuf		*m;
91949076Swpaul{
92049076Swpaul	struct mbuf		*m_new = NULL;
92149076Swpaul
92249076Swpaul	if (m == NULL) {
92349076Swpaul		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
92449076Swpaul		if (m_new == NULL) {
92549076Swpaul			printf("sf%d: no memory for rx list -- "
92649076Swpaul			    "packet dropped!\n", sc->sf_unit);
92749076Swpaul			return(ENOBUFS);
92849076Swpaul		}
92949076Swpaul
93049076Swpaul		MCLGET(m_new, M_DONTWAIT);
93149076Swpaul		if (!(m_new->m_flags & M_EXT)) {
93249076Swpaul			printf("sf%d: no memory for rx list -- "
93349076Swpaul			    "packet dropped!\n", sc->sf_unit);
93449076Swpaul			m_freem(m_new);
93549076Swpaul			return(ENOBUFS);
93649076Swpaul		}
93749076Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
93849076Swpaul	} else {
93949076Swpaul		m_new = m;
94049076Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
94149076Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
94249076Swpaul	}
94349076Swpaul
94449076Swpaul	m_adj(m_new, sizeof(u_int64_t));
94549076Swpaul
94649076Swpaul	c->sf_mbuf = m_new;
94749076Swpaul	c->sf_addrlo = SF_RX_HOSTADDR(vtophys(mtod(m_new, caddr_t)));
94849076Swpaul	c->sf_valid = 1;
94949076Swpaul
95049076Swpaul	return(0);
95149076Swpaul}
95249076Swpaul
95349076Swpaul/*
95449076Swpaul * The starfire is programmed to use 'normal' mode for packet reception,
95549076Swpaul * which means we use the consumer/producer model for both the buffer
95649076Swpaul * descriptor queue and the completion descriptor queue. The only problem
95749076Swpaul * with this is that it involves a lot of register accesses: we have to
95849076Swpaul * read the RX completion consumer and producer indexes and the RX buffer
95949076Swpaul * producer index, plus the RX completion consumer and RX buffer producer
96049076Swpaul * indexes have to be updated. It would have been easier if Adaptec had
96149076Swpaul * put each index in a separate register, especially given that the damn
96249076Swpaul * NIC has a 512K register space.
96349076Swpaul *
96449076Swpaul * In spite of all the lovely features that Adaptec crammed into the 6915,
96549076Swpaul * it is marred by one truly stupid design flaw, which is that receive
96649076Swpaul * buffer addresses must be aligned on a longword boundary. This forces
96749076Swpaul * the packet payload to be unaligned, which is suboptimal on the x86 and
96849076Swpaul * completely unuseable on the Alpha. Our only recourse is to copy received
96949076Swpaul * packets into properly aligned buffers before handing them off.
97049076Swpaul */
97149076Swpaul
97249076Swpaulstatic void sf_rxeof(sc)
97349076Swpaul	struct sf_softc		*sc;
97449076Swpaul{
97549076Swpaul	struct ether_header	*eh;
97649076Swpaul	struct mbuf		*m;
97749076Swpaul	struct ifnet		*ifp;
97849076Swpaul	struct sf_rx_bufdesc_type0	*desc;
97949076Swpaul	struct sf_rx_cmpdesc_type3	*cur_rx;
98049076Swpaul	u_int32_t		rxcons, rxprod;
98149076Swpaul	int			cmpprodidx, cmpconsidx, bufprodidx;
98249076Swpaul
98349076Swpaul	ifp = &sc->arpcom.ac_if;
98449076Swpaul
98549076Swpaul	rxcons = csr_read_4(sc, SF_CQ_CONSIDX);
98649076Swpaul	rxprod = csr_read_4(sc, SF_RXDQ_PTR_Q1);
98749076Swpaul	cmpprodidx = SF_IDX_LO(csr_read_4(sc, SF_CQ_PRODIDX));
98849076Swpaul	cmpconsidx = SF_IDX_LO(rxcons);
98949076Swpaul	bufprodidx = SF_IDX_LO(rxprod);
99049076Swpaul
99149076Swpaul	while (cmpconsidx != cmpprodidx) {
99249076Swpaul		struct mbuf		*m0;
99349076Swpaul
99449076Swpaul		cur_rx = &sc->sf_ldata->sf_rx_clist[cmpconsidx];
99549076Swpaul		desc = &sc->sf_ldata->sf_rx_dlist_big[cur_rx->sf_endidx];
99649076Swpaul		m = desc->sf_mbuf;
99749076Swpaul		SF_INC(cmpconsidx, SF_RX_CLIST_CNT);
99849076Swpaul		SF_INC(bufprodidx, SF_RX_DLIST_CNT);
99949076Swpaul
100049076Swpaul		if (!(cur_rx->sf_status1 & SF_RXSTAT1_OK)) {
100149076Swpaul			ifp->if_ierrors++;
100249076Swpaul			sf_newbuf(sc, desc, m);
100349076Swpaul			continue;
100449076Swpaul		}
100549076Swpaul
100649076Swpaul		m0 = m_devget(mtod(m, char *) - ETHER_ALIGN,
100749076Swpaul		    cur_rx->sf_len + ETHER_ALIGN, 0, ifp, NULL);
100849076Swpaul		sf_newbuf(sc, desc, m);
100949076Swpaul		if (m0 == NULL) {
101049076Swpaul			ifp->if_ierrors++;
101149076Swpaul			continue;
101249076Swpaul		}
101349076Swpaul		m_adj(m0, ETHER_ALIGN);
101449076Swpaul		m = m0;
101549076Swpaul
101649076Swpaul		eh = mtod(m, struct ether_header *);
101749076Swpaul		ifp->if_ipackets++;
101849076Swpaul
101949076Swpaul		/* Remove header from mbuf and pass it on. */
102049076Swpaul		m_adj(m, sizeof(struct ether_header));
102149076Swpaul		ether_input(ifp, eh, m);
102249076Swpaul	}
102349076Swpaul
102449076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX,
102549076Swpaul	    (rxcons & ~SF_CQ_CONSIDX_RXQ1) | cmpconsidx);
102649076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1,
102749076Swpaul	    (rxprod & ~SF_RXDQ_PRODIDX) | bufprodidx);
102849076Swpaul
102949076Swpaul	return;
103049076Swpaul}
103149076Swpaul
103249076Swpaul/*
103349076Swpaul * Read the transmit status from the completion queue and release
103449076Swpaul * mbufs. Note that the buffer descriptor index in the completion
103549076Swpaul * descriptor is an offset from the start of the transmit buffer
103649076Swpaul * descriptor list in bytes. This is important because the manual
103749076Swpaul * gives the impression that it should match the producer/consumer
103849076Swpaul * index, which is the offset in 8 byte blocks.
103949076Swpaul */
104049076Swpaulstatic void sf_txeof(sc)
104149076Swpaul	struct sf_softc		*sc;
104249076Swpaul{
104349076Swpaul	int			txcons, cmpprodidx, cmpconsidx;
104449076Swpaul	struct sf_tx_cmpdesc_type1 *cur_cmp;
104549076Swpaul	struct sf_tx_bufdesc_type0 *cur_tx;
104649076Swpaul	struct ifnet		*ifp;
104749076Swpaul
104849076Swpaul	ifp = &sc->arpcom.ac_if;
104949076Swpaul
105049076Swpaul	txcons = csr_read_4(sc, SF_CQ_CONSIDX);
105149076Swpaul	cmpprodidx = SF_IDX_HI(csr_read_4(sc, SF_CQ_PRODIDX));
105249076Swpaul	cmpconsidx = SF_IDX_HI(txcons);
105349076Swpaul
105449076Swpaul	while (cmpconsidx != cmpprodidx) {
105549076Swpaul		cur_cmp = &sc->sf_ldata->sf_tx_clist[cmpconsidx];
105649076Swpaul		cur_tx = &sc->sf_ldata->sf_tx_dlist[cur_cmp->sf_index >> 7];
105749076Swpaul		SF_INC(cmpconsidx, SF_TX_CLIST_CNT);
105849076Swpaul
105949076Swpaul		if (cur_cmp->sf_txstat & SF_TXSTAT_TX_OK)
106049076Swpaul			ifp->if_opackets++;
106149076Swpaul		else
106249076Swpaul			ifp->if_oerrors++;
106349076Swpaul
106449076Swpaul		sc->sf_tx_cnt--;
106549076Swpaul		if (cur_tx->sf_mbuf != NULL) {
106649076Swpaul			m_freem(cur_tx->sf_mbuf);
106749076Swpaul			cur_tx->sf_mbuf = NULL;
106849076Swpaul		}
106949076Swpaul	}
107049076Swpaul
107149076Swpaul	ifp->if_timer = 0;
107249076Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
107349076Swpaul
107449076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX,
107549076Swpaul	    (txcons & ~SF_CQ_CONSIDX_TXQ) |
107649076Swpaul	    ((cmpconsidx << 16) & 0xFFFF0000));
107749076Swpaul
107849076Swpaul	return;
107949076Swpaul}
108049076Swpaul
108149076Swpaulstatic void sf_intr(arg)
108249076Swpaul	void			*arg;
108349076Swpaul{
108449076Swpaul	struct sf_softc		*sc;
108549076Swpaul	struct ifnet		*ifp;
108649076Swpaul	u_int32_t		status;
108749076Swpaul
108849076Swpaul	sc = arg;
108949076Swpaul	ifp = &sc->arpcom.ac_if;
109049076Swpaul
109149076Swpaul	if (!(csr_read_4(sc, SF_ISR_SHADOW) & SF_ISR_PCIINT_ASSERTED))
109249076Swpaul		return;
109349076Swpaul
109449076Swpaul	/* Disable interrupts. */
109549076Swpaul	csr_write_4(sc, SF_IMR, 0x00000000);
109649076Swpaul
109749076Swpaul	for (;;) {
109849076Swpaul		status = csr_read_4(sc, SF_ISR);
109949076Swpaul		if (status)
110049076Swpaul			csr_write_4(sc, SF_ISR, status);
110149076Swpaul
110249076Swpaul		if (!(status & SF_INTRS))
110349076Swpaul			break;
110449076Swpaul
110549076Swpaul		if (status & SF_ISR_RXDQ1_DMADONE)
110649076Swpaul			sf_rxeof(sc);
110749076Swpaul
110849076Swpaul		if (status & SF_ISR_TX_TXDONE)
110949076Swpaul			sf_txeof(sc);
111049076Swpaul
111149076Swpaul		if (status & SF_ISR_ABNORMALINTR) {
111249076Swpaul			if (status & SF_ISR_STATSOFLOW) {
111349076Swpaul				untimeout(sf_stats_update, sc,
111449076Swpaul				    sc->sf_stat_ch);
111549076Swpaul				sf_stats_update(sc);
111649076Swpaul			} else
111749076Swpaul				sf_init(sc);
111849076Swpaul		}
111949076Swpaul	}
112049076Swpaul
112149076Swpaul	/* Re-enable interrupts. */
112249076Swpaul	csr_write_4(sc, SF_IMR, SF_INTRS);
112349076Swpaul
112449076Swpaul	if (ifp->if_snd.ifq_head != NULL)
112549076Swpaul		sf_start(ifp);
112649076Swpaul
112749076Swpaul	return;
112849076Swpaul}
112949076Swpaul
113049076Swpaulstatic void sf_init(xsc)
113149076Swpaul	void			*xsc;
113249076Swpaul{
113349076Swpaul	struct sf_softc		*sc;
113449076Swpaul	struct ifnet		*ifp;
113550675Swpaul	struct mii_data		*mii;
113649076Swpaul	int			i, s;
113749076Swpaul
113849076Swpaul	s = splimp();
113949076Swpaul
114049076Swpaul	sc = xsc;
114149076Swpaul	ifp = &sc->arpcom.ac_if;
114250675Swpaul	mii = device_get_softc(sc->sf_miibus);
114349076Swpaul
114449076Swpaul	sf_stop(sc);
114549076Swpaul	sf_reset(sc);
114649076Swpaul
114749076Swpaul	/* Init all the receive filter registers */
114849076Swpaul	for (i = SF_RXFILT_PERFECT_BASE;
114949076Swpaul	    i < (SF_RXFILT_HASH_MAX + 1); i += 4)
115049076Swpaul		csr_write_4(sc, i, 0);
115149076Swpaul
115249076Swpaul	/* Empty stats counter registers. */
115349076Swpaul	for (i = 0; i < sizeof(struct sf_stats)/sizeof(u_int32_t); i++)
115449076Swpaul		csr_write_4(sc, SF_STATS_BASE +
115549076Swpaul		    (i + sizeof(u_int32_t)), 0);
115649076Swpaul
115749076Swpaul	/* Init our MAC address */
115849076Swpaul	csr_write_4(sc, SF_PAR0, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0]));
115949076Swpaul	csr_write_4(sc, SF_PAR1, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4]));
116049076Swpaul	sf_setperf(sc, 0, (caddr_t)&sc->arpcom.ac_enaddr);
116149076Swpaul
116249076Swpaul	if (sf_init_rx_ring(sc) == ENOBUFS) {
116349076Swpaul		printf("sf%d: initialization failed: no "
116449076Swpaul		    "memory for rx buffers\n", sc->sf_unit);
116549076Swpaul		(void)splx(s);
116649076Swpaul		return;
116749076Swpaul	}
116849076Swpaul
116949076Swpaul	sf_init_tx_ring(sc);
117049076Swpaul
117149076Swpaul	csr_write_4(sc, SF_RXFILT, SF_PERFMODE_NORMAL|SF_HASHMODE_WITHVLAN);
117249076Swpaul
117349076Swpaul	/* If we want promiscuous mode, set the allframes bit. */
117449076Swpaul	if (ifp->if_flags & IFF_PROMISC) {
117549076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
117649076Swpaul	} else {
117749076Swpaul		SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
117849076Swpaul	}
117949076Swpaul
118049076Swpaul	if (ifp->if_flags & IFF_BROADCAST) {
118149076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_BROAD);
118249076Swpaul	} else {
118349076Swpaul		SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_BROAD);
118449076Swpaul	}
118549076Swpaul
118649076Swpaul	/* Init the completion queue indexes */
118749076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX, 0);
118849076Swpaul	csr_write_4(sc, SF_CQ_PRODIDX, 0);
118949076Swpaul
119049076Swpaul	/* Init the RX completion queue */
119149076Swpaul	csr_write_4(sc, SF_RXCQ_CTL_1,
119249076Swpaul	    vtophys(sc->sf_ldata->sf_rx_clist) & SF_RXCQ_ADDR);
119349076Swpaul	SF_SETBIT(sc, SF_RXCQ_CTL_1, SF_RXCQTYPE_3);
119449076Swpaul
119549076Swpaul	/* Init RX DMA control. */
119649076Swpaul	SF_SETBIT(sc, SF_RXDMA_CTL, SF_RXDMA_REPORTBADPKTS);
119749076Swpaul
119849076Swpaul	/* Init the RX buffer descriptor queue. */
119949076Swpaul	csr_write_4(sc, SF_RXDQ_ADDR_Q1,
120049076Swpaul	    vtophys(sc->sf_ldata->sf_rx_dlist_big));
120149076Swpaul	csr_write_4(sc, SF_RXDQ_CTL_1, (MCLBYTES << 16) | SF_DESCSPACE_16BYTES);
120249076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1, SF_RX_DLIST_CNT - 1);
120349076Swpaul
120449076Swpaul	/* Init the TX completion queue */
120549076Swpaul	csr_write_4(sc, SF_TXCQ_CTL,
120649076Swpaul	    vtophys(sc->sf_ldata->sf_tx_clist) & SF_RXCQ_ADDR);
120749076Swpaul
120849076Swpaul	/* Init the TX buffer descriptor queue. */
120949076Swpaul	csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO,
121049076Swpaul		vtophys(sc->sf_ldata->sf_tx_dlist));
121149076Swpaul	SF_SETBIT(sc, SF_TX_FRAMCTL, SF_TXFRMCTL_CPLAFTERTX);
121249076Swpaul	csr_write_4(sc, SF_TXDQ_CTL,
121349076Swpaul	    SF_TXBUFDESC_TYPE0|SF_TXMINSPACE_128BYTES|SF_TXSKIPLEN_8BYTES);
121449076Swpaul	SF_SETBIT(sc, SF_TXDQ_CTL, SF_TXDQCTL_NODMACMP);
121549076Swpaul
121649076Swpaul	/* Enable autopadding of short TX frames. */
121749076Swpaul	SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_AUTOPAD);
121849076Swpaul
121949076Swpaul	/* Enable interrupts. */
122049076Swpaul	csr_write_4(sc, SF_IMR, SF_INTRS);
122149076Swpaul	SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_INTR_ENB);
122249076Swpaul
122349076Swpaul	/* Enable the RX and TX engines. */
122449076Swpaul	SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_RX_ENB|SF_ETHCTL_RXDMA_ENB);
122549076Swpaul	SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_TX_ENB|SF_ETHCTL_TXDMA_ENB);
122649076Swpaul
122754161Swpaul	/*mii_mediachg(mii);*/
122854161Swpaul	sf_ifmedia_upd(ifp);
122950675Swpaul
123049076Swpaul	ifp->if_flags |= IFF_RUNNING;
123149076Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
123249076Swpaul
123349076Swpaul	sc->sf_stat_ch = timeout(sf_stats_update, sc, hz);
123449076Swpaul
123549076Swpaul	splx(s);
123649076Swpaul
123749076Swpaul	return;
123849076Swpaul}
123949076Swpaul
124049076Swpaulstatic int sf_encap(sc, c, m_head)
124149076Swpaul	struct sf_softc		*sc;
124249076Swpaul	struct sf_tx_bufdesc_type0 *c;
124349076Swpaul	struct mbuf		*m_head;
124449076Swpaul{
124549076Swpaul	int			frag = 0;
124649076Swpaul	struct sf_frag		*f = NULL;
124749076Swpaul	struct mbuf		*m;
124849076Swpaul
124949076Swpaul	m = m_head;
125049076Swpaul
125149076Swpaul	for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
125249076Swpaul		if (m->m_len != 0) {
125349076Swpaul			if (frag == SF_MAXFRAGS)
125449076Swpaul				break;
125549076Swpaul			f = &c->sf_frags[frag];
125649076Swpaul			if (frag == 0)
125749076Swpaul				f->sf_pktlen = m_head->m_pkthdr.len;
125849076Swpaul			f->sf_fraglen = m->m_len;
125949076Swpaul			f->sf_addr = vtophys(mtod(m, vm_offset_t));
126049076Swpaul			frag++;
126149076Swpaul		}
126249076Swpaul	}
126349076Swpaul
126449076Swpaul	if (m != NULL) {
126549076Swpaul		struct mbuf		*m_new = NULL;
126649076Swpaul
126749076Swpaul		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
126849076Swpaul		if (m_new == NULL) {
126949076Swpaul			printf("sf%d: no memory for tx list", sc->sf_unit);
127049076Swpaul			return(1);
127149076Swpaul		}
127249076Swpaul
127349076Swpaul		if (m_head->m_pkthdr.len > MHLEN) {
127449076Swpaul			MCLGET(m_new, M_DONTWAIT);
127549076Swpaul			if (!(m_new->m_flags & M_EXT)) {
127649076Swpaul				m_freem(m_new);
127749076Swpaul				printf("sf%d: no memory for tx list",
127849076Swpaul				    sc->sf_unit);
127949076Swpaul				return(1);
128049076Swpaul			}
128149076Swpaul		}
128249076Swpaul		m_copydata(m_head, 0, m_head->m_pkthdr.len,
128349076Swpaul		    mtod(m_new, caddr_t));
128449076Swpaul		m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
128549076Swpaul		m_freem(m_head);
128649076Swpaul		m_head = m_new;
128749076Swpaul		f = &c->sf_frags[0];
128849076Swpaul		f->sf_fraglen = f->sf_pktlen = m_head->m_pkthdr.len;
128949076Swpaul		f->sf_addr = vtophys(mtod(m_head, caddr_t));
129049076Swpaul		frag = 1;
129149076Swpaul	}
129249076Swpaul
129349076Swpaul	c->sf_mbuf = m_head;
129449076Swpaul	c->sf_id = SF_TX_BUFDESC_ID;
129549076Swpaul	c->sf_fragcnt = frag;
129649076Swpaul	c->sf_intr = 1;
129749076Swpaul	c->sf_caltcp = 0;
129849076Swpaul	c->sf_crcen = 1;
129949076Swpaul
130049076Swpaul	return(0);
130149076Swpaul}
130249076Swpaul
130349076Swpaulstatic void sf_start(ifp)
130449076Swpaul	struct ifnet		*ifp;
130549076Swpaul{
130649076Swpaul	struct sf_softc		*sc;
130749076Swpaul	struct sf_tx_bufdesc_type0 *cur_tx = NULL;
130849076Swpaul	struct mbuf		*m_head = NULL;
130949076Swpaul	int			i, txprod;
131049076Swpaul
131149076Swpaul	sc = ifp->if_softc;
131249076Swpaul
131354161Swpaul	if (!sc->sf_link)
131454161Swpaul		return;
131554161Swpaul
131649076Swpaul	if (ifp->if_flags & IFF_OACTIVE)
131749076Swpaul		return;
131849076Swpaul
131949076Swpaul	txprod = csr_read_4(sc, SF_TXDQ_PRODIDX);
132049076Swpaul	i = SF_IDX_HI(txprod) >> 4;
132149076Swpaul
132249076Swpaul	while(sc->sf_ldata->sf_tx_dlist[i].sf_mbuf == NULL) {
132349076Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
132449076Swpaul		if (m_head == NULL)
132549076Swpaul			break;
132649076Swpaul
132749076Swpaul		cur_tx = &sc->sf_ldata->sf_tx_dlist[i];
132849076Swpaul		sf_encap(sc, cur_tx, m_head);
132949076Swpaul
133049076Swpaul		/*
133149076Swpaul		 * If there's a BPF listener, bounce a copy of this frame
133249076Swpaul		 * to him.
133349076Swpaul		 */
133449076Swpaul		if (ifp->if_bpf)
133549076Swpaul			bpf_mtap(ifp, m_head);
133651583Swpaul
133749076Swpaul		SF_INC(i, SF_TX_DLIST_CNT);
133849076Swpaul		sc->sf_tx_cnt++;
133949076Swpaul		if (sc->sf_tx_cnt == (SF_TX_DLIST_CNT - 2))
134049076Swpaul			break;
134149076Swpaul	}
134249076Swpaul
134349076Swpaul	if (cur_tx == NULL)
134449076Swpaul		return;
134549076Swpaul
134649076Swpaul	/* Transmit */
134749076Swpaul	csr_write_4(sc, SF_TXDQ_PRODIDX,
134849076Swpaul	    (txprod & ~SF_TXDQ_PRODIDX_HIPRIO) |
134949076Swpaul	    ((i << 20) & 0xFFFF0000));
135049076Swpaul
135149076Swpaul	ifp->if_timer = 5;
135249076Swpaul
135349076Swpaul	return;
135449076Swpaul}
135549076Swpaul
135649076Swpaulstatic void sf_stop(sc)
135749076Swpaul	struct sf_softc		*sc;
135849076Swpaul{
135949076Swpaul	int			i;
136049077Swpaul	struct ifnet		*ifp;
136149076Swpaul
136249077Swpaul	ifp = &sc->arpcom.ac_if;
136349077Swpaul
136449076Swpaul	untimeout(sf_stats_update, sc, sc->sf_stat_ch);
136549076Swpaul
136649076Swpaul	csr_write_4(sc, SF_GEN_ETH_CTL, 0);
136749076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX, 0);
136849076Swpaul	csr_write_4(sc, SF_CQ_PRODIDX, 0);
136949076Swpaul	csr_write_4(sc, SF_RXDQ_ADDR_Q1, 0);
137049076Swpaul	csr_write_4(sc, SF_RXDQ_CTL_1, 0);
137149076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1, 0);
137249076Swpaul	csr_write_4(sc, SF_TXCQ_CTL, 0);
137349076Swpaul	csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO, 0);
137449076Swpaul	csr_write_4(sc, SF_TXDQ_CTL, 0);
137549076Swpaul	sf_reset(sc);
137649076Swpaul
137754161Swpaul	sc->sf_link = 0;
137854161Swpaul
137949076Swpaul	for (i = 0; i < SF_RX_DLIST_CNT; i++) {
138049076Swpaul		if (sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf != NULL) {
138149076Swpaul			m_freem(sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf);
138249076Swpaul			sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf = NULL;
138349076Swpaul		}
138449076Swpaul	}
138549076Swpaul
138649076Swpaul	for (i = 0; i < SF_TX_DLIST_CNT; i++) {
138749076Swpaul		if (sc->sf_ldata->sf_tx_dlist[i].sf_mbuf != NULL) {
138849076Swpaul			m_freem(sc->sf_ldata->sf_tx_dlist[i].sf_mbuf);
138949076Swpaul			sc->sf_ldata->sf_tx_dlist[i].sf_mbuf = NULL;
139049076Swpaul		}
139149076Swpaul	}
139249076Swpaul
139349077Swpaul	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
139449077Swpaul
139549076Swpaul	return;
139649076Swpaul}
139749076Swpaul
139849076Swpaul/*
139949076Swpaul * Note: it is important that this function not be interrupted. We
140049076Swpaul * use a two-stage register access scheme: if we are interrupted in
140149076Swpaul * between setting the indirect address register and reading from the
140249076Swpaul * indirect data register, the contents of the address register could
140349076Swpaul * be changed out from under us.
140449076Swpaul */
140549076Swpaulstatic void sf_stats_update(xsc)
140649076Swpaul	void			*xsc;
140749076Swpaul{
140849076Swpaul	struct sf_softc		*sc;
140949076Swpaul	struct ifnet		*ifp;
141050675Swpaul	struct mii_data		*mii;
141149076Swpaul	struct sf_stats		stats;
141249076Swpaul	u_int32_t		*ptr;
141349076Swpaul	int			i, s;
141449076Swpaul
141549076Swpaul	s = splimp();
141649076Swpaul
141749076Swpaul	sc = xsc;
141849076Swpaul	ifp = &sc->arpcom.ac_if;
141950675Swpaul	mii = device_get_softc(sc->sf_miibus);
142049076Swpaul
142149076Swpaul	ptr = (u_int32_t *)&stats;
142249076Swpaul	for (i = 0; i < sizeof(stats)/sizeof(u_int32_t); i++)
142349076Swpaul		ptr[i] = csr_read_4(sc, SF_STATS_BASE +
142449076Swpaul		    (i + sizeof(u_int32_t)));
142549076Swpaul
142649076Swpaul	for (i = 0; i < sizeof(stats)/sizeof(u_int32_t); i++)
142749076Swpaul		csr_write_4(sc, SF_STATS_BASE +
142849076Swpaul		    (i + sizeof(u_int32_t)), 0);
142949076Swpaul
143049076Swpaul	ifp->if_collisions += stats.sf_tx_single_colls +
143149076Swpaul	    stats.sf_tx_multi_colls + stats.sf_tx_excess_colls;
143249076Swpaul
143350675Swpaul	mii_tick(mii);
143454161Swpaul	if (!sc->sf_link) {
143554161Swpaul		mii_pollstat(mii);
143654161Swpaul		if (mii->mii_media_status & IFM_ACTIVE &&
143754161Swpaul		    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE)
143854161Swpaul			sc->sf_link++;
143954161Swpaul			if (ifp->if_snd.ifq_head != NULL)
144054161Swpaul				sf_start(ifp);
144154161Swpaul	}
144250675Swpaul
144349076Swpaul	sc->sf_stat_ch = timeout(sf_stats_update, sc, hz);
144449076Swpaul
144549076Swpaul	splx(s);
144649076Swpaul
144749076Swpaul	return;
144849076Swpaul}
144949076Swpaul
145049076Swpaulstatic void sf_watchdog(ifp)
145149076Swpaul	struct ifnet		*ifp;
145249076Swpaul{
145349076Swpaul	struct sf_softc		*sc;
145449076Swpaul
145549076Swpaul	sc = ifp->if_softc;
145649076Swpaul
145749076Swpaul	ifp->if_oerrors++;
145849076Swpaul	printf("sf%d: watchdog timeout\n", sc->sf_unit);
145949076Swpaul
146049076Swpaul	sf_stop(sc);
146149076Swpaul	sf_reset(sc);
146249076Swpaul	sf_init(sc);
146349076Swpaul
146449076Swpaul	if (ifp->if_snd.ifq_head != NULL)
146549076Swpaul		sf_start(ifp);
146649076Swpaul
146749076Swpaul	return;
146849076Swpaul}
146949076Swpaul
147049076Swpaulstatic void sf_shutdown(dev)
147149076Swpaul	device_t		dev;
147249076Swpaul{
147349076Swpaul	struct sf_softc		*sc;
147449076Swpaul
147549076Swpaul	sc = device_get_softc(dev);
147649076Swpaul
147749076Swpaul	sf_stop(sc);
147849076Swpaul
147949076Swpaul	return;
148049076Swpaul}
1481