if_sis.c revision 144243
1139825Simp/*-
2139740Sphk * Copyright (c) 2005 Poul-Henning Kamp <phk@FreeBSD.org>
350974Swpaul * Copyright (c) 1997, 1998, 1999
450974Swpaul *	Bill Paul <wpaul@ctr.columbia.edu>.  All rights reserved.
550974Swpaul *
650974Swpaul * Redistribution and use in source and binary forms, with or without
750974Swpaul * modification, are permitted provided that the following conditions
850974Swpaul * are met:
950974Swpaul * 1. Redistributions of source code must retain the above copyright
1050974Swpaul *    notice, this list of conditions and the following disclaimer.
1150974Swpaul * 2. Redistributions in binary form must reproduce the above copyright
1250974Swpaul *    notice, this list of conditions and the following disclaimer in the
1350974Swpaul *    documentation and/or other materials provided with the distribution.
1450974Swpaul * 3. All advertising materials mentioning features or use of this software
1550974Swpaul *    must display the following acknowledgement:
1650974Swpaul *	This product includes software developed by Bill Paul.
1750974Swpaul * 4. Neither the name of the author nor the names of any co-contributors
1850974Swpaul *    may be used to endorse or promote products derived from this software
1950974Swpaul *    without specific prior written permission.
2050974Swpaul *
2150974Swpaul * THIS SOFTWARE IS PROVIDED BY Bill Paul AND CONTRIBUTORS ``AS IS'' AND
2250974Swpaul * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
2350974Swpaul * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
2450974Swpaul * ARE DISCLAIMED.  IN NO EVENT SHALL Bill Paul OR THE VOICES IN HIS HEAD
2550974Swpaul * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
2650974Swpaul * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
2750974Swpaul * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
2850974Swpaul * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
2950974Swpaul * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
3050974Swpaul * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
3150974Swpaul * THE POSSIBILITY OF SUCH DAMAGE.
3250974Swpaul */
3350974Swpaul
34122678Sobrien#include <sys/cdefs.h>
35122678Sobrien__FBSDID("$FreeBSD: head/sys/pci/if_sis.c 144243 2005-03-28 18:06:44Z obrien $");
36122678Sobrien
3750974Swpaul/*
3850974Swpaul * SiS 900/SiS 7016 fast ethernet PCI NIC driver. Datasheets are
3950974Swpaul * available from http://www.sis.com.tw.
4050974Swpaul *
4164963Swpaul * This driver also supports the NatSemi DP83815. Datasheets are
4264963Swpaul * available from http://www.national.com.
4364963Swpaul *
4450974Swpaul * Written by Bill Paul <wpaul@ee.columbia.edu>
4550974Swpaul * Electrical Engineering Department
4650974Swpaul * Columbia University, New York City
4750974Swpaul */
4850974Swpaul/*
4950974Swpaul * The SiS 900 is a fairly simple chip. It uses bus master DMA with
5050974Swpaul * simple TX and RX descriptors of 3 longwords in size. The receiver
5150974Swpaul * has a single perfect filter entry for the station address and a
5250974Swpaul * 128-bit multicast hash table. The SiS 900 has a built-in MII-based
5350974Swpaul * transceiver while the 7016 requires an external transceiver chip.
5450974Swpaul * Both chips offer the standard bit-bang MII interface as well as
5550974Swpaul * an enchanced PHY interface which simplifies accessing MII registers.
5650974Swpaul *
5750974Swpaul * The only downside to this chipset is that RX descriptors must be
5850974Swpaul * longword aligned.
5950974Swpaul */
6050974Swpaul
6150974Swpaul#include <sys/param.h>
6250974Swpaul#include <sys/systm.h>
6350974Swpaul#include <sys/sockio.h>
6450974Swpaul#include <sys/mbuf.h>
6550974Swpaul#include <sys/malloc.h>
6650974Swpaul#include <sys/kernel.h>
67129876Sphk#include <sys/module.h>
6850974Swpaul#include <sys/socket.h>
6987059Sluigi#include <sys/sysctl.h>
7050974Swpaul
7150974Swpaul#include <net/if.h>
7250974Swpaul#include <net/if_arp.h>
7350974Swpaul#include <net/ethernet.h>
7450974Swpaul#include <net/if_dl.h>
7550974Swpaul#include <net/if_media.h>
7687390Sjhay#include <net/if_types.h>
7787390Sjhay#include <net/if_vlan_var.h>
7850974Swpaul
7950974Swpaul#include <net/bpf.h>
8050974Swpaul
8150974Swpaul#include <machine/bus_pio.h>
8250974Swpaul#include <machine/bus_memio.h>
8350974Swpaul#include <machine/bus.h>
8450974Swpaul#include <machine/resource.h>
8550974Swpaul#include <sys/bus.h>
8650974Swpaul#include <sys/rman.h>
8750974Swpaul
8850974Swpaul#include <dev/mii/mii.h>
8950974Swpaul#include <dev/mii/miivar.h>
9050974Swpaul
91119288Simp#include <dev/pci/pcireg.h>
92119288Simp#include <dev/pci/pcivar.h>
9350974Swpaul
9450974Swpaul#define SIS_USEIOSPACE
9550974Swpaul
9650974Swpaul#include <pci/if_sisreg.h>
9750974Swpaul
98113506SmdoddMODULE_DEPEND(sis, pci, 1, 1, 1);
99113506SmdoddMODULE_DEPEND(sis, ether, 1, 1, 1);
10059758SpeterMODULE_DEPEND(sis, miibus, 1, 1, 1);
10159758Speter
10251089Speter/* "controller miibus0" required.  See GENERIC if you get errors here. */
10350974Swpaul#include "miibus_if.h"
10450974Swpaul
10550974Swpaul/*
10650974Swpaul * Various supported device vendors/types and their names.
10750974Swpaul */
10850974Swpaulstatic struct sis_type sis_devs[] = {
10950974Swpaul	{ SIS_VENDORID, SIS_DEVICEID_900, "SiS 900 10/100BaseTX" },
11050974Swpaul	{ SIS_VENDORID, SIS_DEVICEID_7016, "SiS 7016 10/100BaseTX" },
111119712Sphk	{ NS_VENDORID, NS_DEVICEID_DP83815, "NatSemi DP8381[56] 10/100BaseTX" },
11250974Swpaul	{ 0, 0, NULL }
11350974Swpaul};
11450974Swpaul
115139801Sphkstatic int sis_detach(device_t);
116139801Sphkstatic void sis_ifmedia_sts(struct ifnet *, struct ifmediareq *);
117139801Sphkstatic int sis_ifmedia_upd(struct ifnet *);
118139801Sphkstatic void sis_init(void *);
119139801Sphkstatic void sis_initl(struct sis_softc *);
120139801Sphkstatic void sis_intr(void *);
121139801Sphkstatic int sis_ioctl(struct ifnet *, u_long, caddr_t);
122139801Sphkstatic int sis_newbuf(struct sis_softc *, struct sis_desc *, struct mbuf *);
123139801Sphkstatic void sis_start(struct ifnet *);
124139801Sphkstatic void sis_startl(struct ifnet *);
125139801Sphkstatic void sis_stop(struct sis_softc *);
126139801Sphkstatic void sis_watchdog(struct ifnet *);
12750974Swpaul
12850974Swpaul#ifdef SIS_USEIOSPACE
12950974Swpaul#define SIS_RES			SYS_RES_IOPORT
13050974Swpaul#define SIS_RID			SIS_PCI_LOIO
13150974Swpaul#else
13251030Swpaul#define SIS_RES			SYS_RES_MEMORY
13351030Swpaul#define SIS_RID			SIS_PCI_LOMEM
13450974Swpaul#endif
13550974Swpaul
13650974Swpaul#define SIS_SETBIT(sc, reg, x)				\
13750974Swpaul	CSR_WRITE_4(sc, reg,				\
13850974Swpaul		CSR_READ_4(sc, reg) | (x))
13950974Swpaul
14050974Swpaul#define SIS_CLRBIT(sc, reg, x)				\
14150974Swpaul	CSR_WRITE_4(sc, reg,				\
14250974Swpaul		CSR_READ_4(sc, reg) & ~(x))
14350974Swpaul
14450974Swpaul#define SIO_SET(x)					\
14550974Swpaul	CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) | x)
14650974Swpaul
14750974Swpaul#define SIO_CLR(x)					\
14850974Swpaul	CSR_WRITE_4(sc, SIS_EECTL, CSR_READ_4(sc, SIS_EECTL) & ~x)
14950974Swpaul
15081713Swpaulstatic void
151139740Sphksis_dma_map_desc_next(void *arg, bus_dma_segment_t *segs, int nseg, int error)
15281713Swpaul{
15381713Swpaul	struct sis_desc	*r;
15481713Swpaul
15581713Swpaul	r = arg;
15681713Swpaul	r->sis_next = segs->ds_addr;
15781713Swpaul}
15881713Swpaul
15981713Swpaulstatic void
160139740Sphksis_dma_map_desc_ptr(void *arg, bus_dma_segment_t *segs, int nseg, int error)
16181713Swpaul{
16281713Swpaul	struct sis_desc	*r;
16381713Swpaul
16481713Swpaul	r = arg;
16581713Swpaul	r->sis_ptr = segs->ds_addr;
16681713Swpaul}
16781713Swpaul
16881713Swpaulstatic void
169139740Sphksis_dma_map_ring(void *arg, bus_dma_segment_t *segs, int nseg, int error)
17081713Swpaul{
17181713Swpaul	u_int32_t *p;
17281713Swpaul
17381713Swpaul	p = arg;
17481713Swpaul	*p = segs->ds_addr;
17581713Swpaul}
17681713Swpaul
17762672Swpaul/*
17862672Swpaul * Routine to reverse the bits in a word. Stolen almost
17962672Swpaul * verbatim from /usr/games/fortune.
18062672Swpaul */
181139740Sphkstatic uint16_t
182139740Sphksis_reverse(uint16_t n)
18362672Swpaul{
18462672Swpaul	n = ((n >>  1) & 0x5555) | ((n <<  1) & 0xaaaa);
18562672Swpaul	n = ((n >>  2) & 0x3333) | ((n <<  2) & 0xcccc);
18662672Swpaul	n = ((n >>  4) & 0x0f0f) | ((n <<  4) & 0xf0f0);
18762672Swpaul	n = ((n >>  8) & 0x00ff) | ((n <<  8) & 0xff00);
18862672Swpaul
18962672Swpaul	return(n);
19062672Swpaul}
19162672Swpaul
192102334Salfredstatic void
193139740Sphksis_delay(struct sis_softc *sc)
19450974Swpaul{
19550974Swpaul	int			idx;
19650974Swpaul
19750974Swpaul	for (idx = (300 / 33) + 1; idx > 0; idx--)
19850974Swpaul		CSR_READ_4(sc, SIS_CSR);
19950974Swpaul}
20050974Swpaul
201102334Salfredstatic void
202139740Sphksis_eeprom_idle(struct sis_softc *sc)
20350974Swpaul{
204139708Sphk	int		i;
20550974Swpaul
20650974Swpaul	SIO_SET(SIS_EECTL_CSEL);
20750974Swpaul	sis_delay(sc);
20850974Swpaul	SIO_SET(SIS_EECTL_CLK);
20950974Swpaul	sis_delay(sc);
21050974Swpaul
21150974Swpaul	for (i = 0; i < 25; i++) {
21250974Swpaul		SIO_CLR(SIS_EECTL_CLK);
21350974Swpaul		sis_delay(sc);
21450974Swpaul		SIO_SET(SIS_EECTL_CLK);
21550974Swpaul		sis_delay(sc);
21650974Swpaul	}
21750974Swpaul
21850974Swpaul	SIO_CLR(SIS_EECTL_CLK);
21950974Swpaul	sis_delay(sc);
22050974Swpaul	SIO_CLR(SIS_EECTL_CSEL);
22150974Swpaul	sis_delay(sc);
22250974Swpaul	CSR_WRITE_4(sc, SIS_EECTL, 0x00000000);
22350974Swpaul}
22450974Swpaul
22550974Swpaul/*
22650974Swpaul * Send a read command and address to the EEPROM, check for ACK.
22750974Swpaul */
228102334Salfredstatic void
229139740Sphksis_eeprom_putbyte(struct sis_softc *sc, int addr)
23050974Swpaul{
231139708Sphk	int		d, i;
23250974Swpaul
23350974Swpaul	d = addr | SIS_EECMD_READ;
23450974Swpaul
23550974Swpaul	/*
23650974Swpaul	 * Feed in each bit and stobe the clock.
23750974Swpaul	 */
23850974Swpaul	for (i = 0x400; i; i >>= 1) {
23950974Swpaul		if (d & i) {
24050974Swpaul			SIO_SET(SIS_EECTL_DIN);
24150974Swpaul		} else {
24250974Swpaul			SIO_CLR(SIS_EECTL_DIN);
24350974Swpaul		}
24450974Swpaul		sis_delay(sc);
24550974Swpaul		SIO_SET(SIS_EECTL_CLK);
24650974Swpaul		sis_delay(sc);
24750974Swpaul		SIO_CLR(SIS_EECTL_CLK);
24850974Swpaul		sis_delay(sc);
24950974Swpaul	}
25050974Swpaul}
25150974Swpaul
25250974Swpaul/*
25350974Swpaul * Read a word of data stored in the EEPROM at address 'addr.'
25450974Swpaul */
255102334Salfredstatic void
256139740Sphksis_eeprom_getword(struct sis_softc *sc, int addr, uint16_t *dest)
25750974Swpaul{
258139708Sphk	int		i;
25950974Swpaul	u_int16_t		word = 0;
26050974Swpaul
26150974Swpaul	/* Force EEPROM to idle state. */
26250974Swpaul	sis_eeprom_idle(sc);
26350974Swpaul
26450974Swpaul	/* Enter EEPROM access mode. */
26550974Swpaul	sis_delay(sc);
26662672Swpaul	SIO_CLR(SIS_EECTL_CLK);
26762672Swpaul	sis_delay(sc);
26850974Swpaul	SIO_SET(SIS_EECTL_CSEL);
26950974Swpaul	sis_delay(sc);
27050974Swpaul
27150974Swpaul	/*
27250974Swpaul	 * Send address of word we want to read.
27350974Swpaul	 */
27450974Swpaul	sis_eeprom_putbyte(sc, addr);
27550974Swpaul
27650974Swpaul	/*
27750974Swpaul	 * Start reading bits from EEPROM.
27850974Swpaul	 */
27950974Swpaul	for (i = 0x8000; i; i >>= 1) {
28050974Swpaul		SIO_SET(SIS_EECTL_CLK);
28150974Swpaul		sis_delay(sc);
28250974Swpaul		if (CSR_READ_4(sc, SIS_EECTL) & SIS_EECTL_DOUT)
28350974Swpaul			word |= i;
28450974Swpaul		sis_delay(sc);
28550974Swpaul		SIO_CLR(SIS_EECTL_CLK);
28650974Swpaul		sis_delay(sc);
28750974Swpaul	}
28850974Swpaul
28950974Swpaul	/* Turn off EEPROM access mode. */
29050974Swpaul	sis_eeprom_idle(sc);
29150974Swpaul
29250974Swpaul	*dest = word;
29350974Swpaul}
29450974Swpaul
29550974Swpaul/*
29650974Swpaul * Read a sequence of words from the EEPROM.
29750974Swpaul */
298102334Salfredstatic void
299139740Sphksis_read_eeprom(struct sis_softc *sc, caddr_t dest, int off, int cnt, int swap)
30050974Swpaul{
30150974Swpaul	int			i;
30250974Swpaul	u_int16_t		word = 0, *ptr;
30350974Swpaul
30450974Swpaul	for (i = 0; i < cnt; i++) {
30550974Swpaul		sis_eeprom_getword(sc, off + i, &word);
30650974Swpaul		ptr = (u_int16_t *)(dest + (i * 2));
30750974Swpaul		if (swap)
30850974Swpaul			*ptr = ntohs(word);
30950974Swpaul		else
31050974Swpaul			*ptr = word;
31150974Swpaul	}
31250974Swpaul}
31350974Swpaul
314144243Sobrien#if defined(__i386__) || defined(__amd64__)
315102334Salfredstatic device_t
316139740Sphksis_find_bridge(device_t dev)
31772197Swpaul{
31872197Swpaul	devclass_t		pci_devclass;
31972197Swpaul	device_t		*pci_devices;
32072197Swpaul	int			pci_count = 0;
32172197Swpaul	device_t		*pci_children;
32272197Swpaul	int			pci_childcount = 0;
32372197Swpaul	device_t		*busp, *childp;
32487994Sarchie	device_t		child = NULL;
32572197Swpaul	int			i, j;
32672197Swpaul
32772197Swpaul	if ((pci_devclass = devclass_find("pci")) == NULL)
32872197Swpaul		return(NULL);
32972197Swpaul
33072197Swpaul	devclass_get_devices(pci_devclass, &pci_devices, &pci_count);
33172197Swpaul
33272197Swpaul	for (i = 0, busp = pci_devices; i < pci_count; i++, busp++) {
33372197Swpaul		pci_childcount = 0;
33472197Swpaul		device_get_children(*busp, &pci_children, &pci_childcount);
33572197Swpaul		for (j = 0, childp = pci_children;
33672197Swpaul		    j < pci_childcount; j++, childp++) {
33772197Swpaul			if (pci_get_vendor(*childp) == SIS_VENDORID &&
33872197Swpaul			    pci_get_device(*childp) == 0x0008) {
33987994Sarchie				child = *childp;
34087994Sarchie				goto done;
34172197Swpaul			}
34272197Swpaul		}
34372197Swpaul	}
34472197Swpaul
34587994Sarchiedone:
34672197Swpaul	free(pci_devices, M_TEMP);
34772197Swpaul	free(pci_children, M_TEMP);
34887994Sarchie	return(child);
34972197Swpaul}
35072197Swpaul
351102334Salfredstatic void
352139740Sphksis_read_cmos(struct sis_softc *sc, device_t dev, caddr_t dest, int off, int cnt)
35372197Swpaul{
35472197Swpaul	device_t		bridge;
35572197Swpaul	u_int8_t		reg;
35672197Swpaul	int			i;
35772197Swpaul	bus_space_tag_t		btag;
35872197Swpaul
35972197Swpaul	bridge = sis_find_bridge(dev);
36072197Swpaul	if (bridge == NULL)
36172197Swpaul		return;
36272197Swpaul	reg = pci_read_config(bridge, 0x48, 1);
36372197Swpaul	pci_write_config(bridge, 0x48, reg|0x40, 1);
36472197Swpaul
36572197Swpaul	/* XXX */
366144243Sobrien#if defined(__i386__)
36772197Swpaul	btag = I386_BUS_SPACE_IO;
368144243Sobrien#elif defined(__amd64__)
369144243Sobrien	btag = AMD64_BUS_SPACE_IO;
370144243Sobrien#endif
37172197Swpaul
37272197Swpaul	for (i = 0; i < cnt; i++) {
37372197Swpaul		bus_space_write_1(btag, 0x0, 0x70, i + off);
37472197Swpaul		*(dest + i) = bus_space_read_1(btag, 0x0, 0x71);
37572197Swpaul	}
37672197Swpaul
37772197Swpaul	pci_write_config(bridge, 0x48, reg & ~0x40, 1);
37872197Swpaul	return;
37972197Swpaul}
38089296Swpaul
381102334Salfredstatic void
382139740Sphksis_read_mac(struct sis_softc *sc, device_t dev, caddr_t dest)
38389296Swpaul{
38489296Swpaul	u_int32_t		filtsave, csrsave;
38589296Swpaul
38689296Swpaul	filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL);
38789296Swpaul	csrsave = CSR_READ_4(sc, SIS_CSR);
38889296Swpaul
38989296Swpaul	CSR_WRITE_4(sc, SIS_CSR, SIS_CSR_RELOAD | filtsave);
39089296Swpaul	CSR_WRITE_4(sc, SIS_CSR, 0);
39189296Swpaul
39289296Swpaul	CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave & ~SIS_RXFILTCTL_ENABLE);
39389296Swpaul
39489296Swpaul	CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0);
39589296Swpaul	((u_int16_t *)dest)[0] = CSR_READ_2(sc, SIS_RXFILT_DATA);
39689296Swpaul	CSR_WRITE_4(sc, SIS_RXFILT_CTL,SIS_FILTADDR_PAR1);
39789296Swpaul	((u_int16_t *)dest)[1] = CSR_READ_2(sc, SIS_RXFILT_DATA);
39889296Swpaul	CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2);
39989296Swpaul	((u_int16_t *)dest)[2] = CSR_READ_2(sc, SIS_RXFILT_DATA);
40089296Swpaul
40189296Swpaul	CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave);
40289296Swpaul	CSR_WRITE_4(sc, SIS_CSR, csrsave);
40389296Swpaul	return;
40489296Swpaul}
40572197Swpaul#endif
40672197Swpaul
407109060Smbr/*
408109060Smbr * Sync the PHYs by setting data bit and strobing the clock 32 times.
409109060Smbr */
410139740Sphkstatic void
411139740Sphksis_mii_sync(struct sis_softc *sc)
412109060Smbr{
413139708Sphk	int		i;
414109060Smbr
415109060Smbr 	SIO_SET(SIS_MII_DIR|SIS_MII_DATA);
416109060Smbr
417109060Smbr 	for (i = 0; i < 32; i++) {
418109060Smbr 		SIO_SET(SIS_MII_CLK);
419109060Smbr 		DELAY(1);
420109060Smbr 		SIO_CLR(SIS_MII_CLK);
421109060Smbr 		DELAY(1);
422109060Smbr 	}
423109060Smbr}
424109060Smbr
425109060Smbr/*
426109060Smbr * Clock a series of bits through the MII.
427109060Smbr */
428139740Sphkstatic void
429139740Sphksis_mii_send(struct sis_softc *sc, uint32_t bits, int cnt)
430109060Smbr{
431109060Smbr	int			i;
432109060Smbr
433109060Smbr	SIO_CLR(SIS_MII_CLK);
434109060Smbr
435109060Smbr	for (i = (0x1 << (cnt - 1)); i; i >>= 1) {
436109060Smbr		if (bits & i) {
437109060Smbr			SIO_SET(SIS_MII_DATA);
438109060Smbr		} else {
439109060Smbr			SIO_CLR(SIS_MII_DATA);
440109060Smbr		}
441109060Smbr		DELAY(1);
442109060Smbr		SIO_CLR(SIS_MII_CLK);
443109060Smbr		DELAY(1);
444109060Smbr		SIO_SET(SIS_MII_CLK);
445109060Smbr	}
446109060Smbr}
447109060Smbr
448109060Smbr/*
449109060Smbr * Read an PHY register through the MII.
450109060Smbr */
451139740Sphkstatic int
452139740Sphksis_mii_readreg(struct sis_softc *sc, struct sis_mii_frame *frame)
453109060Smbr{
454109060Smbr	int			i, ack, s;
455109060Smbr
456109060Smbr	s = splimp();
457109060Smbr
458109060Smbr	/*
459109060Smbr	 * Set up frame for RX.
460109060Smbr	 */
461109060Smbr	frame->mii_stdelim = SIS_MII_STARTDELIM;
462109060Smbr	frame->mii_opcode = SIS_MII_READOP;
463109060Smbr	frame->mii_turnaround = 0;
464109060Smbr	frame->mii_data = 0;
465109060Smbr
466109060Smbr	/*
467109060Smbr 	 * Turn on data xmit.
468109060Smbr	 */
469109060Smbr	SIO_SET(SIS_MII_DIR);
470109060Smbr
471109060Smbr	sis_mii_sync(sc);
472109060Smbr
473109060Smbr	/*
474109060Smbr	 * Send command/address info.
475109060Smbr	 */
476109060Smbr	sis_mii_send(sc, frame->mii_stdelim, 2);
477109060Smbr	sis_mii_send(sc, frame->mii_opcode, 2);
478109060Smbr	sis_mii_send(sc, frame->mii_phyaddr, 5);
479109060Smbr	sis_mii_send(sc, frame->mii_regaddr, 5);
480109060Smbr
481109060Smbr	/* Idle bit */
482109060Smbr	SIO_CLR((SIS_MII_CLK|SIS_MII_DATA));
483109060Smbr	DELAY(1);
484109060Smbr	SIO_SET(SIS_MII_CLK);
485109060Smbr	DELAY(1);
486109060Smbr
487109060Smbr	/* Turn off xmit. */
488109060Smbr	SIO_CLR(SIS_MII_DIR);
489109060Smbr
490109060Smbr	/* Check for ack */
491109060Smbr	SIO_CLR(SIS_MII_CLK);
492109060Smbr	DELAY(1);
493109060Smbr	ack = CSR_READ_4(sc, SIS_EECTL) & SIS_MII_DATA;
494109060Smbr	SIO_SET(SIS_MII_CLK);
495109060Smbr	DELAY(1);
496109060Smbr
497109060Smbr	/*
498109060Smbr	 * Now try reading data bits. If the ack failed, we still
499109060Smbr	 * need to clock through 16 cycles to keep the PHY(s) in sync.
500109060Smbr	 */
501109060Smbr	if (ack) {
502109060Smbr		for(i = 0; i < 16; i++) {
503109060Smbr			SIO_CLR(SIS_MII_CLK);
504109060Smbr			DELAY(1);
505109060Smbr			SIO_SET(SIS_MII_CLK);
506109060Smbr			DELAY(1);
507109060Smbr		}
508109060Smbr		goto fail;
509109060Smbr	}
510109060Smbr
511109060Smbr	for (i = 0x8000; i; i >>= 1) {
512109060Smbr		SIO_CLR(SIS_MII_CLK);
513109060Smbr		DELAY(1);
514109060Smbr		if (!ack) {
515109060Smbr			if (CSR_READ_4(sc, SIS_EECTL) & SIS_MII_DATA)
516109060Smbr				frame->mii_data |= i;
517109060Smbr			DELAY(1);
518109060Smbr		}
519109060Smbr		SIO_SET(SIS_MII_CLK);
520109060Smbr		DELAY(1);
521109060Smbr	}
522109060Smbr
523109060Smbrfail:
524109060Smbr
525109060Smbr	SIO_CLR(SIS_MII_CLK);
526109060Smbr	DELAY(1);
527109060Smbr	SIO_SET(SIS_MII_CLK);
528109060Smbr	DELAY(1);
529109060Smbr
530109060Smbr	splx(s);
531109060Smbr
532109060Smbr	if (ack)
533109060Smbr		return(1);
534109060Smbr	return(0);
535109060Smbr}
536109060Smbr
537109060Smbr/*
538109060Smbr * Write to a PHY register through the MII.
539109060Smbr */
540139740Sphkstatic int
541139740Sphksis_mii_writereg(struct sis_softc *sc, struct sis_mii_frame *frame)
542109060Smbr{
543109060Smbr	int			s;
544109060Smbr
545109060Smbr	 s = splimp();
546109060Smbr 	/*
547109060Smbr 	 * Set up frame for TX.
548109060Smbr 	 */
549109060Smbr
550109060Smbr 	frame->mii_stdelim = SIS_MII_STARTDELIM;
551109060Smbr 	frame->mii_opcode = SIS_MII_WRITEOP;
552109060Smbr 	frame->mii_turnaround = SIS_MII_TURNAROUND;
553109060Smbr
554109060Smbr 	/*
555109060Smbr  	 * Turn on data output.
556109060Smbr 	 */
557109060Smbr 	SIO_SET(SIS_MII_DIR);
558109060Smbr
559109060Smbr 	sis_mii_sync(sc);
560109060Smbr
561109060Smbr 	sis_mii_send(sc, frame->mii_stdelim, 2);
562109060Smbr 	sis_mii_send(sc, frame->mii_opcode, 2);
563109060Smbr 	sis_mii_send(sc, frame->mii_phyaddr, 5);
564109060Smbr 	sis_mii_send(sc, frame->mii_regaddr, 5);
565109060Smbr 	sis_mii_send(sc, frame->mii_turnaround, 2);
566109060Smbr 	sis_mii_send(sc, frame->mii_data, 16);
567109060Smbr
568109060Smbr 	/* Idle bit. */
569109060Smbr 	SIO_SET(SIS_MII_CLK);
570109060Smbr 	DELAY(1);
571109060Smbr 	SIO_CLR(SIS_MII_CLK);
572109060Smbr 	DELAY(1);
573109060Smbr
574109060Smbr 	/*
575109060Smbr 	 * Turn off xmit.
576109060Smbr 	 */
577109060Smbr 	SIO_CLR(SIS_MII_DIR);
578109060Smbr
579109060Smbr 	splx(s);
580109060Smbr
581109060Smbr 	return(0);
582109060Smbr}
583109060Smbr
584102334Salfredstatic int
585139740Sphksis_miibus_readreg(device_t dev, int phy, int reg)
58650974Swpaul{
58750974Swpaul	struct sis_softc	*sc;
588109060Smbr	struct sis_mii_frame    frame;
58950974Swpaul
59050974Swpaul	sc = device_get_softc(dev);
59150974Swpaul
59262672Swpaul	if (sc->sis_type == SIS_TYPE_83815) {
59362672Swpaul		if (phy != 0)
59462672Swpaul			return(0);
59562672Swpaul		/*
59662672Swpaul		 * The NatSemi chip can take a while after
59762672Swpaul		 * a reset to come ready, during which the BMSR
59862672Swpaul		 * returns a value of 0. This is *never* supposed
59962672Swpaul		 * to happen: some of the BMSR bits are meant to
60062672Swpaul		 * be hardwired in the on position, and this can
60162672Swpaul		 * confuse the miibus code a bit during the probe
60262672Swpaul		 * and attach phase. So we make an effort to check
60362672Swpaul		 * for this condition and wait for it to clear.
60462672Swpaul		 */
60562672Swpaul		if (!CSR_READ_4(sc, NS_BMSR))
60662672Swpaul			DELAY(1000);
607109060Smbr		return CSR_READ_4(sc, NS_BMCR + (reg * 4));
60862672Swpaul	}
60962672Swpaul
610109976Smbr	/*
611109976Smbr	 * Chipsets < SIS_635 seem not to be able to read/write
612109976Smbr	 * through mdio. Use the enhanced PHY access register
613109976Smbr	 * again for them.
614109976Smbr	 */
61589296Swpaul	if (sc->sis_type == SIS_TYPE_900 &&
616109976Smbr	    sc->sis_rev < SIS_REV_635) {
617109976Smbr		int i, val = 0;
61850974Swpaul
619109976Smbr		if (phy != 0)
620109976Smbr			return(0);
62150974Swpaul
622109976Smbr		CSR_WRITE_4(sc, SIS_PHYCTL,
623109976Smbr		    (phy << 11) | (reg << 6) | SIS_PHYOP_READ);
624109976Smbr		SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS);
62550974Swpaul
626109976Smbr		for (i = 0; i < SIS_TIMEOUT; i++) {
627109976Smbr			if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS))
628109976Smbr				break;
629109976Smbr		}
630109976Smbr
631109976Smbr		if (i == SIS_TIMEOUT) {
632109976Smbr			printf("sis%d: PHY failed to come ready\n",
633109976Smbr			    sc->sis_unit);
634109976Smbr			return(0);
635109976Smbr		}
636109976Smbr
637109976Smbr		val = (CSR_READ_4(sc, SIS_PHYCTL) >> 16) & 0xFFFF;
638109976Smbr
639109976Smbr		if (val == 0xFFFF)
640109976Smbr			return(0);
641109976Smbr
642109976Smbr		return(val);
643109976Smbr	} else {
644109976Smbr		bzero((char *)&frame, sizeof(frame));
645109976Smbr
646109976Smbr		frame.mii_phyaddr = phy;
647109976Smbr		frame.mii_regaddr = reg;
648109976Smbr		sis_mii_readreg(sc, &frame);
649109976Smbr
650109976Smbr		return(frame.mii_data);
651109976Smbr	}
65250974Swpaul}
65350974Swpaul
654102334Salfredstatic int
655139740Sphksis_miibus_writereg(device_t dev, int phy, int reg, int data)
65650974Swpaul{
65750974Swpaul	struct sis_softc	*sc;
658109060Smbr	struct sis_mii_frame	frame;
65950974Swpaul
66050974Swpaul	sc = device_get_softc(dev);
66150974Swpaul
66262672Swpaul	if (sc->sis_type == SIS_TYPE_83815) {
66362672Swpaul		if (phy != 0)
66462672Swpaul			return(0);
66562672Swpaul		CSR_WRITE_4(sc, NS_BMCR + (reg * 4), data);
66662672Swpaul		return(0);
66762672Swpaul	}
66862672Swpaul
669109976Smbr	/*
670109976Smbr	 * Chipsets < SIS_635 seem not to be able to read/write
671109976Smbr	 * through mdio. Use the enhanced PHY access register
672109976Smbr	 * again for them.
673109976Smbr	 */
674109976Smbr	if (sc->sis_type == SIS_TYPE_900 &&
675109976Smbr	    sc->sis_rev < SIS_REV_635) {
676109976Smbr		int i;
67750974Swpaul
678109976Smbr		if (phy != 0)
679109976Smbr			return(0);
68050974Swpaul
681109976Smbr		CSR_WRITE_4(sc, SIS_PHYCTL, (data << 16) | (phy << 11) |
682109976Smbr		    (reg << 6) | SIS_PHYOP_WRITE);
683109976Smbr		SIS_SETBIT(sc, SIS_PHYCTL, SIS_PHYCTL_ACCESS);
68450974Swpaul
685109976Smbr		for (i = 0; i < SIS_TIMEOUT; i++) {
686109976Smbr			if (!(CSR_READ_4(sc, SIS_PHYCTL) & SIS_PHYCTL_ACCESS))
687109976Smbr				break;
688109976Smbr		}
68950974Swpaul
690109976Smbr		if (i == SIS_TIMEOUT)
691109976Smbr			printf("sis%d: PHY failed to come ready\n",
692109976Smbr			    sc->sis_unit);
693109976Smbr	} else {
694109976Smbr		bzero((char *)&frame, sizeof(frame));
695109976Smbr
696109976Smbr		frame.mii_phyaddr = phy;
697109976Smbr		frame.mii_regaddr = reg;
698109976Smbr		frame.mii_data = data;
699109976Smbr		sis_mii_writereg(sc, &frame);
700109976Smbr	}
70150974Swpaul	return(0);
70250974Swpaul}
70350974Swpaul
704102334Salfredstatic void
705139717Sphksis_miibus_statchg(device_t dev)
70650974Swpaul{
70750974Swpaul	struct sis_softc	*sc;
70850974Swpaul
70950974Swpaul	sc = device_get_softc(dev);
710139717Sphk	SIS_LOCK_ASSERT(sc);
711139717Sphk	sis_initl(sc);
71250974Swpaul}
71350974Swpaul
714139740Sphkstatic uint32_t
715139740Sphksis_mchash(struct sis_softc *sc, const uint8_t *addr)
71650974Swpaul{
717130270Snaddy	uint32_t		crc;
71850974Swpaul
71950974Swpaul	/* Compute CRC for the address value. */
720130270Snaddy	crc = ether_crc32_be(addr, ETHER_ADDR_LEN);
72150974Swpaul
72262672Swpaul	/*
72362672Swpaul	 * return the filter bit position
72462672Swpaul	 *
72562672Swpaul	 * The NatSemi chip has a 512-bit filter, which is
72662672Swpaul	 * different than the SiS, so we special-case it.
72762672Swpaul	 */
72862672Swpaul	if (sc->sis_type == SIS_TYPE_83815)
729109060Smbr		return (crc >> 23);
730109976Smbr	else if (sc->sis_rev >= SIS_REV_635 ||
731109976Smbr	    sc->sis_rev == SIS_REV_900B)
732109060Smbr		return (crc >> 24);
733109976Smbr	else
734109976Smbr		return (crc >> 25);
73550974Swpaul}
73650974Swpaul
737102334Salfredstatic void
738139740Sphksis_setmulti_ns(struct sis_softc *sc)
73950974Swpaul{
74050974Swpaul	struct ifnet		*ifp;
74150974Swpaul	struct ifmultiaddr	*ifma;
74250974Swpaul	u_int32_t		h = 0, i, filtsave;
74362672Swpaul	int			bit, index;
74450974Swpaul
74550974Swpaul	ifp = &sc->arpcom.ac_if;
74650974Swpaul
74750974Swpaul	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
74862672Swpaul		SIS_CLRBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_MCHASH);
74950974Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI);
75050974Swpaul		return;
75150974Swpaul	}
75250974Swpaul
75362672Swpaul	/*
75462672Swpaul	 * We have to explicitly enable the multicast hash table
75562672Swpaul	 * on the NatSemi chip if we want to use it, which we do.
75662672Swpaul	 */
75762672Swpaul	SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_MCHASH);
75850974Swpaul	SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLMULTI);
75950974Swpaul
76050974Swpaul	filtsave = CSR_READ_4(sc, SIS_RXFILT_CTL);
76150974Swpaul
76250974Swpaul	/* first, zot all the existing hash bits */
76362672Swpaul	for (i = 0; i < 32; i++) {
76462672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + (i*2));
76562672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA, 0);
76662672Swpaul	}
76762672Swpaul
76872084Sphk	TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
76962672Swpaul		if (ifma->ifma_addr->sa_family != AF_LINK)
77062672Swpaul			continue;
771122625Sobrien		h = sis_mchash(sc,
772122625Sobrien		    LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
77362672Swpaul		index = h >> 3;
77462672Swpaul		bit = h & 0x1F;
77562672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_FMEM_LO + index);
77662672Swpaul		if (bit > 0xF)
77762672Swpaul			bit -= 0x10;
77862672Swpaul		SIS_SETBIT(sc, SIS_RXFILT_DATA, (1 << bit));
77962672Swpaul	}
78062672Swpaul
78162672Swpaul	CSR_WRITE_4(sc, SIS_RXFILT_CTL, filtsave);
78262672Swpaul
78362672Swpaul	return;
78462672Swpaul}
78562672Swpaul
786102334Salfredstatic void
787139740Sphksis_setmulti_sis(struct sis_softc *sc)
78862672Swpaul{
78962672Swpaul	struct ifnet		*ifp;
79062672Swpaul	struct ifmultiaddr	*ifma;
791109060Smbr	u_int32_t		h, i, n, ctl;
792109060Smbr	u_int16_t		hashes[16];
79362672Swpaul
79462672Swpaul	ifp = &sc->arpcom.ac_if;
79562672Swpaul
796109060Smbr	/* hash table size */
797109976Smbr	if (sc->sis_rev >= SIS_REV_635 ||
798109976Smbr	    sc->sis_rev == SIS_REV_900B)
799109976Smbr		n = 16;
800109976Smbr	else
801109976Smbr		n = 8;
80262672Swpaul
803109060Smbr	ctl = CSR_READ_4(sc, SIS_RXFILT_CTL) & SIS_RXFILTCTL_ENABLE;
80462672Swpaul
805109060Smbr	if (ifp->if_flags & IFF_BROADCAST)
806109060Smbr		ctl |= SIS_RXFILTCTL_BROAD;
80762672Swpaul
808109060Smbr	if (ifp->if_flags & IFF_ALLMULTI || ifp->if_flags & IFF_PROMISC) {
809109060Smbr		ctl |= SIS_RXFILTCTL_ALLMULTI;
810109060Smbr		if (ifp->if_flags & IFF_PROMISC)
811109060Smbr			ctl |= SIS_RXFILTCTL_BROAD|SIS_RXFILTCTL_ALLPHYS;
812109060Smbr		for (i = 0; i < n; i++)
813109060Smbr			hashes[i] = ~0;
814109060Smbr	} else {
815109060Smbr		for (i = 0; i < n; i++)
816109060Smbr			hashes[i] = 0;
817109060Smbr		i = 0;
818109060Smbr		TAILQ_FOREACH(ifma, &ifp->if_multiaddrs, ifma_link) {
819109060Smbr			if (ifma->ifma_addr->sa_family != AF_LINK)
820109060Smbr			continue;
821122625Sobrien			h = sis_mchash(sc,
822109060Smbr			    LLADDR((struct sockaddr_dl *)ifma->ifma_addr));
823109060Smbr			hashes[h >> 4] |= 1 << (h & 0xf);
824109060Smbr			i++;
825109060Smbr		}
826109060Smbr		if (i > n) {
827109060Smbr			ctl |= SIS_RXFILTCTL_ALLMULTI;
828109060Smbr			for (i = 0; i < n; i++)
829109060Smbr				hashes[i] = ~0;
830109060Smbr		}
83150974Swpaul	}
83250974Swpaul
833109060Smbr	for (i = 0; i < n; i++) {
834109060Smbr		CSR_WRITE_4(sc, SIS_RXFILT_CTL, (4 + i) << 16);
835109060Smbr		CSR_WRITE_4(sc, SIS_RXFILT_DATA, hashes[i]);
83650974Swpaul	}
83750974Swpaul
838109060Smbr	CSR_WRITE_4(sc, SIS_RXFILT_CTL, ctl);
83950974Swpaul}
84050974Swpaul
841102334Salfredstatic void
842139717Sphksis_reset(struct sis_softc *sc)
84350974Swpaul{
844139708Sphk	int		i;
84550974Swpaul
84650974Swpaul	SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RESET);
84750974Swpaul
84850974Swpaul	for (i = 0; i < SIS_TIMEOUT; i++) {
84950974Swpaul		if (!(CSR_READ_4(sc, SIS_CSR) & SIS_CSR_RESET))
85050974Swpaul			break;
85150974Swpaul	}
85250974Swpaul
85350974Swpaul	if (i == SIS_TIMEOUT)
85450974Swpaul		printf("sis%d: reset never completed\n", sc->sis_unit);
85550974Swpaul
85650974Swpaul	/* Wait a little while for the chip to get its brains in order. */
85750974Swpaul	DELAY(1000);
85872813Swpaul
85972813Swpaul	/*
86072813Swpaul	 * If this is a NetSemi chip, make sure to clear
86172813Swpaul	 * PME mode.
86272813Swpaul	 */
86372813Swpaul	if (sc->sis_type == SIS_TYPE_83815) {
86472813Swpaul		CSR_WRITE_4(sc, NS_CLKRUN, NS_CLKRUN_PMESTS);
86572813Swpaul		CSR_WRITE_4(sc, NS_CLKRUN, 0);
86672813Swpaul	}
86772813Swpaul
86850974Swpaul        return;
86950974Swpaul}
87050974Swpaul
87150974Swpaul/*
87250974Swpaul * Probe for an SiS chip. Check the PCI vendor and device
87350974Swpaul * IDs against our list and return a device name if we find a match.
87450974Swpaul */
875102334Salfredstatic int
876139740Sphksis_probe(device_t dev)
87750974Swpaul{
87850974Swpaul	struct sis_type		*t;
87950974Swpaul
88050974Swpaul	t = sis_devs;
88150974Swpaul
88250974Swpaul	while(t->sis_name != NULL) {
88350974Swpaul		if ((pci_get_vendor(dev) == t->sis_vid) &&
88450974Swpaul		    (pci_get_device(dev) == t->sis_did)) {
88550974Swpaul			device_set_desc(dev, t->sis_name);
886142398Simp			return (BUS_PROBE_DEFAULT);
88750974Swpaul		}
88850974Swpaul		t++;
88950974Swpaul	}
89050974Swpaul
89150974Swpaul	return(ENXIO);
89250974Swpaul}
89350974Swpaul
89450974Swpaul/*
89550974Swpaul * Attach the interface. Allocate softc structures, do ifmedia
89650974Swpaul * setup and ethernet/BPF attach.
89750974Swpaul */
898102334Salfredstatic int
899139740Sphksis_attach(device_t dev)
90050974Swpaul{
90150974Swpaul	u_char			eaddr[ETHER_ADDR_LEN];
90250974Swpaul	struct sis_softc	*sc;
90350974Swpaul	struct ifnet		*ifp;
904109061Smbr	int			unit, error = 0, rid, waittime = 0;
90550974Swpaul
906109061Smbr	waittime = 0;
90750974Swpaul	sc = device_get_softc(dev);
90850974Swpaul	unit = device_get_unit(dev);
90950974Swpaul
910119712Sphk	sc->sis_self = dev;
911119712Sphk
91293818Sjhb	mtx_init(&sc->sis_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK,
913139810Sphk	    MTX_DEF);
91469583Swpaul
91550974Swpaul	if (pci_get_device(dev) == SIS_DEVICEID_900)
91650974Swpaul		sc->sis_type = SIS_TYPE_900;
91750974Swpaul	if (pci_get_device(dev) == SIS_DEVICEID_7016)
91850974Swpaul		sc->sis_type = SIS_TYPE_7016;
91962672Swpaul	if (pci_get_vendor(dev) == NS_VENDORID)
92062672Swpaul		sc->sis_type = SIS_TYPE_83815;
92150974Swpaul
92289296Swpaul	sc->sis_rev = pci_read_config(dev, PCIR_REVID, 1);
92350974Swpaul	/*
92450974Swpaul	 * Map control/status registers.
92550974Swpaul	 */
92672813Swpaul	pci_enable_busmaster(dev);
92750974Swpaul
92850974Swpaul	rid = SIS_RID;
929127135Snjl	sc->sis_res = bus_alloc_resource_any(dev, SIS_RES, &rid, RF_ACTIVE);
93050974Swpaul
93150974Swpaul	if (sc->sis_res == NULL) {
93250974Swpaul		printf("sis%d: couldn't map ports/memory\n", unit);
93350974Swpaul		error = ENXIO;
93450974Swpaul		goto fail;
93550974Swpaul	}
93650974Swpaul
93750974Swpaul	sc->sis_btag = rman_get_bustag(sc->sis_res);
93850974Swpaul	sc->sis_bhandle = rman_get_bushandle(sc->sis_res);
93950974Swpaul
94050974Swpaul	/* Allocate interrupt */
94150974Swpaul	rid = 0;
942127135Snjl	sc->sis_irq = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid,
94350974Swpaul	    RF_SHAREABLE | RF_ACTIVE);
94450974Swpaul
94550974Swpaul	if (sc->sis_irq == NULL) {
94650974Swpaul		printf("sis%d: couldn't map interrupt\n", unit);
94750974Swpaul		error = ENXIO;
94850974Swpaul		goto fail;
94950974Swpaul	}
95050974Swpaul
95150974Swpaul	/* Reset the adapter. */
95250974Swpaul	sis_reset(sc);
95350974Swpaul
954109976Smbr	if (sc->sis_type == SIS_TYPE_900 &&
955109976Smbr            (sc->sis_rev == SIS_REV_635 ||
956109976Smbr            sc->sis_rev == SIS_REV_900B)) {
957109976Smbr		SIO_SET(SIS_CFG_RND_CNT);
958109976Smbr		SIO_SET(SIS_CFG_PERR_DETECT);
959109976Smbr	}
960109976Smbr
96150974Swpaul	/*
96250974Swpaul	 * Get station address from the EEPROM.
96350974Swpaul	 */
96462672Swpaul	switch (pci_get_vendor(dev)) {
96562672Swpaul	case NS_VENDORID:
966119712Sphk		sc->sis_srr = CSR_READ_4(sc, NS_SRR);
967119712Sphk
968119712Sphk		/* We can't update the device description, so spew */
969119712Sphk		if (sc->sis_srr == NS_SRR_15C)
970119712Sphk			device_printf(dev, "Silicon Revision: DP83815C\n");
971119712Sphk		else if (sc->sis_srr == NS_SRR_15D)
972119712Sphk			device_printf(dev, "Silicon Revision: DP83815D\n");
973119712Sphk		else if (sc->sis_srr == NS_SRR_16A)
974119712Sphk			device_printf(dev, "Silicon Revision: DP83816A\n");
975119712Sphk		else
976119712Sphk			device_printf(dev, "Silicon Revision %x\n", sc->sis_srr);
977119712Sphk
97862672Swpaul		/*
97962672Swpaul		 * Reading the MAC address out of the EEPROM on
98062672Swpaul		 * the NatSemi chip takes a bit more work than
98162672Swpaul		 * you'd expect. The address spans 4 16-bit words,
98262672Swpaul		 * with the first word containing only a single bit.
98362672Swpaul		 * You have to shift everything over one bit to
98462672Swpaul		 * get it aligned properly. Also, the bits are
98562672Swpaul		 * stored backwards (the LSB is really the MSB,
98662672Swpaul		 * and so on) so you have to reverse them in order
98762672Swpaul		 * to get the MAC address into the form we want.
98862672Swpaul		 * Why? Who the hell knows.
98962672Swpaul		 */
99062672Swpaul		{
99162672Swpaul			u_int16_t		tmp[4];
99250974Swpaul
99362672Swpaul			sis_read_eeprom(sc, (caddr_t)&tmp,
99462672Swpaul			    NS_EE_NODEADDR, 4, 0);
99562672Swpaul
99662672Swpaul			/* Shift everything over one bit. */
99762672Swpaul			tmp[3] = tmp[3] >> 1;
99862681Swpaul			tmp[3] |= tmp[2] << 15;
99962672Swpaul			tmp[2] = tmp[2] >> 1;
100062681Swpaul			tmp[2] |= tmp[1] << 15;
100162672Swpaul			tmp[1] = tmp[1] >> 1;
100262681Swpaul			tmp[1] |= tmp[0] << 15;
100362672Swpaul
100462672Swpaul			/* Now reverse all the bits. */
100562672Swpaul			tmp[3] = sis_reverse(tmp[3]);
100662672Swpaul			tmp[2] = sis_reverse(tmp[2]);
100762672Swpaul			tmp[1] = sis_reverse(tmp[1]);
100862672Swpaul
100962672Swpaul			bcopy((char *)&tmp[1], eaddr, ETHER_ADDR_LEN);
101062672Swpaul		}
101162672Swpaul		break;
101262672Swpaul	case SIS_VENDORID:
101362672Swpaul	default:
1014144243Sobrien#if defined(__i386__) || defined(__amd64__)
101572197Swpaul		/*
101672197Swpaul		 * If this is a SiS 630E chipset with an embedded
101772197Swpaul		 * SiS 900 controller, we have to read the MAC address
101872197Swpaul		 * from the APC CMOS RAM. Our method for doing this
101972197Swpaul		 * is very ugly since we have to reach out and grab
102072197Swpaul		 * ahold of hardware for which we cannot properly
102172197Swpaul		 * allocate resources. This code is only compiled on
102272197Swpaul		 * the i386 architecture since the SiS 630E chipset
102372197Swpaul		 * is for x86 motherboards only. Note that there are
102472197Swpaul		 * a lot of magic numbers in this hack. These are
102572197Swpaul		 * taken from SiS's Linux driver. I'd like to replace
102672197Swpaul		 * them with proper symbolic definitions, but that
102772197Swpaul		 * requires some datasheets that I don't have access
102872197Swpaul		 * to at the moment.
102972197Swpaul		 */
103089296Swpaul		if (sc->sis_rev == SIS_REV_630S ||
103189296Swpaul		    sc->sis_rev == SIS_REV_630E ||
103290328Sambrisko		    sc->sis_rev == SIS_REV_630EA1)
103372197Swpaul			sis_read_cmos(sc, dev, (caddr_t)&eaddr, 0x9, 6);
103489296Swpaul
103590328Sambrisko		else if (sc->sis_rev == SIS_REV_635 ||
103690328Sambrisko			 sc->sis_rev == SIS_REV_630ET)
103789296Swpaul			sis_read_mac(sc, dev, (caddr_t)&eaddr);
1038109061Smbr		else if (sc->sis_rev == SIS_REV_96x) {
1039109061Smbr			/* Allow to read EEPROM from LAN. It is shared
1040109061Smbr			 * between a 1394 controller and the NIC and each
1041109061Smbr			 * time we access it, we need to set SIS_EECMD_REQ.
1042109061Smbr			 */
1043109061Smbr			SIO_SET(SIS_EECMD_REQ);
1044109061Smbr			for (waittime = 0; waittime < SIS_TIMEOUT;
1045109061Smbr			    waittime++) {
1046109061Smbr				/* Force EEPROM to idle state. */
1047109061Smbr				sis_eeprom_idle(sc);
1048109061Smbr				if (CSR_READ_4(sc, SIS_EECTL) & SIS_EECMD_GNT) {
1049109061Smbr					sis_read_eeprom(sc, (caddr_t)&eaddr,
1050109061Smbr					    SIS_EE_NODEADDR, 3, 0);
1051109061Smbr					break;
1052109061Smbr				}
1053109061Smbr				DELAY(1);
1054109061Smbr			}
1055109061Smbr			/*
1056109061Smbr			 * Set SIS_EECTL_CLK to high, so a other master
1057109061Smbr			 * can operate on the i2c bus.
1058109061Smbr			 */
1059109061Smbr			SIO_SET(SIS_EECTL_CLK);
1060109061Smbr			/* Refuse EEPROM access by LAN */
1061109061Smbr			SIO_SET(SIS_EECMD_DONE);
1062109061Smbr		} else
106372197Swpaul#endif
106472197Swpaul			sis_read_eeprom(sc, (caddr_t)&eaddr,
106572197Swpaul			    SIS_EE_NODEADDR, 3, 0);
106662672Swpaul		break;
106762672Swpaul	}
106862672Swpaul
106950974Swpaul	sc->sis_unit = unit;
1070129636Srwatson	if (debug_mpsafenet)
1071129636Srwatson		callout_init(&sc->sis_stat_ch, CALLOUT_MPSAFE);
1072129636Srwatson	else
1073129636Srwatson		callout_init(&sc->sis_stat_ch, 0);
107450974Swpaul	bcopy(eaddr, (char *)&sc->arpcom.ac_enaddr, ETHER_ADDR_LEN);
107550974Swpaul
107681713Swpaul	/*
107781713Swpaul	 * Allocate the parent bus DMA tag appropriate for PCI.
107881713Swpaul	 */
107981713Swpaul#define SIS_NSEG_NEW 32
108081713Swpaul	 error = bus_dma_tag_create(NULL,	/* parent */
108181713Swpaul			1, 0,			/* alignment, boundary */
108281713Swpaul			BUS_SPACE_MAXADDR_32BIT,/* lowaddr */
108381713Swpaul			BUS_SPACE_MAXADDR,	/* highaddr */
108481713Swpaul			NULL, NULL,		/* filter, filterarg */
108581713Swpaul			MAXBSIZE, SIS_NSEG_NEW,	/* maxsize, nsegments */
108681713Swpaul			BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
108781713Swpaul			BUS_DMA_ALLOCNOW,	/* flags */
1088117126Sscottl			NULL, NULL,		/* lockfunc, lockarg */
108981713Swpaul			&sc->sis_parent_tag);
1090112872Snjl	if (error)
1091112872Snjl		goto fail;
109250974Swpaul
109381713Swpaul	/*
1094112872Snjl	 * Now allocate a tag for the DMA descriptor lists and a chunk
1095112872Snjl	 * of DMA-able memory based on the tag.  Also obtain the physical
1096112872Snjl	 * addresses of the RX and TX ring, which we'll need later.
109781713Swpaul	 * All of our lists are allocated as a contiguous block
109881713Swpaul	 * of memory.
109981713Swpaul	 */
110081713Swpaul	error = bus_dma_tag_create(sc->sis_parent_tag,	/* parent */
110181713Swpaul			1, 0,			/* alignment, boundary */
110281713Swpaul			BUS_SPACE_MAXADDR,	/* lowaddr */
110381713Swpaul			BUS_SPACE_MAXADDR,	/* highaddr */
110481713Swpaul			NULL, NULL,		/* filter, filterarg */
110581713Swpaul			SIS_RX_LIST_SZ, 1,	/* maxsize,nsegments */
110681713Swpaul			BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
110781713Swpaul			0,			/* flags */
1108117126Sscottl			busdma_lock_mutex,	/* lockfunc */
1109117126Sscottl			&Giant,			/* lockarg */
1110139690Sphk			&sc->sis_rx_tag);
1111112872Snjl	if (error)
1112112872Snjl		goto fail;
111381713Swpaul
1114139690Sphk	error = bus_dmamem_alloc(sc->sis_rx_tag,
1115139690Sphk	    (void **)&sc->sis_rx_list, BUS_DMA_NOWAIT | BUS_DMA_ZERO,
1116139690Sphk	    &sc->sis_rx_dmamap);
1117112872Snjl
1118112872Snjl	if (error) {
1119112872Snjl		printf("sis%d: no memory for rx list buffers!\n", unit);
1120139690Sphk		bus_dma_tag_destroy(sc->sis_rx_tag);
1121139690Sphk		sc->sis_rx_tag = NULL;
1122112872Snjl		goto fail;
1123112872Snjl	}
1124112872Snjl
1125139690Sphk	error = bus_dmamap_load(sc->sis_rx_tag,
1126139690Sphk	    sc->sis_rx_dmamap, &(sc->sis_rx_list[0]),
1127112872Snjl	    sizeof(struct sis_desc), sis_dma_map_ring,
1128139690Sphk	    &sc->sis_rx_paddr, 0);
1129112872Snjl
1130112872Snjl	if (error) {
1131112872Snjl		printf("sis%d: cannot get address of the rx ring!\n", unit);
1132139690Sphk		bus_dmamem_free(sc->sis_rx_tag,
1133139690Sphk		    sc->sis_rx_list, sc->sis_rx_dmamap);
1134139690Sphk		bus_dma_tag_destroy(sc->sis_rx_tag);
1135139690Sphk		sc->sis_rx_tag = NULL;
1136112872Snjl		goto fail;
1137112872Snjl	}
1138112872Snjl
113981713Swpaul	error = bus_dma_tag_create(sc->sis_parent_tag,	/* parent */
114081713Swpaul			1, 0,			/* alignment, boundary */
114181713Swpaul			BUS_SPACE_MAXADDR,	/* lowaddr */
114281713Swpaul			BUS_SPACE_MAXADDR,	/* highaddr */
114381713Swpaul			NULL, NULL,		/* filter, filterarg */
114481713Swpaul			SIS_TX_LIST_SZ, 1,	/* maxsize,nsegments */
114581713Swpaul			BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
114681713Swpaul			0,			/* flags */
1147117126Sscottl			busdma_lock_mutex,	/* lockfunc */
1148117126Sscottl			&Giant,			/* lockarg */
1149139690Sphk			&sc->sis_tx_tag);
1150112872Snjl	if (error)
1151112872Snjl		goto fail;
115281713Swpaul
1153139690Sphk	error = bus_dmamem_alloc(sc->sis_tx_tag,
1154139690Sphk	    (void **)&sc->sis_tx_list, BUS_DMA_NOWAIT | BUS_DMA_ZERO,
1155139690Sphk	    &sc->sis_tx_dmamap);
115681713Swpaul
115781713Swpaul	if (error) {
1158112872Snjl		printf("sis%d: no memory for tx list buffers!\n", unit);
1159139690Sphk		bus_dma_tag_destroy(sc->sis_tx_tag);
1160139690Sphk		sc->sis_tx_tag = NULL;
116150974Swpaul		goto fail;
116250974Swpaul	}
116350974Swpaul
1164139690Sphk	error = bus_dmamap_load(sc->sis_tx_tag,
1165139690Sphk	    sc->sis_tx_dmamap, &(sc->sis_tx_list[0]),
1166112872Snjl	    sizeof(struct sis_desc), sis_dma_map_ring,
1167139690Sphk	    &sc->sis_tx_paddr, 0);
116881713Swpaul
116981713Swpaul	if (error) {
1170112872Snjl		printf("sis%d: cannot get address of the tx ring!\n", unit);
1171139690Sphk		bus_dmamem_free(sc->sis_tx_tag,
1172139690Sphk		    sc->sis_tx_list, sc->sis_tx_dmamap);
1173139690Sphk		bus_dma_tag_destroy(sc->sis_tx_tag);
1174139690Sphk		sc->sis_tx_tag = NULL;
117581713Swpaul		goto fail;
117681713Swpaul	}
117781713Swpaul
1178112872Snjl	error = bus_dma_tag_create(sc->sis_parent_tag,	/* parent */
1179112872Snjl			1, 0,			/* alignment, boundary */
1180112872Snjl			BUS_SPACE_MAXADDR,	/* lowaddr */
1181112872Snjl			BUS_SPACE_MAXADDR,	/* highaddr */
1182112872Snjl			NULL, NULL,		/* filter, filterarg */
1183112872Snjl			MCLBYTES, 1,		/* maxsize,nsegments */
1184112872Snjl			BUS_SPACE_MAXSIZE_32BIT,/* maxsegsize */
1185112872Snjl			0,			/* flags */
1186117126Sscottl			busdma_lock_mutex,	/* lockfunc */
1187117126Sscottl			&Giant,			/* lockarg */
1188112872Snjl			&sc->sis_tag);
1189112872Snjl	if (error)
1190112872Snjl		goto fail;
119181713Swpaul
119281713Swpaul	/*
119381713Swpaul	 * Obtain the physical addresses of the RX and TX
119481713Swpaul	 * rings which we'll need later in the init routine.
119581713Swpaul	 */
119681713Swpaul
119750974Swpaul	ifp = &sc->arpcom.ac_if;
119850974Swpaul	ifp->if_softc = sc;
1199121816Sbrooks	if_initname(ifp, device_get_name(dev), device_get_unit(dev));
120050974Swpaul	ifp->if_mtu = ETHERMTU;
120150974Swpaul	ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST;
120250974Swpaul	ifp->if_ioctl = sis_ioctl;
120350974Swpaul	ifp->if_start = sis_start;
120450974Swpaul	ifp->if_watchdog = sis_watchdog;
120550974Swpaul	ifp->if_init = sis_init;
120650974Swpaul	ifp->if_baudrate = 10000000;
1207131455Smlaier	IFQ_SET_MAXLEN(&ifp->if_snd, SIS_TX_LIST_CNT - 1);
1208131455Smlaier	ifp->if_snd.ifq_drv_maxlen = SIS_TX_LIST_CNT - 1;
1209131455Smlaier	IFQ_SET_READY(&ifp->if_snd);
121050974Swpaul
121150974Swpaul	/*
121250974Swpaul	 * Do MII setup.
121350974Swpaul	 */
121450974Swpaul	if (mii_phy_probe(dev, &sc->sis_miibus,
121550974Swpaul	    sis_ifmedia_upd, sis_ifmedia_sts)) {
121650974Swpaul		printf("sis%d: MII without any PHY!\n", sc->sis_unit);
121750974Swpaul		error = ENXIO;
121850974Swpaul		goto fail;
121950974Swpaul	}
122050974Swpaul
122150974Swpaul	/*
122263090Sarchie	 * Call MI attach routine.
122350974Swpaul	 */
1224106936Ssam	ether_ifattach(ifp, eaddr);
122587390Sjhay
122687390Sjhay	/*
122787390Sjhay	 * Tell the upper layer(s) we support long frames.
122887390Sjhay	 */
122987390Sjhay	ifp->if_data.ifi_hdrlen = sizeof(struct ether_vlan_header);
1230106936Ssam	ifp->if_capabilities |= IFCAP_VLAN_MTU;
123187390Sjhay
1232128138Sru#ifdef DEVICE_POLLING
1233128138Sru	ifp->if_capabilities |= IFCAP_POLLING;
1234128138Sru#endif
1235128138Sru	ifp->if_capenable = ifp->if_capabilities;
1236128138Sru
1237113609Snjl	/* Hook interrupt last to avoid having to lock softc */
1238121697Ssam	error = bus_setup_intr(dev, sc->sis_irq, INTR_TYPE_NET | INTR_MPSAFE,
1239112872Snjl	    sis_intr, sc, &sc->sis_intrhand);
124050974Swpaul
1241112872Snjl	if (error) {
1242112872Snjl		printf("sis%d: couldn't set up irq\n", unit);
1243113609Snjl		ether_ifdetach(ifp);
1244112872Snjl		goto fail;
1245112872Snjl	}
1246112872Snjl
124750974Swpaulfail:
1248112872Snjl	if (error)
1249112872Snjl		sis_detach(dev);
1250112872Snjl
125150974Swpaul	return(error);
125250974Swpaul}
125350974Swpaul
1254113609Snjl/*
1255113609Snjl * Shutdown hardware and free up resources. This can be called any
1256113609Snjl * time after the mutex has been initialized. It is called in both
1257113609Snjl * the error case in attach and the normal detach case so it needs
1258113609Snjl * to be careful about only freeing resources that have actually been
1259113609Snjl * allocated.
1260113609Snjl */
1261102334Salfredstatic int
1262139740Sphksis_detach(device_t dev)
126350974Swpaul{
126450974Swpaul	struct sis_softc	*sc;
126550974Swpaul	struct ifnet		*ifp;
126650974Swpaul
126750974Swpaul	sc = device_get_softc(dev);
1268112880Sjhb	KASSERT(mtx_initialized(&sc->sis_mtx), ("sis mutex not initialized"));
126967087Swpaul	SIS_LOCK(sc);
127050974Swpaul	ifp = &sc->arpcom.ac_if;
127150974Swpaul
1272118089Smux	/* These should only be active if attach succeeded. */
1273113812Simp	if (device_is_attached(dev)) {
1274113609Snjl		sis_reset(sc);
1275113609Snjl		sis_stop(sc);
1276112872Snjl		ether_ifdetach(ifp);
1277113609Snjl	}
1278113609Snjl	if (sc->sis_miibus)
1279112872Snjl		device_delete_child(dev, sc->sis_miibus);
1280113609Snjl	bus_generic_detach(dev);
128150974Swpaul
1282112872Snjl	if (sc->sis_intrhand)
1283112872Snjl		bus_teardown_intr(dev, sc->sis_irq, sc->sis_intrhand);
1284112872Snjl	if (sc->sis_irq)
1285112872Snjl		bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sis_irq);
1286112872Snjl	if (sc->sis_res)
1287112872Snjl		bus_release_resource(dev, SIS_RES, SIS_RID, sc->sis_res);
128850974Swpaul
1289139690Sphk	if (sc->sis_rx_tag) {
1290139690Sphk		bus_dmamap_unload(sc->sis_rx_tag,
1291139690Sphk		    sc->sis_rx_dmamap);
1292139690Sphk		bus_dmamem_free(sc->sis_rx_tag,
1293139690Sphk		    sc->sis_rx_list, sc->sis_rx_dmamap);
1294139690Sphk		bus_dma_tag_destroy(sc->sis_rx_tag);
1295112872Snjl	}
1296139690Sphk	if (sc->sis_tx_tag) {
1297139690Sphk		bus_dmamap_unload(sc->sis_tx_tag,
1298139690Sphk		    sc->sis_tx_dmamap);
1299139690Sphk		bus_dmamem_free(sc->sis_tx_tag,
1300139690Sphk		    sc->sis_tx_list, sc->sis_tx_dmamap);
1301139690Sphk		bus_dma_tag_destroy(sc->sis_tx_tag);
1302112872Snjl	}
1303112872Snjl	if (sc->sis_parent_tag)
1304112872Snjl		bus_dma_tag_destroy(sc->sis_parent_tag);
1305112872Snjl	if (sc->sis_tag)
1306112872Snjl		bus_dma_tag_destroy(sc->sis_tag);
130750974Swpaul
130867087Swpaul	SIS_UNLOCK(sc);
130967087Swpaul	mtx_destroy(&sc->sis_mtx);
131050974Swpaul
131150974Swpaul	return(0);
131250974Swpaul}
131350974Swpaul
131450974Swpaul/*
1315139802Sphk * Initialize the TX and RX descriptors and allocate mbufs for them. Note that
1316139802Sphk * we arrange the descriptors in a closed ring, so that the last descriptor
1317139802Sphk * points back to the first.
131850974Swpaul */
1319102334Salfredstatic int
1320139802Sphksis_ring_init(struct sis_softc *sc)
132150974Swpaul{
1322139802Sphk	int i, error;
1323139802Sphk	struct sis_desc *dp;
132450974Swpaul
1325139802Sphk	dp = &sc->sis_tx_list[0];
1326139802Sphk	for (i = 0; i < SIS_TX_LIST_CNT; i++, dp++) {
1327139802Sphk		if (i == (SIS_TX_LIST_CNT - 1))
1328139802Sphk			dp->sis_nextdesc = &sc->sis_tx_list[0];
1329139802Sphk		else
1330139802Sphk			dp->sis_nextdesc = dp + 1;
1331139802Sphk		bus_dmamap_load(sc->sis_tx_tag,
1332139802Sphk		    sc->sis_tx_dmamap,
1333139802Sphk		    dp->sis_nextdesc, sizeof(struct sis_desc),
1334139802Sphk		    sis_dma_map_desc_next, dp, 0);
1335139802Sphk		dp->sis_mbuf = NULL;
1336139802Sphk		dp->sis_ptr = 0;
1337139802Sphk		dp->sis_ctl = 0;
133850974Swpaul	}
133950974Swpaul
1340139690Sphk	sc->sis_tx_prod = sc->sis_tx_cons = sc->sis_tx_cnt = 0;
134150974Swpaul
1342139690Sphk	bus_dmamap_sync(sc->sis_tx_tag,
1343139690Sphk	    sc->sis_rx_dmamap, BUS_DMASYNC_PREWRITE);
134481713Swpaul
1345139802Sphk	dp = &sc->sis_rx_list[0];
1346139802Sphk	for (i = 0; i < SIS_RX_LIST_CNT; i++, dp++) {
1347139802Sphk		error = sis_newbuf(sc, dp, NULL);
1348139802Sphk		if (error)
1349139802Sphk			return(error);
1350139802Sphk		if (i == (SIS_RX_LIST_CNT - 1))
1351139802Sphk			dp->sis_nextdesc = &sc->sis_rx_list[0];
1352139802Sphk		else
1353139802Sphk			dp->sis_nextdesc = dp + 1;
1354139802Sphk		bus_dmamap_load(sc->sis_rx_tag,
1355139802Sphk		    sc->sis_rx_dmamap,
1356139802Sphk		    dp->sis_nextdesc, sizeof(struct sis_desc),
1357139802Sphk		    sis_dma_map_desc_next, dp, 0);
135850974Swpaul		}
135950974Swpaul
1360139690Sphk	bus_dmamap_sync(sc->sis_rx_tag,
1361139690Sphk	    sc->sis_rx_dmamap, BUS_DMASYNC_PREWRITE);
136281713Swpaul
1363139691Sphk	sc->sis_rx_pdsc = &sc->sis_rx_list[0];
136450974Swpaul
136550974Swpaul	return(0);
136650974Swpaul}
136750974Swpaul
136850974Swpaul/*
136950974Swpaul * Initialize an RX descriptor and attach an MBUF cluster.
137050974Swpaul */
1371102334Salfredstatic int
1372139740Sphksis_newbuf(struct sis_softc *sc, struct sis_desc *c, struct mbuf *m)
137350974Swpaul{
137450974Swpaul
137581713Swpaul	if (c == NULL)
137681713Swpaul		return(EINVAL);
137781713Swpaul
137850974Swpaul	if (m == NULL) {
1379111119Simp		m = m_getcl(M_DONTWAIT, MT_DATA, M_PKTHDR);
1380101340Sluigi		if (m == NULL)
138150974Swpaul			return(ENOBUFS);
1382101340Sluigi	} else
1383101340Sluigi		m->m_data = m->m_ext.ext_buf;
138450974Swpaul
1385101340Sluigi	c->sis_mbuf = m;
138650974Swpaul	c->sis_ctl = SIS_RXLEN;
138750974Swpaul
138881713Swpaul	bus_dmamap_create(sc->sis_tag, 0, &c->sis_map);
138981713Swpaul	bus_dmamap_load(sc->sis_tag, c->sis_map,
1390101464Sluigi	    mtod(m, void *), MCLBYTES,
139181713Swpaul	    sis_dma_map_desc_ptr, c, 0);
1392139944Ssam	bus_dmamap_sync(sc->sis_tag, c->sis_map, BUS_DMASYNC_PREREAD);
139381713Swpaul
139450974Swpaul	return(0);
139550974Swpaul}
139650974Swpaul
139750974Swpaul/*
139850974Swpaul * A frame has been uploaded: pass the resulting mbuf chain up to
139950974Swpaul * the higher level protocols.
140050974Swpaul */
1401102334Salfredstatic void
1402139740Sphksis_rxeof(struct sis_softc *sc)
140350974Swpaul{
140450974Swpaul        struct mbuf		*m;
140550974Swpaul        struct ifnet		*ifp;
140650974Swpaul	struct sis_desc		*cur_rx;
1407139691Sphk	int			total_len = 0;
140850974Swpaul	u_int32_t		rxstat;
140950974Swpaul
1410122689Ssam	SIS_LOCK_ASSERT(sc);
1411122689Ssam
141250974Swpaul	ifp = &sc->arpcom.ac_if;
141350974Swpaul
1414139691Sphk	for(cur_rx = sc->sis_rx_pdsc; SIS_OWNDESC(cur_rx);
1415139691Sphk	    cur_rx = cur_rx->sis_nextdesc) {
141650974Swpaul
141787902Sluigi#ifdef DEVICE_POLLING
1418102052Ssobomax		if (ifp->if_flags & IFF_POLLING) {
141987902Sluigi			if (sc->rxcycles <= 0)
142087902Sluigi				break;
142187902Sluigi			sc->rxcycles--;
142287902Sluigi		}
142387902Sluigi#endif /* DEVICE_POLLING */
142450974Swpaul		rxstat = cur_rx->sis_rxstat;
142581713Swpaul		bus_dmamap_sync(sc->sis_tag,
142681713Swpaul		    cur_rx->sis_map, BUS_DMASYNC_POSTWRITE);
142781713Swpaul		bus_dmamap_unload(sc->sis_tag, cur_rx->sis_map);
142881713Swpaul		bus_dmamap_destroy(sc->sis_tag, cur_rx->sis_map);
142950974Swpaul		m = cur_rx->sis_mbuf;
143050974Swpaul		cur_rx->sis_mbuf = NULL;
143150974Swpaul		total_len = SIS_RXBYTES(cur_rx);
143250974Swpaul
143350974Swpaul		/*
143450974Swpaul		 * If an error occurs, update stats, clear the
143550974Swpaul		 * status word and leave the mbuf cluster in place:
143650974Swpaul		 * it should simply get re-used next time this descriptor
143750974Swpaul	 	 * comes up in the ring.
143850974Swpaul		 */
143950974Swpaul		if (!(rxstat & SIS_CMDSTS_PKT_OK)) {
144050974Swpaul			ifp->if_ierrors++;
144150974Swpaul			if (rxstat & SIS_RXSTAT_COLL)
144250974Swpaul				ifp->if_collisions++;
144350974Swpaul			sis_newbuf(sc, cur_rx, m);
144450974Swpaul			continue;
144550974Swpaul		}
144650974Swpaul
144750974Swpaul		/* No errors; receive the packet. */
1448144243Sobrien#if defined(__i386__) || defined(__amd64__)
144987059Sluigi		/*
145087059Sluigi		 * On the x86 we do not have alignment problems, so try to
145187059Sluigi		 * allocate a new buffer for the receive ring, and pass up
145287059Sluigi		 * the one where the packet is already, saving the expensive
145387059Sluigi		 * copy done in m_devget().
145487059Sluigi		 * If we are on an architecture with alignment problems, or
145587059Sluigi		 * if the allocation fails, then use m_devget and leave the
145687059Sluigi		 * existing buffer in the receive ring.
145787059Sluigi		 */
1458101464Sluigi		if (sis_newbuf(sc, cur_rx, NULL) == 0)
145987059Sluigi			m->m_pkthdr.len = m->m_len = total_len;
1460101464Sluigi		else
146187059Sluigi#endif
146287059Sluigi		{
146387059Sluigi			struct mbuf		*m0;
146487059Sluigi			m0 = m_devget(mtod(m, char *), total_len,
146587059Sluigi				ETHER_ALIGN, ifp, NULL);
146687059Sluigi			sis_newbuf(sc, cur_rx, m);
146787059Sluigi			if (m0 == NULL) {
146887059Sluigi				ifp->if_ierrors++;
146987059Sluigi				continue;
147087059Sluigi			}
147187059Sluigi			m = m0;
147250974Swpaul		}
147350974Swpaul
147450974Swpaul		ifp->if_ipackets++;
1475106936Ssam		m->m_pkthdr.rcvif = ifp;
1476106936Ssam
1477122689Ssam		SIS_UNLOCK(sc);
1478106936Ssam		(*ifp->if_input)(ifp, m);
1479122689Ssam		SIS_LOCK(sc);
148050974Swpaul	}
148150974Swpaul
1482139691Sphk	sc->sis_rx_pdsc = cur_rx;
148350974Swpaul}
148450974Swpaul
1485105219Sphkstatic void
1486139715Sphksis_rxeoc(struct sis_softc *sc)
148750974Swpaul{
1488139715Sphk
1489139715Sphk	SIS_LOCK_ASSERT(sc);
149050974Swpaul	sis_rxeof(sc);
1491139715Sphk	sis_initl(sc);
149250974Swpaul}
149350974Swpaul
149450974Swpaul/*
149550974Swpaul * A frame was downloaded to the chip. It's safe for us to clean up
149650974Swpaul * the list buffers.
149750974Swpaul */
149850974Swpaul
1499102334Salfredstatic void
1500139740Sphksis_txeof(struct sis_softc *sc)
150150974Swpaul{
150250974Swpaul	struct ifnet		*ifp;
150350974Swpaul	u_int32_t		idx;
150450974Swpaul
1505139715Sphk	SIS_LOCK_ASSERT(sc);
150650974Swpaul	ifp = &sc->arpcom.ac_if;
150750974Swpaul
150850974Swpaul	/*
150950974Swpaul	 * Go through our tx list and free mbufs for those
151050974Swpaul	 * frames that have been transmitted.
151150974Swpaul	 */
1512139690Sphk	for (idx = sc->sis_tx_cons; sc->sis_tx_cnt > 0;
1513139690Sphk	    sc->sis_tx_cnt--, SIS_INC(idx, SIS_TX_LIST_CNT) ) {
1514139690Sphk		struct sis_desc *cur_tx = &sc->sis_tx_list[idx];
151550974Swpaul
151650974Swpaul		if (SIS_OWNDESC(cur_tx))
151750974Swpaul			break;
151850974Swpaul
151999163Sluigi		if (cur_tx->sis_ctl & SIS_CMDSTS_MORE)
152050974Swpaul			continue;
152150974Swpaul
152250974Swpaul		if (!(cur_tx->sis_ctl & SIS_CMDSTS_PKT_OK)) {
152350974Swpaul			ifp->if_oerrors++;
152450974Swpaul			if (cur_tx->sis_txstat & SIS_TXSTAT_EXCESSCOLLS)
152550974Swpaul				ifp->if_collisions++;
152650974Swpaul			if (cur_tx->sis_txstat & SIS_TXSTAT_OUTOFWINCOLL)
152750974Swpaul				ifp->if_collisions++;
152850974Swpaul		}
152950974Swpaul
153050974Swpaul		ifp->if_collisions +=
153150974Swpaul		    (cur_tx->sis_txstat & SIS_TXSTAT_COLLCNT) >> 16;
153250974Swpaul
153350974Swpaul		ifp->if_opackets++;
153450974Swpaul		if (cur_tx->sis_mbuf != NULL) {
153550974Swpaul			m_freem(cur_tx->sis_mbuf);
153650974Swpaul			cur_tx->sis_mbuf = NULL;
153781713Swpaul			bus_dmamap_unload(sc->sis_tag, cur_tx->sis_map);
153881713Swpaul			bus_dmamap_destroy(sc->sis_tag, cur_tx->sis_map);
153950974Swpaul		}
154099163Sluigi	}
154150974Swpaul
1542139690Sphk	if (idx != sc->sis_tx_cons) {
154399163Sluigi		/* we freed up some buffers */
1544139690Sphk		sc->sis_tx_cons = idx;
154599163Sluigi		ifp->if_flags &= ~IFF_OACTIVE;
154650974Swpaul	}
154750974Swpaul
1548139690Sphk	ifp->if_timer = (sc->sis_tx_cnt == 0) ? 0 : 5;
154950974Swpaul
155050974Swpaul	return;
155150974Swpaul}
155250974Swpaul
1553102334Salfredstatic void
1554139740Sphksis_tick(void *xsc)
155550974Swpaul{
155650974Swpaul	struct sis_softc	*sc;
155750974Swpaul	struct mii_data		*mii;
155864963Swpaul	struct ifnet		*ifp;
155950974Swpaul
156050974Swpaul	sc = xsc;
156167087Swpaul	SIS_LOCK(sc);
1562117858Scognet	sc->in_tick = 1;
156364963Swpaul	ifp = &sc->arpcom.ac_if;
156464963Swpaul
156550974Swpaul	mii = device_get_softc(sc->sis_miibus);
156650974Swpaul	mii_tick(mii);
156764963Swpaul
156884147Sjlemon	if (!sc->sis_link && mii->mii_media_status & IFM_ACTIVE &&
156984147Sjlemon	    IFM_SUBTYPE(mii->mii_media_active) != IFM_NONE) {
157084147Sjlemon		sc->sis_link++;
1571131455Smlaier		if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1572139714Sphk			sis_startl(ifp);
157364963Swpaul	}
157464963Swpaul
1575119785Ssam	callout_reset(&sc->sis_stat_ch, hz,  sis_tick, sc);
1576117858Scognet	sc->in_tick = 0;
157767087Swpaul	SIS_UNLOCK(sc);
157850974Swpaul}
157950974Swpaul
158087902Sluigi#ifdef DEVICE_POLLING
158187902Sluigistatic poll_handler_t sis_poll;
158287902Sluigi
158387902Sluigistatic void
158487902Sluigisis_poll(struct ifnet *ifp, enum poll_cmd cmd, int count)
158587902Sluigi{
158687973Speter	struct	sis_softc *sc = ifp->if_softc;
158787973Speter
158887902Sluigi	SIS_LOCK(sc);
1589128138Sru	if (!(ifp->if_capenable & IFCAP_POLLING)) {
1590128138Sru		ether_poll_deregister(ifp);
1591128138Sru		cmd = POLL_DEREGISTER;
1592128138Sru	}
159387902Sluigi	if (cmd == POLL_DEREGISTER) { /* final call, enable interrupts */
159487902Sluigi		CSR_WRITE_4(sc, SIS_IER, 1);
159587902Sluigi		goto done;
159687902Sluigi	}
159787902Sluigi
159887902Sluigi	/*
159987902Sluigi	 * On the sis, reading the status register also clears it.
160087902Sluigi	 * So before returning to intr mode we must make sure that all
160187902Sluigi	 * possible pending sources of interrupts have been served.
160287902Sluigi	 * In practice this means run to completion the *eof routines,
160387902Sluigi	 * and then call the interrupt routine
160487902Sluigi	 */
160587902Sluigi	sc->rxcycles = count;
160687902Sluigi	sis_rxeof(sc);
160787902Sluigi	sis_txeof(sc);
1608131455Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1609139714Sphk		sis_startl(ifp);
161087902Sluigi
161187902Sluigi	if (sc->rxcycles > 0 || cmd == POLL_AND_CHECK_STATUS) {
161287902Sluigi		u_int32_t	status;
161387902Sluigi
161487902Sluigi		/* Reading the ISR register clears all interrupts. */
161587902Sluigi		status = CSR_READ_4(sc, SIS_ISR);
161687902Sluigi
161787902Sluigi		if (status & (SIS_ISR_RX_ERR|SIS_ISR_RX_OFLOW))
161887902Sluigi			sis_rxeoc(sc);
161987902Sluigi
162087902Sluigi		if (status & (SIS_ISR_RX_IDLE))
162187902Sluigi			SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE);
162287902Sluigi
162387902Sluigi		if (status & SIS_ISR_SYSERR) {
162487902Sluigi			sis_reset(sc);
1625139715Sphk			sis_initl(sc);
162687902Sluigi		}
162787902Sluigi	}
162887902Sluigidone:
162987902Sluigi	SIS_UNLOCK(sc);
163087902Sluigi}
163187902Sluigi#endif /* DEVICE_POLLING */
163287902Sluigi
1633102334Salfredstatic void
1634139740Sphksis_intr(void *arg)
163550974Swpaul{
163650974Swpaul	struct sis_softc	*sc;
163750974Swpaul	struct ifnet		*ifp;
163850974Swpaul	u_int32_t		status;
163950974Swpaul
164050974Swpaul	sc = arg;
164150974Swpaul	ifp = &sc->arpcom.ac_if;
164250974Swpaul
1643139809Sphk	if (sc->sis_stopped)	/* Most likely shared interrupt */
1644139809Sphk		return;
1645139809Sphk
164686984Sluigi	SIS_LOCK(sc);
164787902Sluigi#ifdef DEVICE_POLLING
1648139974Sru	if (ifp->if_flags & IFF_POLLING)
1649139974Sru		goto done;
1650139974Sru	if ((ifp->if_capenable & IFCAP_POLLING) &&
1651139974Sru	    ether_poll_register(sis_poll, ifp)) { /* ok, disable interrupts */
165287902Sluigi		CSR_WRITE_4(sc, SIS_IER, 0);
1653139974Sru		goto done;
165487902Sluigi	}
165587902Sluigi#endif /* DEVICE_POLLING */
165687902Sluigi
165750974Swpaul	/* Disable interrupts. */
165850974Swpaul	CSR_WRITE_4(sc, SIS_IER, 0);
165950974Swpaul
166050974Swpaul	for (;;) {
1661139717Sphk		SIS_LOCK_ASSERT(sc);
166250974Swpaul		/* Reading the ISR register clears all interrupts. */
166350974Swpaul		status = CSR_READ_4(sc, SIS_ISR);
166450974Swpaul
166550974Swpaul		if ((status & SIS_INTRS) == 0)
166650974Swpaul			break;
166750974Swpaul
166886984Sluigi		if (status &
166986984Sluigi		    (SIS_ISR_TX_DESC_OK | SIS_ISR_TX_ERR |
167086984Sluigi		     SIS_ISR_TX_OK | SIS_ISR_TX_IDLE) )
167150974Swpaul			sis_txeof(sc);
167250974Swpaul
167386984Sluigi		if (status & (SIS_ISR_RX_DESC_OK|SIS_ISR_RX_OK|SIS_ISR_RX_IDLE))
167450974Swpaul			sis_rxeof(sc);
167550974Swpaul
167686984Sluigi		if (status & (SIS_ISR_RX_ERR | SIS_ISR_RX_OFLOW))
167750974Swpaul			sis_rxeoc(sc);
167850974Swpaul
167986984Sluigi		if (status & (SIS_ISR_RX_IDLE))
168086984Sluigi			SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE);
168186984Sluigi
168250974Swpaul		if (status & SIS_ISR_SYSERR) {
168350974Swpaul			sis_reset(sc);
1684139715Sphk			sis_initl(sc);
168550974Swpaul		}
168650974Swpaul	}
168750974Swpaul
168850974Swpaul	/* Re-enable interrupts. */
168950974Swpaul	CSR_WRITE_4(sc, SIS_IER, 1);
169050974Swpaul
1691131455Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
1692139714Sphk		sis_startl(ifp);
1693139809Sphk
1694139974Sru#ifdef DEVICE_POLLING
1695139974Srudone:
1696139974Sru#endif /* DEVICE_POLLING */
169767087Swpaul	SIS_UNLOCK(sc);
169850974Swpaul}
169950974Swpaul
170050974Swpaul/*
170150974Swpaul * Encapsulate an mbuf chain in a descriptor by coupling the mbuf data
170250974Swpaul * pointers to the fragment pointers.
170350974Swpaul */
1704102334Salfredstatic int
1705139740Sphksis_encap(struct sis_softc *sc, struct mbuf **m_head, uint32_t *txidx)
170650974Swpaul{
170750974Swpaul	struct sis_desc		*f = NULL;
170850974Swpaul	struct mbuf		*m;
1709112808Ssilby	int			frag, cur, cnt = 0, chainlen = 0;
171050974Swpaul
171150974Swpaul	/*
1712112808Ssilby	 * If there's no way we can send any packets, return now.
1713112808Ssilby	 */
1714139690Sphk	if (SIS_TX_LIST_CNT - sc->sis_tx_cnt < 2)
1715112808Ssilby		return (ENOBUFS);
1716112808Ssilby
1717112808Ssilby	/*
1718112808Ssilby	 * Count the number of frags in this chain to see if
1719112808Ssilby	 * we need to m_defrag.  Since the descriptor list is shared
1720112808Ssilby	 * by all packets, we'll m_defrag long chains so that they
1721112808Ssilby	 * do not use up the entire list, even if they would fit.
1722112808Ssilby	 */
1723112808Ssilby
1724121262Ssilby	for (m = *m_head; m != NULL; m = m->m_next)
1725112808Ssilby		chainlen++;
1726112808Ssilby
1727112808Ssilby	if ((chainlen > SIS_TX_LIST_CNT / 4) ||
1728139690Sphk	    ((SIS_TX_LIST_CNT - (chainlen + sc->sis_tx_cnt)) < 2)) {
1729121262Ssilby		m = m_defrag(*m_head, M_DONTWAIT);
1730112808Ssilby		if (m == NULL)
1731112808Ssilby			return (ENOBUFS);
1732121262Ssilby		*m_head = m;
1733112808Ssilby	}
1734112808Ssilby
1735112808Ssilby	/*
173650974Swpaul 	 * Start packing the mbufs in this chain into
173750974Swpaul	 * the fragment pointers. Stop when we run out
173850974Swpaul 	 * of fragments or hit the end of the mbuf chain.
173950974Swpaul	 */
174050974Swpaul	cur = frag = *txidx;
174150974Swpaul
1742121262Ssilby	for (m = *m_head; m != NULL; m = m->m_next) {
174350974Swpaul		if (m->m_len != 0) {
174451042Swpaul			if ((SIS_TX_LIST_CNT -
1745139690Sphk			    (sc->sis_tx_cnt + cnt)) < 2)
174650974Swpaul				return(ENOBUFS);
1747139690Sphk			f = &sc->sis_tx_list[frag];
174850974Swpaul			f->sis_ctl = SIS_CMDSTS_MORE | m->m_len;
174981713Swpaul			bus_dmamap_create(sc->sis_tag, 0, &f->sis_map);
175081713Swpaul			bus_dmamap_load(sc->sis_tag, f->sis_map,
175181713Swpaul			    mtod(m, void *), m->m_len,
175281713Swpaul			    sis_dma_map_desc_ptr, f, 0);
175381713Swpaul			bus_dmamap_sync(sc->sis_tag,
175481713Swpaul			    f->sis_map, BUS_DMASYNC_PREREAD);
175550974Swpaul			if (cnt != 0)
175650974Swpaul				f->sis_ctl |= SIS_CMDSTS_OWN;
175750974Swpaul			cur = frag;
175850974Swpaul			SIS_INC(frag, SIS_TX_LIST_CNT);
175950974Swpaul			cnt++;
176050974Swpaul		}
176150974Swpaul	}
176250974Swpaul
176350974Swpaul	if (m != NULL)
176450974Swpaul		return(ENOBUFS);
176550974Swpaul
1766139690Sphk	sc->sis_tx_list[cur].sis_mbuf = *m_head;
1767139690Sphk	sc->sis_tx_list[cur].sis_ctl &= ~SIS_CMDSTS_MORE;
1768139690Sphk	sc->sis_tx_list[*txidx].sis_ctl |= SIS_CMDSTS_OWN;
1769139690Sphk	sc->sis_tx_cnt += cnt;
177050974Swpaul	*txidx = frag;
177150974Swpaul
177250974Swpaul	return(0);
177350974Swpaul}
177450974Swpaul
177550974Swpaul/*
177650974Swpaul * Main transmit routine. To avoid having to do mbuf copies, we put pointers
177750974Swpaul * to the mbuf data regions directly in the transmit lists. We also save a
177850974Swpaul * copy of the pointers since the transmit list fragment pointers are
177950974Swpaul * physical addresses.
178050974Swpaul */
178150974Swpaul
1782102334Salfredstatic void
1783139717Sphksis_start(struct ifnet *ifp)
178450974Swpaul{
178550974Swpaul	struct sis_softc	*sc;
1786139714Sphk
1787139714Sphk	sc = ifp->if_softc;
1788139714Sphk	SIS_LOCK(sc);
1789139714Sphk	sis_startl(ifp);
1790139714Sphk	SIS_UNLOCK(sc);
1791139714Sphk}
1792139714Sphk
1793139714Sphkstatic void
1794139714Sphksis_startl(struct ifnet *ifp)
1795139714Sphk{
1796139714Sphk	struct sis_softc	*sc;
179750974Swpaul	struct mbuf		*m_head = NULL;
1798136269Smlaier	u_int32_t		idx, queued = 0;
179950974Swpaul
180050974Swpaul	sc = ifp->if_softc;
180150974Swpaul
1802139714Sphk	SIS_LOCK_ASSERT(sc);
1803139714Sphk
1804139714Sphk	if (!sc->sis_link)
180564963Swpaul		return;
180664963Swpaul
1807139690Sphk	idx = sc->sis_tx_prod;
180850974Swpaul
1809139714Sphk	if (ifp->if_flags & IFF_OACTIVE)
181050974Swpaul		return;
181150974Swpaul
1812139690Sphk	while(sc->sis_tx_list[idx].sis_mbuf == NULL) {
1813131455Smlaier		IFQ_DRV_DEQUEUE(&ifp->if_snd, m_head);
181450974Swpaul		if (m_head == NULL)
181550974Swpaul			break;
181650974Swpaul
1817121262Ssilby		if (sis_encap(sc, &m_head, &idx)) {
1818131455Smlaier			IFQ_DRV_PREPEND(&ifp->if_snd, m_head);
181950974Swpaul			ifp->if_flags |= IFF_OACTIVE;
182050974Swpaul			break;
182150974Swpaul		}
182250974Swpaul
1823136269Smlaier		queued++;
1824136269Smlaier
182550974Swpaul		/*
182650974Swpaul		 * If there's a BPF listener, bounce a copy of this frame
182750974Swpaul		 * to him.
182850974Swpaul		 */
1829106936Ssam		BPF_MTAP(ifp, m_head);
183051583Swpaul
183150974Swpaul	}
183250974Swpaul
1833136269Smlaier	if (queued) {
1834136269Smlaier		/* Transmit */
1835139690Sphk		sc->sis_tx_prod = idx;
1836136269Smlaier		SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_ENABLE);
183750974Swpaul
1838136269Smlaier		/*
1839136269Smlaier		 * Set a timeout in case the chip goes out to lunch.
1840136269Smlaier		 */
1841136269Smlaier		ifp->if_timer = 5;
1842136269Smlaier	}
184350974Swpaul}
184450974Swpaul
1845102334Salfredstatic void
1846139715Sphksis_init(void *xsc)
184750974Swpaul{
184850974Swpaul	struct sis_softc	*sc = xsc;
1849139715Sphk
1850139715Sphk	SIS_LOCK(sc);
1851139717Sphk	sis_initl(sc);
1852139715Sphk	SIS_UNLOCK(sc);
1853139715Sphk}
1854139715Sphk
1855139715Sphkstatic void
1856139717Sphksis_initl(struct sis_softc *sc)
1857139715Sphk{
185850974Swpaul	struct ifnet		*ifp = &sc->arpcom.ac_if;
185950974Swpaul	struct mii_data		*mii;
186050974Swpaul
1861139715Sphk	SIS_LOCK_ASSERT(sc);
186250974Swpaul
186350974Swpaul	/*
186450974Swpaul	 * Cancel pending I/O and free all RX/TX buffers.
186550974Swpaul	 */
186650974Swpaul	sis_stop(sc);
1867123833Sphk	sc->sis_stopped = 0;
186850974Swpaul
1869119712Sphk#ifdef notyet
1870119712Sphk	if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr >= NS_SRR_16A) {
1871119712Sphk		/*
1872119712Sphk		 * Configure 400usec of interrupt holdoff.  This is based
1873119712Sphk		 * on emperical tests on a Soekris 4801.
1874119712Sphk 		 */
1875119712Sphk		CSR_WRITE_4(sc, NS_IHR, 0x100 | 4);
1876119712Sphk	}
1877119712Sphk#endif
1878119712Sphk
187950974Swpaul	mii = device_get_softc(sc->sis_miibus);
188050974Swpaul
188150974Swpaul	/* Set MAC address */
188262672Swpaul	if (sc->sis_type == SIS_TYPE_83815) {
188362672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR0);
188462672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
188562672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[0]);
188662672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR1);
188762672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
188862672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[1]);
188962672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, NS_FILTADDR_PAR2);
189062672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
189162672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[2]);
189262672Swpaul	} else {
189362672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR0);
189462672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
189562672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[0]);
189662672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR1);
189762672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
189862672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[1]);
189962672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_CTL, SIS_FILTADDR_PAR2);
190062672Swpaul		CSR_WRITE_4(sc, SIS_RXFILT_DATA,
190162672Swpaul		    ((u_int16_t *)sc->arpcom.ac_enaddr)[2]);
190262672Swpaul	}
190350974Swpaul
1904139802Sphk	/* Init circular TX/RX lists. */
1905139802Sphk	if (sis_ring_init(sc) != 0) {
190650974Swpaul		printf("sis%d: initialization failed: no "
190750974Swpaul			"memory for rx buffers\n", sc->sis_unit);
190850974Swpaul		sis_stop(sc);
190950974Swpaul		return;
191050974Swpaul	}
191150974Swpaul
191250974Swpaul	/*
1913139806Sphk	 * Short Cable Receive Errors (MP21.E)
1914139806Sphk	 * also: Page 78 of the DP83815 data sheet (september 2002 version)
1915123491Sphk	 * recommends the following register settings "for optimum
1916123491Sphk	 * performance." for rev 15C.  The driver from NS also sets
1917123491Sphk	 * the PHY_CR register for later versions.
1918123491Sphk	 */
1919139806Sphk	if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr <= NS_SRR_15D) {
1920123491Sphk		CSR_WRITE_4(sc, NS_PHY_PAGE, 0x0001);
1921123491Sphk		CSR_WRITE_4(sc, NS_PHY_CR, 0x189C);
1922123491Sphk		if (sc->sis_srr == NS_SRR_15C) {
1923123491Sphk			/* set val for c2 */
1924123491Sphk			CSR_WRITE_4(sc, NS_PHY_TDATA, 0x0000);
1925123491Sphk			/* load/kill c2 */
1926123491Sphk			CSR_WRITE_4(sc, NS_PHY_DSPCFG, 0x5040);
1927123491Sphk			/* rais SD off, from 4 to c */
1928123491Sphk			CSR_WRITE_4(sc, NS_PHY_SDCFG, 0x008C);
1929123491Sphk		}
1930123491Sphk		CSR_WRITE_4(sc, NS_PHY_PAGE, 0);
1931123491Sphk	}
1932123491Sphk
1933123491Sphk
1934123491Sphk	/*
193562672Swpaul	 * For the NatSemi chip, we have to explicitly enable the
193662672Swpaul	 * reception of ARP frames, as well as turn on the 'perfect
193762672Swpaul	 * match' filter where we store the station address, otherwise
193862672Swpaul	 * we won't receive unicasts meant for this host.
193962672Swpaul	 */
194062672Swpaul	if (sc->sis_type == SIS_TYPE_83815) {
194162672Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_ARP);
194262672Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, NS_RXFILTCTL_PERFECT);
194362672Swpaul	}
194462672Swpaul
194550974Swpaul	 /* If we want promiscuous mode, set the allframes bit. */
194650974Swpaul	if (ifp->if_flags & IFF_PROMISC) {
194750974Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLPHYS);
194850974Swpaul	} else {
194950974Swpaul		SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ALLPHYS);
195050974Swpaul	}
195150974Swpaul
195250974Swpaul	/*
195350974Swpaul	 * Set the capture broadcast bit to capture broadcast frames.
195450974Swpaul	 */
195550974Swpaul	if (ifp->if_flags & IFF_BROADCAST) {
195650974Swpaul		SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_BROAD);
195750974Swpaul	} else {
195850974Swpaul		SIS_CLRBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_BROAD);
195950974Swpaul	}
196050974Swpaul
196150974Swpaul	/*
196250974Swpaul	 * Load the multicast filter.
196350974Swpaul	 */
196462672Swpaul	if (sc->sis_type == SIS_TYPE_83815)
196562672Swpaul		sis_setmulti_ns(sc);
196662672Swpaul	else
196762672Swpaul		sis_setmulti_sis(sc);
196850974Swpaul
196950974Swpaul	/* Turn the receive filter on */
197050974Swpaul	SIS_SETBIT(sc, SIS_RXFILT_CTL, SIS_RXFILTCTL_ENABLE);
197150974Swpaul
197250974Swpaul	/*
197350974Swpaul	 * Load the address of the RX and TX lists.
197450974Swpaul	 */
1975139690Sphk	CSR_WRITE_4(sc, SIS_RX_LISTPTR, sc->sis_rx_paddr);
1976139690Sphk	CSR_WRITE_4(sc, SIS_TX_LISTPTR, sc->sis_tx_paddr);
197750974Swpaul
1978109059Smbr	/* SIS_CFG_EDB_MASTER_EN indicates the EDB bus is used instead of
1979109059Smbr	 * the PCI bus. When this bit is set, the Max DMA Burst Size
1980109059Smbr	 * for TX/RX DMA should be no larger than 16 double words.
1981109059Smbr	 */
1982109059Smbr	if (CSR_READ_4(sc, SIS_CFG) & SIS_CFG_EDB_MASTER_EN) {
1983109059Smbr		CSR_WRITE_4(sc, SIS_RX_CFG, SIS_RXCFG64);
1984109059Smbr	} else {
1985109059Smbr		CSR_WRITE_4(sc, SIS_RX_CFG, SIS_RXCFG256);
1986109059Smbr	}
198764963Swpaul
198887390Sjhay	/* Accept Long Packets for VLAN support */
198987390Sjhay	SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_JABBER);
199087390Sjhay
199150974Swpaul	/* Set TX configuration */
199264963Swpaul	if (IFM_SUBTYPE(mii->mii_media_active) == IFM_10_T) {
199364963Swpaul		CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_10);
199464963Swpaul	} else {
199564963Swpaul		CSR_WRITE_4(sc, SIS_TX_CFG, SIS_TXCFG_100);
199664963Swpaul	}
199750974Swpaul
199864963Swpaul	/* Set full/half duplex mode. */
199964963Swpaul	if ((mii->mii_media_active & IFM_GMASK) == IFM_FDX) {
200064963Swpaul		SIS_SETBIT(sc, SIS_TX_CFG,
200164963Swpaul		    (SIS_TXCFG_IGN_HBEAT|SIS_TXCFG_IGN_CARR));
200264963Swpaul		SIS_SETBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS);
200364963Swpaul	} else {
200464963Swpaul		SIS_CLRBIT(sc, SIS_TX_CFG,
200564963Swpaul		    (SIS_TXCFG_IGN_HBEAT|SIS_TXCFG_IGN_CARR));
200664963Swpaul		SIS_CLRBIT(sc, SIS_RX_CFG, SIS_RXCFG_RX_TXPKTS);
200764963Swpaul	}
200864963Swpaul
2009139807Sphk	if (sc->sis_type == SIS_TYPE_83816) {
2010139807Sphk		/*
2011139807Sphk		 * MPII03.D: Half Duplex Excessive Collisions.
2012139807Sphk		 * Also page 49 in 83816 manual
2013139807Sphk		 */
2014139807Sphk		SIS_SETBIT(sc, SIS_TX_CFG, SIS_TXCFG_MPII03D);
2015139807Sphk	}
2016139807Sphk
2017139808Sphk	if (sc->sis_type == SIS_TYPE_83815 && sc->sis_srr < NS_SRR_16A &&
2018119130Ssam	     IFM_SUBTYPE(mii->mii_media_active) == IFM_100_TX) {
2019119130Ssam		uint32_t reg;
2020119130Ssam
2021119130Ssam		/*
2022139806Sphk		 * Short Cable Receive Errors (MP21.E)
2023119130Ssam		 */
2024119130Ssam		CSR_WRITE_4(sc, NS_PHY_PAGE, 0x0001);
2025139806Sphk		reg = CSR_READ_4(sc, NS_PHY_DSPCFG) & 0xfff;
2026139806Sphk		CSR_WRITE_4(sc, NS_PHY_DSPCFG, reg | 0x1000);
2027139806Sphk		DELAY(100000);
2028139806Sphk		reg = CSR_READ_4(sc, NS_PHY_TDATA) & 0xff;
2029139806Sphk		if ((reg & 0x0080) == 0 || (reg > 0xd8 && reg <= 0xff)) {
2030139806Sphk			device_printf(sc->sis_self,
2031139806Sphk			    "Applying short cable fix (reg=%x)\n", reg);
2032119130Ssam			CSR_WRITE_4(sc, NS_PHY_TDATA, 0x00e8);
2033139806Sphk			reg = CSR_READ_4(sc, NS_PHY_DSPCFG);
2034139806Sphk			SIS_SETBIT(sc, NS_PHY_DSPCFG, reg | 0x20);
2035119130Ssam		}
2036119130Ssam		CSR_WRITE_4(sc, NS_PHY_PAGE, 0);
2037119130Ssam	}
2038119130Ssam
203950974Swpaul	/*
204050974Swpaul	 * Enable interrupts.
204150974Swpaul	 */
204250974Swpaul	CSR_WRITE_4(sc, SIS_IMR, SIS_INTRS);
204387902Sluigi#ifdef DEVICE_POLLING
204487902Sluigi	/*
204587902Sluigi	 * ... only enable interrupts if we are not polling, make sure
204687902Sluigi	 * they are off otherwise.
204787902Sluigi	 */
2048102052Ssobomax	if (ifp->if_flags & IFF_POLLING)
204987902Sluigi		CSR_WRITE_4(sc, SIS_IER, 0);
205087902Sluigi	else
205187902Sluigi#endif /* DEVICE_POLLING */
205250974Swpaul	CSR_WRITE_4(sc, SIS_IER, 1);
205350974Swpaul
205450974Swpaul	/* Enable receiver and transmitter. */
205550974Swpaul	SIS_CLRBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE);
205650974Swpaul	SIS_SETBIT(sc, SIS_CSR, SIS_CSR_RX_ENABLE);
205750974Swpaul
205864963Swpaul#ifdef notdef
205950974Swpaul	mii_mediachg(mii);
206064963Swpaul#endif
206150974Swpaul
206250974Swpaul	ifp->if_flags |= IFF_RUNNING;
206350974Swpaul	ifp->if_flags &= ~IFF_OACTIVE;
206450974Swpaul
2065117858Scognet	if (!sc->in_tick)
2066119785Ssam		callout_reset(&sc->sis_stat_ch, hz,  sis_tick, sc);
206750974Swpaul}
206850974Swpaul
206950974Swpaul/*
207050974Swpaul * Set media options.
207150974Swpaul */
2072102334Salfredstatic int
2073139740Sphksis_ifmedia_upd(struct ifnet *ifp)
207450974Swpaul{
207550974Swpaul	struct sis_softc	*sc;
207664963Swpaul	struct mii_data		*mii;
207750974Swpaul
207850974Swpaul	sc = ifp->if_softc;
207950974Swpaul
208064963Swpaul	mii = device_get_softc(sc->sis_miibus);
208164963Swpaul	sc->sis_link = 0;
208264963Swpaul	if (mii->mii_instance) {
208364963Swpaul		struct mii_softc	*miisc;
208472012Sphk		LIST_FOREACH(miisc, &mii->mii_phys, mii_list)
208564963Swpaul			mii_phy_reset(miisc);
208664963Swpaul	}
208764963Swpaul	mii_mediachg(mii);
208850974Swpaul
208950974Swpaul	return(0);
209050974Swpaul}
209150974Swpaul
209250974Swpaul/*
209350974Swpaul * Report current media status.
209450974Swpaul */
2095102334Salfredstatic void
2096139740Sphksis_ifmedia_sts(struct ifnet *ifp, struct ifmediareq *ifmr)
209750974Swpaul{
209850974Swpaul	struct sis_softc	*sc;
209950974Swpaul	struct mii_data		*mii;
210050974Swpaul
210150974Swpaul	sc = ifp->if_softc;
210250974Swpaul
210350974Swpaul	mii = device_get_softc(sc->sis_miibus);
210450974Swpaul	mii_pollstat(mii);
210550974Swpaul	ifmr->ifm_active = mii->mii_media_active;
210650974Swpaul	ifmr->ifm_status = mii->mii_media_status;
210750974Swpaul}
210850974Swpaul
2109102334Salfredstatic int
2110139740Sphksis_ioctl(struct ifnet *ifp, u_long command, caddr_t data)
211150974Swpaul{
211250974Swpaul	struct sis_softc	*sc = ifp->if_softc;
211350974Swpaul	struct ifreq		*ifr = (struct ifreq *) data;
211450974Swpaul	struct mii_data		*mii;
211567087Swpaul	int			error = 0;
211650974Swpaul
211750974Swpaul	switch(command) {
211850974Swpaul	case SIOCSIFFLAGS:
211950974Swpaul		if (ifp->if_flags & IFF_UP) {
212050974Swpaul			sis_init(sc);
2121139741Sphk		} else if (ifp->if_flags & IFF_RUNNING) {
2122139741Sphk			SIS_LOCK(sc);
2123139741Sphk			sis_stop(sc);
2124139741Sphk			SIS_UNLOCK(sc);
212550974Swpaul		}
212650974Swpaul		error = 0;
212750974Swpaul		break;
212850974Swpaul	case SIOCADDMULTI:
212950974Swpaul	case SIOCDELMULTI:
213081713Swpaul		SIS_LOCK(sc);
213162672Swpaul		if (sc->sis_type == SIS_TYPE_83815)
213262672Swpaul			sis_setmulti_ns(sc);
213362672Swpaul		else
213462672Swpaul			sis_setmulti_sis(sc);
213581713Swpaul		SIS_UNLOCK(sc);
213650974Swpaul		error = 0;
213750974Swpaul		break;
213850974Swpaul	case SIOCGIFMEDIA:
213950974Swpaul	case SIOCSIFMEDIA:
214050974Swpaul		mii = device_get_softc(sc->sis_miibus);
214181713Swpaul		SIS_LOCK(sc);
214250974Swpaul		error = ifmedia_ioctl(ifp, ifr, &mii->mii_media, command);
214381713Swpaul		SIS_UNLOCK(sc);
214450974Swpaul		break;
2145128138Sru	case SIOCSIFCAP:
2146129633Syar		ifp->if_capenable &= ~IFCAP_POLLING;
2147129633Syar		ifp->if_capenable |= ifr->ifr_reqcap & IFCAP_POLLING;
2148128138Sru		break;
214950974Swpaul	default:
2150106936Ssam		error = ether_ioctl(ifp, command, data);
215150974Swpaul		break;
215250974Swpaul	}
215350974Swpaul
215450974Swpaul	return(error);
215550974Swpaul}
215650974Swpaul
2157102334Salfredstatic void
2158139740Sphksis_watchdog(struct ifnet *ifp)
215950974Swpaul{
2160139797Sphk	struct sis_softc *sc;
216150974Swpaul
216250974Swpaul	sc = ifp->if_softc;
216350974Swpaul
216467087Swpaul	SIS_LOCK(sc);
2165139797Sphk	if (sc->sis_stopped) {
2166139797Sphk		SIS_UNLOCK(sc);
2167139797Sphk		return;
2168139797Sphk	}
216967087Swpaul
217050974Swpaul	ifp->if_oerrors++;
217150974Swpaul	printf("sis%d: watchdog timeout\n", sc->sis_unit);
217250974Swpaul
217350974Swpaul	sis_stop(sc);
217450974Swpaul	sis_reset(sc);
2175139715Sphk	sis_initl(sc);
217650974Swpaul
2177131455Smlaier	if (!IFQ_DRV_IS_EMPTY(&ifp->if_snd))
2178139714Sphk		sis_startl(ifp);
217950974Swpaul
218067087Swpaul	SIS_UNLOCK(sc);
218150974Swpaul}
218250974Swpaul
218350974Swpaul/*
218450974Swpaul * Stop the adapter and free any mbufs allocated to the
218550974Swpaul * RX and TX lists.
218650974Swpaul */
2187102334Salfredstatic void
2188139740Sphksis_stop(struct sis_softc *sc)
218950974Swpaul{
2190139805Sphk	int i;
2191139805Sphk	struct ifnet *ifp;
2192139805Sphk	struct sis_desc *dp;
219350974Swpaul
2194123833Sphk	if (sc->sis_stopped)
2195123833Sphk		return;
2196139717Sphk	SIS_LOCK_ASSERT(sc);
219750974Swpaul	ifp = &sc->arpcom.ac_if;
219850974Swpaul	ifp->if_timer = 0;
219950974Swpaul
2200119785Ssam	callout_stop(&sc->sis_stat_ch);
220187472Speter
220287472Speter	ifp->if_flags &= ~(IFF_RUNNING | IFF_OACTIVE);
220387902Sluigi#ifdef DEVICE_POLLING
220487902Sluigi	ether_poll_deregister(ifp);
220587902Sluigi#endif
220650974Swpaul	CSR_WRITE_4(sc, SIS_IER, 0);
220750974Swpaul	CSR_WRITE_4(sc, SIS_IMR, 0);
2208139798Sphk	CSR_READ_4(sc, SIS_ISR); /* clear any interrupts already pending */
220950974Swpaul	SIS_SETBIT(sc, SIS_CSR, SIS_CSR_TX_DISABLE|SIS_CSR_RX_DISABLE);
221050974Swpaul	DELAY(1000);
221150974Swpaul	CSR_WRITE_4(sc, SIS_TX_LISTPTR, 0);
221250974Swpaul	CSR_WRITE_4(sc, SIS_RX_LISTPTR, 0);
221350974Swpaul
221464963Swpaul	sc->sis_link = 0;
221564963Swpaul
221650974Swpaul	/*
221750974Swpaul	 * Free data in the RX lists.
221850974Swpaul	 */
2219139805Sphk	dp = &sc->sis_rx_list[0];
2220139805Sphk	for (i = 0; i < SIS_RX_LIST_CNT; i++, dp++) {
2221139805Sphk		if (dp->sis_mbuf == NULL)
2222139805Sphk			continue;
2223139805Sphk		bus_dmamap_unload(sc->sis_tag, dp->sis_map);
2224139805Sphk		bus_dmamap_destroy(sc->sis_tag, dp->sis_map);
2225139805Sphk		m_freem(dp->sis_mbuf);
2226139805Sphk		dp->sis_mbuf = NULL;
222750974Swpaul	}
2228139805Sphk	bzero(sc->sis_rx_list, SIS_RX_LIST_SZ);
222950974Swpaul
223050974Swpaul	/*
223150974Swpaul	 * Free the TX list buffers.
223250974Swpaul	 */
2233139805Sphk	dp = &sc->sis_tx_list[0];
2234139805Sphk	for (i = 0; i < SIS_TX_LIST_CNT; i++, dp++) {
2235139805Sphk		if (dp->sis_mbuf == NULL)
2236139805Sphk			continue;
2237139805Sphk		bus_dmamap_unload(sc->sis_tag, dp->sis_map);
2238139805Sphk		bus_dmamap_destroy(sc->sis_tag, dp->sis_map);
2239139805Sphk		m_freem(dp->sis_mbuf);
2240139805Sphk		dp->sis_mbuf = NULL;
224150974Swpaul	}
224250974Swpaul
2243139805Sphk	bzero(sc->sis_tx_list, SIS_TX_LIST_SZ);
224450974Swpaul
2245123833Sphk	sc->sis_stopped = 1;
224650974Swpaul}
224750974Swpaul
224850974Swpaul/*
224950974Swpaul * Stop all chip I/O so that the kernel's probe routines don't
225050974Swpaul * get confused by errant DMAs when rebooting.
225150974Swpaul */
2252102334Salfredstatic void
2253139717Sphksis_shutdown(device_t dev)
225450974Swpaul{
225550974Swpaul	struct sis_softc	*sc;
225650974Swpaul
225750974Swpaul	sc = device_get_softc(dev);
225867087Swpaul	SIS_LOCK(sc);
225950974Swpaul	sis_reset(sc);
226050974Swpaul	sis_stop(sc);
226167087Swpaul	SIS_UNLOCK(sc);
226250974Swpaul}
2263139800Sphk
2264139800Sphkstatic device_method_t sis_methods[] = {
2265139800Sphk	/* Device interface */
2266139800Sphk	DEVMETHOD(device_probe,		sis_probe),
2267139800Sphk	DEVMETHOD(device_attach,	sis_attach),
2268139800Sphk	DEVMETHOD(device_detach,	sis_detach),
2269139800Sphk	DEVMETHOD(device_shutdown,	sis_shutdown),
2270139800Sphk
2271139800Sphk	/* bus interface */
2272139800Sphk	DEVMETHOD(bus_print_child,	bus_generic_print_child),
2273139800Sphk	DEVMETHOD(bus_driver_added,	bus_generic_driver_added),
2274139800Sphk
2275139800Sphk	/* MII interface */
2276139800Sphk	DEVMETHOD(miibus_readreg,	sis_miibus_readreg),
2277139800Sphk	DEVMETHOD(miibus_writereg,	sis_miibus_writereg),
2278139800Sphk	DEVMETHOD(miibus_statchg,	sis_miibus_statchg),
2279139800Sphk
2280139800Sphk	{ 0, 0 }
2281139800Sphk};
2282139800Sphk
2283139800Sphkstatic driver_t sis_driver = {
2284139800Sphk	"sis",
2285139800Sphk	sis_methods,
2286139800Sphk	sizeof(struct sis_softc)
2287139800Sphk};
2288139800Sphk
2289139800Sphkstatic devclass_t sis_devclass;
2290139800Sphk
2291139800SphkDRIVER_MODULE(sis, pci, sis_driver, sis_devclass, 0, 0);
2292139800SphkDRIVER_MODULE(miibus, sis, miibus_driver, miibus_devclass, 0, 0);
2293