if_sf.c revision 51336
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 51336 1999-09-17 00:47:41Z wpaul $
3349076Swpaul */
3449076Swpaul
3549076Swpaul/*
3649076Swpaul * Adaptec AIC-6915 "Starfire" PCI fast ethernet driver for FreeBSD.
3749076Swpaul * Programming manual is available from www.adaptec.com.
3849076Swpaul *
3949076Swpaul * Written by Bill Paul <wpaul@ctr.columbia.edu>
4049076Swpaul * Department of Electical Engineering
4149076Swpaul * Columbia University, New York City
4249076Swpaul */
4349076Swpaul
4449076Swpaul/*
4549076Swpaul * The Adaptec AIC-6915 "Starfire" is a 64-bit 10/100 PCI ethernet
4649076Swpaul * controller designed with flexibility and reducing CPU load in mind.
4749076Swpaul * The Starfire offers high and low priority buffer queues, a
4849076Swpaul * producer/consumer index mechanism and several different buffer
4949076Swpaul * queue and completion queue descriptor types. Any one of a number
5049076Swpaul * of different driver designs can be used, depending on system and
5149076Swpaul * OS requirements. This driver makes use of type0 transmit frame
5249076Swpaul * descriptors (since BSD fragments packets across an mbuf chain)
5349076Swpaul * and two RX buffer queues prioritized on size (one queue for small
5449076Swpaul * frames that will fit into a single mbuf, another with full size
5549076Swpaul * mbuf clusters for everything else). The producer/consumer indexes
5649076Swpaul * and completion queues are also used.
5749076Swpaul *
5849076Swpaul * One downside to the Starfire has to do with alignment: buffer
5949076Swpaul * queues must be aligned on 256-byte boundaries, and receive buffers
6049076Swpaul * must be aligned on longword boundaries. The receive buffer alignment
6149076Swpaul * causes problems on the Alpha platform, where the packet payload
6249076Swpaul * should be longword aligned. There is no simple way around this.
6349076Swpaul *
6449076Swpaul * For receive filtering, the Starfire offers 16 perfect filter slots
6549076Swpaul * and a 512-bit hash table.
6649076Swpaul *
6749076Swpaul * The Starfire has no internal transceiver, relying instead on an
6849076Swpaul * external MII-based transceiver. Accessing registers on external
6949076Swpaul * PHYs is done through a special register map rather than with the
7049076Swpaul * usual bitbang MDIO method.
7149076Swpaul *
7249076Swpaul * Acesssing the registers on the Starfire is a little tricky. The
7349076Swpaul * Starfire has a 512K internal register space. When programmed for
7449076Swpaul * PCI memory mapped mode, the entire register space can be accessed
7549076Swpaul * directly. However in I/O space mode, only 256 bytes are directly
7649076Swpaul * mapped into PCI I/O space. The other registers can be accessed
7749076Swpaul * indirectly using the SF_INDIRECTIO_ADDR and SF_INDIRECTIO_DATA
7849076Swpaul * registers inside the 256-byte I/O window.
7949076Swpaul */
8049076Swpaul
8149076Swpaul#include "bpf.h"
8249076Swpaul
8349076Swpaul#include <sys/param.h>
8449076Swpaul#include <sys/systm.h>
8549076Swpaul#include <sys/sockio.h>
8649076Swpaul#include <sys/mbuf.h>
8749076Swpaul#include <sys/malloc.h>
8849076Swpaul#include <sys/kernel.h>
8949076Swpaul#include <sys/socket.h>
9049076Swpaul
9149076Swpaul#include <net/if.h>
9249076Swpaul#include <net/if_arp.h>
9349076Swpaul#include <net/ethernet.h>
9449076Swpaul#include <net/if_dl.h>
9549076Swpaul#include <net/if_media.h>
9649076Swpaul
9749076Swpaul#if NBPF > 0
9849076Swpaul#include <net/bpf.h>
9949076Swpaul#endif
10049076Swpaul
10149076Swpaul#include <vm/vm.h>              /* for vtophys */
10249076Swpaul#include <vm/pmap.h>            /* for vtophys */
10349076Swpaul#include <machine/clock.h>      /* for DELAY */
10449076Swpaul#include <machine/bus_pio.h>
10549076Swpaul#include <machine/bus_memio.h>
10649076Swpaul#include <machine/bus.h>
10749076Swpaul#include <machine/resource.h>
10849076Swpaul#include <sys/bus.h>
10949076Swpaul#include <sys/rman.h>
11049076Swpaul
11150675Swpaul#include <dev/mii/mii.h>
11250675Swpaul#include <dev/mii/miivar.h>
11350675Swpaul
11451089Speter/* "controller miibus0" required.  See GENERIC if you get errors here. */
11550675Swpaul#include "miibus_if.h"
11650675Swpaul
11749076Swpaul#include <pci/pcireg.h>
11849076Swpaul#include <pci/pcivar.h>
11949076Swpaul
12049076Swpaul#define SF_USEIOSPACE
12149076Swpaul
12249076Swpaul#include <pci/if_sfreg.h>
12349076Swpaul
12449076Swpaul#ifndef lint
12549076Swpaulstatic const char rcsid[] =
12650477Speter  "$FreeBSD: head/sys/dev/sf/if_sf.c 51336 1999-09-17 00:47:41Z wpaul $";
12749076Swpaul#endif
12849076Swpaul
12949076Swpaulstatic struct sf_type sf_devs[] = {
13049076Swpaul	{ AD_VENDORID, AD_DEVICEID_STARFIRE,
13149076Swpaul		"Adaptec AIC-6915 10/100BaseTX" },
13249076Swpaul	{ 0, 0, NULL }
13349076Swpaul};
13449076Swpaul
13549076Swpaulstatic int sf_probe		__P((device_t));
13649076Swpaulstatic int sf_attach		__P((device_t));
13749076Swpaulstatic int sf_detach		__P((device_t));
13849076Swpaulstatic void sf_intr		__P((void *));
13949076Swpaulstatic void sf_stats_update	__P((void *));
14049076Swpaulstatic void sf_rxeof		__P((struct sf_softc *));
14149076Swpaulstatic void sf_txeof		__P((struct sf_softc *));
14249076Swpaulstatic int sf_encap		__P((struct sf_softc *,
14349076Swpaul					struct sf_tx_bufdesc_type0 *,
14449076Swpaul					struct mbuf *));
14549076Swpaulstatic void sf_start		__P((struct ifnet *));
14649076Swpaulstatic int sf_ioctl		__P((struct ifnet *, u_long, caddr_t));
14749076Swpaulstatic void sf_init		__P((void *));
14849076Swpaulstatic void sf_stop		__P((struct sf_softc *));
14949076Swpaulstatic void sf_watchdog		__P((struct ifnet *));
15049076Swpaulstatic void sf_shutdown		__P((device_t));
15149076Swpaulstatic int sf_ifmedia_upd	__P((struct ifnet *));
15249076Swpaulstatic void sf_ifmedia_sts	__P((struct ifnet *, struct ifmediareq *));
15349076Swpaulstatic void sf_reset		__P((struct sf_softc *));
15449076Swpaulstatic int sf_init_rx_ring	__P((struct sf_softc *));
15549076Swpaulstatic void sf_init_tx_ring	__P((struct sf_softc *));
15649076Swpaulstatic int sf_newbuf		__P((struct sf_softc *,
15749076Swpaul					struct sf_rx_bufdesc_type0 *,
15849076Swpaul					struct mbuf *));
15949076Swpaulstatic void sf_setmulti		__P((struct sf_softc *));
16049076Swpaulstatic int sf_setperf		__P((struct sf_softc *, int, caddr_t));
16149076Swpaulstatic int sf_sethash		__P((struct sf_softc *, caddr_t, int));
16249076Swpaul#ifdef notdef
16349076Swpaulstatic int sf_setvlan		__P((struct sf_softc *, int, u_int32_t));
16449076Swpaul#endif
16549076Swpaul
16649076Swpaulstatic u_int8_t sf_read_eeprom	__P((struct sf_softc *, int));
16749076Swpaulstatic u_int32_t sf_calchash	__P((caddr_t));
16849076Swpaul
16950675Swpaulstatic int sf_miibus_readreg	__P((device_t, int, int));
17050675Swpaulstatic int sf_miibus_writereg	__P((device_t, int, int, int));
17150675Swpaulstatic void sf_miibus_statchg	__P((device_t));
17249076Swpaul
17349076Swpaulstatic u_int32_t csr_read_4	__P((struct sf_softc *, int));
17449076Swpaulstatic void csr_write_4		__P((struct sf_softc *, int, u_int32_t));
17549076Swpaul
17649076Swpaul#ifdef SF_USEIOSPACE
17749076Swpaul#define SF_RES			SYS_RES_IOPORT
17849076Swpaul#define SF_RID			SF_PCI_LOIO
17949076Swpaul#else
18049076Swpaul#define SF_RES			SYS_RES_MEMORY
18149076Swpaul#define SF_RID			SF_PCI_LOMEM
18249076Swpaul#endif
18349076Swpaul
18449076Swpaulstatic device_method_t sf_methods[] = {
18549076Swpaul	/* Device interface */
18649076Swpaul	DEVMETHOD(device_probe,		sf_probe),
18749076Swpaul	DEVMETHOD(device_attach,	sf_attach),
18849076Swpaul	DEVMETHOD(device_detach,	sf_detach),
18949076Swpaul	DEVMETHOD(device_shutdown,	sf_shutdown),
19050675Swpaul
19150675Swpaul	/* bus interface */
19250675Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
19350675Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
19450675Swpaul
19550675Swpaul	/* MII interface */
19650675Swpaul	DEVMETHOD(miibus_readreg,	sf_miibus_readreg),
19750675Swpaul	DEVMETHOD(miibus_writereg,	sf_miibus_writereg),
19850675Swpaul	DEVMETHOD(miibus_statchg,	sf_miibus_statchg),
19950675Swpaul
20049076Swpaul	{ 0, 0 }
20149076Swpaul};
20249076Swpaul
20349076Swpaulstatic driver_t sf_driver = {
20449076Swpaul	"sf",
20549076Swpaul	sf_methods,
20649076Swpaul	sizeof(struct sf_softc),
20749076Swpaul};
20849076Swpaul
20949076Swpaulstatic devclass_t sf_devclass;
21049076Swpaul
21149076SwpaulDRIVER_MODULE(sf, pci, sf_driver, sf_devclass, 0, 0);
21250675SwpaulDRIVER_MODULE(miibus, sf, miibus_driver, miibus_devclass, 0, 0);
21349076Swpaul
21449076Swpaul#define SF_SETBIT(sc, reg, x)	\
21549076Swpaul	csr_write_4(sc, reg, csr_read_4(sc, reg) | x)
21649076Swpaul
21749076Swpaul#define SF_CLRBIT(sc, reg, x)				\
21849076Swpaul	csr_write_4(sc, reg, csr_read_4(sc, reg) & ~x)
21949076Swpaul
22049076Swpaulstatic u_int32_t csr_read_4(sc, reg)
22149076Swpaul	struct sf_softc		*sc;
22249076Swpaul	int			reg;
22349076Swpaul{
22449076Swpaul	u_int32_t		val;
22549076Swpaul
22649076Swpaul#ifdef SF_USEIOSPACE
22749076Swpaul	CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE);
22849076Swpaul	val = CSR_READ_4(sc, SF_INDIRECTIO_DATA);
22949076Swpaul#else
23049076Swpaul	val = CSR_READ_4(sc, (reg + SF_RMAP_INTREG_BASE));
23149076Swpaul#endif
23249076Swpaul
23349076Swpaul	return(val);
23449076Swpaul}
23549076Swpaul
23649076Swpaulstatic u_int8_t sf_read_eeprom(sc, reg)
23749076Swpaul	struct sf_softc		*sc;
23849076Swpaul	int			reg;
23949076Swpaul{
24049076Swpaul	u_int8_t		val;
24149076Swpaul
24249076Swpaul	val = (csr_read_4(sc, SF_EEADDR_BASE +
24349076Swpaul	    (reg & 0xFFFFFFFC)) >> (8 * (reg & 3))) & 0xFF;
24449076Swpaul
24549076Swpaul	return(val);
24649076Swpaul}
24749076Swpaul
24849076Swpaulstatic void csr_write_4(sc, reg, val)
24949076Swpaul	struct sf_softc		*sc;
25049076Swpaul	int			reg;
25149076Swpaul	u_int32_t		val;
25249076Swpaul{
25349076Swpaul#ifdef SF_USEIOSPACE
25449076Swpaul	CSR_WRITE_4(sc, SF_INDIRECTIO_ADDR, reg + SF_RMAP_INTREG_BASE);
25549076Swpaul	CSR_WRITE_4(sc, SF_INDIRECTIO_DATA, val);
25649076Swpaul#else
25749076Swpaul	CSR_WRITE_4(sc, (reg + SF_RMAP_INTREG_BASE), val);
25849076Swpaul#endif
25949076Swpaul	return;
26049076Swpaul}
26149076Swpaul
26249076Swpaulstatic u_int32_t sf_calchash(addr)
26349076Swpaul	caddr_t			addr;
26449076Swpaul{
26549076Swpaul	u_int32_t		crc, carry;
26649076Swpaul	int			i, j;
26749076Swpaul	u_int8_t		c;
26849076Swpaul
26949076Swpaul	/* Compute CRC for the address value. */
27049076Swpaul	crc = 0xFFFFFFFF; /* initial value */
27149076Swpaul
27249076Swpaul	for (i = 0; i < 6; i++) {
27349076Swpaul		c = *(addr + i);
27449076Swpaul		for (j = 0; j < 8; j++) {
27549076Swpaul			carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
27649076Swpaul			crc <<= 1;
27749076Swpaul			c >>= 1;
27849076Swpaul			if (carry)
27949076Swpaul				crc = (crc ^ 0x04c11db6) | carry;
28049076Swpaul		}
28149076Swpaul	}
28249076Swpaul
28349076Swpaul	/* return the filter bit position */
28449076Swpaul	return(crc >> 23 & 0x1FF);
28549076Swpaul}
28649076Swpaul
28749076Swpaul/*
28849076Swpaul * Copy the address 'mac' into the perfect RX filter entry at
28949076Swpaul * offset 'idx.' The perfect filter only has 16 entries so do
29049076Swpaul * some sanity tests.
29149076Swpaul */
29249076Swpaulstatic int sf_setperf(sc, idx, mac)
29349076Swpaul	struct sf_softc		*sc;
29449076Swpaul	int			idx;
29549076Swpaul	caddr_t			mac;
29649076Swpaul{
29749076Swpaul	u_int16_t		*p;
29849076Swpaul
29949076Swpaul	if (idx < 0 || idx > SF_RXFILT_PERFECT_CNT)
30049076Swpaul		return(EINVAL);
30149076Swpaul
30249076Swpaul	if (mac == NULL)
30349076Swpaul		return(EINVAL);
30449076Swpaul
30549076Swpaul	p = (u_int16_t *)mac;
30649076Swpaul
30749076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
30849076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP), htons(p[2]));
30949076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
31049076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP) + 4, htons(p[1]));
31149076Swpaul	csr_write_4(sc, SF_RXFILT_PERFECT_BASE +
31249076Swpaul	    (idx * SF_RXFILT_PERFECT_SKIP) + 8, htons(p[0]));
31349076Swpaul
31449076Swpaul	return(0);
31549076Swpaul}
31649076Swpaul
31749076Swpaul/*
31849076Swpaul * Set the bit in the 512-bit hash table that corresponds to the
31949076Swpaul * specified mac address 'mac.' If 'prio' is nonzero, update the
32049076Swpaul * priority hash table instead of the filter hash table.
32149076Swpaul */
32249076Swpaulstatic int sf_sethash(sc, mac, prio)
32349076Swpaul	struct sf_softc		*sc;
32449076Swpaul	caddr_t			mac;
32549076Swpaul	int			prio;
32649076Swpaul{
32749076Swpaul	u_int32_t		h = 0;
32849076Swpaul
32949076Swpaul	if (mac == NULL)
33049076Swpaul		return(EINVAL);
33149076Swpaul
33249076Swpaul	h = sf_calchash(mac);
33349076Swpaul
33449076Swpaul	if (prio) {
33549076Swpaul		SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_PRIOOFF +
33649076Swpaul		    (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF)));
33749076Swpaul	} else {
33849076Swpaul		SF_SETBIT(sc, SF_RXFILT_HASH_BASE + SF_RXFILT_HASH_ADDROFF +
33949076Swpaul		    (SF_RXFILT_HASH_SKIP * (h >> 4)), (1 << (h & 0xF)));
34049076Swpaul	}
34149076Swpaul
34249076Swpaul	return(0);
34349076Swpaul}
34449076Swpaul
34549076Swpaul#ifdef notdef
34649076Swpaul/*
34749076Swpaul * Set a VLAN tag in the receive filter.
34849076Swpaul */
34949076Swpaulstatic int sf_setvlan(sc, idx, vlan)
35049076Swpaul	struct sf_softc		*sc;
35149076Swpaul	int			idx;
35249076Swpaul	u_int32_t		vlan;
35349076Swpaul{
35449076Swpaul	if (idx < 0 || idx >> SF_RXFILT_HASH_CNT)
35549076Swpaul		return(EINVAL);
35649076Swpaul
35749076Swpaul	csr_write_4(sc, SF_RXFILT_HASH_BASE +
35849076Swpaul	    (idx * SF_RXFILT_HASH_SKIP) + SF_RXFILT_HASH_VLANOFF, vlan);
35949076Swpaul
36049076Swpaul	return(0);
36149076Swpaul}
36249076Swpaul#endif
36349076Swpaul
36450675Swpaulstatic int sf_miibus_readreg(dev, phy, reg)
36550675Swpaul	device_t		dev;
36650675Swpaul	int			phy, reg;
36750675Swpaul{
36849076Swpaul	struct sf_softc		*sc;
36949076Swpaul	int			i;
37049076Swpaul	u_int32_t		val = 0;
37149076Swpaul
37250675Swpaul	sc = device_get_softc(dev);
37350675Swpaul
37449076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
37550675Swpaul		val = csr_read_4(sc, SF_PHY_REG(phy, reg));
37649076Swpaul		if (val & SF_MII_DATAVALID)
37749076Swpaul			break;
37849076Swpaul	}
37949076Swpaul
38049076Swpaul	if (i == SF_TIMEOUT)
38149076Swpaul		return(0);
38249076Swpaul
38349076Swpaul	if ((val & 0x0000FFFF) == 0xFFFF)
38449076Swpaul		return(0);
38549076Swpaul
38649076Swpaul	return(val & 0x0000FFFF);
38749076Swpaul}
38849076Swpaul
38950675Swpaulstatic int sf_miibus_writereg(dev, phy, reg, val)
39050675Swpaul	device_t		dev;
39150675Swpaul	int			phy, reg, val;
39250675Swpaul{
39349076Swpaul	struct sf_softc		*sc;
39449076Swpaul	int			i;
39549076Swpaul	int			busy;
39649076Swpaul
39750675Swpaul	sc = device_get_softc(dev);
39849076Swpaul
39950675Swpaul	csr_write_4(sc, SF_PHY_REG(phy, reg), val);
40050675Swpaul
40149076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
40250675Swpaul		busy = csr_read_4(sc, SF_PHY_REG(phy, reg));
40349076Swpaul		if (!(busy & SF_MII_BUSY))
40449076Swpaul			break;
40549076Swpaul	}
40649076Swpaul
40750675Swpaul	return(0);
40850675Swpaul}
40950675Swpaul
41050675Swpaulstatic void sf_miibus_statchg(dev)
41150675Swpaul	device_t		dev;
41250675Swpaul{
41350675Swpaul	struct sf_softc		*sc;
41450675Swpaul	struct mii_data		*mii;
41550675Swpaul
41650675Swpaul	sc = device_get_softc(dev);
41750675Swpaul	mii = device_get_softc(sc->sf_miibus);
41850675Swpaul
41950675Swpaul	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
42050675Swpaul		SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX);
42150675Swpaul	} else {
42250675Swpaul		SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX);
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;
45149076Swpaul		/* First find the tail of the list. */
45249076Swpaul		for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
45349076Swpaul					ifma = ifma->ifma_link.le_next) {
45449076Swpaul			if (ifma->ifma_link.le_next == NULL)
45549076Swpaul				break;
45649076Swpaul		}
45749076Swpaul		/* Now traverse the list backwards. */
45849076Swpaul		for (; ifma != NULL && ifma != (void *)&ifp->if_multiaddrs;
45949076Swpaul			ifma = (struct ifmultiaddr *)ifma->ifma_link.le_prev) {
46049076Swpaul			if (ifma->ifma_addr->sa_family != AF_LINK)
46149076Swpaul				continue;
46249076Swpaul			/*
46349076Swpaul			 * Program the first 15 multicast groups
46449076Swpaul			 * into the perfect filter. For all others,
46549076Swpaul			 * use the hash table.
46649076Swpaul			 */
46749076Swpaul			if (i < SF_RXFILT_PERFECT_CNT) {
46849076Swpaul				sf_setperf(sc, i,
46949076Swpaul			LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
47049076Swpaul				i++;
47149076Swpaul				continue;
47249076Swpaul			}
47349076Swpaul
47449076Swpaul			sf_sethash(sc,
47549076Swpaul			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr), 0);
47649076Swpaul		}
47749076Swpaul	}
47849076Swpaul
47949076Swpaul	return;
48049076Swpaul}
48149076Swpaul
48249076Swpaul/*
48349076Swpaul * Set media options.
48449076Swpaul */
48549076Swpaulstatic int sf_ifmedia_upd(ifp)
48649076Swpaul	struct ifnet		*ifp;
48749076Swpaul{
48849076Swpaul	struct sf_softc		*sc;
48950675Swpaul	struct mii_data		*mii;
49049076Swpaul
49149076Swpaul	sc = ifp->if_softc;
49250675Swpaul	mii = device_get_softc(sc->sf_miibus);
49350675Swpaul	mii_mediachg(mii);
49449076Swpaul
49549076Swpaul	return(0);
49649076Swpaul}
49749076Swpaul
49849076Swpaul/*
49949076Swpaul * Report current media status.
50049076Swpaul */
50149076Swpaulstatic void sf_ifmedia_sts(ifp, ifmr)
50249076Swpaul	struct ifnet		*ifp;
50349076Swpaul	struct ifmediareq	*ifmr;
50449076Swpaul{
50549076Swpaul	struct sf_softc		*sc;
50650675Swpaul	struct mii_data		*mii;
50749076Swpaul
50849076Swpaul	sc = ifp->if_softc;
50950675Swpaul	mii = device_get_softc(sc->sf_miibus);
51049076Swpaul
51150675Swpaul	mii_pollstat(mii);
51250675Swpaul	ifmr->ifm_active = mii->mii_media_active;
51350675Swpaul	ifmr->ifm_status = mii->mii_media_status;
51449076Swpaul
51549076Swpaul	return;
51649076Swpaul}
51749076Swpaul
51849076Swpaulstatic int sf_ioctl(ifp, command, data)
51949076Swpaul	struct ifnet		*ifp;
52049076Swpaul	u_long			command;
52149076Swpaul	caddr_t			data;
52249076Swpaul{
52349076Swpaul	struct sf_softc		*sc = ifp->if_softc;
52449076Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
52550675Swpaul	struct mii_data		*mii;
52649076Swpaul	int			s, error = 0;
52749076Swpaul
52849076Swpaul	s = splimp();
52949076Swpaul
53049076Swpaul	switch(command) {
53149076Swpaul	case SIOCSIFADDR:
53249076Swpaul	case SIOCGIFADDR:
53349076Swpaul	case SIOCSIFMTU:
53449076Swpaul		error = ether_ioctl(ifp, command, data);
53549076Swpaul		break;
53649076Swpaul	case SIOCSIFFLAGS:
53749076Swpaul		if (ifp->if_flags & IFF_UP) {
53849076Swpaul			sf_init(sc);
53949076Swpaul		} else {
54049076Swpaul			if (ifp->if_flags & IFF_RUNNING)
54149076Swpaul				sf_stop(sc);
54249076Swpaul		}
54349076Swpaul		error = 0;
54449076Swpaul		break;
54549076Swpaul	case SIOCADDMULTI:
54649076Swpaul	case SIOCDELMULTI:
54749076Swpaul		sf_setmulti(sc);
54849076Swpaul		error = 0;
54949076Swpaul		break;
55049076Swpaul	case SIOCGIFMEDIA:
55149076Swpaul	case SIOCSIFMEDIA:
55250675Swpaul		mii = device_get_softc(sc->sf_miibus);
55350675Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
55449076Swpaul		break;
55549076Swpaul	default:
55649076Swpaul		error = EINVAL;
55749076Swpaul		break;
55849076Swpaul	}
55949076Swpaul
56049076Swpaul	(void)splx(s);
56149076Swpaul
56249076Swpaul	return(error);
56349076Swpaul}
56449076Swpaul
56549076Swpaulstatic void sf_reset(sc)
56649076Swpaul	struct sf_softc		*sc;
56749076Swpaul{
56849076Swpaul	register int		i;
56949076Swpaul
57049076Swpaul	csr_write_4(sc, SF_GEN_ETH_CTL, 0);
57149076Swpaul	SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
57249076Swpaul	DELAY(1000);
57349076Swpaul	SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_SOFTRESET);
57449076Swpaul
57549076Swpaul	SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_RESET);
57649076Swpaul
57749076Swpaul	for (i = 0; i < SF_TIMEOUT; i++) {
57849076Swpaul		DELAY(10);
57949076Swpaul		if (!(csr_read_4(sc, SF_PCI_DEVCFG) & SF_PCIDEVCFG_RESET))
58049076Swpaul			break;
58149076Swpaul	}
58249076Swpaul
58349076Swpaul	if (i == SF_TIMEOUT)
58449076Swpaul		printf("sf%d: reset never completed!\n", sc->sf_unit);
58549076Swpaul
58649076Swpaul	/* Wait a little while for the chip to get its brains in order. */
58749076Swpaul	DELAY(1000);
58849076Swpaul	return;
58949076Swpaul}
59049076Swpaul
59149076Swpaul/*
59249076Swpaul * Probe for an Adaptec AIC-6915 chip. Check the PCI vendor and device
59349076Swpaul * IDs against our list and return a device name if we find a match.
59449076Swpaul * We also check the subsystem ID so that we can identify exactly which
59549076Swpaul * NIC has been found, if possible.
59649076Swpaul */
59749076Swpaulstatic int sf_probe(dev)
59849076Swpaul	device_t		dev;
59949076Swpaul{
60049076Swpaul	struct sf_type		*t;
60149076Swpaul
60249076Swpaul	t = sf_devs;
60349076Swpaul
60449076Swpaul	while(t->sf_name != NULL) {
60549076Swpaul		if ((pci_get_vendor(dev) == t->sf_vid) &&
60649076Swpaul		    (pci_get_device(dev) == t->sf_did)) {
60751336Swpaul			switch((pci_read_config(dev,
60851336Swpaul			    SF_PCI_SUBVEN_ID, 4) >> 16) & 0xFFFF) {
60949076Swpaul			case AD_SUBSYSID_62011_REV0:
61049076Swpaul			case AD_SUBSYSID_62011_REV1:
61149076Swpaul				device_set_desc(dev,
61249076Swpaul				    "Adaptec ANA-62011 10/100BaseTX");
61349076Swpaul				return(0);
61449076Swpaul				break;
61549076Swpaul			case AD_SUBSYSID_62022:
61649076Swpaul				device_set_desc(dev,
61749076Swpaul				    "Adaptec ANA-62022 10/100BaseTX");
61849076Swpaul				return(0);
61949076Swpaul				break;
62049076Swpaul			case AD_SUBSYSID_62044:
62149076Swpaul				device_set_desc(dev,
62249076Swpaul				    "Adaptec ANA-62044 10/100BaseTX");
62349076Swpaul				return(0);
62449076Swpaul				break;
62549076Swpaul			case AD_SUBSYSID_62020:
62649076Swpaul				device_set_desc(dev,
62749076Swpaul				    "Adaptec ANA-62020 10/100BaseFX");
62849076Swpaul				return(0);
62949076Swpaul				break;
63049076Swpaul			case AD_SUBSYSID_69011:
63149076Swpaul				device_set_desc(dev,
63249076Swpaul				    "Adaptec ANA-69011 10/100BaseTX");
63349076Swpaul				return(0);
63449076Swpaul				break;
63549076Swpaul			default:
63649076Swpaul				device_set_desc(dev, t->sf_name);
63749076Swpaul				return(0);
63849076Swpaul				break;
63949076Swpaul			}
64049076Swpaul		}
64149076Swpaul		t++;
64249076Swpaul	}
64349076Swpaul
64449076Swpaul	return(ENXIO);
64549076Swpaul}
64649076Swpaul
64749076Swpaul/*
64849076Swpaul * Attach the interface. Allocate softc structures, do ifmedia
64949076Swpaul * setup and ethernet/BPF attach.
65049076Swpaul */
65149076Swpaulstatic int sf_attach(dev)
65249076Swpaul	device_t		dev;
65349076Swpaul{
65449076Swpaul	int			s, i;
65549076Swpaul	u_int32_t		command;
65649076Swpaul	struct sf_softc		*sc;
65749076Swpaul	struct ifnet		*ifp;
65849076Swpaul	int			unit, rid, error = 0;
65949076Swpaul
66049076Swpaul	s = splimp();
66149076Swpaul
66249076Swpaul	sc = device_get_softc(dev);
66349076Swpaul	unit = device_get_unit(dev);
66449076Swpaul	bzero(sc, sizeof(struct sf_softc));
66549076Swpaul
66649076Swpaul	/*
66749076Swpaul	 * Handle power management nonsense.
66849076Swpaul	 */
66949076Swpaul	command = pci_read_config(dev, SF_PCI_CAPID, 4) & 0x000000FF;
67049076Swpaul	if (command == 0x01) {
67149076Swpaul
67249076Swpaul		command = pci_read_config(dev, SF_PCI_PWRMGMTCTRL, 4);
67349076Swpaul		if (command & SF_PSTATE_MASK) {
67449076Swpaul			u_int32_t		iobase, membase, irq;
67549076Swpaul
67649076Swpaul			/* Save important PCI config data. */
67749076Swpaul			iobase = pci_read_config(dev, SF_PCI_LOIO, 4);
67849076Swpaul			membase = pci_read_config(dev, SF_PCI_LOMEM, 4);
67949076Swpaul			irq = pci_read_config(dev, SF_PCI_INTLINE, 4);
68049076Swpaul
68149076Swpaul			/* Reset the power state. */
68249076Swpaul			printf("sf%d: chip is in D%d power mode "
68349076Swpaul			"-- setting to D0\n", unit, command & SF_PSTATE_MASK);
68449076Swpaul			command &= 0xFFFFFFFC;
68549076Swpaul			pci_write_config(dev, SF_PCI_PWRMGMTCTRL, command, 4);
68649076Swpaul
68749076Swpaul			/* Restore PCI config data. */
68849076Swpaul			pci_write_config(dev, SF_PCI_LOIO, iobase, 4);
68949076Swpaul			pci_write_config(dev, SF_PCI_LOMEM, membase, 4);
69049076Swpaul			pci_write_config(dev, SF_PCI_INTLINE, irq, 4);
69149076Swpaul		}
69249076Swpaul	}
69349076Swpaul
69449076Swpaul	/*
69549076Swpaul	 * Map control/status registers.
69649076Swpaul	 */
69749076Swpaul	command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
69849076Swpaul	command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
69949076Swpaul	pci_write_config(dev, PCI_COMMAND_STATUS_REG, command, 4);
70049076Swpaul	command = pci_read_config(dev, PCI_COMMAND_STATUS_REG, 4);
70149076Swpaul
70249076Swpaul#ifdef SF_USEIOSPACE
70349076Swpaul	if (!(command & PCIM_CMD_PORTEN)) {
70449076Swpaul		printf("sf%d: failed to enable I/O ports!\n", unit);
70549076Swpaul		error = ENXIO;
70649076Swpaul		goto fail;
70749076Swpaul	}
70849076Swpaul#else
70949076Swpaul	if (!(command & PCIM_CMD_MEMEN)) {
71049076Swpaul		printf("sf%d: failed to enable memory mapping!\n", unit);
71149076Swpaul		error = ENXIO;
71249076Swpaul		goto fail;
71349076Swpaul	}
71449076Swpaul#endif
71549076Swpaul
71649076Swpaul	rid = SF_RID;
71749076Swpaul	sc->sf_res = bus_alloc_resource(dev, SF_RES, &rid,
71849076Swpaul	    0, ~0, 1, RF_ACTIVE);
71949076Swpaul
72049076Swpaul	if (sc->sf_res == NULL) {
72149076Swpaul		printf ("sf%d: couldn't map ports\n", unit);
72249076Swpaul		error = ENXIO;
72349076Swpaul		goto fail;
72449076Swpaul	}
72549076Swpaul
72649076Swpaul	sc->sf_btag = rman_get_bustag(sc->sf_res);
72749076Swpaul	sc->sf_bhandle = rman_get_bushandle(sc->sf_res);
72849076Swpaul
72949076Swpaul	/* Allocate interrupt */
73049076Swpaul	rid = 0;
73149076Swpaul	sc->sf_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
73249076Swpaul	    RF_SHAREABLE | RF_ACTIVE);
73349076Swpaul
73449076Swpaul	if (sc->sf_irq == NULL) {
73549076Swpaul		printf("sf%d: couldn't map interrupt\n", unit);
73649076Swpaul		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
73749076Swpaul		error = ENXIO;
73849076Swpaul		goto fail;
73949076Swpaul	}
74049076Swpaul
74149076Swpaul	error = bus_setup_intr(dev, sc->sf_irq, INTR_TYPE_NET,
74249076Swpaul	    sf_intr, sc, &sc->sf_intrhand);
74349076Swpaul
74449076Swpaul	if (error) {
74549076Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_res);
74649076Swpaul		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
74749076Swpaul		printf("sf%d: couldn't set up irq\n", unit);
74849076Swpaul		goto fail;
74949076Swpaul	}
75049076Swpaul
75149076Swpaul	callout_handle_init(&sc->sf_stat_ch);
75249076Swpaul
75349076Swpaul	/* Reset the adapter. */
75449076Swpaul	sf_reset(sc);
75549076Swpaul
75649076Swpaul	/*
75749076Swpaul	 * Get station address from the EEPROM.
75849076Swpaul	 */
75949076Swpaul	for (i = 0; i < ETHER_ADDR_LEN; i++)
76049076Swpaul		sc->arpcom.ac_enaddr[i] =
76149076Swpaul		    sf_read_eeprom(sc, SF_EE_NODEADDR + ETHER_ADDR_LEN - i);
76249076Swpaul
76349076Swpaul	/*
76449076Swpaul	 * An Adaptec chip was detected. Inform the world.
76549076Swpaul	 */
76649076Swpaul	printf("sf%d: Ethernet address: %6D\n", unit,
76749076Swpaul	    sc->arpcom.ac_enaddr, ":");
76849076Swpaul
76949076Swpaul	sc->sf_unit = unit;
77049076Swpaul
77149076Swpaul	/* Allocate the descriptor queues. */
77249076Swpaul	sc->sf_ldata = contigmalloc(sizeof(struct sf_list_data), M_DEVBUF,
77350675Swpaul	    M_NOWAIT, 0x100000, 0xffffffff, PAGE_SIZE, 0);
77449076Swpaul
77549076Swpaul	if (sc->sf_ldata == NULL) {
77649076Swpaul		printf("sf%d: no memory for list buffers!\n", unit);
77749076Swpaul		bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
77849076Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
77949076Swpaul		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
78049076Swpaul		error = ENXIO;
78149076Swpaul		goto fail;
78249076Swpaul	}
78349076Swpaul
78449076Swpaul	bzero(sc->sf_ldata, sizeof(struct sf_list_data));
78549076Swpaul
78650675Swpaul	/* Do MII setup. */
78750675Swpaul	if (mii_phy_probe(dev, &sc->sf_miibus,
78850675Swpaul	    sf_ifmedia_upd, sf_ifmedia_sts)) {
78949076Swpaul		printf("sf%d: MII without any phy!\n", sc->sf_unit);
79049076Swpaul		free(sc->sf_ldata, M_DEVBUF);
79149076Swpaul		bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
79249076Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
79349076Swpaul		bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
79449076Swpaul		error = ENXIO;
79549076Swpaul		goto fail;
79649076Swpaul	}
79749076Swpaul
79849076Swpaul	ifp = &sc->arpcom.ac_if;
79949076Swpaul	ifp->if_softc = sc;
80049076Swpaul	ifp->if_unit = unit;
80149076Swpaul	ifp->if_name = "sf";
80249076Swpaul	ifp->if_mtu = ETHERMTU;
80349076Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
80449076Swpaul	ifp->if_ioctl = sf_ioctl;
80549076Swpaul	ifp->if_output = ether_output;
80649076Swpaul	ifp->if_start = sf_start;
80749076Swpaul	ifp->if_watchdog = sf_watchdog;
80849076Swpaul	ifp->if_init = sf_init;
80949076Swpaul	ifp->if_baudrate = 10000000;
81049076Swpaul	ifp->if_snd.ifq_maxlen = SF_TX_DLIST_CNT - 1;
81149076Swpaul
81249076Swpaul	/*
81349076Swpaul	 * Call MI attach routines.
81449076Swpaul	 */
81549076Swpaul	if_attach(ifp);
81649076Swpaul	ether_ifattach(ifp);
81749076Swpaul
81849076Swpaul#if NBPF > 0
81949076Swpaul	bpfattach(ifp, DLT_EN10MB, sizeof(struct ether_header));
82049076Swpaul#endif
82149076Swpaul
82249076Swpaulfail:
82349076Swpaul	splx(s);
82449076Swpaul	return(error);
82549076Swpaul}
82649076Swpaul
82749076Swpaulstatic int sf_detach(dev)
82849076Swpaul	device_t		dev;
82949076Swpaul{
83049076Swpaul	struct sf_softc		*sc;
83149076Swpaul	struct ifnet		*ifp;
83249076Swpaul	int			s;
83349076Swpaul
83449076Swpaul	s = splimp();
83549076Swpaul
83649076Swpaul	sc = device_get_softc(dev);
83749076Swpaul	ifp = &sc->arpcom.ac_if;
83849076Swpaul
83949076Swpaul	if_detach(ifp);
84049076Swpaul	sf_stop(sc);
84149076Swpaul
84250675Swpaul	bus_generic_detach(dev);
84350675Swpaul	device_delete_child(dev, sc->sf_miibus);
84450675Swpaul
84549076Swpaul	bus_teardown_intr(dev, sc->sf_irq, sc->sf_intrhand);
84649076Swpaul	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sf_irq);
84749076Swpaul	bus_release_resource(dev, SF_RES, SF_RID, sc->sf_res);
84849076Swpaul
84949076Swpaul	free(sc->sf_ldata, M_DEVBUF);
85049076Swpaul
85149076Swpaul	splx(s);
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
99249076Swpaul		m0 = m_devget(mtod(m, char *) - ETHER_ALIGN,
99349076Swpaul		    cur_rx->sf_len + ETHER_ALIGN, 0, ifp, NULL);
99449076Swpaul		sf_newbuf(sc, desc, m);
99549076Swpaul		if (m0 == NULL) {
99649076Swpaul			ifp->if_ierrors++;
99749076Swpaul			continue;
99849076Swpaul		}
99949076Swpaul		m_adj(m0, ETHER_ALIGN);
100049076Swpaul		m = m0;
100149076Swpaul
100249076Swpaul		eh = mtod(m, struct ether_header *);
100349076Swpaul		ifp->if_ipackets++;
100449076Swpaul
100549076Swpaul#if NBPF > 0
100649076Swpaul		if (ifp->if_bpf) {
100749076Swpaul			bpf_mtap(ifp, m);
100849076Swpaul			if (ifp->if_flags & IFF_PROMISC &&
100949076Swpaul			    (bcmp(eh->ether_dhost, sc->arpcom.ac_enaddr,
101049076Swpaul			    ETHER_ADDR_LEN) && !(eh->ether_dhost[0] & 1))) {
101149076Swpaul				m_freem(m);
101249076Swpaul				continue;
101349076Swpaul			}
101449076Swpaul		}
101549076Swpaul#endif
101649076Swpaul
101749076Swpaul		/* Remove header from mbuf and pass it on. */
101849076Swpaul		m_adj(m, sizeof(struct ether_header));
101949076Swpaul		ether_input(ifp, eh, m);
102049076Swpaul
102149076Swpaul	}
102249076Swpaul
102349076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX,
102449076Swpaul	    (rxcons & ~SF_CQ_CONSIDX_RXQ1) | cmpconsidx);
102549076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1,
102649076Swpaul	    (rxprod & ~SF_RXDQ_PRODIDX) | bufprodidx);
102749076Swpaul
102849076Swpaul	return;
102949076Swpaul}
103049076Swpaul
103149076Swpaul/*
103249076Swpaul * Read the transmit status from the completion queue and release
103349076Swpaul * mbufs. Note that the buffer descriptor index in the completion
103449076Swpaul * descriptor is an offset from the start of the transmit buffer
103549076Swpaul * descriptor list in bytes. This is important because the manual
103649076Swpaul * gives the impression that it should match the producer/consumer
103749076Swpaul * index, which is the offset in 8 byte blocks.
103849076Swpaul */
103949076Swpaulstatic void sf_txeof(sc)
104049076Swpaul	struct sf_softc		*sc;
104149076Swpaul{
104249076Swpaul	int			txcons, cmpprodidx, cmpconsidx;
104349076Swpaul	struct sf_tx_cmpdesc_type1 *cur_cmp;
104449076Swpaul	struct sf_tx_bufdesc_type0 *cur_tx;
104549076Swpaul	struct ifnet		*ifp;
104649076Swpaul
104749076Swpaul	ifp = &sc->arpcom.ac_if;
104849076Swpaul
104949076Swpaul	txcons = csr_read_4(sc, SF_CQ_CONSIDX);
105049076Swpaul	cmpprodidx = SF_IDX_HI(csr_read_4(sc, SF_CQ_PRODIDX));
105149076Swpaul	cmpconsidx = SF_IDX_HI(txcons);
105249076Swpaul
105349076Swpaul	while (cmpconsidx != cmpprodidx) {
105449076Swpaul		cur_cmp = &sc->sf_ldata->sf_tx_clist[cmpconsidx];
105549076Swpaul		cur_tx = &sc->sf_ldata->sf_tx_dlist[cur_cmp->sf_index >> 7];
105649076Swpaul		SF_INC(cmpconsidx, SF_TX_CLIST_CNT);
105749076Swpaul
105849076Swpaul		if (cur_cmp->sf_txstat & SF_TXSTAT_TX_OK)
105949076Swpaul			ifp->if_opackets++;
106049076Swpaul		else
106149076Swpaul			ifp->if_oerrors++;
106249076Swpaul
106349076Swpaul		sc->sf_tx_cnt--;
106449076Swpaul		if (cur_tx->sf_mbuf != NULL) {
106549076Swpaul			m_freem(cur_tx->sf_mbuf);
106649076Swpaul			cur_tx->sf_mbuf = NULL;
106749076Swpaul		}
106849076Swpaul	}
106949076Swpaul
107049076Swpaul	ifp->if_timer = 0;
107149076Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
107249076Swpaul
107349076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX,
107449076Swpaul	    (txcons & ~SF_CQ_CONSIDX_TXQ) |
107549076Swpaul	    ((cmpconsidx << 16) & 0xFFFF0000));
107649076Swpaul
107749076Swpaul	return;
107849076Swpaul}
107949076Swpaul
108049076Swpaulstatic void sf_intr(arg)
108149076Swpaul	void			*arg;
108249076Swpaul{
108349076Swpaul	struct sf_softc		*sc;
108449076Swpaul	struct ifnet		*ifp;
108549076Swpaul	u_int32_t		status;
108649076Swpaul
108749076Swpaul	sc = arg;
108849076Swpaul	ifp = &sc->arpcom.ac_if;
108949076Swpaul
109049076Swpaul	if (!(csr_read_4(sc, SF_ISR_SHADOW) & SF_ISR_PCIINT_ASSERTED))
109149076Swpaul		return;
109249076Swpaul
109349076Swpaul	/* Disable interrupts. */
109449076Swpaul	csr_write_4(sc, SF_IMR, 0x00000000);
109549076Swpaul
109649076Swpaul	for (;;) {
109749076Swpaul		status = csr_read_4(sc, SF_ISR);
109849076Swpaul		if (status)
109949076Swpaul			csr_write_4(sc, SF_ISR, status);
110049076Swpaul
110149076Swpaul		if (!(status & SF_INTRS))
110249076Swpaul			break;
110349076Swpaul
110449076Swpaul		if (status & SF_ISR_RXDQ1_DMADONE)
110549076Swpaul			sf_rxeof(sc);
110649076Swpaul
110749076Swpaul		if (status & SF_ISR_TX_TXDONE)
110849076Swpaul			sf_txeof(sc);
110949076Swpaul
111049076Swpaul		if (status & SF_ISR_ABNORMALINTR) {
111149076Swpaul			if (status & SF_ISR_STATSOFLOW) {
111249076Swpaul				untimeout(sf_stats_update, sc,
111349076Swpaul				    sc->sf_stat_ch);
111449076Swpaul				sf_stats_update(sc);
111549076Swpaul			} else
111649076Swpaul				sf_init(sc);
111749076Swpaul		}
111849076Swpaul	}
111949076Swpaul
112049076Swpaul	/* Re-enable interrupts. */
112149076Swpaul	csr_write_4(sc, SF_IMR, SF_INTRS);
112249076Swpaul
112349076Swpaul	if (ifp->if_snd.ifq_head != NULL)
112449076Swpaul		sf_start(ifp);
112549076Swpaul
112649076Swpaul	return;
112749076Swpaul}
112849076Swpaul
112949076Swpaulstatic void sf_init(xsc)
113049076Swpaul	void			*xsc;
113149076Swpaul{
113249076Swpaul	struct sf_softc		*sc;
113349076Swpaul	struct ifnet		*ifp;
113450675Swpaul	struct mii_data		*mii;
113549076Swpaul	int			i, s;
113649076Swpaul
113749076Swpaul	s = splimp();
113849076Swpaul
113949076Swpaul	sc = xsc;
114049076Swpaul	ifp = &sc->arpcom.ac_if;
114150675Swpaul	mii = device_get_softc(sc->sf_miibus);
114249076Swpaul
114349076Swpaul	sf_stop(sc);
114449076Swpaul	sf_reset(sc);
114549076Swpaul
114649076Swpaul	/* Init all the receive filter registers */
114749076Swpaul	for (i = SF_RXFILT_PERFECT_BASE;
114849076Swpaul	    i < (SF_RXFILT_HASH_MAX + 1); i += 4)
114949076Swpaul		csr_write_4(sc, i, 0);
115049076Swpaul
115149076Swpaul	/* Empty stats counter registers. */
115249076Swpaul	for (i = 0; i < sizeof(struct sf_stats)/sizeof(u_int32_t); i++)
115349076Swpaul		csr_write_4(sc, SF_STATS_BASE +
115449076Swpaul		    (i + sizeof(u_int32_t)), 0);
115549076Swpaul
115649076Swpaul	/* Init our MAC address */
115749076Swpaul	csr_write_4(sc, SF_PAR0, *(u_int32_t *)(&sc->arpcom.ac_enaddr[0]));
115849076Swpaul	csr_write_4(sc, SF_PAR1, *(u_int32_t *)(&sc->arpcom.ac_enaddr[4]));
115949076Swpaul	sf_setperf(sc, 0, (caddr_t)&sc->arpcom.ac_enaddr);
116049076Swpaul
116149076Swpaul	if (sf_init_rx_ring(sc) == ENOBUFS) {
116249076Swpaul		printf("sf%d: initialization failed: no "
116349076Swpaul		    "memory for rx buffers\n", sc->sf_unit);
116449076Swpaul		(void)splx(s);
116549076Swpaul		return;
116649076Swpaul	}
116749076Swpaul
116849076Swpaul	sf_init_tx_ring(sc);
116949076Swpaul
117049076Swpaul	csr_write_4(sc, SF_RXFILT, SF_PERFMODE_NORMAL|SF_HASHMODE_WITHVLAN);
117149076Swpaul
117249076Swpaul	/* If we want promiscuous mode, set the allframes bit. */
117349076Swpaul	if (ifp->if_flags & IFF_PROMISC) {
117449076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
117549076Swpaul	} else {
117649076Swpaul		SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_PROMISC);
117749076Swpaul	}
117849076Swpaul
117949076Swpaul	if (ifp->if_flags & IFF_BROADCAST) {
118049076Swpaul		SF_SETBIT(sc, SF_RXFILT, SF_RXFILT_BROAD);
118149076Swpaul	} else {
118249076Swpaul		SF_CLRBIT(sc, SF_RXFILT, SF_RXFILT_BROAD);
118349076Swpaul	}
118449076Swpaul
118549076Swpaul	/* Init the completion queue indexes */
118649076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX, 0);
118749076Swpaul	csr_write_4(sc, SF_CQ_PRODIDX, 0);
118849076Swpaul
118949076Swpaul	/* Init the RX completion queue */
119049076Swpaul	csr_write_4(sc, SF_RXCQ_CTL_1,
119149076Swpaul	    vtophys(sc->sf_ldata->sf_rx_clist) & SF_RXCQ_ADDR);
119249076Swpaul	SF_SETBIT(sc, SF_RXCQ_CTL_1, SF_RXCQTYPE_3);
119349076Swpaul
119449076Swpaul	/* Init RX DMA control. */
119549076Swpaul	SF_SETBIT(sc, SF_RXDMA_CTL, SF_RXDMA_REPORTBADPKTS);
119649076Swpaul
119749076Swpaul	/* Init the RX buffer descriptor queue. */
119849076Swpaul	csr_write_4(sc, SF_RXDQ_ADDR_Q1,
119949076Swpaul	    vtophys(sc->sf_ldata->sf_rx_dlist_big));
120049076Swpaul	csr_write_4(sc, SF_RXDQ_CTL_1, (MCLBYTES << 16) | SF_DESCSPACE_16BYTES);
120149076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1, SF_RX_DLIST_CNT - 1);
120249076Swpaul
120349076Swpaul	/* Init the TX completion queue */
120449076Swpaul	csr_write_4(sc, SF_TXCQ_CTL,
120549076Swpaul	    vtophys(sc->sf_ldata->sf_tx_clist) & SF_RXCQ_ADDR);
120649076Swpaul
120749076Swpaul	/* Init the TX buffer descriptor queue. */
120849076Swpaul	csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO,
120949076Swpaul		vtophys(sc->sf_ldata->sf_tx_dlist));
121049076Swpaul	SF_SETBIT(sc, SF_TX_FRAMCTL, SF_TXFRMCTL_CPLAFTERTX);
121149076Swpaul	csr_write_4(sc, SF_TXDQ_CTL,
121249076Swpaul	    SF_TXBUFDESC_TYPE0|SF_TXMINSPACE_128BYTES|SF_TXSKIPLEN_8BYTES);
121349076Swpaul	SF_SETBIT(sc, SF_TXDQ_CTL, SF_TXDQCTL_NODMACMP);
121449076Swpaul
121549076Swpaul	/* Enable autopadding of short TX frames. */
121649076Swpaul	SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_AUTOPAD);
121749076Swpaul
121849076Swpaul	/* Make sure the duplex mode is set correctly. */
121950675Swpaul	if ((mii->mii_media.ifm_media & IFM_GMASK) == IFM_FDX) {
122049076Swpaul		SF_SETBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX);
122149076Swpaul	} else {
122249076Swpaul		SF_CLRBIT(sc, SF_MACCFG_1, SF_MACCFG1_FULLDUPLEX);
122349076Swpaul	}
122449076Swpaul
122549076Swpaul	/* Enable interrupts. */
122649076Swpaul	csr_write_4(sc, SF_IMR, SF_INTRS);
122749076Swpaul	SF_SETBIT(sc, SF_PCI_DEVCFG, SF_PCIDEVCFG_INTR_ENB);
122849076Swpaul
122949076Swpaul	/* Enable the RX and TX engines. */
123049076Swpaul	SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_RX_ENB|SF_ETHCTL_RXDMA_ENB);
123149076Swpaul	SF_SETBIT(sc, SF_GEN_ETH_CTL, SF_ETHCTL_TX_ENB|SF_ETHCTL_TXDMA_ENB);
123249076Swpaul
123350675Swpaul	mii_mediachg(mii);
123450675Swpaul
123549076Swpaul	ifp->if_flags |= IFF_RUNNING;
123649076Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
123749076Swpaul
123849076Swpaul	sc->sf_stat_ch = timeout(sf_stats_update, sc, hz);
123949076Swpaul
124049076Swpaul	splx(s);
124149076Swpaul
124249076Swpaul	return;
124349076Swpaul}
124449076Swpaul
124549076Swpaulstatic int sf_encap(sc, c, m_head)
124649076Swpaul	struct sf_softc		*sc;
124749076Swpaul	struct sf_tx_bufdesc_type0 *c;
124849076Swpaul	struct mbuf		*m_head;
124949076Swpaul{
125049076Swpaul	int			frag = 0;
125149076Swpaul	struct sf_frag		*f = NULL;
125249076Swpaul	struct mbuf		*m;
125349076Swpaul
125449076Swpaul	m = m_head;
125549076Swpaul
125649076Swpaul	for (m = m_head, frag = 0; m != NULL; m = m->m_next) {
125749076Swpaul		if (m->m_len != 0) {
125849076Swpaul			if (frag == SF_MAXFRAGS)
125949076Swpaul				break;
126049076Swpaul			f = &c->sf_frags[frag];
126149076Swpaul			if (frag == 0)
126249076Swpaul				f->sf_pktlen = m_head->m_pkthdr.len;
126349076Swpaul			f->sf_fraglen = m->m_len;
126449076Swpaul			f->sf_addr = vtophys(mtod(m, vm_offset_t));
126549076Swpaul			frag++;
126649076Swpaul		}
126749076Swpaul	}
126849076Swpaul
126949076Swpaul	if (m != NULL) {
127049076Swpaul		struct mbuf		*m_new = NULL;
127149076Swpaul
127249076Swpaul		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
127349076Swpaul		if (m_new == NULL) {
127449076Swpaul			printf("sf%d: no memory for tx list", sc->sf_unit);
127549076Swpaul			return(1);
127649076Swpaul		}
127749076Swpaul
127849076Swpaul		if (m_head->m_pkthdr.len > MHLEN) {
127949076Swpaul			MCLGET(m_new, M_DONTWAIT);
128049076Swpaul			if (!(m_new->m_flags & M_EXT)) {
128149076Swpaul				m_freem(m_new);
128249076Swpaul				printf("sf%d: no memory for tx list",
128349076Swpaul				    sc->sf_unit);
128449076Swpaul				return(1);
128549076Swpaul			}
128649076Swpaul		}
128749076Swpaul		m_copydata(m_head, 0, m_head->m_pkthdr.len,
128849076Swpaul		    mtod(m_new, caddr_t));
128949076Swpaul		m_new->m_pkthdr.len = m_new->m_len = m_head->m_pkthdr.len;
129049076Swpaul		m_freem(m_head);
129149076Swpaul		m_head = m_new;
129249076Swpaul		f = &c->sf_frags[0];
129349076Swpaul		f->sf_fraglen = f->sf_pktlen = m_head->m_pkthdr.len;
129449076Swpaul		f->sf_addr = vtophys(mtod(m_head, caddr_t));
129549076Swpaul		frag = 1;
129649076Swpaul	}
129749076Swpaul
129849076Swpaul	c->sf_mbuf = m_head;
129949076Swpaul	c->sf_id = SF_TX_BUFDESC_ID;
130049076Swpaul	c->sf_fragcnt = frag;
130149076Swpaul	c->sf_intr = 1;
130249076Swpaul	c->sf_caltcp = 0;
130349076Swpaul	c->sf_crcen = 1;
130449076Swpaul
130549076Swpaul	return(0);
130649076Swpaul}
130749076Swpaul
130849076Swpaulstatic void sf_start(ifp)
130949076Swpaul	struct ifnet		*ifp;
131049076Swpaul{
131149076Swpaul	struct sf_softc		*sc;
131249076Swpaul	struct sf_tx_bufdesc_type0 *cur_tx = NULL;
131349076Swpaul	struct mbuf		*m_head = NULL;
131449076Swpaul	int			i, txprod;
131549076Swpaul
131649076Swpaul	sc = ifp->if_softc;
131749076Swpaul
131849076Swpaul	if (ifp->if_flags & IFF_OACTIVE)
131949076Swpaul		return;
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) {
132549076Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
132649076Swpaul		if (m_head == NULL)
132749076Swpaul			break;
132849076Swpaul
132949076Swpaul		cur_tx = &sc->sf_ldata->sf_tx_dlist[i];
133049076Swpaul		sf_encap(sc, cur_tx, m_head);
133149076Swpaul
133249076Swpaul		/*
133349076Swpaul		 * If there's a BPF listener, bounce a copy of this frame
133449076Swpaul		 * to him.
133549076Swpaul		 */
133649076Swpaul#if NBPF > 0
133749076Swpaul		if (ifp->if_bpf)
133849076Swpaul			bpf_mtap(ifp, m_head);
133949076Swpaul#endif
134049076Swpaul		SF_INC(i, SF_TX_DLIST_CNT);
134149076Swpaul		sc->sf_tx_cnt++;
134249076Swpaul		if (sc->sf_tx_cnt == (SF_TX_DLIST_CNT - 2))
134349076Swpaul			break;
134449076Swpaul	}
134549076Swpaul
134649076Swpaul	if (cur_tx == NULL)
134749076Swpaul		return;
134849076Swpaul
134949076Swpaul	/* Transmit */
135049076Swpaul	csr_write_4(sc, SF_TXDQ_PRODIDX,
135149076Swpaul	    (txprod & ~SF_TXDQ_PRODIDX_HIPRIO) |
135249076Swpaul	    ((i << 20) & 0xFFFF0000));
135349076Swpaul
135449076Swpaul	ifp->if_timer = 5;
135549076Swpaul
135649076Swpaul	return;
135749076Swpaul}
135849076Swpaul
135949076Swpaulstatic void sf_stop(sc)
136049076Swpaul	struct sf_softc		*sc;
136149076Swpaul{
136249076Swpaul	int			i;
136349077Swpaul	struct ifnet		*ifp;
136449076Swpaul
136549077Swpaul	ifp = &sc->arpcom.ac_if;
136649077Swpaul
136749076Swpaul	untimeout(sf_stats_update, sc, sc->sf_stat_ch);
136849076Swpaul
136949076Swpaul	csr_write_4(sc, SF_GEN_ETH_CTL, 0);
137049076Swpaul	csr_write_4(sc, SF_CQ_CONSIDX, 0);
137149076Swpaul	csr_write_4(sc, SF_CQ_PRODIDX, 0);
137249076Swpaul	csr_write_4(sc, SF_RXDQ_ADDR_Q1, 0);
137349076Swpaul	csr_write_4(sc, SF_RXDQ_CTL_1, 0);
137449076Swpaul	csr_write_4(sc, SF_RXDQ_PTR_Q1, 0);
137549076Swpaul	csr_write_4(sc, SF_TXCQ_CTL, 0);
137649076Swpaul	csr_write_4(sc, SF_TXDQ_ADDR_HIPRIO, 0);
137749076Swpaul	csr_write_4(sc, SF_TXDQ_CTL, 0);
137849076Swpaul	sf_reset(sc);
137949076Swpaul
138049076Swpaul	for (i = 0; i < SF_RX_DLIST_CNT; i++) {
138149076Swpaul		if (sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf != NULL) {
138249076Swpaul			m_freem(sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf);
138349076Swpaul			sc->sf_ldata->sf_rx_dlist_big[i].sf_mbuf = NULL;
138449076Swpaul		}
138549076Swpaul	}
138649076Swpaul
138749076Swpaul	for (i = 0; i < SF_TX_DLIST_CNT; i++) {
138849076Swpaul		if (sc->sf_ldata->sf_tx_dlist[i].sf_mbuf != NULL) {
138949076Swpaul			m_freem(sc->sf_ldata->sf_tx_dlist[i].sf_mbuf);
139049076Swpaul			sc->sf_ldata->sf_tx_dlist[i].sf_mbuf = NULL;
139149076Swpaul		}
139249076Swpaul	}
139349076Swpaul
139449077Swpaul	ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE);
139549077Swpaul
139649076Swpaul	return;
139749076Swpaul}
139849076Swpaul
139949076Swpaul/*
140049076Swpaul * Note: it is important that this function not be interrupted. We
140149076Swpaul * use a two-stage register access scheme: if we are interrupted in
140249076Swpaul * between setting the indirect address register and reading from the
140349076Swpaul * indirect data register, the contents of the address register could
140449076Swpaul * be changed out from under us.
140549076Swpaul */
140649076Swpaulstatic void sf_stats_update(xsc)
140749076Swpaul	void			*xsc;
140849076Swpaul{
140949076Swpaul	struct sf_softc		*sc;
141049076Swpaul	struct ifnet		*ifp;
141150675Swpaul	struct mii_data		*mii;
141249076Swpaul	struct sf_stats		stats;
141349076Swpaul	u_int32_t		*ptr;
141449076Swpaul	int			i, s;
141549076Swpaul
141649076Swpaul	s = splimp();
141749076Swpaul
141849076Swpaul	sc = xsc;
141949076Swpaul	ifp = &sc->arpcom.ac_if;
142050675Swpaul	mii = device_get_softc(sc->sf_miibus);
142149076Swpaul
142249076Swpaul	ptr = (u_int32_t *)&stats;
142349076Swpaul	for (i = 0; i < sizeof(stats)/sizeof(u_int32_t); i++)
142449076Swpaul		ptr[i] = csr_read_4(sc, SF_STATS_BASE +
142549076Swpaul		    (i + sizeof(u_int32_t)));
142649076Swpaul
142749076Swpaul	for (i = 0; i < sizeof(stats)/sizeof(u_int32_t); i++)
142849076Swpaul		csr_write_4(sc, SF_STATS_BASE +
142949076Swpaul		    (i + sizeof(u_int32_t)), 0);
143049076Swpaul
143149076Swpaul	ifp->if_collisions += stats.sf_tx_single_colls +
143249076Swpaul	    stats.sf_tx_multi_colls + stats.sf_tx_excess_colls;
143349076Swpaul
143450675Swpaul	mii_tick(mii);
143550675Swpaul
143649076Swpaul	sc->sf_stat_ch = timeout(sf_stats_update, sc, hz);
143749076Swpaul
143849076Swpaul	splx(s);
143949076Swpaul
144049076Swpaul	return;
144149076Swpaul}
144249076Swpaul
144349076Swpaulstatic void sf_watchdog(ifp)
144449076Swpaul	struct ifnet		*ifp;
144549076Swpaul{
144649076Swpaul	struct sf_softc		*sc;
144749076Swpaul
144849076Swpaul	sc = ifp->if_softc;
144949076Swpaul
145049076Swpaul	ifp->if_oerrors++;
145149076Swpaul	printf("sf%d: watchdog timeout\n", sc->sf_unit);
145249076Swpaul
145349076Swpaul	sf_stop(sc);
145449076Swpaul	sf_reset(sc);
145549076Swpaul	sf_init(sc);
145649076Swpaul
145749076Swpaul	if (ifp->if_snd.ifq_head != NULL)
145849076Swpaul		sf_start(ifp);
145949076Swpaul
146049076Swpaul	return;
146149076Swpaul}
146249076Swpaul
146349076Swpaulstatic void sf_shutdown(dev)
146449076Swpaul	device_t		dev;
146549076Swpaul{
146649076Swpaul	struct sf_softc		*sc;
146749076Swpaul
146849076Swpaul	sc = device_get_softc(dev);
146949076Swpaul
147049076Swpaul	sf_stop(sc);
147149076Swpaul
147249076Swpaul	return;
147349076Swpaul}
1474