if_sis.c revision 63090
150974Swpaul/*
250974Swpaul * Copyright (c) 1997, 1998, 1999
350974Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
450974Swpaul *
550974Swpaul * Redistribution and use in source and binary forms, with or without
650974Swpaul * modification, are permitted provided that the following conditions
750974Swpaul * are met:
850974Swpaul * 1. Redistributions of source code must retain the above copyright
950974Swpaul *    notice, this list of conditions and the following disclaimer.
1050974Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1150974Swpaul *    notice, this list of conditions and the following disclaimer in the
1250974Swpaul *    documentation and/or other materials provided with the distribution.
1350974Swpaul * 3. All advertising materials mentioning features or use of this software
1450974Swpaul *    must display the following acknowledgement:
1550974Swpaul *	This product includes software developed by Bill Paul.
1650974Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1750974Swpaul *    may be used to endorse or promote products derived from this software
1850974Swpaul *    without specific prior written permission.
1950974Swpaul *
2050974Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2150974Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2250974Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2350974Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2450974Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2550974Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2650974Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2750974Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2850974Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
2950974Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3050974Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
3150974Swpaul *
3250974Swpaul * $FreeBSD: head/sys/pci/if_sis.c 63090 2000-07-13 22:54:34Z archie $
3350974Swpaul */
3450974Swpaul
3550974Swpaul/*
3650974Swpaul * SiS 900/SiS 7016 fast ethernet PCI NIC driver. Datasheets are
3750974Swpaul * available from http://www.sis.com.tw.
3850974Swpaul *
3950974Swpaul * Written by Bill Paul <wpaul@ee.columbia.edu>
4050974Swpaul * Electrical Engineering Department
4150974Swpaul * Columbia University, New York City
4250974Swpaul */
4350974Swpaul
4450974Swpaul/*
4550974Swpaul * The SiS 900 is a fairly simple chip. It uses bus master DMA with
4650974Swpaul * simple TX and RX descriptors of 3 longwords in size. The receiver
4750974Swpaul * has a single perfect filter entry for the station address and a
4850974Swpaul * 128-bit multicast hash table. The SiS 900 has a built-in MII-based
4950974Swpaul * transceiver while the 7016 requires an external transceiver chip.
5050974Swpaul * Both chips offer the standard bit-bang MII interface as well as
5150974Swpaul * an enchanced PHY interface which simplifies accessing MII registers.
5250974Swpaul *
5350974Swpaul * The only downside to this chipset is that RX descriptors must be
5450974Swpaul * longword aligned.
5550974Swpaul */
5650974Swpaul
5750974Swpaul#include <sys/param.h>
5850974Swpaul#include <sys/systm.h>
5950974Swpaul#include <sys/sockio.h>
6050974Swpaul#include <sys/mbuf.h>
6150974Swpaul#include <sys/malloc.h>
6250974Swpaul#include <sys/kernel.h>
6350974Swpaul#include <sys/socket.h>
6450974Swpaul
6550974Swpaul#include <net/if.h>
6650974Swpaul#include <net/if_arp.h>
6750974Swpaul#include <net/ethernet.h>
6850974Swpaul#include <net/if_dl.h>
6950974Swpaul#include <net/if_media.h>
7050974Swpaul
7150974Swpaul#include <net/bpf.h>
7250974Swpaul
7350974Swpaul#include <vm/vm.h>              /* for vtophys */
7450974Swpaul#include <vm/pmap.h>            /* for vtophys */
7550974Swpaul#include <machine/clock.h>      /* for DELAY */
7650974Swpaul#include <machine/bus_pio.h>
7750974Swpaul#include <machine/bus_memio.h>
7850974Swpaul#include <machine/bus.h>
7950974Swpaul#include <machine/resource.h>
8050974Swpaul#include <sys/bus.h>
8150974Swpaul#include <sys/rman.h>
8250974Swpaul
8350974Swpaul#include <dev/mii/mii.h>
8450974Swpaul#include <dev/mii/miivar.h>
8550974Swpaul
8650974Swpaul#include <pci/pcireg.h>
8750974Swpaul#include <pci/pcivar.h>
8850974Swpaul
8950974Swpaul#define SIS_USEIOSPACE
9050974Swpaul
9150974Swpaul#include <pci/if_sisreg.h>
9250974Swpaul
9359758SpeterMODULE_DEPEND(sis, miibus, 1, 1, 1);
9459758Speter
9551089Speter/* "controller miibus0" required.  See GENERIC if you get errors here. */
9650974Swpaul#include "miibus_if.h"
9750974Swpaul
9850974Swpaul#ifndef lint
9950974Swpaulstatic const char rcsid[] =
10050974Swpaul  "$FreeBSD: head/sys/pci/if_sis.c 63090 2000-07-13 22:54:34Z archie $";
10150974Swpaul#endif
10250974Swpaul
10350974Swpaul/*
10450974Swpaul * Various supported device vendors/types and their names.
10550974Swpaul */
10650974Swpaulstatic struct sis_type sis_devs[] = {
10750974Swpaul	{ SIS_VENDORID, SIS_DEVICEID_900, "SiS 900 10/100BaseTX" },
10850974Swpaul	{ SIS_VENDORID, SIS_DEVICEID_7016, "SiS 7016 10/100BaseTX" },
10962672Swpaul	{ NS_VENDORID, NS_DEVICEID_DP83815, "NatSemi DP83815 10/100BaseTX" },
11050974Swpaul	{ 0, 0, NULL }
11150974Swpaul};
11250974Swpaul
11350974Swpaulstatic int sis_probe		__P((device_t));
11450974Swpaulstatic int sis_attach		__P((device_t));
11550974Swpaulstatic int sis_detach		__P((device_t));
11650974Swpaul
11750974Swpaulstatic int sis_newbuf		__P((struct sis_softc *,
11850974Swpaul					struct sis_desc *,
11950974Swpaul					struct mbuf *));
12050974Swpaulstatic int sis_encap		__P((struct sis_softc *,
12150974Swpaul					struct mbuf *, u_int32_t *));
12250974Swpaulstatic void sis_rxeof		__P((struct sis_softc *));
12350974Swpaulstatic void sis_rxeoc		__P((struct sis_softc *));
12450974Swpaulstatic void sis_txeof		__P((struct sis_softc *));
12550974Swpaulstatic void sis_intr		__P((void *));
12650974Swpaulstatic void sis_tick		__P((void *));
12750974Swpaulstatic void sis_start		__P((struct ifnet *));
12850974Swpaulstatic int sis_ioctl		__P((struct ifnet *, u_long, caddr_t));
12950974Swpaulstatic void sis_init		__P((void *));
13050974Swpaulstatic void sis_stop		__P((struct sis_softc *));
13150974Swpaulstatic void sis_watchdog		__P((struct ifnet *));
13250974Swpaulstatic void sis_shutdown		__P((device_t));
13350974Swpaulstatic int sis_ifmedia_upd	__P((struct ifnet *));
13450974Swpaulstatic void sis_ifmedia_sts	__P((struct ifnet *, struct ifmediareq *));
13550974Swpaul
13662672Swpaulstatic u_int16_t sis_reverse	__P((u_int16_t));
13750974Swpaulstatic void sis_delay		__P((struct sis_softc *));
13850974Swpaulstatic void sis_eeprom_idle	__P((struct sis_softc *));
13950974Swpaulstatic void sis_eeprom_putbyte	__P((struct sis_softc *, int));
14050974Swpaulstatic void sis_eeprom_getword	__P((struct sis_softc *, int, u_int16_t *));
14150974Swpaulstatic void sis_read_eeprom	__P((struct sis_softc *, caddr_t, int,
14250974Swpaul							int, int));
14350974Swpaulstatic int sis_miibus_readreg	__P((device_t, int, int));
14450974Swpaulstatic int sis_miibus_writereg	__P((device_t, int, int, int));
14550974Swpaulstatic void sis_miibus_statchg	__P((device_t));
14650974Swpaul
14762672Swpaulstatic void sis_setmulti_sis	__P((struct sis_softc *));
14862672Swpaulstatic void sis_setmulti_ns	__P((struct sis_softc *));
14962672Swpaulstatic u_int32_t sis_crc	__P((struct sis_softc *, caddr_t));
15050974Swpaulstatic void sis_reset		__P((struct sis_softc *));
15150974Swpaulstatic int sis_list_rx_init	__P((struct sis_softc *));
15250974Swpaulstatic int sis_list_tx_init	__P((struct sis_softc *));
15350974Swpaul
15450974Swpaul#ifdef SIS_USEIOSPACE
15550974Swpaul#define SIS_RES			SYS_RES_IOPORT
15650974Swpaul#define SIS_RID			SIS_PCI_LOIO
15750974Swpaul#else
15851030Swpaul#define SIS_RES			SYS_RES_MEMORY
15951030Swpaul#define SIS_RID			SIS_PCI_LOMEM
16050974Swpaul#endif
16150974Swpaul
16250974Swpaulstatic device_method_t sis_methods[] = {
16350974Swpaul	/* Device interface */
16450974Swpaul	DEVMETHOD(device_probe,		sis_probe),
16550974Swpaul	DEVMETHOD(device_attach,	sis_attach),
16650974Swpaul	DEVMETHOD(device_detach,	sis_detach),
16750974Swpaul	DEVMETHOD(device_shutdown,	sis_shutdown),
16850974Swpaul
16950974Swpaul	/* bus interface */
17050974Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
17150974Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
17250974Swpaul
17350974Swpaul	/* MII interface */
17450974Swpaul	DEVMETHOD(miibus_readreg,	sis_miibus_readreg),
17550974Swpaul	DEVMETHOD(miibus_writereg,	sis_miibus_writereg),
17650974Swpaul	DEVMETHOD(miibus_statchg,	sis_miibus_statchg),
17750974Swpaul
17850974Swpaul	{ 0, 0 }
17950974Swpaul};
18050974Swpaul
18150974Swpaulstatic driver_t sis_driver = {
18251455Swpaul	"sis",
18350974Swpaul	sis_methods,
18450974Swpaul	sizeof(struct sis_softc)
18550974Swpaul};
18650974Swpaul
18750974Swpaulstatic devclass_t sis_devclass;
18850974Swpaul
18951533SwpaulDRIVER_MODULE(if_sis, pci, sis_driver, sis_devclass, 0, 0);
19051473SwpaulDRIVER_MODULE(miibus, sis, miibus_driver, miibus_devclass, 0, 0);
19150974Swpaul
19250974Swpaul#define SIS_SETBIT(sc, reg, x)				\
19350974Swpaul	CSR_WRITE_4(sc, reg,				\
19450974Swpaul		CSR_READ_4(sc, reg) | (x))
19550974Swpaul
19650974Swpaul#define SIS_CLRBIT(sc, reg, x)				\
19750974Swpaul	CSR_WRITE_4(sc, reg,				\
19850974Swpaul		CSR_READ_4(sc, reg) & ~(x))
19950974Swpaul
20050974Swpaul#define SIO_SET(x)					\
20150974Swpaul	CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) | x)
20250974Swpaul
20350974Swpaul#define SIO_CLR(x)					\
20450974Swpaul	CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) & ~x)
20550974Swpaul
20662672Swpaul/*
20762672Swpaul * Routine to reverse the bits in a word. Stolen almost
20862672Swpaul * verbatim from /usr/games/fortune.
20962672Swpaul */
21062672Swpaulstatic u_int16_t sis_reverse(n)
21162672Swpaul	u_int16_t		n;
21262672Swpaul{
21362672Swpaul	n = ((n >>  1) & 0x5555) | ((n <<  1) & 0xaaaa);
21462672Swpaul	n = ((n >>  2) & 0x3333) | ((n <<  2) & 0xcccc);
21562672Swpaul	n = ((n >>  4) & 0x0f0f) | ((n <<  4) & 0xf0f0);
21662672Swpaul	n = ((n >>  8) & 0x00ff) | ((n <<  8) & 0xff00);
21762672Swpaul
21862672Swpaul	return(n);
21962672Swpaul}
22062672Swpaul
22150974Swpaulstatic void sis_delay(sc)
22250974Swpaul	struct sis_softc	*sc;
22350974Swpaul{
22450974Swpaul	int			idx;
22550974Swpaul
22650974Swpaul	for (idx = (300 / 33) + 1; idx > 0; idx--)
22750974Swpaul		CSR_READ_4(sc, SIS_CSR);
22850974Swpaul
22950974Swpaul	return;
23050974Swpaul}
23150974Swpaul
23250974Swpaulstatic void sis_eeprom_idle(sc)
23350974Swpaul	struct sis_softc	*sc;
23450974Swpaul{
23550974Swpaul	register int		i;
23650974Swpaul
23750974Swpaul	SIO_SET(SIS_EECTL_CSEL);
23850974Swpaul	sis_delay(sc);
23950974Swpaul	SIO_SET(SIS_EECTL_CLK);
24050974Swpaul	sis_delay(sc);
24150974Swpaul
24250974Swpaul	for (i = 0; i < 25; i++) {
24350974Swpaul		SIO_CLR(SIS_EECTL_CLK);
24450974Swpaul		sis_delay(sc);
24550974Swpaul		SIO_SET(SIS_EECTL_CLK);
24650974Swpaul		sis_delay(sc);
24750974Swpaul	}
24850974Swpaul
24950974Swpaul	SIO_CLR(SIS_EECTL_CLK);
25050974Swpaul	sis_delay(sc);
25150974Swpaul	SIO_CLR(SIS_EECTL_CSEL);
25250974Swpaul	sis_delay(sc);
25350974Swpaul	CSR_WRITE_4(sc, SIS_EECTL, 0x00000000);
25450974Swpaul
25550974Swpaul	return;
25650974Swpaul}
25750974Swpaul
25850974Swpaul/*
25950974Swpaul * Send a read command and address to the EEPROM, check for ACK.
26050974Swpaul */
26150974Swpaulstatic void sis_eeprom_putbyte(sc, addr)
26250974Swpaul	struct sis_softc	*sc;
26350974Swpaul	int			addr;
26450974Swpaul{
26550974Swpaul	register int		d, i;
26650974Swpaul
26750974Swpaul	d = addr | SIS_EECMD_READ;
26850974Swpaul
26950974Swpaul	/*
27050974Swpaul	 * Feed in each bit and stobe the clock.
27150974Swpaul	 */
27250974Swpaul	for (i = 0x400; i; i >>= 1) {
27350974Swpaul		if (d & i) {
27450974Swpaul			SIO_SET(SIS_EECTL_DIN);
27550974Swpaul		} else {
27650974Swpaul			SIO_CLR(SIS_EECTL_DIN);
27750974Swpaul		}
27850974Swpaul		sis_delay(sc);
27950974Swpaul		SIO_SET(SIS_EECTL_CLK);
28050974Swpaul		sis_delay(sc);
28150974Swpaul		SIO_CLR(SIS_EECTL_CLK);
28250974Swpaul		sis_delay(sc);
28350974Swpaul	}
28450974Swpaul
28550974Swpaul	return;
28650974Swpaul}
28750974Swpaul
28850974Swpaul/*
28950974Swpaul * Read a word of data stored in the EEPROM at address 'addr.'
29050974Swpaul */
29150974Swpaulstatic void sis_eeprom_getword(sc, addr, dest)
29250974Swpaul	struct sis_softc	*sc;
29350974Swpaul	int			addr;
29450974Swpaul	u_int16_t		*dest;
29550974Swpaul{
29650974Swpaul	register int		i;
29750974Swpaul	u_int16_t		word = 0;
29850974Swpaul
29950974Swpaul	/* Force EEPROM to idle state. */
30050974Swpaul	sis_eeprom_idle(sc);
30150974Swpaul
30250974Swpaul	/* Enter EEPROM access mode. */
30350974Swpaul	sis_delay(sc);
30462672Swpaul	SIO_CLR(SIS_EECTL_CLK);
30562672Swpaul	sis_delay(sc);
30650974Swpaul	SIO_SET(SIS_EECTL_CSEL);
30750974Swpaul	sis_delay(sc);
30850974Swpaul
30950974Swpaul	/*
31050974Swpaul	 * Send address of word we want to read.
31150974Swpaul	 */
31250974Swpaul	sis_eeprom_putbyte(sc, addr);
31350974Swpaul
31450974Swpaul	/*
31550974Swpaul	 * Start reading bits from EEPROM.
31650974Swpaul	 */
31750974Swpaul	for (i = 0x8000; i; i >>= 1) {
31850974Swpaul		SIO_SET(SIS_EECTL_CLK);
31950974Swpaul		sis_delay(sc);
32050974Swpaul		if (CSR_READ_4(sc, SIS_EECTL) & SIS_EECTL_DOUT)
32150974Swpaul			word |= i;
32250974Swpaul		sis_delay(sc);
32350974Swpaul		SIO_CLR(SIS_EECTL_CLK);
32450974Swpaul		sis_delay(sc);
32550974Swpaul	}
32650974Swpaul
32750974Swpaul	/* Turn off EEPROM access mode. */
32850974Swpaul	sis_eeprom_idle(sc);
32950974Swpaul
33050974Swpaul	*dest = word;
33150974Swpaul
33250974Swpaul	return;
33350974Swpaul}
33450974Swpaul
33550974Swpaul/*
33650974Swpaul * Read a sequence of words from the EEPROM.
33750974Swpaul */
33850974Swpaulstatic void sis_read_eeprom(sc, dest, off, cnt, swap)
33950974Swpaul	struct sis_softc	*sc;
34050974Swpaul	caddr_t			dest;
34150974Swpaul	int			off;
34250974Swpaul	int			cnt;
34350974Swpaul	int			swap;
34450974Swpaul{
34550974Swpaul	int			i;
34650974Swpaul	u_int16_t		word = 0, *ptr;
34750974Swpaul
34850974Swpaul	for (i = 0; i < cnt; i++) {
34950974Swpaul		sis_eeprom_getword(sc, off + i, &word);
35050974Swpaul		ptr = (u_int16_t *)(dest + (i * 2));
35150974Swpaul		if (swap)
35250974Swpaul			*ptr = ntohs(word);
35350974Swpaul		else
35450974Swpaul			*ptr = word;
35550974Swpaul	}
35650974Swpaul
35750974Swpaul	return;
35850974Swpaul}
35950974Swpaul
36050974Swpaulstatic int sis_miibus_readreg(dev, phy, reg)
36150974Swpaul	device_t		dev;
36250974Swpaul	int			phy, reg;
36350974Swpaul{
36450974Swpaul	struct sis_softc	*sc;
36562672Swpaul	int			i, val = 0;
36650974Swpaul
36750974Swpaul	sc = device_get_softc(dev);
36850974Swpaul
36962672Swpaul	if (sc->sis_type == SIS_TYPE_83815) {
37062672Swpaul		if (phy != 0)
37162672Swpaul			return(0);
37262672Swpaul		/*
37362672Swpaul		 * The NatSemi chip can take a while after
37462672Swpaul		 * a reset to come ready, during which the BMSR
37562672Swpaul		 * returns a value of 0. This is *never* supposed
37662672Swpaul		 * to happen: some of the BMSR bits are meant to
37762672Swpaul		 * be hardwired in the on position, and this can
37862672Swpaul		 * confuse the miibus code a bit during the probe
37962672Swpaul		 * and attach phase. So we make an effort to check
38062672Swpaul		 * for this condition and wait for it to clear.
38162672Swpaul		 */
38262672Swpaul		if (!CSR_READ_4(sc, NS_BMSR))
38362672Swpaul			DELAY(1000);
38462672Swpaul		val = CSR_READ_4(sc, NS_BMCR + (reg * 4));
38562672Swpaul		return(val);
38662672Swpaul	}
38762672Swpaul
38850974Swpaul	if (sc->sis_type == SIS_TYPE_900 && phy != 0)
38950974Swpaul		return(0);
39050974Swpaul
39150974Swpaul	CSR_WRITE_4(sc, SIS_PHYCTL, (phy << 11) | (reg << 6) | SIS_PHYOP_READ);
39250974Swpaul	SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS);
39350974Swpaul
39450974Swpaul	for (i = 0; i < SIS_TIMEOUT; i++) {
39550974Swpaul		if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS))
39650974Swpaul			break;
39750974Swpaul	}
39850974Swpaul
39950974Swpaul	if (i == SIS_TIMEOUT) {
40050974Swpaul		printf("sis%d: PHY failed to come ready\n", sc->sis_unit);
40150974Swpaul		return(0);
40250974Swpaul	}
40350974Swpaul
40450974Swpaul	val = (CSR_READ_4(sc, SIS_PHYCTL) >> 16) & 0xFFFF;
40550974Swpaul
40650974Swpaul	if (val == 0xFFFF)
40750974Swpaul		return(0);
40850974Swpaul
40950974Swpaul	return(val);
41050974Swpaul}
41150974Swpaul
41250974Swpaulstatic int sis_miibus_writereg(dev, phy, reg, data)
41350974Swpaul	device_t		dev;
41450974Swpaul	int			phy, reg, data;
41550974Swpaul{
41650974Swpaul	struct sis_softc	*sc;
41750974Swpaul	int			i;
41850974Swpaul
41950974Swpaul	sc = device_get_softc(dev);
42050974Swpaul
42162672Swpaul	if (sc->sis_type == SIS_TYPE_83815) {
42262672Swpaul		if (phy != 0)
42362672Swpaul			return(0);
42462672Swpaul		CSR_WRITE_4(sc, NS_BMCR + (reg * 4), data);
42562672Swpaul		return(0);
42662672Swpaul	}
42762672Swpaul
42850974Swpaul	if (sc->sis_type == SIS_TYPE_900 && phy != 0)
42950974Swpaul		return(0);
43050974Swpaul
43162672Swpaul	if (sc->sis_type == SIS_TYPE_900 && phy != 0)
43262672Swpaul		return(0);
43362672Swpaul
43450974Swpaul	CSR_WRITE_4(sc, SIS_PHYCTL, (data << 16) | (phy << 11) |
43550974Swpaul	    (reg << 6) | SIS_PHYOP_WRITE);
43650974Swpaul	SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS);
43750974Swpaul
43850974Swpaul	for (i = 0; i < SIS_TIMEOUT; i++) {
43950974Swpaul		if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS))
44050974Swpaul			break;
44150974Swpaul	}
44250974Swpaul
44350974Swpaul	if (i == SIS_TIMEOUT)
44450974Swpaul		printf("sis%d: PHY failed to come ready\n", sc->sis_unit);
44550974Swpaul
44650974Swpaul	return(0);
44750974Swpaul}
44850974Swpaul
44950974Swpaulstatic void sis_miibus_statchg(dev)
45050974Swpaul	device_t		dev;
45150974Swpaul{
45250974Swpaul	struct sis_softc	*sc;
45350974Swpaul	struct mii_data		*mii;
45450974Swpaul
45550974Swpaul	sc = device_get_softc(dev);
45650974Swpaul	mii = device_get_softc(sc->sis_miibus);
45750974Swpaul
45850974Swpaul	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
45950974Swpaul		SIS_SETBIT(sc, SIS_TX_CFG,
46050974Swpaul		    (SIS_TXCFG_IGN_HBEAT|SIS_TXCFG_IGN_CARR));
46150974Swpaul		SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS);
46250974Swpaul	} else {
46350974Swpaul		SIS_CLRBIT(sc, SIS_TX_CFG,
46450974Swpaul		    (SIS_TXCFG_IGN_HBEAT|SIS_TXCFG_IGN_CARR));
46550974Swpaul		SIS_CLRBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS);
46650974Swpaul	}
46750974Swpaul
46850974Swpaul	return;
46950974Swpaul}
47050974Swpaul
47162672Swpaulstatic u_int32_t sis_crc(sc, addr)
47262672Swpaul	struct sis_softc	*sc;
47350974Swpaul	caddr_t			addr;
47450974Swpaul{
47550974Swpaul	u_int32_t		crc, carry;
47650974Swpaul	int			i, j;
47750974Swpaul	u_int8_t		c;
47850974Swpaul
47950974Swpaul	/* Compute CRC for the address value. */
48050974Swpaul	crc = 0xFFFFFFFF; /* initial value */
48150974Swpaul
48250974Swpaul	for (i = 0; i < 6; i++) {
48350974Swpaul		c = *(addr + i);
48450974Swpaul		for (j = 0; j < 8; j++) {
48550974Swpaul			carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
48650974Swpaul			crc <<= 1;
48750974Swpaul			c >>= 1;
48850974Swpaul			if (carry)
48950974Swpaul				crc = (crc ^ 0x04c11db6) | carry;
49050974Swpaul		}
49150974Swpaul	}
49250974Swpaul
49362672Swpaul	/*
49462672Swpaul	 * return the filter bit position
49562672Swpaul	 *
49662672Swpaul	 * The NatSemi chip has a 512-bit filter, which is
49762672Swpaul	 * different than the SiS, so we special-case it.
49862672Swpaul	 */
49962672Swpaul	if (sc->sis_type == SIS_TYPE_83815)
50062672Swpaul		return((crc >> 23) & 0x1FF);
50162672Swpaul
50250974Swpaul	return((crc >> 25) & 0x0000007F);
50350974Swpaul}
50450974Swpaul
50562672Swpaulstatic void sis_setmulti_ns(sc)
50650974Swpaul	struct sis_softc	*sc;
50750974Swpaul{
50850974Swpaul	struct ifnet		*ifp;
50950974Swpaul	struct ifmultiaddr	*ifma;
51050974Swpaul	u_int32_t		h = 0, i, filtsave;
51162672Swpaul	int			bit, index;
51250974Swpaul
51350974Swpaul	ifp = &sc->arpcom.ac_if;
51450974Swpaul
51550974Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
51662672Swpaul		SIS_CLRBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_MCHASH);
51750974Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI);
51850974Swpaul		return;
51950974Swpaul	}
52050974Swpaul
52162672Swpaul	/*
52262672Swpaul	 * We have to explicitly enable the multicast hash table
52362672Swpaul	 * on the NatSemi chip if we want to use it, which we do.
52462672Swpaul	 */
52562672Swpaul	SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_MCHASH);
52650974Swpaul	SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI);
52750974Swpaul
52850974Swpaul	filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL);
52950974Swpaul
53050974Swpaul	/* first, zot all the existing hash bits */
53162672Swpaul	for (i = 0; i < 32; i++) {
53262672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + (i*2));
53362672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA, 0);
53462672Swpaul	}
53562672Swpaul
53662672Swpaul	for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
53762672Swpaul	    ifma = ifma->ifma_link.le_next) {
53862672Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
53962672Swpaul			continue;
54062672Swpaul		h = sis_crc(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
54162672Swpaul		index = h >> 3;
54262672Swpaul		bit = h & 0x1F;
54362672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + index);
54462672Swpaul		if (bit > 0xF)
54562672Swpaul			bit -= 0x10;
54662672Swpaul		SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << bit));
54762672Swpaul	}
54862672Swpaul
54962672Swpaul	CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave);
55062672Swpaul
55162672Swpaul	return;
55262672Swpaul}
55362672Swpaul
55462672Swpaulstatic void sis_setmulti_sis(sc)
55562672Swpaul	struct sis_softc	*sc;
55662672Swpaul{
55762672Swpaul	struct ifnet		*ifp;
55862672Swpaul	struct ifmultiaddr	*ifma;
55962672Swpaul	u_int32_t		h = 0, i, filtsave;
56062672Swpaul
56162672Swpaul	ifp = &sc->arpcom.ac_if;
56262672Swpaul
56362672Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
56462672Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI);
56562672Swpaul		return;
56662672Swpaul	}
56762672Swpaul
56862672Swpaul	SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI);
56962672Swpaul
57062672Swpaul	filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL);
57162672Swpaul
57262672Swpaul	/* first, zot all the existing hash bits */
57350974Swpaul	for (i = 0; i < 8; i++) {
57450974Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, (4 + ((i * 16) >> 4)) << 16);
57550974Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA, 0);
57650974Swpaul	}
57750974Swpaul
57850974Swpaul	/* now program new ones */
57950974Swpaul	for (ifma = ifp->if_multiaddrs.lh_first; ifma != NULL;
58050974Swpaul	    ifma = ifma->ifma_link.le_next) {
58150974Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
58250974Swpaul			continue;
58362672Swpaul		h = sis_crc(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
58450974Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, (4 + (h >> 4)) << 16);
58550974Swpaul		SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << (h & 0xF)));
58650974Swpaul	}
58750974Swpaul
58850974Swpaul	CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave);
58950974Swpaul
59050974Swpaul	return;
59150974Swpaul}
59250974Swpaul
59350974Swpaulstatic void sis_reset(sc)
59450974Swpaul	struct sis_softc	*sc;
59550974Swpaul{
59650974Swpaul	register int		i;
59750974Swpaul
59850974Swpaul	SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RESET);
59950974Swpaul
60050974Swpaul	for (i = 0; i < SIS_TIMEOUT; i++) {
60150974Swpaul		if (!(CSR_READ_4(sc, SIS_CSR) & SIS_CSR_RESET))
60250974Swpaul			break;
60350974Swpaul	}
60450974Swpaul
60550974Swpaul	if (i == SIS_TIMEOUT)
60650974Swpaul		printf("sis%d: reset never completed\n", sc->sis_unit);
60750974Swpaul
60850974Swpaul	/* Wait a little while for the chip to get its brains in order. */
60950974Swpaul	DELAY(1000);
61050974Swpaul        return;
61150974Swpaul}
61250974Swpaul
61350974Swpaul/*
61450974Swpaul * Probe for an SiS chip. Check the PCI vendor and device
61550974Swpaul * IDs against our list and return a device name if we find a match.
61650974Swpaul */
61750974Swpaulstatic int sis_probe(dev)
61850974Swpaul	device_t		dev;
61950974Swpaul{
62050974Swpaul	struct sis_type		*t;
62150974Swpaul
62250974Swpaul	t = sis_devs;
62350974Swpaul
62450974Swpaul	while(t->sis_name != NULL) {
62550974Swpaul		if ((pci_get_vendor(dev) == t->sis_vid) &&
62650974Swpaul		    (pci_get_device(dev) == t->sis_did)) {
62750974Swpaul			device_set_desc(dev, t->sis_name);
62850974Swpaul			return(0);
62950974Swpaul		}
63050974Swpaul		t++;
63150974Swpaul	}
63250974Swpaul
63350974Swpaul	return(ENXIO);
63450974Swpaul}
63550974Swpaul
63650974Swpaul/*
63750974Swpaul * Attach the interface. Allocate softc structures, do ifmedia
63850974Swpaul * setup and ethernet/BPF attach.
63950974Swpaul */
64050974Swpaulstatic int sis_attach(dev)
64150974Swpaul	device_t		dev;
64250974Swpaul{
64350974Swpaul	int			s;
64450974Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
64550974Swpaul	u_int32_t		command;
64650974Swpaul	struct sis_softc	*sc;
64750974Swpaul	struct ifnet		*ifp;
64850974Swpaul	int			unit, error = 0, rid;
64950974Swpaul
65050974Swpaul	s = splimp();
65150974Swpaul
65250974Swpaul	sc = device_get_softc(dev);
65350974Swpaul	unit = device_get_unit(dev);
65450974Swpaul	bzero(sc, sizeof(struct sis_softc));
65550974Swpaul
65650974Swpaul	if (pci_get_device(dev) == SIS_DEVICEID_900)
65750974Swpaul		sc->sis_type = SIS_TYPE_900;
65850974Swpaul	if (pci_get_device(dev) == SIS_DEVICEID_7016)
65950974Swpaul		sc->sis_type = SIS_TYPE_7016;
66062672Swpaul	if (pci_get_vendor(dev) == NS_VENDORID)
66162672Swpaul		sc->sis_type = SIS_TYPE_83815;
66250974Swpaul
66350974Swpaul	/*
66450974Swpaul	 * Handle power management nonsense.
66550974Swpaul	 */
66650974Swpaul
66750974Swpaul	command = pci_read_config(dev, SIS_PCI_CAPID, 4) & 0x000000FF;
66850974Swpaul	if (command == 0x01) {
66950974Swpaul
67050974Swpaul		command = pci_read_config(dev, SIS_PCI_PWRMGMTCTRL, 4);
67150974Swpaul		if (command & SIS_PSTATE_MASK) {
67250974Swpaul			u_int32_t		iobase, membase, irq;
67350974Swpaul
67450974Swpaul			/* Save important PCI config data. */
67550974Swpaul			iobase = pci_read_config(dev, SIS_PCI_LOIO, 4);
67650974Swpaul			membase = pci_read_config(dev, SIS_PCI_LOMEM, 4);
67750974Swpaul			irq = pci_read_config(dev, SIS_PCI_INTLINE, 4);
67850974Swpaul
67950974Swpaul			/* Reset the power state. */
68050974Swpaul			printf("sis%d: chip is in D%d power mode "
68150974Swpaul			"-- setting to D0\n", unit, command & SIS_PSTATE_MASK);
68250974Swpaul			command &= 0xFFFFFFFC;
68350974Swpaul			pci_write_config(dev, SIS_PCI_PWRMGMTCTRL, command, 4);
68450974Swpaul
68550974Swpaul			/* Restore PCI config data. */
68650974Swpaul			pci_write_config(dev, SIS_PCI_LOIO, iobase, 4);
68750974Swpaul			pci_write_config(dev, SIS_PCI_LOMEM, membase, 4);
68850974Swpaul			pci_write_config(dev, SIS_PCI_INTLINE, irq, 4);
68950974Swpaul		}
69050974Swpaul	}
69150974Swpaul
69250974Swpaul	/*
69350974Swpaul	 * Map control/status registers.
69450974Swpaul	 */
69561041Speter	command = pci_read_config(dev, PCIR_COMMAND, 4);
69650974Swpaul	command |= (PCIM_CMD_PORTEN|PCIM_CMD_MEMEN|PCIM_CMD_BUSMASTEREN);
69761041Speter	pci_write_config(dev, PCIR_COMMAND, command, 4);
69861041Speter	command = pci_read_config(dev, PCIR_COMMAND, 4);
69950974Swpaul
70050974Swpaul#ifdef SIS_USEIOSPACE
70150974Swpaul	if (!(command & PCIM_CMD_PORTEN)) {
70250974Swpaul		printf("sis%d: failed to enable I/O ports!\n", unit);
70350974Swpaul		error = ENXIO;;
70450974Swpaul		goto fail;
70550974Swpaul	}
70650974Swpaul#else
70750974Swpaul	if (!(command & PCIM_CMD_MEMEN)) {
70850974Swpaul		printf("sis%d: failed to enable memory mapping!\n", unit);
70950974Swpaul		error = ENXIO;;
71050974Swpaul		goto fail;
71150974Swpaul	}
71250974Swpaul#endif
71350974Swpaul
71450974Swpaul	rid = SIS_RID;
71550974Swpaul	sc->sis_res = bus_alloc_resource(dev, SIS_RES, &rid,
71650974Swpaul	    0, ~0, 1, RF_ACTIVE);
71750974Swpaul
71850974Swpaul	if (sc->sis_res == NULL) {
71950974Swpaul		printf("sis%d: couldn't map ports/memory\n", unit);
72050974Swpaul		error = ENXIO;
72150974Swpaul		goto fail;
72250974Swpaul	}
72350974Swpaul
72450974Swpaul	sc->sis_btag = rman_get_bustag(sc->sis_res);
72550974Swpaul	sc->sis_bhandle = rman_get_bushandle(sc->sis_res);
72650974Swpaul
72750974Swpaul	/* Allocate interrupt */
72850974Swpaul	rid = 0;
72950974Swpaul	sc->sis_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
73050974Swpaul	    RF_SHAREABLE | RF_ACTIVE);
73150974Swpaul
73250974Swpaul	if (sc->sis_irq == NULL) {
73350974Swpaul		printf("sis%d: couldn't map interrupt\n", unit);
73450974Swpaul		bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
73550974Swpaul		error = ENXIO;
73650974Swpaul		goto fail;
73750974Swpaul	}
73850974Swpaul
73950974Swpaul	error = bus_setup_intr(dev, sc->sis_irq, INTR_TYPE_NET,
74050974Swpaul	    sis_intr, sc, &sc->sis_intrhand);
74150974Swpaul
74250974Swpaul	if (error) {
74350974Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_res);
74450974Swpaul		bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
74550974Swpaul		printf("sis%d: couldn't set up irq\n", unit);
74650974Swpaul		goto fail;
74750974Swpaul	}
74850974Swpaul
74950974Swpaul	/* Reset the adapter. */
75050974Swpaul	sis_reset(sc);
75150974Swpaul
75250974Swpaul	/*
75350974Swpaul	 * Get station address from the EEPROM.
75450974Swpaul	 */
75562672Swpaul	switch (pci_get_vendor(dev)) {
75662672Swpaul	case NS_VENDORID:
75762672Swpaul		/*
75862672Swpaul		 * Reading the MAC address out of the EEPROM on
75962672Swpaul		 * the NatSemi chip takes a bit more work than
76062672Swpaul		 * you'd expect. The address spans 4 16-bit words,
76162672Swpaul		 * with the first word containing only a single bit.
76262672Swpaul		 * You have to shift everything over one bit to
76362672Swpaul		 * get it aligned properly. Also, the bits are
76462672Swpaul		 * stored backwards (the LSB is really the MSB,
76562672Swpaul		 * and so on) so you have to reverse them in order
76662672Swpaul		 * to get the MAC address into the form we want.
76762672Swpaul		 * Why? Who the hell knows.
76862672Swpaul		 */
76962672Swpaul		{
77062672Swpaul			u_int16_t		tmp[4];
77150974Swpaul
77262672Swpaul			sis_read_eeprom(sc, (caddr_t)&tmp,
77362672Swpaul			    NS_EE_NODEADDR, 4, 0);
77462672Swpaul
77562672Swpaul			/* Shift everything over one bit. */
77662672Swpaul			tmp[3] = tmp[3] >> 1;
77762681Swpaul			tmp[3] |= tmp[2] << 15;
77862672Swpaul			tmp[2] = tmp[2] >> 1;
77962681Swpaul			tmp[2] |= tmp[1] << 15;
78062672Swpaul			tmp[1] = tmp[1] >> 1;
78162681Swpaul			tmp[1] |= tmp[0] << 15;
78262672Swpaul
78362672Swpaul			/* Now reverse all the bits. */
78462672Swpaul			tmp[3] = sis_reverse(tmp[3]);
78562672Swpaul			tmp[2] = sis_reverse(tmp[2]);
78662672Swpaul			tmp[1] = sis_reverse(tmp[1]);
78762672Swpaul
78862672Swpaul			bcopy((char *)&tmp[1], eaddr, ETHER_ADDR_LEN);
78962672Swpaul		}
79062672Swpaul		break;
79162672Swpaul	case SIS_VENDORID:
79262672Swpaul	default:
79362672Swpaul		sis_read_eeprom(sc, (caddr_t)&eaddr, SIS_EE_NODEADDR, 3, 0);
79462672Swpaul		break;
79562672Swpaul	}
79662672Swpaul
79750974Swpaul	/*
79850974Swpaul	 * A SiS chip was detected. Inform the world.
79950974Swpaul	 */
80050974Swpaul	printf("sis%d: Ethernet address: %6D\n", unit, eaddr, ":");
80150974Swpaul
80250974Swpaul	sc->sis_unit = unit;
80350974Swpaul	callout_handle_init(&sc->sis_stat_ch);
80450974Swpaul	bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
80550974Swpaul
80650974Swpaul	sc->sis_ldata = contigmalloc(sizeof(struct sis_list_data), M_DEVBUF,
80751657Swpaul	    M_NOWAIT, 0, 0xffffffff, PAGE_SIZE, 0);
80850974Swpaul
80950974Swpaul	if (sc->sis_ldata == NULL) {
81050974Swpaul		printf("sis%d: no memory for list buffers!\n", unit);
81150974Swpaul		bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand);
81250974Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq);
81350974Swpaul		bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
81450974Swpaul		error = ENXIO;
81550974Swpaul		goto fail;
81650974Swpaul	}
81750974Swpaul	bzero(sc->sis_ldata, sizeof(struct sis_list_data));
81850974Swpaul
81950974Swpaul	ifp = &sc->arpcom.ac_if;
82050974Swpaul	ifp->if_softc = sc;
82150974Swpaul	ifp->if_unit = unit;
82250974Swpaul	ifp->if_name = "sis";
82350974Swpaul	ifp->if_mtu = ETHERMTU;
82450974Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
82550974Swpaul	ifp->if_ioctl = sis_ioctl;
82650974Swpaul	ifp->if_output = ether_output;
82750974Swpaul	ifp->if_start = sis_start;
82850974Swpaul	ifp->if_watchdog = sis_watchdog;
82950974Swpaul	ifp->if_init = sis_init;
83050974Swpaul	ifp->if_baudrate = 10000000;
83150974Swpaul	ifp->if_snd.ifq_maxlen = SIS_TX_LIST_CNT - 1;
83250974Swpaul
83350974Swpaul	/*
83450974Swpaul	 * Do MII setup.
83550974Swpaul	 */
83650974Swpaul	if (mii_phy_probe(dev, &sc->sis_miibus,
83750974Swpaul	    sis_ifmedia_upd, sis_ifmedia_sts)) {
83850974Swpaul		printf("sis%d: MII without any PHY!\n", sc->sis_unit);
83950974Swpaul		bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand);
84050974Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq);
84150974Swpaul		bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
84250974Swpaul		error = ENXIO;
84350974Swpaul		goto fail;
84450974Swpaul	}
84550974Swpaul
84650974Swpaul	/*
84763090Sarchie	 * Call MI attach routine.
84850974Swpaul	 */
84963090Sarchie	ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
85050974Swpaul	callout_handle_init(&sc->sis_stat_ch);
85150974Swpaul
85250974Swpaulfail:
85350974Swpaul	splx(s);
85450974Swpaul	return(error);
85550974Swpaul}
85650974Swpaul
85750974Swpaulstatic int sis_detach(dev)
85850974Swpaul	device_t		dev;
85950974Swpaul{
86050974Swpaul	struct sis_softc	*sc;
86150974Swpaul	struct ifnet		*ifp;
86250974Swpaul	int			s;
86350974Swpaul
86450974Swpaul	s = splimp();
86550974Swpaul
86650974Swpaul	sc = device_get_softc(dev);
86750974Swpaul	ifp = &sc->arpcom.ac_if;
86850974Swpaul
86950974Swpaul	sis_reset(sc);
87050974Swpaul	sis_stop(sc);
87163090Sarchie	ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
87250974Swpaul
87350974Swpaul	bus_generic_detach(dev);
87450974Swpaul	device_delete_child(dev, sc->sis_miibus);
87550974Swpaul
87650974Swpaul	bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand);
87750974Swpaul	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq);
87850974Swpaul	bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
87950974Swpaul
88050974Swpaul	contigfree(sc->sis_ldata, sizeof(struct sis_list_data), M_DEVBUF);
88150974Swpaul
88250974Swpaul	splx(s);
88350974Swpaul
88450974Swpaul	return(0);
88550974Swpaul}
88650974Swpaul
88750974Swpaul/*
88850974Swpaul * Initialize the transmit descriptors.
88950974Swpaul */
89050974Swpaulstatic int sis_list_tx_init(sc)
89150974Swpaul	struct sis_softc	*sc;
89250974Swpaul{
89350974Swpaul	struct sis_list_data	*ld;
89450974Swpaul	struct sis_ring_data	*cd;
89550974Swpaul	int			i;
89650974Swpaul
89750974Swpaul	cd = &sc->sis_cdata;
89850974Swpaul	ld = sc->sis_ldata;
89950974Swpaul
90050974Swpaul	for (i = 0; i < SIS_TX_LIST_CNT; i++) {
90150974Swpaul		if (i == (SIS_TX_LIST_CNT - 1)) {
90250974Swpaul			ld->sis_tx_list[i].sis_nextdesc =
90350974Swpaul			    &ld->sis_tx_list[0];
90450974Swpaul			ld->sis_tx_list[i].sis_next =
90550974Swpaul			    vtophys(&ld->sis_tx_list[0]);
90650974Swpaul		} else {
90750974Swpaul			ld->sis_tx_list[i].sis_nextdesc =
90850974Swpaul			    &ld->sis_tx_list[i + 1];
90950974Swpaul			ld->sis_tx_list[i].sis_next =
91050974Swpaul			    vtophys(&ld->sis_tx_list[i + 1]);
91150974Swpaul		}
91250974Swpaul		ld->sis_tx_list[i].sis_mbuf = NULL;
91350974Swpaul		ld->sis_tx_list[i].sis_ptr = 0;
91450974Swpaul		ld->sis_tx_list[i].sis_ctl = 0;
91550974Swpaul	}
91650974Swpaul
91750974Swpaul	cd->sis_tx_prod = cd->sis_tx_cons = cd->sis_tx_cnt = 0;
91850974Swpaul
91950974Swpaul	return(0);
92050974Swpaul}
92150974Swpaul
92250974Swpaul
92350974Swpaul/*
92450974Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
92550974Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
92650974Swpaul * points back to the first.
92750974Swpaul */
92850974Swpaulstatic int sis_list_rx_init(sc)
92950974Swpaul	struct sis_softc	*sc;
93050974Swpaul{
93150974Swpaul	struct sis_list_data	*ld;
93250974Swpaul	struct sis_ring_data	*cd;
93350974Swpaul	int			i;
93450974Swpaul
93550974Swpaul	ld = sc->sis_ldata;
93650974Swpaul	cd = &sc->sis_cdata;
93750974Swpaul
93850974Swpaul	for (i = 0; i < SIS_RX_LIST_CNT; i++) {
93950974Swpaul		if (sis_newbuf(sc, &ld->sis_rx_list[i], NULL) == ENOBUFS)
94050974Swpaul			return(ENOBUFS);
94150974Swpaul		if (i == (SIS_RX_LIST_CNT - 1)) {
94250974Swpaul			ld->sis_rx_list[i].sis_nextdesc =
94350974Swpaul			    &ld->sis_rx_list[0];
94450974Swpaul			ld->sis_rx_list[i].sis_next =
94550974Swpaul			    vtophys(&ld->sis_rx_list[0]);
94650974Swpaul		} else {
94750974Swpaul			ld->sis_rx_list[i].sis_nextdesc =
94850974Swpaul			    &ld->sis_rx_list[i + 1];
94950974Swpaul			ld->sis_rx_list[i].sis_next =
95050974Swpaul			    vtophys(&ld->sis_rx_list[i + 1]);
95150974Swpaul		}
95250974Swpaul	}
95350974Swpaul
95450974Swpaul	cd->sis_rx_prod = 0;
95550974Swpaul
95650974Swpaul	return(0);
95750974Swpaul}
95850974Swpaul
95950974Swpaul/*
96050974Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
96150974Swpaul */
96250974Swpaulstatic int sis_newbuf(sc, c, m)
96350974Swpaul	struct sis_softc	*sc;
96450974Swpaul	struct sis_desc		*c;
96550974Swpaul	struct mbuf		*m;
96650974Swpaul{
96750974Swpaul	struct mbuf		*m_new = NULL;
96850974Swpaul
96950974Swpaul	if (m == NULL) {
97050974Swpaul		MGETHDR(m_new, M_DONTWAIT, MT_DATA);
97150974Swpaul		if (m_new == NULL) {
97250974Swpaul			printf("sis%d: no memory for rx list "
97350974Swpaul			    "-- packet dropped!\n", sc->sis_unit);
97450974Swpaul			return(ENOBUFS);
97550974Swpaul		}
97650974Swpaul
97750974Swpaul		MCLGET(m_new, M_DONTWAIT);
97850974Swpaul		if (!(m_new->m_flags & M_EXT)) {
97950974Swpaul			printf("sis%d: no memory for rx list "
98050974Swpaul			    "-- packet dropped!\n", sc->sis_unit);
98150974Swpaul			m_freem(m_new);
98250974Swpaul			return(ENOBUFS);
98350974Swpaul		}
98450974Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
98550974Swpaul	} else {
98650974Swpaul		m_new = m;
98750974Swpaul		m_new->m_len = m_new->m_pkthdr.len = MCLBYTES;
98850974Swpaul		m_new->m_data = m_new->m_ext.ext_buf;
98950974Swpaul	}
99050974Swpaul
99150974Swpaul	m_adj(m_new, sizeof(u_int64_t));
99250974Swpaul
99350974Swpaul	c->sis_mbuf = m_new;
99450974Swpaul	c->sis_ptr = vtophys(mtod(m_new, caddr_t));
99550974Swpaul	c->sis_ctl = SIS_RXLEN;
99650974Swpaul
99750974Swpaul	return(0);
99850974Swpaul}
99950974Swpaul
100050974Swpaul/*
100150974Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
100250974Swpaul * the higher level protocols.
100350974Swpaul */
100450974Swpaulstatic void sis_rxeof(sc)
100550974Swpaul	struct sis_softc	*sc;
100650974Swpaul{
100750974Swpaul        struct ether_header	*eh;
100850974Swpaul        struct mbuf		*m;
100950974Swpaul        struct ifnet		*ifp;
101050974Swpaul	struct sis_desc		*cur_rx;
101150974Swpaul	int			i, total_len = 0;
101250974Swpaul	u_int32_t		rxstat;
101350974Swpaul
101450974Swpaul	ifp = &sc->arpcom.ac_if;
101550974Swpaul	i = sc->sis_cdata.sis_rx_prod;
101650974Swpaul
101750974Swpaul	while(SIS_OWNDESC(&sc->sis_ldata->sis_rx_list[i])) {
101850974Swpaul		struct mbuf		*m0 = NULL;
101950974Swpaul
102050974Swpaul		cur_rx = &sc->sis_ldata->sis_rx_list[i];
102150974Swpaul		rxstat = cur_rx->sis_rxstat;
102250974Swpaul		m = cur_rx->sis_mbuf;
102350974Swpaul		cur_rx->sis_mbuf = NULL;
102450974Swpaul		total_len = SIS_RXBYTES(cur_rx);
102550974Swpaul		SIS_INC(i, SIS_RX_LIST_CNT);
102650974Swpaul
102750974Swpaul		/*
102850974Swpaul		 * If an error occurs, update stats, clear the
102950974Swpaul		 * status word and leave the mbuf cluster in place:
103050974Swpaul		 * it should simply get re-used next time this descriptor
103150974Swpaul	 	 * comes up in the ring.
103250974Swpaul		 */
103350974Swpaul		if (!(rxstat & SIS_CMDSTS_PKT_OK)) {
103450974Swpaul			ifp->if_ierrors++;
103550974Swpaul			if (rxstat & SIS_RXSTAT_COLL)
103650974Swpaul				ifp->if_collisions++;
103750974Swpaul			sis_newbuf(sc, cur_rx, m);
103850974Swpaul			continue;
103950974Swpaul		}
104050974Swpaul
104150974Swpaul		/* No errors; receive the packet. */
104250974Swpaul		m0 = m_devget(mtod(m, char *) - ETHER_ALIGN,
104350974Swpaul		    total_len + ETHER_ALIGN, 0, ifp, NULL);
104450974Swpaul		sis_newbuf(sc, cur_rx, m);
104550974Swpaul		if (m0 == NULL) {
104650974Swpaul			ifp->if_ierrors++;
104750974Swpaul			continue;
104850974Swpaul		}
104950974Swpaul		m_adj(m0, ETHER_ALIGN);
105050974Swpaul		m = m0;
105150974Swpaul
105250974Swpaul		ifp->if_ipackets++;
105350974Swpaul		eh = mtod(m, struct ether_header *);
105451583Swpaul
105550974Swpaul		/* Remove header from mbuf and pass it on. */
105650974Swpaul		m_adj(m, sizeof(struct ether_header));
105750974Swpaul		ether_input(ifp, eh, m);
105850974Swpaul	}
105950974Swpaul
106050974Swpaul	sc->sis_cdata.sis_rx_prod = i;
106150974Swpaul
106250974Swpaul	return;
106350974Swpaul}
106450974Swpaul
106550974Swpaulvoid sis_rxeoc(sc)
106650974Swpaul	struct sis_softc	*sc;
106750974Swpaul{
106850974Swpaul	sis_rxeof(sc);
106950974Swpaul	sis_init(sc);
107050974Swpaul	return;
107150974Swpaul}
107250974Swpaul
107350974Swpaul/*
107450974Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
107550974Swpaul * the list buffers.
107650974Swpaul */
107750974Swpaul
107850974Swpaulstatic void sis_txeof(sc)
107950974Swpaul	struct sis_softc	*sc;
108050974Swpaul{
108150974Swpaul	struct sis_desc		*cur_tx = NULL;
108250974Swpaul	struct ifnet		*ifp;
108350974Swpaul	u_int32_t		idx;
108450974Swpaul
108550974Swpaul	ifp = &sc->arpcom.ac_if;
108650974Swpaul
108750974Swpaul	/* Clear the timeout timer. */
108850974Swpaul	ifp->if_timer = 0;
108950974Swpaul
109050974Swpaul	/*
109150974Swpaul	 * Go through our tx list and free mbufs for those
109250974Swpaul	 * frames that have been transmitted.
109350974Swpaul	 */
109450974Swpaul	idx = sc->sis_cdata.sis_tx_cons;
109550974Swpaul	while (idx != sc->sis_cdata.sis_tx_prod) {
109650974Swpaul		cur_tx = &sc->sis_ldata->sis_tx_list[idx];
109750974Swpaul
109850974Swpaul		if (SIS_OWNDESC(cur_tx))
109950974Swpaul			break;
110050974Swpaul
110150974Swpaul		if (cur_tx->sis_ctl & SIS_CMDSTS_MORE) {
110250974Swpaul			sc->sis_cdata.sis_tx_cnt--;
110350974Swpaul			SIS_INC(idx, SIS_TX_LIST_CNT);
110450974Swpaul			continue;
110550974Swpaul		}
110650974Swpaul
110750974Swpaul		if (!(cur_tx->sis_ctl & SIS_CMDSTS_PKT_OK)) {
110850974Swpaul			ifp->if_oerrors++;
110950974Swpaul			if (cur_tx->sis_txstat & SIS_TXSTAT_EXCESSCOLLS)
111050974Swpaul				ifp->if_collisions++;
111150974Swpaul			if (cur_tx->sis_txstat & SIS_TXSTAT_OUTOFWINCOLL)
111250974Swpaul				ifp->if_collisions++;
111350974Swpaul		}
111450974Swpaul
111550974Swpaul		ifp->if_collisions +=
111650974Swpaul		    (cur_tx->sis_txstat & SIS_TXSTAT_COLLCNT) >> 16;
111750974Swpaul
111850974Swpaul		ifp->if_opackets++;
111950974Swpaul		if (cur_tx->sis_mbuf != NULL) {
112050974Swpaul			m_freem(cur_tx->sis_mbuf);
112150974Swpaul			cur_tx->sis_mbuf = NULL;
112250974Swpaul		}
112350974Swpaul
112450974Swpaul		sc->sis_cdata.sis_tx_cnt--;
112550974Swpaul		SIS_INC(idx, SIS_TX_LIST_CNT);
112650974Swpaul		ifp->if_timer = 0;
112750974Swpaul	}
112850974Swpaul
112950974Swpaul	sc->sis_cdata.sis_tx_cons = idx;
113050974Swpaul
113150974Swpaul	if (cur_tx != NULL)
113250974Swpaul		ifp->if_flags &= ~IFF_OACTIVE;
113350974Swpaul
113450974Swpaul	return;
113550974Swpaul}
113650974Swpaul
113750974Swpaulstatic void sis_tick(xsc)
113850974Swpaul	void			*xsc;
113950974Swpaul{
114050974Swpaul	struct sis_softc	*sc;
114150974Swpaul	struct mii_data		*mii;
114250974Swpaul	int			s;
114350974Swpaul
114450974Swpaul	s = splimp();
114550974Swpaul
114650974Swpaul	sc = xsc;
114750974Swpaul	mii = device_get_softc(sc->sis_miibus);
114850974Swpaul	mii_tick(mii);
114951031Swpaul	sc->sis_stat_ch = timeout(sis_tick, sc, hz);
115050974Swpaul
115150974Swpaul	splx(s);
115250974Swpaul
115350974Swpaul	return;
115450974Swpaul}
115550974Swpaul
115650974Swpaulstatic void sis_intr(arg)
115750974Swpaul	void			*arg;
115850974Swpaul{
115950974Swpaul	struct sis_softc	*sc;
116050974Swpaul	struct ifnet		*ifp;
116150974Swpaul	u_int32_t		status;
116250974Swpaul
116350974Swpaul	sc = arg;
116450974Swpaul	ifp = &sc->arpcom.ac_if;
116550974Swpaul
116650974Swpaul	/* Supress unwanted interrupts */
116750974Swpaul	if (!(ifp->if_flags & IFF_UP)) {
116850974Swpaul		sis_stop(sc);
116950974Swpaul		return;
117050974Swpaul	}
117150974Swpaul
117250974Swpaul	/* Disable interrupts. */
117350974Swpaul	CSR_WRITE_4(sc, SIS_IER, 0);
117450974Swpaul
117550974Swpaul	for (;;) {
117650974Swpaul		/* Reading the ISR register clears all interrupts. */
117750974Swpaul		status = CSR_READ_4(sc, SIS_ISR);
117850974Swpaul
117950974Swpaul		if ((status & SIS_INTRS) == 0)
118050974Swpaul			break;
118150974Swpaul
118250974Swpaul		if ((status & SIS_ISR_TX_OK) ||
118350974Swpaul		    (status & SIS_ISR_TX_ERR) ||
118450974Swpaul		    (status & SIS_ISR_TX_IDLE))
118550974Swpaul			sis_txeof(sc);
118650974Swpaul
118750974Swpaul		if (status & SIS_ISR_RX_OK)
118850974Swpaul			sis_rxeof(sc);
118950974Swpaul
119050974Swpaul		if ((status & SIS_ISR_RX_ERR) ||
119150974Swpaul		    (status & SIS_ISR_RX_OFLOW)) {
119250974Swpaul			sis_rxeoc(sc);
119350974Swpaul		}
119450974Swpaul
119550974Swpaul		if (status & SIS_ISR_SYSERR) {
119650974Swpaul			sis_reset(sc);
119750974Swpaul			sis_init(sc);
119850974Swpaul		}
119950974Swpaul	}
120050974Swpaul
120150974Swpaul	/* Re-enable interrupts. */
120250974Swpaul	CSR_WRITE_4(sc, SIS_IER, 1);
120350974Swpaul
120450974Swpaul	if (ifp->if_snd.ifq_head != NULL)
120550974Swpaul		sis_start(ifp);
120650974Swpaul
120750974Swpaul	return;
120850974Swpaul}
120950974Swpaul
121050974Swpaul/*
121150974Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
121250974Swpaul * pointers to the fragment pointers.
121350974Swpaul */
121450974Swpaulstatic int sis_encap(sc, m_head, txidx)
121550974Swpaul	struct sis_softc	*sc;
121650974Swpaul	struct mbuf		*m_head;
121750974Swpaul	u_int32_t		*txidx;
121850974Swpaul{
121950974Swpaul	struct sis_desc		*f = NULL;
122050974Swpaul	struct mbuf		*m;
122150974Swpaul	int			frag, cur, cnt = 0;
122250974Swpaul
122350974Swpaul	/*
122450974Swpaul 	 * Start packing the mbufs in this chain into
122550974Swpaul	 * the fragment pointers. Stop when we run out
122650974Swpaul 	 * of fragments or hit the end of the mbuf chain.
122750974Swpaul	 */
122850974Swpaul	m = m_head;
122950974Swpaul	cur = frag = *txidx;
123050974Swpaul
123150974Swpaul	for (m = m_head; m != NULL; m = m->m_next) {
123250974Swpaul		if (m->m_len != 0) {
123351042Swpaul			if ((SIS_TX_LIST_CNT -
123450974Swpaul			    (sc->sis_cdata.sis_tx_cnt + cnt)) < 2)
123550974Swpaul				return(ENOBUFS);
123650974Swpaul			f = &sc->sis_ldata->sis_tx_list[frag];
123750974Swpaul			f->sis_ctl = SIS_CMDSTS_MORE | m->m_len;
123850974Swpaul			f->sis_ptr = vtophys(mtod(m, vm_offset_t));
123950974Swpaul			if (cnt != 0)
124050974Swpaul				f->sis_ctl |= SIS_CMDSTS_OWN;
124150974Swpaul			cur = frag;
124250974Swpaul			SIS_INC(frag, SIS_TX_LIST_CNT);
124350974Swpaul			cnt++;
124450974Swpaul		}
124550974Swpaul	}
124650974Swpaul
124750974Swpaul	if (m != NULL)
124850974Swpaul		return(ENOBUFS);
124950974Swpaul
125050974Swpaul	sc->sis_ldata->sis_tx_list[cur].sis_mbuf = m_head;
125150974Swpaul	sc->sis_ldata->sis_tx_list[cur].sis_ctl &= ~SIS_CMDSTS_MORE;
125250974Swpaul	sc->sis_ldata->sis_tx_list[*txidx].sis_ctl |= SIS_CMDSTS_OWN;
125350974Swpaul	sc->sis_cdata.sis_tx_cnt += cnt;
125450974Swpaul	*txidx = frag;
125550974Swpaul
125650974Swpaul	return(0);
125750974Swpaul}
125850974Swpaul
125950974Swpaul/*
126050974Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
126150974Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
126250974Swpaul * copy of the pointers since the transmit list fragment pointers are
126350974Swpaul * physical addresses.
126450974Swpaul */
126550974Swpaul
126650974Swpaulstatic void sis_start(ifp)
126750974Swpaul	struct ifnet		*ifp;
126850974Swpaul{
126950974Swpaul	struct sis_softc	*sc;
127050974Swpaul	struct mbuf		*m_head = NULL;
127150974Swpaul	u_int32_t		idx;
127250974Swpaul
127350974Swpaul	sc = ifp->if_softc;
127450974Swpaul
127550974Swpaul	idx = sc->sis_cdata.sis_tx_prod;
127650974Swpaul
127750974Swpaul	if (ifp->if_flags & IFF_OACTIVE)
127850974Swpaul		return;
127950974Swpaul
128050974Swpaul	while(sc->sis_ldata->sis_tx_list[idx].sis_mbuf == NULL) {
128150974Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
128250974Swpaul		if (m_head == NULL)
128350974Swpaul			break;
128450974Swpaul
128550974Swpaul		if (sis_encap(sc, m_head, &idx)) {
128650974Swpaul			IF_PREPEND(&ifp->if_snd, m_head);
128750974Swpaul			ifp->if_flags |= IFF_OACTIVE;
128850974Swpaul			break;
128950974Swpaul		}
129050974Swpaul
129150974Swpaul		/*
129250974Swpaul		 * If there's a BPF listener, bounce a copy of this frame
129350974Swpaul		 * to him.
129450974Swpaul		 */
129550974Swpaul		if (ifp->if_bpf)
129650974Swpaul			bpf_mtap(ifp, m_head);
129751583Swpaul
129850974Swpaul	}
129950974Swpaul
130050974Swpaul	/* Transmit */
130150974Swpaul	sc->sis_cdata.sis_tx_prod = idx;
130250974Swpaul	SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_ENABLE);
130350974Swpaul
130450974Swpaul	/*
130550974Swpaul	 * Set a timeout in case the chip goes out to lunch.
130650974Swpaul	 */
130750974Swpaul	ifp->if_timer = 5;
130850974Swpaul
130950974Swpaul	return;
131050974Swpaul}
131150974Swpaul
131250974Swpaulstatic void sis_init(xsc)
131350974Swpaul	void			*xsc;
131450974Swpaul{
131550974Swpaul	struct sis_softc	*sc = xsc;
131650974Swpaul	struct ifnet		*ifp = &sc->arpcom.ac_if;
131750974Swpaul	struct mii_data		*mii;
131850974Swpaul	int			s;
131950974Swpaul
132050974Swpaul	s = splimp();
132150974Swpaul
132250974Swpaul	/*
132350974Swpaul	 * Cancel pending I/O and free all RX/TX buffers.
132450974Swpaul	 */
132550974Swpaul	sis_stop(sc);
132650974Swpaul
132750974Swpaul	mii = device_get_softc(sc->sis_miibus);
132850974Swpaul
132950974Swpaul	/* Set MAC address */
133062672Swpaul	if (sc->sis_type == SIS_TYPE_83815) {
133162672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR0);
133262672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
133362672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[0]);
133462672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR1);
133562672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
133662672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[1]);
133762672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR2);
133862672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
133962672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[2]);
134062672Swpaul	} else {
134162672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0);
134262672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
134362672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[0]);
134462672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR1);
134562672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
134662672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[1]);
134762672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2);
134862672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
134962672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[2]);
135062672Swpaul	}
135150974Swpaul
135250974Swpaul	/* Init circular RX list. */
135350974Swpaul	if (sis_list_rx_init(sc) == ENOBUFS) {
135450974Swpaul		printf("sis%d: initialization failed: no "
135550974Swpaul			"memory for rx buffers\n", sc->sis_unit);
135650974Swpaul		sis_stop(sc);
135750974Swpaul		(void)splx(s);
135850974Swpaul		return;
135950974Swpaul	}
136050974Swpaul
136150974Swpaul	/*
136250974Swpaul	 * Init tx descriptors.
136350974Swpaul	 */
136450974Swpaul	sis_list_tx_init(sc);
136550974Swpaul
136662672Swpaul	/*
136762672Swpaul	 * For the NatSemi chip, we have to explicitly enable the
136862672Swpaul	 * reception of ARP frames, as well as turn on the 'perfect
136962672Swpaul	 * match' filter where we store the station address, otherwise
137062672Swpaul	 * we won't receive unicasts meant for this host.
137162672Swpaul	 */
137262672Swpaul	if (sc->sis_type == SIS_TYPE_83815) {
137362672Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_ARP);
137462672Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_PERFECT);
137562672Swpaul	}
137662672Swpaul
137750974Swpaul	 /* If we want promiscuous mode, set the allframes bit. */
137850974Swpaul	if (ifp->if_flags & IFF_PROMISC) {
137950974Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLPHYS);
138050974Swpaul	} else {
138150974Swpaul		SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLPHYS);
138250974Swpaul	}
138350974Swpaul
138450974Swpaul	/*
138550974Swpaul	 * Set the capture broadcast bit to capture broadcast frames.
138650974Swpaul	 */
138750974Swpaul	if (ifp->if_flags & IFF_BROADCAST) {
138850974Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_BROAD);
138950974Swpaul	} else {
139050974Swpaul		SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_BROAD);
139150974Swpaul	}
139250974Swpaul
139350974Swpaul	/*
139450974Swpaul	 * Load the multicast filter.
139550974Swpaul	 */
139662672Swpaul	if (sc->sis_type == SIS_TYPE_83815)
139762672Swpaul		sis_setmulti_ns(sc);
139862672Swpaul	else
139962672Swpaul		sis_setmulti_sis(sc);
140050974Swpaul
140150974Swpaul	/* Turn the receive filter on */
140250974Swpaul	SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ENABLE);
140350974Swpaul
140450974Swpaul	/*
140550974Swpaul	 * Load the address of the RX and TX lists.
140650974Swpaul	 */
140750974Swpaul	CSR_WRITE_4(sc, SIS_RX_LISTPTR,
140850974Swpaul	    vtophys(&sc->sis_ldata->sis_rx_list[0]));
140950974Swpaul	CSR_WRITE_4(sc, SIS_TX_LISTPTR,
141050974Swpaul	    vtophys(&sc->sis_ldata->sis_tx_list[0]));
141150974Swpaul
141250974Swpaul	/* Set RX configuration */
141350974Swpaul	CSR_WRITE_4(sc, SIS_RX_CFG, SIS_RXCFG);
141450974Swpaul	/* Set TX configuration */
141550974Swpaul	CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG);
141650974Swpaul
141750974Swpaul	/*
141850974Swpaul	 * Enable interrupts.
141950974Swpaul	 */
142050974Swpaul	CSR_WRITE_4(sc, SIS_IMR, SIS_INTRS);
142150974Swpaul	CSR_WRITE_4(sc, SIS_IER, 1);
142250974Swpaul
142350974Swpaul	/* Enable receiver and transmitter. */
142450974Swpaul	SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE);
142550974Swpaul	SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE);
142650974Swpaul
142750974Swpaul	mii_mediachg(mii);
142850974Swpaul
142950974Swpaul	ifp->if_flags |= IFF_RUNNING;
143050974Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
143150974Swpaul
143250974Swpaul	(void)splx(s);
143350974Swpaul
143450974Swpaul	sc->sis_stat_ch = timeout(sis_tick, sc, hz);
143550974Swpaul
143650974Swpaul	return;
143750974Swpaul}
143850974Swpaul
143950974Swpaul/*
144050974Swpaul * Set media options.
144150974Swpaul */
144250974Swpaulstatic int sis_ifmedia_upd(ifp)
144350974Swpaul	struct ifnet		*ifp;
144450974Swpaul{
144550974Swpaul	struct sis_softc	*sc;
144650974Swpaul
144750974Swpaul	sc = ifp->if_softc;
144850974Swpaul
144950974Swpaul	if (ifp->if_flags & IFF_UP)
145050974Swpaul		sis_init(sc);
145150974Swpaul
145250974Swpaul	return(0);
145350974Swpaul}
145450974Swpaul
145550974Swpaul/*
145650974Swpaul * Report current media status.
145750974Swpaul */
145850974Swpaulstatic void sis_ifmedia_sts(ifp, ifmr)
145950974Swpaul	struct ifnet		*ifp;
146050974Swpaul	struct ifmediareq	*ifmr;
146150974Swpaul{
146250974Swpaul	struct sis_softc	*sc;
146350974Swpaul	struct mii_data		*mii;
146450974Swpaul
146550974Swpaul	sc = ifp->if_softc;
146650974Swpaul
146750974Swpaul	mii = device_get_softc(sc->sis_miibus);
146850974Swpaul	mii_pollstat(mii);
146950974Swpaul	ifmr->ifm_active = mii->mii_media_active;
147050974Swpaul	ifmr->ifm_status = mii->mii_media_status;
147150974Swpaul
147250974Swpaul	return;
147350974Swpaul}
147450974Swpaul
147550974Swpaulstatic int sis_ioctl(ifp, command, data)
147650974Swpaul	struct ifnet		*ifp;
147750974Swpaul	u_long			command;
147850974Swpaul	caddr_t			data;
147950974Swpaul{
148050974Swpaul	struct sis_softc	*sc = ifp->if_softc;
148150974Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
148250974Swpaul	struct mii_data		*mii;
148350974Swpaul	int			s, error = 0;
148450974Swpaul
148550974Swpaul	s = splimp();
148650974Swpaul
148750974Swpaul	switch(command) {
148850974Swpaul	case SIOCSIFADDR:
148950974Swpaul	case SIOCGIFADDR:
149050974Swpaul	case SIOCSIFMTU:
149150974Swpaul		error = ether_ioctl(ifp, command, data);
149250974Swpaul		break;
149350974Swpaul	case SIOCSIFFLAGS:
149450974Swpaul		if (ifp->if_flags & IFF_UP) {
149550974Swpaul			sis_init(sc);
149650974Swpaul		} else {
149750974Swpaul			if (ifp->if_flags & IFF_RUNNING)
149850974Swpaul				sis_stop(sc);
149950974Swpaul		}
150050974Swpaul		error = 0;
150150974Swpaul		break;
150250974Swpaul	case SIOCADDMULTI:
150350974Swpaul	case SIOCDELMULTI:
150462672Swpaul		if (sc->sis_type == SIS_TYPE_83815)
150562672Swpaul			sis_setmulti_ns(sc);
150662672Swpaul		else
150762672Swpaul			sis_setmulti_sis(sc);
150850974Swpaul		error = 0;
150950974Swpaul		break;
151050974Swpaul	case SIOCGIFMEDIA:
151150974Swpaul	case SIOCSIFMEDIA:
151250974Swpaul		mii = device_get_softc(sc->sis_miibus);
151350974Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
151450974Swpaul		break;
151550974Swpaul	default:
151650974Swpaul		error = EINVAL;
151750974Swpaul		break;
151850974Swpaul	}
151950974Swpaul
152050974Swpaul	(void)splx(s);
152150974Swpaul
152250974Swpaul	return(error);
152350974Swpaul}
152450974Swpaul
152550974Swpaulstatic void sis_watchdog(ifp)
152650974Swpaul	struct ifnet		*ifp;
152750974Swpaul{
152850974Swpaul	struct sis_softc	*sc;
152950974Swpaul
153050974Swpaul	sc = ifp->if_softc;
153150974Swpaul
153250974Swpaul	ifp->if_oerrors++;
153350974Swpaul	printf("sis%d: watchdog timeout\n", sc->sis_unit);
153450974Swpaul
153550974Swpaul	sis_stop(sc);
153650974Swpaul	sis_reset(sc);
153750974Swpaul	sis_init(sc);
153850974Swpaul
153950974Swpaul	if (ifp->if_snd.ifq_head != NULL)
154050974Swpaul		sis_start(ifp);
154150974Swpaul
154250974Swpaul	return;
154350974Swpaul}
154450974Swpaul
154550974Swpaul/*
154650974Swpaul * Stop the adapter and free any mbufs allocated to the
154750974Swpaul * RX and TX lists.
154850974Swpaul */
154950974Swpaulstatic void sis_stop(sc)
155050974Swpaul	struct sis_softc	*sc;
155150974Swpaul{
155250974Swpaul	register int		i;
155350974Swpaul	struct ifnet		*ifp;
155450974Swpaul
155550974Swpaul	ifp = &sc->arpcom.ac_if;
155650974Swpaul	ifp->if_timer = 0;
155750974Swpaul
155850974Swpaul	untimeout(sis_tick, sc, sc->sis_stat_ch);
155950974Swpaul	CSR_WRITE_4(sc, SIS_IER, 0);
156050974Swpaul	CSR_WRITE_4(sc, SIS_IMR, 0);
156150974Swpaul	SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE);
156250974Swpaul	DELAY(1000);
156350974Swpaul	CSR_WRITE_4(sc, SIS_TX_LISTPTR, 0);
156450974Swpaul	CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0);
156550974Swpaul
156650974Swpaul	/*
156750974Swpaul	 * Free data in the RX lists.
156850974Swpaul	 */
156950974Swpaul	for (i = 0; i < SIS_RX_LIST_CNT; i++) {
157050974Swpaul		if (sc->sis_ldata->sis_rx_list[i].sis_mbuf != NULL) {
157150974Swpaul			m_freem(sc->sis_ldata->sis_rx_list[i].sis_mbuf);
157250974Swpaul			sc->sis_ldata->sis_rx_list[i].sis_mbuf = NULL;
157350974Swpaul		}
157450974Swpaul	}
157550974Swpaul	bzero((char *)&sc->sis_ldata->sis_rx_list,
157650974Swpaul		sizeof(sc->sis_ldata->sis_rx_list));
157750974Swpaul
157850974Swpaul	/*
157950974Swpaul	 * Free the TX list buffers.
158050974Swpaul	 */
158150974Swpaul	for (i = 0; i < SIS_TX_LIST_CNT; i++) {
158250974Swpaul		if (sc->sis_ldata->sis_tx_list[i].sis_mbuf != NULL) {
158350974Swpaul			m_freem(sc->sis_ldata->sis_tx_list[i].sis_mbuf);
158450974Swpaul			sc->sis_ldata->sis_tx_list[i].sis_mbuf = NULL;
158550974Swpaul		}
158650974Swpaul	}
158750974Swpaul
158850974Swpaul	bzero((char *)&sc->sis_ldata->sis_tx_list,
158950974Swpaul		sizeof(sc->sis_ldata->sis_tx_list));
159050974Swpaul
159150974Swpaul	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
159250974Swpaul
159350974Swpaul	return;
159450974Swpaul}
159550974Swpaul
159650974Swpaul/*
159750974Swpaul * Stop all chip I/O so that the kernel's probe routines don't
159850974Swpaul * get confused by errant DMAs when rebooting.
159950974Swpaul */
160050974Swpaulstatic void sis_shutdown(dev)
160150974Swpaul	device_t		dev;
160250974Swpaul{
160350974Swpaul	struct sis_softc	*sc;
160450974Swpaul
160550974Swpaul	sc = device_get_softc(dev);
160650974Swpaul
160750974Swpaul	sis_reset(sc);
160850974Swpaul	sis_stop(sc);
160950974Swpaul
161050974Swpaul	return;
161150974Swpaul}
1612