if_sis.c revision 101464
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 101464 2002-08-07 16:08:54Z luigi $
3350974Swpaul */
3450974Swpaul
3550974Swpaul/*
3650974Swpaul * SiS 900/SiS 7016 fast ethernet PCI NIC driver. Datasheets are
3750974Swpaul * available from http://www.sis.com.tw.
3850974Swpaul *
3964963Swpaul * This driver also supports the NatSemi DP83815. Datasheets are
4064963Swpaul * available from http://www.national.com.
4164963Swpaul *
4250974Swpaul * Written by Bill Paul <wpaul@ee.columbia.edu>
4350974Swpaul * Electrical Engineering Department
4450974Swpaul * Columbia University, New York City
4550974Swpaul */
4650974Swpaul
4750974Swpaul/*
4850974Swpaul * The SiS 900 is a fairly simple chip. It uses bus master DMA with
4950974Swpaul * simple TX and RX descriptors of 3 longwords in size. The receiver
5050974Swpaul * has a single perfect filter entry for the station address and a
5150974Swpaul * 128-bit multicast hash table. The SiS 900 has a built-in MII-based
5250974Swpaul * transceiver while the 7016 requires an external transceiver chip.
5350974Swpaul * Both chips offer the standard bit-bang MII interface as well as
5450974Swpaul * an enchanced PHY interface which simplifies accessing MII registers.
5550974Swpaul *
5650974Swpaul * The only downside to this chipset is that RX descriptors must be
5750974Swpaul * longword aligned.
5850974Swpaul */
5950974Swpaul
6050974Swpaul#include <sys/param.h>
6150974Swpaul#include <sys/systm.h>
6250974Swpaul#include <sys/sockio.h>
6350974Swpaul#include <sys/mbuf.h>
6450974Swpaul#include <sys/malloc.h>
6550974Swpaul#include <sys/kernel.h>
6650974Swpaul#include <sys/socket.h>
6787059Sluigi#include <sys/sysctl.h>
6850974Swpaul
6950974Swpaul#include <net/if.h>
7050974Swpaul#include <net/if_arp.h>
7150974Swpaul#include <net/ethernet.h>
7250974Swpaul#include <net/if_dl.h>
7350974Swpaul#include <net/if_media.h>
7487390Sjhay#include <net/if_types.h>
7587390Sjhay#include <net/if_vlan_var.h>
7650974Swpaul
7750974Swpaul#include <net/bpf.h>
7850974Swpaul
7950974Swpaul#include <machine/bus_pio.h>
8050974Swpaul#include <machine/bus_memio.h>
8150974Swpaul#include <machine/bus.h>
8250974Swpaul#include <machine/resource.h>
8350974Swpaul#include <sys/bus.h>
8450974Swpaul#include <sys/rman.h>
8550974Swpaul
8650974Swpaul#include <dev/mii/mii.h>
8750974Swpaul#include <dev/mii/miivar.h>
8850974Swpaul
8950974Swpaul#include <pci/pcireg.h>
9050974Swpaul#include <pci/pcivar.h>
9150974Swpaul
9250974Swpaul#define SIS_USEIOSPACE
9350974Swpaul
9450974Swpaul#include <pci/if_sisreg.h>
9550974Swpaul
9659758SpeterMODULE_DEPEND(sis, miibus, 1, 1, 1);
9759758Speter
9851089Speter/* "controller miibus0" required.  See GENERIC if you get errors here. */
9950974Swpaul#include "miibus_if.h"
10050974Swpaul
10150974Swpaul#ifndef lint
10250974Swpaulstatic const char rcsid[] =
10350974Swpaul  "$FreeBSD: head/sys/pci/if_sis.c 101464 2002-08-07 16:08:54Z luigi $";
10450974Swpaul#endif
10550974Swpaul
10650974Swpaul/*
10750974Swpaul * Various supported device vendors/types and their names.
10850974Swpaul */
10950974Swpaulstatic struct sis_type sis_devs[] = {
11050974Swpaul	{ SIS_VENDORID, SIS_DEVICEID_900, "SiS 900 10/100BaseTX" },
11150974Swpaul	{ SIS_VENDORID, SIS_DEVICEID_7016, "SiS 7016 10/100BaseTX" },
11262672Swpaul	{ NS_VENDORID, NS_DEVICEID_DP83815, "NatSemi DP83815 10/100BaseTX" },
11350974Swpaul	{ 0, 0, NULL }
11450974Swpaul};
11550974Swpaul
11692739Salfredstatic int sis_probe		(device_t);
11792739Salfredstatic int sis_attach		(device_t);
11892739Salfredstatic int sis_detach		(device_t);
11950974Swpaul
12092739Salfredstatic int sis_newbuf		(struct sis_softc *,
12192739Salfred					struct sis_desc *, struct mbuf *);
12292739Salfredstatic int sis_encap		(struct sis_softc *,
12392739Salfred					struct mbuf *, u_int32_t *);
12492739Salfredstatic void sis_rxeof		(struct sis_softc *);
12592739Salfredstatic void sis_rxeoc		(struct sis_softc *);
12692739Salfredstatic void sis_txeof		(struct sis_softc *);
12792739Salfredstatic void sis_intr		(void *);
12892739Salfredstatic void sis_tick		(void *);
12992739Salfredstatic void sis_start		(struct ifnet *);
13092739Salfredstatic int sis_ioctl		(struct ifnet *, u_long, caddr_t);
13192739Salfredstatic void sis_init		(void *);
13292739Salfredstatic void sis_stop		(struct sis_softc *);
13392739Salfredstatic void sis_watchdog		(struct ifnet *);
13492739Salfredstatic void sis_shutdown		(device_t);
13592739Salfredstatic int sis_ifmedia_upd	(struct ifnet *);
13692739Salfredstatic void sis_ifmedia_sts	(struct ifnet *, struct ifmediareq *);
13750974Swpaul
13892739Salfredstatic u_int16_t sis_reverse	(u_int16_t);
13992739Salfredstatic void sis_delay		(struct sis_softc *);
14092739Salfredstatic void sis_eeprom_idle	(struct sis_softc *);
14192739Salfredstatic void sis_eeprom_putbyte	(struct sis_softc *, int);
14292739Salfredstatic void sis_eeprom_getword	(struct sis_softc *, int, u_int16_t *);
14392739Salfredstatic void sis_read_eeprom	(struct sis_softc *, caddr_t, int, int, int);
14472197Swpaul#ifdef __i386__
14592739Salfredstatic void sis_read_cmos	(struct sis_softc *, device_t, caddr_t,
14692739Salfred							int, int);
14792739Salfredstatic void sis_read_mac	(struct sis_softc *, device_t, caddr_t);
14892739Salfredstatic device_t sis_find_bridge	(device_t);
14972197Swpaul#endif
15072197Swpaul
15192739Salfredstatic int sis_miibus_readreg	(device_t, int, int);
15292739Salfredstatic int sis_miibus_writereg	(device_t, int, int, int);
15392739Salfredstatic void sis_miibus_statchg	(device_t);
15450974Swpaul
15592739Salfredstatic void sis_setmulti_sis	(struct sis_softc *);
15692739Salfredstatic void sis_setmulti_ns	(struct sis_softc *);
15792739Salfredstatic u_int32_t sis_crc	(struct sis_softc *, caddr_t);
15892739Salfredstatic void sis_reset		(struct sis_softc *);
15992739Salfredstatic int sis_list_rx_init	(struct sis_softc *);
16092739Salfredstatic int sis_list_tx_init	(struct sis_softc *);
16150974Swpaul
16292739Salfredstatic void sis_dma_map_desc_ptr	(void *, bus_dma_segment_t *, int, int);
16392739Salfredstatic void sis_dma_map_desc_next	(void *, bus_dma_segment_t *, int, int);
16492739Salfredstatic void sis_dma_map_ring		(void *, bus_dma_segment_t *, int, int);
16550974Swpaul#ifdef SIS_USEIOSPACE
16650974Swpaul#define SIS_RES			SYS_RES_IOPORT
16750974Swpaul#define SIS_RID			SIS_PCI_LOIO
16850974Swpaul#else
16951030Swpaul#define SIS_RES			SYS_RES_MEMORY
17051030Swpaul#define SIS_RID			SIS_PCI_LOMEM
17150974Swpaul#endif
17250974Swpaul
17350974Swpaulstatic device_method_t sis_methods[] = {
17450974Swpaul	/* Device interface */
17550974Swpaul	DEVMETHOD(device_probe,		sis_probe),
17650974Swpaul	DEVMETHOD(device_attach,	sis_attach),
17750974Swpaul	DEVMETHOD(device_detach,	sis_detach),
17850974Swpaul	DEVMETHOD(device_shutdown,	sis_shutdown),
17950974Swpaul
18050974Swpaul	/* bus interface */
18150974Swpaul	DEVMETHOD(bus_print_child,	bus_generic_print_child),
18250974Swpaul	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
18350974Swpaul
18450974Swpaul	/* MII interface */
18550974Swpaul	DEVMETHOD(miibus_readreg,	sis_miibus_readreg),
18650974Swpaul	DEVMETHOD(miibus_writereg,	sis_miibus_writereg),
18750974Swpaul	DEVMETHOD(miibus_statchg,	sis_miibus_statchg),
18850974Swpaul
18950974Swpaul	{ 0, 0 }
19050974Swpaul};
19150974Swpaul
19250974Swpaulstatic driver_t sis_driver = {
19351455Swpaul	"sis",
19450974Swpaul	sis_methods,
19550974Swpaul	sizeof(struct sis_softc)
19650974Swpaul};
19750974Swpaul
19850974Swpaulstatic devclass_t sis_devclass;
19950974Swpaul
20051533SwpaulDRIVER_MODULE(if_sis, pci, sis_driver, sis_devclass, 0, 0);
20151473SwpaulDRIVER_MODULE(miibus, sis, miibus_driver, miibus_devclass, 0, 0);
20250974Swpaul
20350974Swpaul#define SIS_SETBIT(sc, reg, x)				\
20450974Swpaul	CSR_WRITE_4(sc, reg,				\
20550974Swpaul		CSR_READ_4(sc, reg) | (x))
20650974Swpaul
20750974Swpaul#define SIS_CLRBIT(sc, reg, x)				\
20850974Swpaul	CSR_WRITE_4(sc, reg,				\
20950974Swpaul		CSR_READ_4(sc, reg) & ~(x))
21050974Swpaul
21150974Swpaul#define SIO_SET(x)					\
21250974Swpaul	CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) | x)
21350974Swpaul
21450974Swpaul#define SIO_CLR(x)					\
21550974Swpaul	CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) & ~x)
21650974Swpaul
21781713Swpaulstatic void
21881713Swpaulsis_dma_map_desc_next(arg, segs, nseg, error)
21981713Swpaul	void *arg;
22081713Swpaul	bus_dma_segment_t *segs;
22181713Swpaul	int nseg, error;
22281713Swpaul{
22381713Swpaul	struct sis_desc	*r;
22481713Swpaul
22581713Swpaul	r = arg;
22681713Swpaul	r->sis_next = segs->ds_addr;
22781713Swpaul
22881713Swpaul	return;
22981713Swpaul}
23081713Swpaul
23181713Swpaulstatic void
23281713Swpaulsis_dma_map_desc_ptr(arg, segs, nseg, error)
23381713Swpaul	void *arg;
23481713Swpaul	bus_dma_segment_t *segs;
23581713Swpaul	int nseg, error;
23681713Swpaul{
23781713Swpaul	struct sis_desc	*r;
23881713Swpaul
23981713Swpaul	r = arg;
24081713Swpaul	r->sis_ptr = segs->ds_addr;
24181713Swpaul
24281713Swpaul	return;
24381713Swpaul}
24481713Swpaul
24581713Swpaulstatic void
24681713Swpaulsis_dma_map_ring(arg, segs, nseg, error)
24781713Swpaul	void *arg;
24881713Swpaul	bus_dma_segment_t *segs;
24981713Swpaul	int nseg, error;
25081713Swpaul{
25181713Swpaul	u_int32_t *p;
25281713Swpaul
25381713Swpaul	p = arg;
25481713Swpaul	*p = segs->ds_addr;
25581713Swpaul
25681713Swpaul	return;
25781713Swpaul}
25881713Swpaul
25962672Swpaul/*
26062672Swpaul * Routine to reverse the bits in a word. Stolen almost
26162672Swpaul * verbatim from /usr/games/fortune.
26262672Swpaul */
26362672Swpaulstatic u_int16_t sis_reverse(n)
26462672Swpaul	u_int16_t		n;
26562672Swpaul{
26662672Swpaul	n = ((n >>  1) & 0x5555) | ((n <<  1) & 0xaaaa);
26762672Swpaul	n = ((n >>  2) & 0x3333) | ((n <<  2) & 0xcccc);
26862672Swpaul	n = ((n >>  4) & 0x0f0f) | ((n <<  4) & 0xf0f0);
26962672Swpaul	n = ((n >>  8) & 0x00ff) | ((n <<  8) & 0xff00);
27062672Swpaul
27162672Swpaul	return(n);
27262672Swpaul}
27362672Swpaul
27450974Swpaulstatic void sis_delay(sc)
27550974Swpaul	struct sis_softc	*sc;
27650974Swpaul{
27750974Swpaul	int			idx;
27850974Swpaul
27950974Swpaul	for (idx = (300 / 33) + 1; idx > 0; idx--)
28050974Swpaul		CSR_READ_4(sc, SIS_CSR);
28150974Swpaul
28250974Swpaul	return;
28350974Swpaul}
28450974Swpaul
28550974Swpaulstatic void sis_eeprom_idle(sc)
28650974Swpaul	struct sis_softc	*sc;
28750974Swpaul{
28850974Swpaul	register int		i;
28950974Swpaul
29050974Swpaul	SIO_SET(SIS_EECTL_CSEL);
29150974Swpaul	sis_delay(sc);
29250974Swpaul	SIO_SET(SIS_EECTL_CLK);
29350974Swpaul	sis_delay(sc);
29450974Swpaul
29550974Swpaul	for (i = 0; i < 25; i++) {
29650974Swpaul		SIO_CLR(SIS_EECTL_CLK);
29750974Swpaul		sis_delay(sc);
29850974Swpaul		SIO_SET(SIS_EECTL_CLK);
29950974Swpaul		sis_delay(sc);
30050974Swpaul	}
30150974Swpaul
30250974Swpaul	SIO_CLR(SIS_EECTL_CLK);
30350974Swpaul	sis_delay(sc);
30450974Swpaul	SIO_CLR(SIS_EECTL_CSEL);
30550974Swpaul	sis_delay(sc);
30650974Swpaul	CSR_WRITE_4(sc, SIS_EECTL, 0x00000000);
30750974Swpaul
30850974Swpaul	return;
30950974Swpaul}
31050974Swpaul
31150974Swpaul/*
31250974Swpaul * Send a read command and address to the EEPROM, check for ACK.
31350974Swpaul */
31450974Swpaulstatic void sis_eeprom_putbyte(sc, addr)
31550974Swpaul	struct sis_softc	*sc;
31650974Swpaul	int			addr;
31750974Swpaul{
31850974Swpaul	register int		d, i;
31950974Swpaul
32050974Swpaul	d = addr | SIS_EECMD_READ;
32150974Swpaul
32250974Swpaul	/*
32350974Swpaul	 * Feed in each bit and stobe the clock.
32450974Swpaul	 */
32550974Swpaul	for (i = 0x400; i; i >>= 1) {
32650974Swpaul		if (d & i) {
32750974Swpaul			SIO_SET(SIS_EECTL_DIN);
32850974Swpaul		} else {
32950974Swpaul			SIO_CLR(SIS_EECTL_DIN);
33050974Swpaul		}
33150974Swpaul		sis_delay(sc);
33250974Swpaul		SIO_SET(SIS_EECTL_CLK);
33350974Swpaul		sis_delay(sc);
33450974Swpaul		SIO_CLR(SIS_EECTL_CLK);
33550974Swpaul		sis_delay(sc);
33650974Swpaul	}
33750974Swpaul
33850974Swpaul	return;
33950974Swpaul}
34050974Swpaul
34150974Swpaul/*
34250974Swpaul * Read a word of data stored in the EEPROM at address 'addr.'
34350974Swpaul */
34450974Swpaulstatic void sis_eeprom_getword(sc, addr, dest)
34550974Swpaul	struct sis_softc	*sc;
34650974Swpaul	int			addr;
34750974Swpaul	u_int16_t		*dest;
34850974Swpaul{
34950974Swpaul	register int		i;
35050974Swpaul	u_int16_t		word = 0;
35150974Swpaul
35250974Swpaul	/* Force EEPROM to idle state. */
35350974Swpaul	sis_eeprom_idle(sc);
35450974Swpaul
35550974Swpaul	/* Enter EEPROM access mode. */
35650974Swpaul	sis_delay(sc);
35762672Swpaul	SIO_CLR(SIS_EECTL_CLK);
35862672Swpaul	sis_delay(sc);
35950974Swpaul	SIO_SET(SIS_EECTL_CSEL);
36050974Swpaul	sis_delay(sc);
36150974Swpaul
36250974Swpaul	/*
36350974Swpaul	 * Send address of word we want to read.
36450974Swpaul	 */
36550974Swpaul	sis_eeprom_putbyte(sc, addr);
36650974Swpaul
36750974Swpaul	/*
36850974Swpaul	 * Start reading bits from EEPROM.
36950974Swpaul	 */
37050974Swpaul	for (i = 0x8000; i; i >>= 1) {
37150974Swpaul		SIO_SET(SIS_EECTL_CLK);
37250974Swpaul		sis_delay(sc);
37350974Swpaul		if (CSR_READ_4(sc, SIS_EECTL) & SIS_EECTL_DOUT)
37450974Swpaul			word |= i;
37550974Swpaul		sis_delay(sc);
37650974Swpaul		SIO_CLR(SIS_EECTL_CLK);
37750974Swpaul		sis_delay(sc);
37850974Swpaul	}
37950974Swpaul
38050974Swpaul	/* Turn off EEPROM access mode. */
38150974Swpaul	sis_eeprom_idle(sc);
38250974Swpaul
38350974Swpaul	*dest = word;
38450974Swpaul
38550974Swpaul	return;
38650974Swpaul}
38750974Swpaul
38850974Swpaul/*
38950974Swpaul * Read a sequence of words from the EEPROM.
39050974Swpaul */
39150974Swpaulstatic void sis_read_eeprom(sc, dest, off, cnt, swap)
39250974Swpaul	struct sis_softc	*sc;
39350974Swpaul	caddr_t			dest;
39450974Swpaul	int			off;
39550974Swpaul	int			cnt;
39650974Swpaul	int			swap;
39750974Swpaul{
39850974Swpaul	int			i;
39950974Swpaul	u_int16_t		word = 0, *ptr;
40050974Swpaul
40150974Swpaul	for (i = 0; i < cnt; i++) {
40250974Swpaul		sis_eeprom_getword(sc, off + i, &word);
40350974Swpaul		ptr = (u_int16_t *)(dest + (i * 2));
40450974Swpaul		if (swap)
40550974Swpaul			*ptr = ntohs(word);
40650974Swpaul		else
40750974Swpaul			*ptr = word;
40850974Swpaul	}
40950974Swpaul
41050974Swpaul	return;
41150974Swpaul}
41250974Swpaul
41372197Swpaul#ifdef __i386__
41472197Swpaulstatic device_t sis_find_bridge(dev)
41572197Swpaul	device_t		dev;
41672197Swpaul{
41772197Swpaul	devclass_t		pci_devclass;
41872197Swpaul	device_t		*pci_devices;
41972197Swpaul	int			pci_count = 0;
42072197Swpaul	device_t		*pci_children;
42172197Swpaul	int			pci_childcount = 0;
42272197Swpaul	device_t		*busp, *childp;
42387994Sarchie	device_t		child = NULL;
42472197Swpaul	int			i, j;
42572197Swpaul
42672197Swpaul	if ((pci_devclass = devclass_find("pci")) == NULL)
42772197Swpaul		return(NULL);
42872197Swpaul
42972197Swpaul	devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
43072197Swpaul
43172197Swpaul	for (i = 0, busp = pci_devices; i < pci_count; i++, busp++) {
43272197Swpaul		pci_childcount = 0;
43372197Swpaul		device_get_children(*busp, &pci_children, &pci_childcount);
43472197Swpaul		for (j = 0, childp = pci_children;
43572197Swpaul		    j < pci_childcount; j++, childp++) {
43672197Swpaul			if (pci_get_vendor(*childp) == SIS_VENDORID &&
43772197Swpaul			    pci_get_device(*childp) == 0x0008) {
43887994Sarchie				child = *childp;
43987994Sarchie				goto done;
44072197Swpaul			}
44172197Swpaul		}
44272197Swpaul	}
44372197Swpaul
44487994Sarchiedone:
44572197Swpaul	free(pci_devices, M_TEMP);
44672197Swpaul	free(pci_children, M_TEMP);
44787994Sarchie	return(child);
44872197Swpaul}
44972197Swpaul
45072197Swpaulstatic void sis_read_cmos(sc, dev, dest, off, cnt)
45172197Swpaul	struct sis_softc	*sc;
45272197Swpaul	device_t		dev;
45372197Swpaul	caddr_t			dest;
45472197Swpaul	int			off;
45572197Swpaul	int			cnt;
45672197Swpaul{
45772197Swpaul	device_t		bridge;
45872197Swpaul	u_int8_t		reg;
45972197Swpaul	int			i;
46072197Swpaul	bus_space_tag_t		btag;
46172197Swpaul
46272197Swpaul	bridge = sis_find_bridge(dev);
46372197Swpaul	if (bridge == NULL)
46472197Swpaul		return;
46572197Swpaul	reg = pci_read_config(bridge, 0x48, 1);
46672197Swpaul	pci_write_config(bridge, 0x48, reg|0x40, 1);
46772197Swpaul
46872197Swpaul	/* XXX */
46972197Swpaul	btag = I386_BUS_SPACE_IO;
47072197Swpaul
47172197Swpaul	for (i = 0; i < cnt; i++) {
47272197Swpaul		bus_space_write_1(btag, 0x0, 0x70, i + off);
47372197Swpaul		*(dest + i) = bus_space_read_1(btag, 0x0, 0x71);
47472197Swpaul	}
47572197Swpaul
47672197Swpaul	pci_write_config(bridge, 0x48, reg & ~0x40, 1);
47772197Swpaul	return;
47872197Swpaul}
47989296Swpaul
48089296Swpaulstatic void sis_read_mac(sc, dev, dest)
48189296Swpaul	struct sis_softc	*sc;
48289296Swpaul	device_t		dev;
48389296Swpaul	caddr_t			dest;
48489296Swpaul{
48589296Swpaul	u_int32_t		filtsave, csrsave;
48689296Swpaul
48789296Swpaul	filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL);
48889296Swpaul	csrsave = CSR_READ_4(sc, SIS_CSR);
48989296Swpaul
49089296Swpaul	CSR_WRITE_4(sc, SIS_CSR, SIS_CSR_RELOAD | filtsave);
49189296Swpaul	CSR_WRITE_4(sc, SIS_CSR, 0);
49289296Swpaul
49389296Swpaul	CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave & ~SIS_RXFILTCTL_ENABLE);
49489296Swpaul
49589296Swpaul	CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0);
49689296Swpaul	((u_int16_t *)dest)[0] = CSR_READ_2(sc, SIS_RXFILT_DATA);
49789296Swpaul	CSR_WRITE_4(sc, SIS_RXFILT_CTL,SIS_FILTADDR_PAR1);
49889296Swpaul	((u_int16_t *)dest)[1] = CSR_READ_2(sc, SIS_RXFILT_DATA);
49989296Swpaul	CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2);
50089296Swpaul	((u_int16_t *)dest)[2] = CSR_READ_2(sc, SIS_RXFILT_DATA);
50189296Swpaul
50289296Swpaul	CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave);
50389296Swpaul	CSR_WRITE_4(sc, SIS_CSR, csrsave);
50489296Swpaul	return;
50589296Swpaul}
50672197Swpaul#endif
50772197Swpaul
50850974Swpaulstatic int sis_miibus_readreg(dev, phy, reg)
50950974Swpaul	device_t		dev;
51050974Swpaul	int			phy, reg;
51150974Swpaul{
51250974Swpaul	struct sis_softc	*sc;
51362672Swpaul	int			i, val = 0;
51450974Swpaul
51550974Swpaul	sc = device_get_softc(dev);
51650974Swpaul
51762672Swpaul	if (sc->sis_type == SIS_TYPE_83815) {
51862672Swpaul		if (phy != 0)
51962672Swpaul			return(0);
52062672Swpaul		/*
52162672Swpaul		 * The NatSemi chip can take a while after
52262672Swpaul		 * a reset to come ready, during which the BMSR
52362672Swpaul		 * returns a value of 0. This is *never* supposed
52462672Swpaul		 * to happen: some of the BMSR bits are meant to
52562672Swpaul		 * be hardwired in the on position, and this can
52662672Swpaul		 * confuse the miibus code a bit during the probe
52762672Swpaul		 * and attach phase. So we make an effort to check
52862672Swpaul		 * for this condition and wait for it to clear.
52962672Swpaul		 */
53062672Swpaul		if (!CSR_READ_4(sc, NS_BMSR))
53162672Swpaul			DELAY(1000);
53262672Swpaul		val = CSR_READ_4(sc, NS_BMCR + (reg * 4));
53362672Swpaul		return(val);
53462672Swpaul	}
53562672Swpaul
53689296Swpaul	if (sc->sis_type == SIS_TYPE_900 &&
53789296Swpaul	    sc->sis_rev < SIS_REV_635 && phy != 0)
53850974Swpaul		return(0);
53950974Swpaul
54050974Swpaul	CSR_WRITE_4(sc, SIS_PHYCTL, (phy << 11) | (reg << 6) | SIS_PHYOP_READ);
54150974Swpaul	SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS);
54250974Swpaul
54350974Swpaul	for (i = 0; i < SIS_TIMEOUT; i++) {
54450974Swpaul		if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS))
54550974Swpaul			break;
54650974Swpaul	}
54750974Swpaul
54850974Swpaul	if (i == SIS_TIMEOUT) {
54950974Swpaul		printf("sis%d: PHY failed to come ready\n", sc->sis_unit);
55050974Swpaul		return(0);
55150974Swpaul	}
55250974Swpaul
55350974Swpaul	val = (CSR_READ_4(sc, SIS_PHYCTL) >> 16) & 0xFFFF;
55450974Swpaul
55550974Swpaul	if (val == 0xFFFF)
55650974Swpaul		return(0);
55750974Swpaul
55850974Swpaul	return(val);
55950974Swpaul}
56050974Swpaul
56150974Swpaulstatic int sis_miibus_writereg(dev, phy, reg, data)
56250974Swpaul	device_t		dev;
56350974Swpaul	int			phy, reg, data;
56450974Swpaul{
56550974Swpaul	struct sis_softc	*sc;
56650974Swpaul	int			i;
56750974Swpaul
56850974Swpaul	sc = device_get_softc(dev);
56950974Swpaul
57062672Swpaul	if (sc->sis_type == SIS_TYPE_83815) {
57162672Swpaul		if (phy != 0)
57262672Swpaul			return(0);
57362672Swpaul		CSR_WRITE_4(sc, NS_BMCR + (reg * 4), data);
57462672Swpaul		return(0);
57562672Swpaul	}
57662672Swpaul
57750974Swpaul	if (sc->sis_type == SIS_TYPE_900 && phy != 0)
57850974Swpaul		return(0);
57950974Swpaul
58050974Swpaul	CSR_WRITE_4(sc, SIS_PHYCTL, (data << 16) | (phy << 11) |
58150974Swpaul	    (reg << 6) | SIS_PHYOP_WRITE);
58250974Swpaul	SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS);
58350974Swpaul
58450974Swpaul	for (i = 0; i < SIS_TIMEOUT; i++) {
58550974Swpaul		if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS))
58650974Swpaul			break;
58750974Swpaul	}
58850974Swpaul
58950974Swpaul	if (i == SIS_TIMEOUT)
59050974Swpaul		printf("sis%d: PHY failed to come ready\n", sc->sis_unit);
59150974Swpaul
59250974Swpaul	return(0);
59350974Swpaul}
59450974Swpaul
59550974Swpaulstatic void sis_miibus_statchg(dev)
59650974Swpaul	device_t		dev;
59750974Swpaul{
59850974Swpaul	struct sis_softc	*sc;
59950974Swpaul
60050974Swpaul	sc = device_get_softc(dev);
60164963Swpaul	sis_init(sc);
60250974Swpaul
60350974Swpaul	return;
60450974Swpaul}
60550974Swpaul
60662672Swpaulstatic u_int32_t sis_crc(sc, addr)
60762672Swpaul	struct sis_softc	*sc;
60850974Swpaul	caddr_t			addr;
60950974Swpaul{
61050974Swpaul	u_int32_t		crc, carry;
61150974Swpaul	int			i, j;
61250974Swpaul	u_int8_t		c;
61350974Swpaul
61450974Swpaul	/* Compute CRC for the address value. */
61550974Swpaul	crc = 0xFFFFFFFF; /* initial value */
61650974Swpaul
61750974Swpaul	for (i = 0; i < 6; i++) {
61850974Swpaul		c = *(addr + i);
61950974Swpaul		for (j = 0; j < 8; j++) {
62050974Swpaul			carry = ((crc & 0x80000000) ? 1 : 0) ^ (c & 0x01);
62150974Swpaul			crc <<= 1;
62250974Swpaul			c >>= 1;
62350974Swpaul			if (carry)
62450974Swpaul				crc = (crc ^ 0x04c11db6) | carry;
62550974Swpaul		}
62650974Swpaul	}
62750974Swpaul
62862672Swpaul	/*
62962672Swpaul	 * return the filter bit position
63062672Swpaul	 *
63162672Swpaul	 * The NatSemi chip has a 512-bit filter, which is
63262672Swpaul	 * different than the SiS, so we special-case it.
63362672Swpaul	 */
63462672Swpaul	if (sc->sis_type == SIS_TYPE_83815)
63562672Swpaul		return((crc >> 23) & 0x1FF);
63662672Swpaul
63750974Swpaul	return((crc >> 25) & 0x0000007F);
63850974Swpaul}
63950974Swpaul
64062672Swpaulstatic void sis_setmulti_ns(sc)
64150974Swpaul	struct sis_softc	*sc;
64250974Swpaul{
64350974Swpaul	struct ifnet		*ifp;
64450974Swpaul	struct ifmultiaddr	*ifma;
64550974Swpaul	u_int32_t		h = 0, i, filtsave;
64662672Swpaul	int			bit, index;
64750974Swpaul
64850974Swpaul	ifp = &sc->arpcom.ac_if;
64950974Swpaul
65050974Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
65162672Swpaul		SIS_CLRBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_MCHASH);
65250974Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI);
65350974Swpaul		return;
65450974Swpaul	}
65550974Swpaul
65662672Swpaul	/*
65762672Swpaul	 * We have to explicitly enable the multicast hash table
65862672Swpaul	 * on the NatSemi chip if we want to use it, which we do.
65962672Swpaul	 */
66062672Swpaul	SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_MCHASH);
66150974Swpaul	SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI);
66250974Swpaul
66350974Swpaul	filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL);
66450974Swpaul
66550974Swpaul	/* first, zot all the existing hash bits */
66662672Swpaul	for (i = 0; i < 32; i++) {
66762672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + (i*2));
66862672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA, 0);
66962672Swpaul	}
67062672Swpaul
67172084Sphk	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
67262672Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
67362672Swpaul			continue;
67462672Swpaul		h = sis_crc(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
67562672Swpaul		index = h >> 3;
67662672Swpaul		bit = h & 0x1F;
67762672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + index);
67862672Swpaul		if (bit > 0xF)
67962672Swpaul			bit -= 0x10;
68062672Swpaul		SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << bit));
68162672Swpaul	}
68262672Swpaul
68362672Swpaul	CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave);
68462672Swpaul
68562672Swpaul	return;
68662672Swpaul}
68762672Swpaul
68862672Swpaulstatic void sis_setmulti_sis(sc)
68962672Swpaul	struct sis_softc	*sc;
69062672Swpaul{
69162672Swpaul	struct ifnet		*ifp;
69262672Swpaul	struct ifmultiaddr	*ifma;
69362672Swpaul	u_int32_t		h = 0, i, filtsave;
69462672Swpaul
69562672Swpaul	ifp = &sc->arpcom.ac_if;
69662672Swpaul
69762672Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
69862672Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI);
69962672Swpaul		return;
70062672Swpaul	}
70162672Swpaul
70262672Swpaul	SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI);
70362672Swpaul
70462672Swpaul	filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL);
70562672Swpaul
70662672Swpaul	/* first, zot all the existing hash bits */
70750974Swpaul	for (i = 0; i < 8; i++) {
70850974Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, (4 + ((i * 16) >> 4)) << 16);
70950974Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA, 0);
71050974Swpaul	}
71150974Swpaul
71250974Swpaul	/* now program new ones */
71372084Sphk	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
71450974Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
71550974Swpaul			continue;
71662672Swpaul		h = sis_crc(sc, LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
71750974Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, (4 + (h >> 4)) << 16);
71850974Swpaul		SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << (h & 0xF)));
71950974Swpaul	}
72050974Swpaul
72150974Swpaul	CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave);
72250974Swpaul
72350974Swpaul	return;
72450974Swpaul}
72550974Swpaul
72650974Swpaulstatic void sis_reset(sc)
72750974Swpaul	struct sis_softc	*sc;
72850974Swpaul{
72950974Swpaul	register int		i;
73050974Swpaul
73150974Swpaul	SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RESET);
73250974Swpaul
73350974Swpaul	for (i = 0; i < SIS_TIMEOUT; i++) {
73450974Swpaul		if (!(CSR_READ_4(sc, SIS_CSR) & SIS_CSR_RESET))
73550974Swpaul			break;
73650974Swpaul	}
73750974Swpaul
73850974Swpaul	if (i == SIS_TIMEOUT)
73950974Swpaul		printf("sis%d: reset never completed\n", sc->sis_unit);
74050974Swpaul
74150974Swpaul	/* Wait a little while for the chip to get its brains in order. */
74250974Swpaul	DELAY(1000);
74372813Swpaul
74472813Swpaul	/*
74572813Swpaul	 * If this is a NetSemi chip, make sure to clear
74672813Swpaul	 * PME mode.
74772813Swpaul	 */
74872813Swpaul	if (sc->sis_type == SIS_TYPE_83815) {
74972813Swpaul		CSR_WRITE_4(sc, NS_CLKRUN, NS_CLKRUN_PMESTS);
75072813Swpaul		CSR_WRITE_4(sc, NS_CLKRUN, 0);
75172813Swpaul	}
75272813Swpaul
75350974Swpaul        return;
75450974Swpaul}
75550974Swpaul
75650974Swpaul/*
75750974Swpaul * Probe for an SiS chip. Check the PCI vendor and device
75850974Swpaul * IDs against our list and return a device name if we find a match.
75950974Swpaul */
76050974Swpaulstatic int sis_probe(dev)
76150974Swpaul	device_t		dev;
76250974Swpaul{
76350974Swpaul	struct sis_type		*t;
76450974Swpaul
76550974Swpaul	t = sis_devs;
76650974Swpaul
76750974Swpaul	while(t->sis_name != NULL) {
76850974Swpaul		if ((pci_get_vendor(dev) == t->sis_vid) &&
76950974Swpaul		    (pci_get_device(dev) == t->sis_did)) {
77050974Swpaul			device_set_desc(dev, t->sis_name);
77150974Swpaul			return(0);
77250974Swpaul		}
77350974Swpaul		t++;
77450974Swpaul	}
77550974Swpaul
77650974Swpaul	return(ENXIO);
77750974Swpaul}
77850974Swpaul
77950974Swpaul/*
78050974Swpaul * Attach the interface. Allocate softc structures, do ifmedia
78150974Swpaul * setup and ethernet/BPF attach.
78250974Swpaul */
78350974Swpaulstatic int sis_attach(dev)
78450974Swpaul	device_t		dev;
78550974Swpaul{
78650974Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
78750974Swpaul	u_int32_t		command;
78850974Swpaul	struct sis_softc	*sc;
78950974Swpaul	struct ifnet		*ifp;
79050974Swpaul	int			unit, error = 0, rid;
79150974Swpaul
79250974Swpaul	sc = device_get_softc(dev);
79350974Swpaul	unit = device_get_unit(dev);
79450974Swpaul	bzero(sc, sizeof(struct sis_softc));
79550974Swpaul
79693818Sjhb	mtx_init(&sc->sis_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
79793818Sjhb	    MTX_DEF | MTX_RECURSE);
79869583Swpaul	SIS_LOCK(sc);
79969583Swpaul
80050974Swpaul	if (pci_get_device(dev) == SIS_DEVICEID_900)
80150974Swpaul		sc->sis_type = SIS_TYPE_900;
80250974Swpaul	if (pci_get_device(dev) == SIS_DEVICEID_7016)
80350974Swpaul		sc->sis_type = SIS_TYPE_7016;
80462672Swpaul	if (pci_get_vendor(dev) == NS_VENDORID)
80562672Swpaul		sc->sis_type = SIS_TYPE_83815;
80650974Swpaul
80789296Swpaul	sc->sis_rev = pci_read_config(dev, PCIR_REVID, 1);
80889296Swpaul
80950974Swpaul	/*
81050974Swpaul	 * Handle power management nonsense.
81150974Swpaul	 */
81272813Swpaul	if (pci_get_powerstate(dev) != PCI_POWERSTATE_D0) {
81372813Swpaul		u_int32_t		iobase, membase, irq;
81450974Swpaul
81572813Swpaul		/* Save important PCI config data. */
81672813Swpaul		iobase = pci_read_config(dev, SIS_PCI_LOIO, 4);
81772813Swpaul		membase = pci_read_config(dev, SIS_PCI_LOMEM, 4);
81872813Swpaul		irq = pci_read_config(dev, SIS_PCI_INTLINE, 4);
81950974Swpaul
82072813Swpaul		/* Reset the power state. */
82172813Swpaul		printf("sis%d: chip is in D%d power mode "
82272813Swpaul		    "-- setting to D0\n", unit,
82372813Swpaul		    pci_get_powerstate(dev));
82472813Swpaul		pci_set_powerstate(dev, PCI_POWERSTATE_D0);
82550974Swpaul
82672813Swpaul		/* Restore PCI config data. */
82772813Swpaul		pci_write_config(dev, SIS_PCI_LOIO, iobase, 4);
82872813Swpaul		pci_write_config(dev, SIS_PCI_LOMEM, membase, 4);
82972813Swpaul		pci_write_config(dev, SIS_PCI_INTLINE, irq, 4);
83050974Swpaul	}
83150974Swpaul
83250974Swpaul	/*
83350974Swpaul	 * Map control/status registers.
83450974Swpaul	 */
83572813Swpaul	pci_enable_busmaster(dev);
83679472Swpaul	pci_enable_io(dev, SYS_RES_IOPORT);
83779472Swpaul	pci_enable_io(dev, SYS_RES_MEMORY);
83861041Speter	command = pci_read_config(dev, PCIR_COMMAND, 4);
83950974Swpaul
84050974Swpaul#ifdef SIS_USEIOSPACE
84150974Swpaul	if (!(command & PCIM_CMD_PORTEN)) {
84250974Swpaul		printf("sis%d: failed to enable I/O ports!\n", unit);
84350974Swpaul		error = ENXIO;;
84450974Swpaul		goto fail;
84550974Swpaul	}
84650974Swpaul#else
84750974Swpaul	if (!(command & PCIM_CMD_MEMEN)) {
84850974Swpaul		printf("sis%d: failed to enable memory mapping!\n", unit);
84950974Swpaul		error = ENXIO;;
85050974Swpaul		goto fail;
85150974Swpaul	}
85250974Swpaul#endif
85350974Swpaul
85450974Swpaul	rid = SIS_RID;
85550974Swpaul	sc->sis_res = bus_alloc_resource(dev, SIS_RES, &rid,
85650974Swpaul	    0, ~0, 1, RF_ACTIVE);
85750974Swpaul
85850974Swpaul	if (sc->sis_res == NULL) {
85950974Swpaul		printf("sis%d: couldn't map ports/memory\n", unit);
86050974Swpaul		error = ENXIO;
86150974Swpaul		goto fail;
86250974Swpaul	}
86350974Swpaul
86450974Swpaul	sc->sis_btag = rman_get_bustag(sc->sis_res);
86550974Swpaul	sc->sis_bhandle = rman_get_bushandle(sc->sis_res);
86650974Swpaul
86750974Swpaul	/* Allocate interrupt */
86850974Swpaul	rid = 0;
86950974Swpaul	sc->sis_irq = bus_alloc_resource(dev, SYS_RES_IRQ, &rid, 0, ~0, 1,
87050974Swpaul	    RF_SHAREABLE | RF_ACTIVE);
87150974Swpaul
87250974Swpaul	if (sc->sis_irq == NULL) {
87350974Swpaul		printf("sis%d: couldn't map interrupt\n", unit);
87450974Swpaul		bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
87550974Swpaul		error = ENXIO;
87650974Swpaul		goto fail;
87750974Swpaul	}
87850974Swpaul
87950974Swpaul	error = bus_setup_intr(dev, sc->sis_irq, INTR_TYPE_NET,
88050974Swpaul	    sis_intr, sc, &sc->sis_intrhand);
88150974Swpaul
88250974Swpaul	if (error) {
88368216Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq);
88450974Swpaul		bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
88550974Swpaul		printf("sis%d: couldn't set up irq\n", unit);
88650974Swpaul		goto fail;
88750974Swpaul	}
88850974Swpaul
88950974Swpaul	/* Reset the adapter. */
89050974Swpaul	sis_reset(sc);
89150974Swpaul
89250974Swpaul	/*
89350974Swpaul	 * Get station address from the EEPROM.
89450974Swpaul	 */
89562672Swpaul	switch (pci_get_vendor(dev)) {
89662672Swpaul	case NS_VENDORID:
89762672Swpaul		/*
89862672Swpaul		 * Reading the MAC address out of the EEPROM on
89962672Swpaul		 * the NatSemi chip takes a bit more work than
90062672Swpaul		 * you'd expect. The address spans 4 16-bit words,
90162672Swpaul		 * with the first word containing only a single bit.
90262672Swpaul		 * You have to shift everything over one bit to
90362672Swpaul		 * get it aligned properly. Also, the bits are
90462672Swpaul		 * stored backwards (the LSB is really the MSB,
90562672Swpaul		 * and so on) so you have to reverse them in order
90662672Swpaul		 * to get the MAC address into the form we want.
90762672Swpaul		 * Why? Who the hell knows.
90862672Swpaul		 */
90962672Swpaul		{
91062672Swpaul			u_int16_t		tmp[4];
91150974Swpaul
91262672Swpaul			sis_read_eeprom(sc, (caddr_t)&tmp,
91362672Swpaul			    NS_EE_NODEADDR, 4, 0);
91462672Swpaul
91562672Swpaul			/* Shift everything over one bit. */
91662672Swpaul			tmp[3] = tmp[3] >> 1;
91762681Swpaul			tmp[3] |= tmp[2] << 15;
91862672Swpaul			tmp[2] = tmp[2] >> 1;
91962681Swpaul			tmp[2] |= tmp[1] << 15;
92062672Swpaul			tmp[1] = tmp[1] >> 1;
92162681Swpaul			tmp[1] |= tmp[0] << 15;
92262672Swpaul
92362672Swpaul			/* Now reverse all the bits. */
92462672Swpaul			tmp[3] = sis_reverse(tmp[3]);
92562672Swpaul			tmp[2] = sis_reverse(tmp[2]);
92662672Swpaul			tmp[1] = sis_reverse(tmp[1]);
92762672Swpaul
92862672Swpaul			bcopy((char *)&tmp[1], eaddr, ETHER_ADDR_LEN);
92962672Swpaul		}
93062672Swpaul		break;
93162672Swpaul	case SIS_VENDORID:
93262672Swpaul	default:
93372197Swpaul#ifdef __i386__
93472197Swpaul		/*
93572197Swpaul		 * If this is a SiS 630E chipset with an embedded
93672197Swpaul		 * SiS 900 controller, we have to read the MAC address
93772197Swpaul		 * from the APC CMOS RAM. Our method for doing this
93872197Swpaul		 * is very ugly since we have to reach out and grab
93972197Swpaul		 * ahold of hardware for which we cannot properly
94072197Swpaul		 * allocate resources. This code is only compiled on
94172197Swpaul		 * the i386 architecture since the SiS 630E chipset
94272197Swpaul		 * is for x86 motherboards only. Note that there are
94372197Swpaul		 * a lot of magic numbers in this hack. These are
94472197Swpaul		 * taken from SiS's Linux driver. I'd like to replace
94572197Swpaul		 * them with proper symbolic definitions, but that
94672197Swpaul		 * requires some datasheets that I don't have access
94772197Swpaul		 * to at the moment.
94872197Swpaul		 */
94989296Swpaul		if (sc->sis_rev == SIS_REV_630S ||
95089296Swpaul		    sc->sis_rev == SIS_REV_630E ||
95190328Sambrisko		    sc->sis_rev == SIS_REV_630EA1)
95272197Swpaul			sis_read_cmos(sc, dev, (caddr_t)&eaddr, 0x9, 6);
95389296Swpaul
95490328Sambrisko		else if (sc->sis_rev == SIS_REV_635 ||
95590328Sambrisko			 sc->sis_rev == SIS_REV_630ET)
95689296Swpaul			sis_read_mac(sc, dev, (caddr_t)&eaddr);
95772197Swpaul		else
95872197Swpaul#endif
95972197Swpaul			sis_read_eeprom(sc, (caddr_t)&eaddr,
96072197Swpaul			    SIS_EE_NODEADDR, 3, 0);
96162672Swpaul		break;
96262672Swpaul	}
96362672Swpaul
96450974Swpaul	/*
96550974Swpaul	 * A SiS chip was detected. Inform the world.
96650974Swpaul	 */
96750974Swpaul	printf("sis%d: Ethernet address: %6D\n", unit, eaddr, ":");
96850974Swpaul
96950974Swpaul	sc->sis_unit = unit;
97050974Swpaul	callout_handle_init(&sc->sis_stat_ch);
97150974Swpaul	bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
97250974Swpaul
97381713Swpaul	/*
97481713Swpaul	 * Allocate the parent bus DMA tag appropriate for PCI.
97581713Swpaul	 */
97681713Swpaul#define SIS_NSEG_NEW 32
97781713Swpaul	 error = bus_dma_tag_create(NULL,	/* parent */
97881713Swpaul			1, 0,			/* alignment, boundary */
97981713Swpaul			BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
98081713Swpaul			BUS_SPACE_MAXADDR,	/* highaddr */
98181713Swpaul			NULL, NULL,		/* filter, filterarg */
98281713Swpaul			MAXBSIZE, SIS_NSEG_NEW,	/* maxsize, nsegments */
98381713Swpaul			BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
98481713Swpaul			BUS_DMA_ALLOCNOW,	/* flags */
98581713Swpaul			&sc->sis_parent_tag);
98650974Swpaul
98781713Swpaul	/*
98881713Swpaul	 * Now allocate a tag for the DMA descriptor lists.
98981713Swpaul	 * All of our lists are allocated as a contiguous block
99081713Swpaul	 * of memory.
99181713Swpaul	 */
99281713Swpaul	error = bus_dma_tag_create(sc->sis_parent_tag,	/* parent */
99381713Swpaul			1, 0,			/* alignment, boundary */
99481713Swpaul			BUS_SPACE_MAXADDR,	/* lowaddr */
99581713Swpaul			BUS_SPACE_MAXADDR,	/* highaddr */
99681713Swpaul			NULL, NULL,		/* filter, filterarg */
99781713Swpaul			SIS_RX_LIST_SZ, 1,	/* maxsize,nsegments */
99881713Swpaul			BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
99981713Swpaul			0,			/* flags */
100081713Swpaul			&sc->sis_ldata.sis_rx_tag);
100181713Swpaul
100281713Swpaul	error = bus_dma_tag_create(sc->sis_parent_tag,	/* parent */
100381713Swpaul			1, 0,			/* alignment, boundary */
100481713Swpaul			BUS_SPACE_MAXADDR,	/* lowaddr */
100581713Swpaul			BUS_SPACE_MAXADDR,	/* highaddr */
100681713Swpaul			NULL, NULL,		/* filter, filterarg */
100781713Swpaul			SIS_TX_LIST_SZ, 1,	/* maxsize,nsegments */
100881713Swpaul			BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
100981713Swpaul			0,			/* flags */
101081713Swpaul			&sc->sis_ldata.sis_tx_tag);
101181713Swpaul
101281713Swpaul	error = bus_dma_tag_create(sc->sis_parent_tag,	/* parent */
101381713Swpaul			1, 0,			/* alignment, boundary */
101481713Swpaul			BUS_SPACE_MAXADDR,	/* lowaddr */
101581713Swpaul			BUS_SPACE_MAXADDR,	/* highaddr */
101681713Swpaul			NULL, NULL,		/* filter, filterarg */
101781713Swpaul			SIS_TX_LIST_SZ, 1,	/* maxsize,nsegments */
101881713Swpaul			BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
101981713Swpaul			0,			/* flags */
102081713Swpaul			&sc->sis_tag);
102181713Swpaul
102281713Swpaul	/*
102381713Swpaul	 * Now allocate a chunk of DMA-able memory based on the
102481713Swpaul	 * tag we just created.
102581713Swpaul	 */
102681713Swpaul	error = bus_dmamem_alloc(sc->sis_ldata.sis_tx_tag,
102781713Swpaul	    (void **)&sc->sis_ldata.sis_tx_list, BUS_DMA_NOWAIT,
102881713Swpaul	    &sc->sis_ldata.sis_tx_dmamap);
102981713Swpaul
103081713Swpaul	if (error) {
103150974Swpaul		printf("sis%d: no memory for list buffers!\n", unit);
103250974Swpaul		bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand);
103350974Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq);
103450974Swpaul		bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
103581713Swpaul		bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag);
103681713Swpaul		bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag);
103750974Swpaul		error = ENXIO;
103850974Swpaul		goto fail;
103950974Swpaul	}
104050974Swpaul
104181713Swpaul	error = bus_dmamem_alloc(sc->sis_ldata.sis_rx_tag,
104281713Swpaul	    (void **)&sc->sis_ldata.sis_rx_list, BUS_DMA_NOWAIT,
104381713Swpaul	    &sc->sis_ldata.sis_rx_dmamap);
104481713Swpaul
104581713Swpaul	if (error) {
104681713Swpaul		printf("sis%d: no memory for list buffers!\n", unit);
104781713Swpaul		bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand);
104881713Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq);
104981713Swpaul		bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
105081713Swpaul		bus_dmamem_free(sc->sis_ldata.sis_rx_tag,
105181713Swpaul		    sc->sis_ldata.sis_tx_list, sc->sis_ldata.sis_tx_dmamap);
105281713Swpaul		bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag);
105381713Swpaul		bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag);
105481713Swpaul		error = ENXIO;
105581713Swpaul		goto fail;
105681713Swpaul	}
105781713Swpaul
105881713Swpaul
105981713Swpaul	bzero(sc->sis_ldata.sis_tx_list, SIS_TX_LIST_SZ);
106081713Swpaul	bzero(sc->sis_ldata.sis_rx_list, SIS_RX_LIST_SZ);
106181713Swpaul
106281713Swpaul	/*
106381713Swpaul	 * Obtain the physical addresses of the RX and TX
106481713Swpaul	 * rings which we'll need later in the init routine.
106581713Swpaul	 */
106681713Swpaul	bus_dmamap_load(sc->sis_ldata.sis_tx_tag,
106781713Swpaul	    sc->sis_ldata.sis_tx_dmamap, &(sc->sis_ldata.sis_tx_list[0]),
106881713Swpaul	    sizeof(struct sis_desc), sis_dma_map_ring,
106981713Swpaul	    &sc->sis_cdata.sis_tx_paddr, 0);
107081713Swpaul	bus_dmamap_load(sc->sis_ldata.sis_rx_tag,
107181713Swpaul	    sc->sis_ldata.sis_rx_dmamap, &(sc->sis_ldata.sis_rx_list[0]),
107281713Swpaul	    sizeof(struct sis_desc), sis_dma_map_ring,
107381713Swpaul	    &sc->sis_cdata.sis_rx_paddr, 0);
107481713Swpaul
107550974Swpaul	ifp = &sc->arpcom.ac_if;
107650974Swpaul	ifp->if_softc = sc;
107750974Swpaul	ifp->if_unit = unit;
107850974Swpaul	ifp->if_name = "sis";
107950974Swpaul	ifp->if_mtu = ETHERMTU;
108050974Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
108150974Swpaul	ifp->if_ioctl = sis_ioctl;
108250974Swpaul	ifp->if_output = ether_output;
108350974Swpaul	ifp->if_start = sis_start;
108450974Swpaul	ifp->if_watchdog = sis_watchdog;
108550974Swpaul	ifp->if_init = sis_init;
108650974Swpaul	ifp->if_baudrate = 10000000;
108750974Swpaul	ifp->if_snd.ifq_maxlen = SIS_TX_LIST_CNT - 1;
108850974Swpaul
108950974Swpaul	/*
109050974Swpaul	 * Do MII setup.
109150974Swpaul	 */
109250974Swpaul	if (mii_phy_probe(dev, &sc->sis_miibus,
109350974Swpaul	    sis_ifmedia_upd, sis_ifmedia_sts)) {
109450974Swpaul		printf("sis%d: MII without any PHY!\n", sc->sis_unit);
109550974Swpaul		bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand);
109650974Swpaul		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq);
109750974Swpaul		bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
109881713Swpaul		bus_dmamem_free(sc->sis_ldata.sis_rx_tag,
109981713Swpaul		    sc->sis_ldata.sis_rx_list, sc->sis_ldata.sis_rx_dmamap);
110081713Swpaul		bus_dmamem_free(sc->sis_ldata.sis_rx_tag,
110181713Swpaul		    sc->sis_ldata.sis_tx_list, sc->sis_ldata.sis_tx_dmamap);
110281713Swpaul		bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag);
110381713Swpaul		bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag);
110450974Swpaul		error = ENXIO;
110550974Swpaul		goto fail;
110650974Swpaul	}
110750974Swpaul
110850974Swpaul	/*
110963090Sarchie	 * Call MI attach routine.
111050974Swpaul	 */
111163090Sarchie	ether_ifattach(ifp, ETHER_BPF_SUPPORTED);
111287390Sjhay
111387390Sjhay	/*
111487390Sjhay	 * Tell the upper layer(s) we support long frames.
111587390Sjhay	 */
111687390Sjhay	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
111787390Sjhay
111850974Swpaul	callout_handle_init(&sc->sis_stat_ch);
111967087Swpaul	SIS_UNLOCK(sc);
112067087Swpaul	return(0);
112150974Swpaul
112250974Swpaulfail:
112367087Swpaul	SIS_UNLOCK(sc);
112467087Swpaul	mtx_destroy(&sc->sis_mtx);
112550974Swpaul	return(error);
112650974Swpaul}
112750974Swpaul
112850974Swpaulstatic int sis_detach(dev)
112950974Swpaul	device_t		dev;
113050974Swpaul{
113150974Swpaul	struct sis_softc	*sc;
113250974Swpaul	struct ifnet		*ifp;
113350974Swpaul
113450974Swpaul
113550974Swpaul	sc = device_get_softc(dev);
113667087Swpaul	SIS_LOCK(sc);
113750974Swpaul	ifp = &sc->arpcom.ac_if;
113850974Swpaul
113950974Swpaul	sis_reset(sc);
114050974Swpaul	sis_stop(sc);
114163090Sarchie	ether_ifdetach(ifp, ETHER_BPF_SUPPORTED);
114250974Swpaul
114350974Swpaul	bus_generic_detach(dev);
114450974Swpaul	device_delete_child(dev, sc->sis_miibus);
114550974Swpaul
114650974Swpaul	bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand);
114750974Swpaul	bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq);
114850974Swpaul	bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
114950974Swpaul
115081713Swpaul	bus_dmamap_unload(sc->sis_ldata.sis_rx_tag,
115181713Swpaul	    sc->sis_ldata.sis_rx_dmamap);
115281713Swpaul	bus_dmamap_unload(sc->sis_ldata.sis_tx_tag,
115381713Swpaul	    sc->sis_ldata.sis_tx_dmamap);
115481713Swpaul	bus_dmamem_free(sc->sis_ldata.sis_rx_tag,
115581713Swpaul	    sc->sis_ldata.sis_rx_list, sc->sis_ldata.sis_rx_dmamap);
115681713Swpaul	bus_dmamem_free(sc->sis_ldata.sis_rx_tag,
115781713Swpaul	    sc->sis_ldata.sis_tx_list, sc->sis_ldata.sis_tx_dmamap);
115881713Swpaul	bus_dma_tag_destroy(sc->sis_ldata.sis_rx_tag);
115981713Swpaul	bus_dma_tag_destroy(sc->sis_ldata.sis_tx_tag);
116081713Swpaul	bus_dma_tag_destroy(sc->sis_parent_tag);
116150974Swpaul
116267087Swpaul	SIS_UNLOCK(sc);
116367087Swpaul	mtx_destroy(&sc->sis_mtx);
116450974Swpaul
116550974Swpaul	return(0);
116650974Swpaul}
116750974Swpaul
116850974Swpaul/*
116950974Swpaul * Initialize the transmit descriptors.
117050974Swpaul */
117150974Swpaulstatic int sis_list_tx_init(sc)
117250974Swpaul	struct sis_softc	*sc;
117350974Swpaul{
117450974Swpaul	struct sis_list_data	*ld;
117550974Swpaul	struct sis_ring_data	*cd;
117687059Sluigi	int			i, nexti;
117750974Swpaul
117850974Swpaul	cd = &sc->sis_cdata;
117981713Swpaul	ld = &sc->sis_ldata;
118050974Swpaul
118150974Swpaul	for (i = 0; i < SIS_TX_LIST_CNT; i++) {
118287102Sluigi		nexti = (i == (SIS_TX_LIST_CNT - 1)) ? 0 : i+1;
118350974Swpaul			ld->sis_tx_list[i].sis_nextdesc =
118487059Sluigi			    &ld->sis_tx_list[nexti];
118581713Swpaul			bus_dmamap_load(sc->sis_ldata.sis_tx_tag,
118681713Swpaul			    sc->sis_ldata.sis_tx_dmamap,
118787059Sluigi			    &ld->sis_tx_list[nexti], sizeof(struct sis_desc),
118881713Swpaul			    sis_dma_map_desc_next, &ld->sis_tx_list[i], 0);
118950974Swpaul		ld->sis_tx_list[i].sis_mbuf = NULL;
119050974Swpaul		ld->sis_tx_list[i].sis_ptr = 0;
119150974Swpaul		ld->sis_tx_list[i].sis_ctl = 0;
119250974Swpaul	}
119350974Swpaul
119450974Swpaul	cd->sis_tx_prod = cd->sis_tx_cons = cd->sis_tx_cnt = 0;
119550974Swpaul
119681713Swpaul	bus_dmamap_sync(sc->sis_ldata.sis_tx_tag,
119781713Swpaul	    sc->sis_ldata.sis_rx_dmamap, BUS_DMASYNC_PREWRITE);
119881713Swpaul
119950974Swpaul	return(0);
120050974Swpaul}
120150974Swpaul
120250974Swpaul/*
120350974Swpaul * Initialize the RX descriptors and allocate mbufs for them. Note that
120450974Swpaul * we arrange the descriptors in a closed ring, so that the last descriptor
120550974Swpaul * points back to the first.
120650974Swpaul */
120750974Swpaulstatic int sis_list_rx_init(sc)
120850974Swpaul	struct sis_softc	*sc;
120950974Swpaul{
121050974Swpaul	struct sis_list_data	*ld;
121150974Swpaul	struct sis_ring_data	*cd;
121287059Sluigi	int			i,nexti;
121350974Swpaul
121481713Swpaul	ld = &sc->sis_ldata;
121550974Swpaul	cd = &sc->sis_cdata;
121650974Swpaul
121750974Swpaul	for (i = 0; i < SIS_RX_LIST_CNT; i++) {
121850974Swpaul		if (sis_newbuf(sc, &ld->sis_rx_list[i], NULL) == ENOBUFS)
121950974Swpaul			return(ENOBUFS);
122087102Sluigi		nexti = (i == (SIS_RX_LIST_CNT - 1)) ? 0 : i+1;
122150974Swpaul			ld->sis_rx_list[i].sis_nextdesc =
122287059Sluigi			    &ld->sis_rx_list[nexti];
122381713Swpaul			bus_dmamap_load(sc->sis_ldata.sis_rx_tag,
122481713Swpaul			    sc->sis_ldata.sis_rx_dmamap,
122587059Sluigi			    &ld->sis_rx_list[nexti],
122681713Swpaul			    sizeof(struct sis_desc), sis_dma_map_desc_next,
122781713Swpaul			    &ld->sis_rx_list[i], 0);
122850974Swpaul		}
122950974Swpaul
123081713Swpaul	bus_dmamap_sync(sc->sis_ldata.sis_rx_tag,
123181713Swpaul	    sc->sis_ldata.sis_rx_dmamap, BUS_DMASYNC_PREWRITE);
123281713Swpaul
123350974Swpaul	cd->sis_rx_prod = 0;
123450974Swpaul
123550974Swpaul	return(0);
123650974Swpaul}
123750974Swpaul
123850974Swpaul/*
123950974Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
124050974Swpaul */
124150974Swpaulstatic int sis_newbuf(sc, c, m)
124250974Swpaul	struct sis_softc	*sc;
124350974Swpaul	struct sis_desc		*c;
124450974Swpaul	struct mbuf		*m;
124550974Swpaul{
124650974Swpaul
124781713Swpaul	if (c == NULL)
124881713Swpaul		return(EINVAL);
124981713Swpaul
125050974Swpaul	if (m == NULL) {
1251101340Sluigi		m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1252101340Sluigi		if (m == NULL)
125350974Swpaul			return(ENOBUFS);
1254101340Sluigi	} else
1255101340Sluigi		m->m_data = m->m_ext.ext_buf;
125650974Swpaul
1257101340Sluigi	c->sis_mbuf = m;
125850974Swpaul	c->sis_ctl = SIS_RXLEN;
125950974Swpaul
126081713Swpaul	bus_dmamap_create(sc->sis_tag, 0, &c->sis_map);
126181713Swpaul	bus_dmamap_load(sc->sis_tag, c->sis_map,
1262101464Sluigi	    mtod(m, void *), MCLBYTES,
126381713Swpaul	    sis_dma_map_desc_ptr, c, 0);
126481713Swpaul	bus_dmamap_sync(sc->sis_tag, c->sis_map, BUS_DMASYNC_PREWRITE);
126581713Swpaul
126650974Swpaul	return(0);
126750974Swpaul}
126850974Swpaul
126950974Swpaul/*
127050974Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
127150974Swpaul * the higher level protocols.
127250974Swpaul */
127350974Swpaulstatic void sis_rxeof(sc)
127450974Swpaul	struct sis_softc	*sc;
127550974Swpaul{
127650974Swpaul        struct mbuf		*m;
127750974Swpaul        struct ifnet		*ifp;
127850974Swpaul	struct sis_desc		*cur_rx;
127950974Swpaul	int			i, total_len = 0;
128050974Swpaul	u_int32_t		rxstat;
128150974Swpaul
128250974Swpaul	ifp = &sc->arpcom.ac_if;
128350974Swpaul	i = sc->sis_cdata.sis_rx_prod;
128450974Swpaul
128581713Swpaul	while(SIS_OWNDESC(&sc->sis_ldata.sis_rx_list[i])) {
128650974Swpaul
128787902Sluigi#ifdef DEVICE_POLLING
128887902Sluigi		if (ifp->if_ipending & IFF_POLLING) {
128987902Sluigi			if (sc->rxcycles <= 0)
129087902Sluigi				break;
129187902Sluigi			sc->rxcycles--;
129287902Sluigi		}
129387902Sluigi#endif /* DEVICE_POLLING */
129481713Swpaul		cur_rx = &sc->sis_ldata.sis_rx_list[i];
129550974Swpaul		rxstat = cur_rx->sis_rxstat;
129681713Swpaul		bus_dmamap_sync(sc->sis_tag,
129781713Swpaul		    cur_rx->sis_map, BUS_DMASYNC_POSTWRITE);
129881713Swpaul		bus_dmamap_unload(sc->sis_tag, cur_rx->sis_map);
129981713Swpaul		bus_dmamap_destroy(sc->sis_tag, cur_rx->sis_map);
130050974Swpaul		m = cur_rx->sis_mbuf;
130150974Swpaul		cur_rx->sis_mbuf = NULL;
130250974Swpaul		total_len = SIS_RXBYTES(cur_rx);
130350974Swpaul		SIS_INC(i, SIS_RX_LIST_CNT);
130450974Swpaul
130550974Swpaul		/*
130650974Swpaul		 * If an error occurs, update stats, clear the
130750974Swpaul		 * status word and leave the mbuf cluster in place:
130850974Swpaul		 * it should simply get re-used next time this descriptor
130950974Swpaul	 	 * comes up in the ring.
131050974Swpaul		 */
131150974Swpaul		if (!(rxstat & SIS_CMDSTS_PKT_OK)) {
131250974Swpaul			ifp->if_ierrors++;
131350974Swpaul			if (rxstat & SIS_RXSTAT_COLL)
131450974Swpaul				ifp->if_collisions++;
131550974Swpaul			sis_newbuf(sc, cur_rx, m);
131650974Swpaul			continue;
131750974Swpaul		}
131850974Swpaul
131950974Swpaul		/* No errors; receive the packet. */
132087059Sluigi#ifdef __i386__
132187059Sluigi		/*
132287059Sluigi		 * On the x86 we do not have alignment problems, so try to
132387059Sluigi		 * allocate a new buffer for the receive ring, and pass up
132487059Sluigi		 * the one where the packet is already, saving the expensive
132587059Sluigi		 * copy done in m_devget().
132687059Sluigi		 * If we are on an architecture with alignment problems, or
132787059Sluigi		 * if the allocation fails, then use m_devget and leave the
132887059Sluigi		 * existing buffer in the receive ring.
132987059Sluigi		 */
1330101464Sluigi		if (sis_newbuf(sc, cur_rx, NULL) == 0)
133187059Sluigi			m->m_pkthdr.len = m->m_len = total_len;
1332101464Sluigi		else
133387059Sluigi#endif
133487059Sluigi		{
133587059Sluigi			struct mbuf		*m0;
133687059Sluigi			m0 = m_devget(mtod(m, char *), total_len,
133787059Sluigi				ETHER_ALIGN, ifp, NULL);
133887059Sluigi			sis_newbuf(sc, cur_rx, m);
133987059Sluigi			if (m0 == NULL) {
134087059Sluigi				ifp->if_ierrors++;
134187059Sluigi				continue;
134287059Sluigi			}
134387059Sluigi			m = m0;
134450974Swpaul		}
134550974Swpaul
134650974Swpaul		ifp->if_ipackets++;
1347101464Sluigi		ether_input(ifp, NULL, m);
134850974Swpaul	}
134950974Swpaul
135050974Swpaul	sc->sis_cdata.sis_rx_prod = i;
135150974Swpaul
135250974Swpaul	return;
135350974Swpaul}
135450974Swpaul
135550974Swpaulvoid sis_rxeoc(sc)
135650974Swpaul	struct sis_softc	*sc;
135750974Swpaul{
135850974Swpaul	sis_rxeof(sc);
135950974Swpaul	sis_init(sc);
136050974Swpaul	return;
136150974Swpaul}
136250974Swpaul
136350974Swpaul/*
136450974Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
136550974Swpaul * the list buffers.
136650974Swpaul */
136750974Swpaul
136850974Swpaulstatic void sis_txeof(sc)
136950974Swpaul	struct sis_softc	*sc;
137050974Swpaul{
137150974Swpaul	struct ifnet		*ifp;
137250974Swpaul	u_int32_t		idx;
137350974Swpaul
137450974Swpaul	ifp = &sc->arpcom.ac_if;
137550974Swpaul
137650974Swpaul	/*
137750974Swpaul	 * Go through our tx list and free mbufs for those
137850974Swpaul	 * frames that have been transmitted.
137950974Swpaul	 */
138099163Sluigi	for (idx = sc->sis_cdata.sis_tx_cons; sc->sis_cdata.sis_tx_cnt > 0;
138199163Sluigi	    sc->sis_cdata.sis_tx_cnt--, SIS_INC(idx, SIS_TX_LIST_CNT) ) {
138299163Sluigi		struct sis_desc *cur_tx = &sc->sis_ldata.sis_tx_list[idx];
138350974Swpaul
138450974Swpaul		if (SIS_OWNDESC(cur_tx))
138550974Swpaul			break;
138650974Swpaul
138799163Sluigi		if (cur_tx->sis_ctl & SIS_CMDSTS_MORE)
138850974Swpaul			continue;
138950974Swpaul
139050974Swpaul		if (!(cur_tx->sis_ctl & SIS_CMDSTS_PKT_OK)) {
139150974Swpaul			ifp->if_oerrors++;
139250974Swpaul			if (cur_tx->sis_txstat & SIS_TXSTAT_EXCESSCOLLS)
139350974Swpaul				ifp->if_collisions++;
139450974Swpaul			if (cur_tx->sis_txstat & SIS_TXSTAT_OUTOFWINCOLL)
139550974Swpaul				ifp->if_collisions++;
139650974Swpaul		}
139750974Swpaul
139850974Swpaul		ifp->if_collisions +=
139950974Swpaul		    (cur_tx->sis_txstat & SIS_TXSTAT_COLLCNT) >> 16;
140050974Swpaul
140150974Swpaul		ifp->if_opackets++;
140250974Swpaul		if (cur_tx->sis_mbuf != NULL) {
140350974Swpaul			m_freem(cur_tx->sis_mbuf);
140450974Swpaul			cur_tx->sis_mbuf = NULL;
140581713Swpaul			bus_dmamap_unload(sc->sis_tag, cur_tx->sis_map);
140681713Swpaul			bus_dmamap_destroy(sc->sis_tag, cur_tx->sis_map);
140750974Swpaul		}
140899163Sluigi	}
140950974Swpaul
141099163Sluigi	if (idx != sc->sis_cdata.sis_tx_cons) {
141199163Sluigi		/* we freed up some buffers */
141299163Sluigi		sc->sis_cdata.sis_tx_cons = idx;
141399163Sluigi		ifp->if_flags &= ~IFF_OACTIVE;
141450974Swpaul	}
141550974Swpaul
141699163Sluigi	ifp->if_timer = (sc->sis_cdata.sis_tx_cnt == 0) ? 0 : 5;
141750974Swpaul
141850974Swpaul	return;
141950974Swpaul}
142050974Swpaul
142150974Swpaulstatic void sis_tick(xsc)
142250974Swpaul	void			*xsc;
142350974Swpaul{
142450974Swpaul	struct sis_softc	*sc;
142550974Swpaul	struct mii_data		*mii;
142664963Swpaul	struct ifnet		*ifp;
142750974Swpaul
142850974Swpaul	sc = xsc;
142967087Swpaul	SIS_LOCK(sc);
143064963Swpaul	ifp = &sc->arpcom.ac_if;
143164963Swpaul
143250974Swpaul	mii = device_get_softc(sc->sis_miibus);
143350974Swpaul	mii_tick(mii);
143464963Swpaul
143584147Sjlemon	if (!sc->sis_link && mii->mii_media_status & IFM_ACTIVE &&
143684147Sjlemon	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
143784147Sjlemon		sc->sis_link++;
143884147Sjlemon		if (ifp->if_snd.ifq_head != NULL)
143984147Sjlemon			sis_start(ifp);
144064963Swpaul	}
144164963Swpaul
144251031Swpaul	sc->sis_stat_ch = timeout(sis_tick, sc, hz);
144350974Swpaul
144467087Swpaul	SIS_UNLOCK(sc);
144550974Swpaul
144650974Swpaul	return;
144750974Swpaul}
144850974Swpaul
144987902Sluigi#ifdef DEVICE_POLLING
145087902Sluigistatic poll_handler_t sis_poll;
145187902Sluigi
145287902Sluigistatic void
145387902Sluigisis_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
145487902Sluigi{
145587973Speter	struct	sis_softc *sc = ifp->if_softc;
145687973Speter
145787902Sluigi	SIS_LOCK(sc);
145887902Sluigi	if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */
145987902Sluigi		CSR_WRITE_4(sc, SIS_IER, 1);
146087902Sluigi		goto done;
146187902Sluigi	}
146287902Sluigi
146387902Sluigi	/*
146487902Sluigi	 * On the sis, reading the status register also clears it.
146587902Sluigi	 * So before returning to intr mode we must make sure that all
146687902Sluigi	 * possible pending sources of interrupts have been served.
146787902Sluigi	 * In practice this means run to completion the *eof routines,
146887902Sluigi	 * and then call the interrupt routine
146987902Sluigi	 */
147087902Sluigi	sc->rxcycles = count;
147187902Sluigi	sis_rxeof(sc);
147287902Sluigi	sis_txeof(sc);
147387902Sluigi	if (ifp->if_snd.ifq_head != NULL)
147487902Sluigi		sis_start(ifp);
147587902Sluigi
147687902Sluigi	if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) {
147787902Sluigi		u_int32_t	status;
147887902Sluigi
147987902Sluigi		/* Reading the ISR register clears all interrupts. */
148087902Sluigi		status = CSR_READ_4(sc, SIS_ISR);
148187902Sluigi
148287902Sluigi		if (status & (SIS_ISR_RX_ERR|SIS_ISR_RX_OFLOW))
148387902Sluigi			sis_rxeoc(sc);
148487902Sluigi
148587902Sluigi		if (status & (SIS_ISR_RX_IDLE))
148687902Sluigi			SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE);
148787902Sluigi
148887902Sluigi		if (status & SIS_ISR_SYSERR) {
148987902Sluigi			sis_reset(sc);
149087902Sluigi			sis_init(sc);
149187902Sluigi		}
149287902Sluigi	}
149387902Sluigidone:
149487902Sluigi	SIS_UNLOCK(sc);
149587902Sluigi	return;
149687902Sluigi}
149787902Sluigi#endif /* DEVICE_POLLING */
149887902Sluigi
149950974Swpaulstatic void sis_intr(arg)
150050974Swpaul	void			*arg;
150150974Swpaul{
150250974Swpaul	struct sis_softc	*sc;
150350974Swpaul	struct ifnet		*ifp;
150450974Swpaul	u_int32_t		status;
150550974Swpaul
150650974Swpaul	sc = arg;
150750974Swpaul	ifp = &sc->arpcom.ac_if;
150850974Swpaul
150986984Sluigi	SIS_LOCK(sc);
151087902Sluigi#ifdef DEVICE_POLLING
151187902Sluigi	if (ifp->if_ipending & IFF_POLLING)
151287902Sluigi		goto done;
151387902Sluigi	if (ether_poll_register(sis_poll, ifp)) { /* ok, disable interrupts */
151487902Sluigi		CSR_WRITE_4(sc, SIS_IER, 0);
151587902Sluigi		goto done;
151687902Sluigi	}
151787902Sluigi#endif /* DEVICE_POLLING */
151887902Sluigi
151950974Swpaul	/* Supress unwanted interrupts */
152050974Swpaul	if (!(ifp->if_flags & IFF_UP)) {
152150974Swpaul		sis_stop(sc);
152286984Sluigi		goto done;
152350974Swpaul	}
152450974Swpaul
152550974Swpaul	/* Disable interrupts. */
152650974Swpaul	CSR_WRITE_4(sc, SIS_IER, 0);
152750974Swpaul
152850974Swpaul	for (;;) {
152950974Swpaul		/* Reading the ISR register clears all interrupts. */
153050974Swpaul		status = CSR_READ_4(sc, SIS_ISR);
153150974Swpaul
153250974Swpaul		if ((status & SIS_INTRS) == 0)
153350974Swpaul			break;
153450974Swpaul
153586984Sluigi		if (status &
153686984Sluigi		    (SIS_ISR_TX_DESC_OK | SIS_ISR_TX_ERR |
153786984Sluigi		     SIS_ISR_TX_OK | SIS_ISR_TX_IDLE) )
153850974Swpaul			sis_txeof(sc);
153950974Swpaul
154086984Sluigi		if (status & (SIS_ISR_RX_DESC_OK|SIS_ISR_RX_OK|SIS_ISR_RX_IDLE))
154150974Swpaul			sis_rxeof(sc);
154250974Swpaul
154386984Sluigi		if (status & (SIS_ISR_RX_ERR | SIS_ISR_RX_OFLOW))
154450974Swpaul			sis_rxeoc(sc);
154550974Swpaul
154686984Sluigi		if (status & (SIS_ISR_RX_IDLE))
154786984Sluigi			SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE);
154886984Sluigi
154950974Swpaul		if (status & SIS_ISR_SYSERR) {
155050974Swpaul			sis_reset(sc);
155150974Swpaul			sis_init(sc);
155250974Swpaul		}
155350974Swpaul	}
155450974Swpaul
155550974Swpaul	/* Re-enable interrupts. */
155650974Swpaul	CSR_WRITE_4(sc, SIS_IER, 1);
155750974Swpaul
155850974Swpaul	if (ifp->if_snd.ifq_head != NULL)
155950974Swpaul		sis_start(ifp);
156086984Sluigidone:
156167087Swpaul	SIS_UNLOCK(sc);
156267087Swpaul
156350974Swpaul	return;
156450974Swpaul}
156550974Swpaul
156650974Swpaul/*
156750974Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
156850974Swpaul * pointers to the fragment pointers.
156950974Swpaul */
157050974Swpaulstatic int sis_encap(sc, m_head, txidx)
157150974Swpaul	struct sis_softc	*sc;
157250974Swpaul	struct mbuf		*m_head;
157350974Swpaul	u_int32_t		*txidx;
157450974Swpaul{
157550974Swpaul	struct sis_desc		*f = NULL;
157650974Swpaul	struct mbuf		*m;
157750974Swpaul	int			frag, cur, cnt = 0;
157850974Swpaul
157950974Swpaul	/*
158050974Swpaul 	 * Start packing the mbufs in this chain into
158150974Swpaul	 * the fragment pointers. Stop when we run out
158250974Swpaul 	 * of fragments or hit the end of the mbuf chain.
158350974Swpaul	 */
158450974Swpaul	m = m_head;
158550974Swpaul	cur = frag = *txidx;
158650974Swpaul
158750974Swpaul	for (m = m_head; m != NULL; m = m->m_next) {
158850974Swpaul		if (m->m_len != 0) {
158951042Swpaul			if ((SIS_TX_LIST_CNT -
159050974Swpaul			    (sc->sis_cdata.sis_tx_cnt + cnt)) < 2)
159150974Swpaul				return(ENOBUFS);
159281713Swpaul			f = &sc->sis_ldata.sis_tx_list[frag];
159350974Swpaul			f->sis_ctl = SIS_CMDSTS_MORE | m->m_len;
159481713Swpaul			bus_dmamap_create(sc->sis_tag, 0, &f->sis_map);
159581713Swpaul			bus_dmamap_load(sc->sis_tag, f->sis_map,
159681713Swpaul			    mtod(m, void *), m->m_len,
159781713Swpaul			    sis_dma_map_desc_ptr, f, 0);
159881713Swpaul			bus_dmamap_sync(sc->sis_tag,
159981713Swpaul			    f->sis_map, BUS_DMASYNC_PREREAD);
160050974Swpaul			if (cnt != 0)
160150974Swpaul				f->sis_ctl |= SIS_CMDSTS_OWN;
160250974Swpaul			cur = frag;
160350974Swpaul			SIS_INC(frag, SIS_TX_LIST_CNT);
160450974Swpaul			cnt++;
160550974Swpaul		}
160650974Swpaul	}
160750974Swpaul
160850974Swpaul	if (m != NULL)
160950974Swpaul		return(ENOBUFS);
161050974Swpaul
161181713Swpaul	sc->sis_ldata.sis_tx_list[cur].sis_mbuf = m_head;
161281713Swpaul	sc->sis_ldata.sis_tx_list[cur].sis_ctl &= ~SIS_CMDSTS_MORE;
161381713Swpaul	sc->sis_ldata.sis_tx_list[*txidx].sis_ctl |= SIS_CMDSTS_OWN;
161450974Swpaul	sc->sis_cdata.sis_tx_cnt += cnt;
161550974Swpaul	*txidx = frag;
161650974Swpaul
161750974Swpaul	return(0);
161850974Swpaul}
161950974Swpaul
162050974Swpaul/*
162150974Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
162250974Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
162350974Swpaul * copy of the pointers since the transmit list fragment pointers are
162450974Swpaul * physical addresses.
162550974Swpaul */
162650974Swpaul
162750974Swpaulstatic void sis_start(ifp)
162850974Swpaul	struct ifnet		*ifp;
162950974Swpaul{
163050974Swpaul	struct sis_softc	*sc;
163150974Swpaul	struct mbuf		*m_head = NULL;
163250974Swpaul	u_int32_t		idx;
163350974Swpaul
163450974Swpaul	sc = ifp->if_softc;
163567087Swpaul	SIS_LOCK(sc);
163650974Swpaul
163767087Swpaul	if (!sc->sis_link) {
163867087Swpaul		SIS_UNLOCK(sc);
163964963Swpaul		return;
164067087Swpaul	}
164164963Swpaul
164250974Swpaul	idx = sc->sis_cdata.sis_tx_prod;
164350974Swpaul
164467087Swpaul	if (ifp->if_flags & IFF_OACTIVE) {
164567087Swpaul		SIS_UNLOCK(sc);
164650974Swpaul		return;
164767087Swpaul	}
164850974Swpaul
164981713Swpaul	while(sc->sis_ldata.sis_tx_list[idx].sis_mbuf == NULL) {
165050974Swpaul		IF_DEQUEUE(&ifp->if_snd, m_head);
165150974Swpaul		if (m_head == NULL)
165250974Swpaul			break;
165350974Swpaul
165450974Swpaul		if (sis_encap(sc, m_head, &idx)) {
165550974Swpaul			IF_PREPEND(&ifp->if_snd, m_head);
165650974Swpaul			ifp->if_flags |= IFF_OACTIVE;
165750974Swpaul			break;
165850974Swpaul		}
165950974Swpaul
166050974Swpaul		/*
166150974Swpaul		 * If there's a BPF listener, bounce a copy of this frame
166250974Swpaul		 * to him.
166350974Swpaul		 */
166450974Swpaul		if (ifp->if_bpf)
166550974Swpaul			bpf_mtap(ifp, m_head);
166651583Swpaul
166750974Swpaul	}
166850974Swpaul
166950974Swpaul	/* Transmit */
167050974Swpaul	sc->sis_cdata.sis_tx_prod = idx;
167150974Swpaul	SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_ENABLE);
167250974Swpaul
167350974Swpaul	/*
167450974Swpaul	 * Set a timeout in case the chip goes out to lunch.
167550974Swpaul	 */
167650974Swpaul	ifp->if_timer = 5;
167750974Swpaul
167867087Swpaul	SIS_UNLOCK(sc);
167967087Swpaul
168050974Swpaul	return;
168150974Swpaul}
168250974Swpaul
168350974Swpaulstatic void sis_init(xsc)
168450974Swpaul	void			*xsc;
168550974Swpaul{
168650974Swpaul	struct sis_softc	*sc = xsc;
168750974Swpaul	struct ifnet		*ifp = &sc->arpcom.ac_if;
168850974Swpaul	struct mii_data		*mii;
168950974Swpaul
169067087Swpaul	SIS_LOCK(sc);
169150974Swpaul
169250974Swpaul	/*
169350974Swpaul	 * Cancel pending I/O and free all RX/TX buffers.
169450974Swpaul	 */
169550974Swpaul	sis_stop(sc);
169650974Swpaul
169750974Swpaul	mii = device_get_softc(sc->sis_miibus);
169850974Swpaul
169950974Swpaul	/* Set MAC address */
170062672Swpaul	if (sc->sis_type == SIS_TYPE_83815) {
170162672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR0);
170262672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
170362672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[0]);
170462672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR1);
170562672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
170662672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[1]);
170762672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR2);
170862672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
170962672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[2]);
171062672Swpaul	} else {
171162672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0);
171262672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
171362672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[0]);
171462672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR1);
171562672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
171662672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[1]);
171762672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2);
171862672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
171962672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[2]);
172062672Swpaul	}
172150974Swpaul
172250974Swpaul	/* Init circular RX list. */
172350974Swpaul	if (sis_list_rx_init(sc) == ENOBUFS) {
172450974Swpaul		printf("sis%d: initialization failed: no "
172550974Swpaul			"memory for rx buffers\n", sc->sis_unit);
172650974Swpaul		sis_stop(sc);
172767087Swpaul		SIS_UNLOCK(sc);
172850974Swpaul		return;
172950974Swpaul	}
173050974Swpaul
173150974Swpaul	/*
173250974Swpaul	 * Init tx descriptors.
173350974Swpaul	 */
173450974Swpaul	sis_list_tx_init(sc);
173550974Swpaul
173662672Swpaul	/*
173762672Swpaul	 * For the NatSemi chip, we have to explicitly enable the
173862672Swpaul	 * reception of ARP frames, as well as turn on the 'perfect
173962672Swpaul	 * match' filter where we store the station address, otherwise
174062672Swpaul	 * we won't receive unicasts meant for this host.
174162672Swpaul	 */
174262672Swpaul	if (sc->sis_type == SIS_TYPE_83815) {
174362672Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_ARP);
174462672Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_PERFECT);
174562672Swpaul	}
174662672Swpaul
174750974Swpaul	 /* If we want promiscuous mode, set the allframes bit. */
174850974Swpaul	if (ifp->if_flags & IFF_PROMISC) {
174950974Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLPHYS);
175050974Swpaul	} else {
175150974Swpaul		SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLPHYS);
175250974Swpaul	}
175350974Swpaul
175450974Swpaul	/*
175550974Swpaul	 * Set the capture broadcast bit to capture broadcast frames.
175650974Swpaul	 */
175750974Swpaul	if (ifp->if_flags & IFF_BROADCAST) {
175850974Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_BROAD);
175950974Swpaul	} else {
176050974Swpaul		SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_BROAD);
176150974Swpaul	}
176250974Swpaul
176350974Swpaul	/*
176450974Swpaul	 * Load the multicast filter.
176550974Swpaul	 */
176662672Swpaul	if (sc->sis_type == SIS_TYPE_83815)
176762672Swpaul		sis_setmulti_ns(sc);
176862672Swpaul	else
176962672Swpaul		sis_setmulti_sis(sc);
177050974Swpaul
177150974Swpaul	/* Turn the receive filter on */
177250974Swpaul	SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ENABLE);
177350974Swpaul
177450974Swpaul	/*
177550974Swpaul	 * Load the address of the RX and TX lists.
177650974Swpaul	 */
177781713Swpaul	CSR_WRITE_4(sc, SIS_RX_LISTPTR, sc->sis_cdata.sis_rx_paddr);
177881713Swpaul	CSR_WRITE_4(sc, SIS_TX_LISTPTR, sc->sis_cdata.sis_tx_paddr);
177950974Swpaul
178050974Swpaul	/* Set RX configuration */
178150974Swpaul	CSR_WRITE_4(sc, SIS_RX_CFG, SIS_RXCFG);
178264963Swpaul
178387390Sjhay	/* Accept Long Packets for VLAN support */
178487390Sjhay	SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_JABBER);
178587390Sjhay
178650974Swpaul	/* Set TX configuration */
178764963Swpaul	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) {
178864963Swpaul		CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_10);
178964963Swpaul	} else {
179064963Swpaul		CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_100);
179164963Swpaul	}
179250974Swpaul
179364963Swpaul	/* Set full/half duplex mode. */
179464963Swpaul	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
179564963Swpaul		SIS_SETBIT(sc, SIS_TX_CFG,
179664963Swpaul		    (SIS_TXCFG_IGN_HBEAT|SIS_TXCFG_IGN_CARR));
179764963Swpaul		SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS);
179864963Swpaul	} else {
179964963Swpaul		SIS_CLRBIT(sc, SIS_TX_CFG,
180064963Swpaul		    (SIS_TXCFG_IGN_HBEAT|SIS_TXCFG_IGN_CARR));
180164963Swpaul		SIS_CLRBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS);
180264963Swpaul	}
180364963Swpaul
180450974Swpaul	/*
180550974Swpaul	 * Enable interrupts.
180650974Swpaul	 */
180750974Swpaul	CSR_WRITE_4(sc, SIS_IMR, SIS_INTRS);
180887902Sluigi#ifdef DEVICE_POLLING
180987902Sluigi	/*
181087902Sluigi	 * ... only enable interrupts if we are not polling, make sure
181187902Sluigi	 * they are off otherwise.
181287902Sluigi	 */
181387902Sluigi	if (ifp->if_ipending & IFF_POLLING)
181487902Sluigi		CSR_WRITE_4(sc, SIS_IER, 0);
181587902Sluigi	else
181687902Sluigi#endif /* DEVICE_POLLING */
181750974Swpaul	CSR_WRITE_4(sc, SIS_IER, 1);
181850974Swpaul
181950974Swpaul	/* Enable receiver and transmitter. */
182050974Swpaul	SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE);
182150974Swpaul	SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE);
182250974Swpaul
182364963Swpaul#ifdef notdef
182450974Swpaul	mii_mediachg(mii);
182564963Swpaul#endif
182650974Swpaul
182764963Swpaul	/*
182864963Swpaul	 * Page 75 of the DP83815 manual recommends the
182964963Swpaul	 * following register settings "for optimum
183064963Swpaul	 * performance." Note however that at least three
183164963Swpaul	 * of the registers are listed as "reserved" in
183264963Swpaul	 * the register map, so who knows what they do.
183364963Swpaul	 */
183464963Swpaul	if (sc->sis_type == SIS_TYPE_83815) {
183564963Swpaul		CSR_WRITE_4(sc, NS_PHY_PAGE, 0x0001);
183664963Swpaul		CSR_WRITE_4(sc, NS_PHY_CR, 0x189C);
183764963Swpaul		CSR_WRITE_4(sc, NS_PHY_TDATA, 0x0000);
183864963Swpaul		CSR_WRITE_4(sc, NS_PHY_DSPCFG, 0x5040);
183964963Swpaul		CSR_WRITE_4(sc, NS_PHY_SDCFG, 0x008C);
184064963Swpaul	}
184164963Swpaul
184250974Swpaul	ifp->if_flags |= IFF_RUNNING;
184350974Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
184450974Swpaul
184550974Swpaul	sc->sis_stat_ch = timeout(sis_tick, sc, hz);
184650974Swpaul
184767087Swpaul	SIS_UNLOCK(sc);
184867087Swpaul
184950974Swpaul	return;
185050974Swpaul}
185150974Swpaul
185250974Swpaul/*
185350974Swpaul * Set media options.
185450974Swpaul */
185550974Swpaulstatic int sis_ifmedia_upd(ifp)
185650974Swpaul	struct ifnet		*ifp;
185750974Swpaul{
185850974Swpaul	struct sis_softc	*sc;
185964963Swpaul	struct mii_data		*mii;
186050974Swpaul
186150974Swpaul	sc = ifp->if_softc;
186250974Swpaul
186364963Swpaul	mii = device_get_softc(sc->sis_miibus);
186464963Swpaul	sc->sis_link = 0;
186564963Swpaul	if (mii->mii_instance) {
186664963Swpaul		struct mii_softc	*miisc;
186772012Sphk		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
186864963Swpaul			mii_phy_reset(miisc);
186964963Swpaul	}
187064963Swpaul	mii_mediachg(mii);
187150974Swpaul
187250974Swpaul	return(0);
187350974Swpaul}
187450974Swpaul
187550974Swpaul/*
187650974Swpaul * Report current media status.
187750974Swpaul */
187850974Swpaulstatic void sis_ifmedia_sts(ifp, ifmr)
187950974Swpaul	struct ifnet		*ifp;
188050974Swpaul	struct ifmediareq	*ifmr;
188150974Swpaul{
188250974Swpaul	struct sis_softc	*sc;
188350974Swpaul	struct mii_data		*mii;
188450974Swpaul
188550974Swpaul	sc = ifp->if_softc;
188650974Swpaul
188750974Swpaul	mii = device_get_softc(sc->sis_miibus);
188850974Swpaul	mii_pollstat(mii);
188950974Swpaul	ifmr->ifm_active = mii->mii_media_active;
189050974Swpaul	ifmr->ifm_status = mii->mii_media_status;
189150974Swpaul
189250974Swpaul	return;
189350974Swpaul}
189450974Swpaul
189550974Swpaulstatic int sis_ioctl(ifp, command, data)
189650974Swpaul	struct ifnet		*ifp;
189750974Swpaul	u_long			command;
189850974Swpaul	caddr_t			data;
189950974Swpaul{
190050974Swpaul	struct sis_softc	*sc = ifp->if_softc;
190150974Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
190250974Swpaul	struct mii_data		*mii;
190367087Swpaul	int			error = 0;
190450974Swpaul
190550974Swpaul	switch(command) {
190650974Swpaul	case SIOCSIFADDR:
190750974Swpaul	case SIOCGIFADDR:
190850974Swpaul	case SIOCSIFMTU:
190950974Swpaul		error = ether_ioctl(ifp, command, data);
191050974Swpaul		break;
191150974Swpaul	case SIOCSIFFLAGS:
191250974Swpaul		if (ifp->if_flags & IFF_UP) {
191350974Swpaul			sis_init(sc);
191450974Swpaul		} else {
191550974Swpaul			if (ifp->if_flags & IFF_RUNNING)
191650974Swpaul				sis_stop(sc);
191750974Swpaul		}
191850974Swpaul		error = 0;
191950974Swpaul		break;
192050974Swpaul	case SIOCADDMULTI:
192150974Swpaul	case SIOCDELMULTI:
192281713Swpaul		SIS_LOCK(sc);
192362672Swpaul		if (sc->sis_type == SIS_TYPE_83815)
192462672Swpaul			sis_setmulti_ns(sc);
192562672Swpaul		else
192662672Swpaul			sis_setmulti_sis(sc);
192781713Swpaul		SIS_UNLOCK(sc);
192850974Swpaul		error = 0;
192950974Swpaul		break;
193050974Swpaul	case SIOCGIFMEDIA:
193150974Swpaul	case SIOCSIFMEDIA:
193250974Swpaul		mii = device_get_softc(sc->sis_miibus);
193381713Swpaul		SIS_LOCK(sc);
193450974Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
193581713Swpaul		SIS_UNLOCK(sc);
193650974Swpaul		break;
193750974Swpaul	default:
193850974Swpaul		error = EINVAL;
193950974Swpaul		break;
194050974Swpaul	}
194150974Swpaul
194250974Swpaul	return(error);
194350974Swpaul}
194450974Swpaul
194550974Swpaulstatic void sis_watchdog(ifp)
194650974Swpaul	struct ifnet		*ifp;
194750974Swpaul{
194850974Swpaul	struct sis_softc	*sc;
194950974Swpaul
195050974Swpaul	sc = ifp->if_softc;
195150974Swpaul
195267087Swpaul	SIS_LOCK(sc);
195367087Swpaul
195450974Swpaul	ifp->if_oerrors++;
195550974Swpaul	printf("sis%d: watchdog timeout\n", sc->sis_unit);
195650974Swpaul
195750974Swpaul	sis_stop(sc);
195850974Swpaul	sis_reset(sc);
195950974Swpaul	sis_init(sc);
196050974Swpaul
196150974Swpaul	if (ifp->if_snd.ifq_head != NULL)
196250974Swpaul		sis_start(ifp);
196350974Swpaul
196467087Swpaul	SIS_UNLOCK(sc);
196567087Swpaul
196650974Swpaul	return;
196750974Swpaul}
196850974Swpaul
196950974Swpaul/*
197050974Swpaul * Stop the adapter and free any mbufs allocated to the
197150974Swpaul * RX and TX lists.
197250974Swpaul */
197350974Swpaulstatic void sis_stop(sc)
197450974Swpaul	struct sis_softc	*sc;
197550974Swpaul{
197650974Swpaul	register int		i;
197750974Swpaul	struct ifnet		*ifp;
197850974Swpaul
197967087Swpaul	SIS_LOCK(sc);
198050974Swpaul	ifp = &sc->arpcom.ac_if;
198150974Swpaul	ifp->if_timer = 0;
198250974Swpaul
198350974Swpaul	untimeout(sis_tick, sc, sc->sis_stat_ch);
198487472Speter
198587472Speter	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
198687902Sluigi#ifdef DEVICE_POLLING
198787902Sluigi	ether_poll_deregister(ifp);
198887902Sluigi#endif
198950974Swpaul	CSR_WRITE_4(sc, SIS_IER, 0);
199050974Swpaul	CSR_WRITE_4(sc, SIS_IMR, 0);
199150974Swpaul	SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE);
199250974Swpaul	DELAY(1000);
199350974Swpaul	CSR_WRITE_4(sc, SIS_TX_LISTPTR, 0);
199450974Swpaul	CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0);
199550974Swpaul
199664963Swpaul	sc->sis_link = 0;
199764963Swpaul
199850974Swpaul	/*
199950974Swpaul	 * Free data in the RX lists.
200050974Swpaul	 */
200150974Swpaul	for (i = 0; i < SIS_RX_LIST_CNT; i++) {
200281713Swpaul		if (sc->sis_ldata.sis_rx_list[i].sis_mbuf != NULL) {
200381713Swpaul			bus_dmamap_unload(sc->sis_tag,
200481713Swpaul			    sc->sis_ldata.sis_rx_list[i].sis_map);
200581713Swpaul			bus_dmamap_destroy(sc->sis_tag,
200681713Swpaul			    sc->sis_ldata.sis_rx_list[i].sis_map);
200781713Swpaul			m_freem(sc->sis_ldata.sis_rx_list[i].sis_mbuf);
200881713Swpaul			sc->sis_ldata.sis_rx_list[i].sis_mbuf = NULL;
200950974Swpaul		}
201050974Swpaul	}
201181713Swpaul	bzero(sc->sis_ldata.sis_rx_list,
201281713Swpaul		sizeof(sc->sis_ldata.sis_rx_list));
201350974Swpaul
201450974Swpaul	/*
201550974Swpaul	 * Free the TX list buffers.
201650974Swpaul	 */
201750974Swpaul	for (i = 0; i < SIS_TX_LIST_CNT; i++) {
201881713Swpaul		if (sc->sis_ldata.sis_tx_list[i].sis_mbuf != NULL) {
201981713Swpaul			bus_dmamap_unload(sc->sis_tag,
202081713Swpaul			    sc->sis_ldata.sis_tx_list[i].sis_map);
202181713Swpaul			bus_dmamap_destroy(sc->sis_tag,
202281713Swpaul			    sc->sis_ldata.sis_tx_list[i].sis_map);
202381713Swpaul			m_freem(sc->sis_ldata.sis_tx_list[i].sis_mbuf);
202481713Swpaul			sc->sis_ldata.sis_tx_list[i].sis_mbuf = NULL;
202550974Swpaul		}
202650974Swpaul	}
202750974Swpaul
202881713Swpaul	bzero(sc->sis_ldata.sis_tx_list,
202981713Swpaul		sizeof(sc->sis_ldata.sis_tx_list));
203050974Swpaul
203167087Swpaul	SIS_UNLOCK(sc);
203267087Swpaul
203350974Swpaul	return;
203450974Swpaul}
203550974Swpaul
203650974Swpaul/*
203750974Swpaul * Stop all chip I/O so that the kernel's probe routines don't
203850974Swpaul * get confused by errant DMAs when rebooting.
203950974Swpaul */
204050974Swpaulstatic void sis_shutdown(dev)
204150974Swpaul	device_t		dev;
204250974Swpaul{
204350974Swpaul	struct sis_softc	*sc;
204450974Swpaul
204550974Swpaul	sc = device_get_softc(dev);
204667087Swpaul	SIS_LOCK(sc);
204750974Swpaul	sis_reset(sc);
204850974Swpaul	sis_stop(sc);
204967087Swpaul	SIS_UNLOCK(sc);
205050974Swpaul
205150974Swpaul	return;
205250974Swpaul}
2053