xref: /onnv-gate/usr/src/uts/common/io/sfe/sfe.c (revision 7116:d3fc64db3280)
15748Sduboff /*
25748Sduboff  *  sfe.c : DP83815/DP83816/SiS900 Fast Ethernet MAC driver for Solaris
35748Sduboff  *
4*7116Sduboff  * Copyright (c) 2002-2008 Masayuki Murayama.  All rights reserved.
55748Sduboff  *
65748Sduboff  * Redistribution and use in source and binary forms, with or without
75748Sduboff  * modification, are permitted provided that the following conditions are met:
85748Sduboff  *
95748Sduboff  * 1. Redistributions of source code must retain the above copyright notice,
105748Sduboff  *    this list of conditions and the following disclaimer.
115748Sduboff  *
125748Sduboff  * 2. Redistributions in binary form must reproduce the above copyright notice,
135748Sduboff  *    this list of conditions and the following disclaimer in the documentation
145748Sduboff  *    and/or other materials provided with the distribution.
155748Sduboff  *
165748Sduboff  * 3. Neither the name of the author nor the names of its contributors may be
175748Sduboff  *    used to endorse or promote products derived from this software without
185748Sduboff  *    specific prior written permission.
195748Sduboff  *
205748Sduboff  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
215748Sduboff  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
225748Sduboff  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
235748Sduboff  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
245748Sduboff  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
255748Sduboff  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
265748Sduboff  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
275748Sduboff  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
285748Sduboff  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
295748Sduboff  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
305748Sduboff  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
315748Sduboff  * DAMAGE.
325748Sduboff  */
335748Sduboff 
345748Sduboff #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* sfe device driver */
355748Sduboff 
365748Sduboff /*
375748Sduboff  * System Header files.
385748Sduboff  */
395748Sduboff #include <sys/types.h>
405748Sduboff #include <sys/conf.h>
415748Sduboff #include <sys/debug.h>
425748Sduboff #include <sys/kmem.h>
435748Sduboff #include <sys/modctl.h>
445748Sduboff #include <sys/errno.h>
455748Sduboff #include <sys/ddi.h>
465748Sduboff #include <sys/sunddi.h>
475748Sduboff #include <sys/byteorder.h>
485748Sduboff #include <sys/ethernet.h>
495748Sduboff #include <sys/pci.h>
505748Sduboff 
515748Sduboff #include "sfe_mii.h"
525748Sduboff #include "sfe_util.h"
535748Sduboff #include "sfereg.h"
545748Sduboff 
55*7116Sduboff char	ident[] = "sis900/dp83815 driver v" "2.6.1t27os";
565748Sduboff 
575748Sduboff /* Debugging support */
585748Sduboff #ifdef DEBUG_LEVEL
595748Sduboff static int sfe_debug = DEBUG_LEVEL;
605748Sduboff #if DEBUG_LEVEL > 4
615748Sduboff #define	CONS	"^"
625748Sduboff #else
635748Sduboff #define	CONS	"!"
645748Sduboff #endif
655748Sduboff #define	DPRINTF(n, args)	if (sfe_debug > (n)) cmn_err args
665748Sduboff #else
675748Sduboff #define	CONS	"!"
685748Sduboff #define	DPRINTF(n, args)
695748Sduboff #endif
705748Sduboff 
715748Sduboff /*
725748Sduboff  * Useful macros and typedefs
735748Sduboff  */
745748Sduboff #define	ONESEC		(drv_usectohz(1*1000000))
755748Sduboff #define	ROUNDUP2(x, a)	(((x) + (a) - 1) & ~((a) - 1))
765748Sduboff 
775748Sduboff /*
785748Sduboff  * Our configuration
795748Sduboff  */
805748Sduboff #define	MAXTXFRAGS	1
815748Sduboff #define	MAXRXFRAGS	1
825748Sduboff 
835748Sduboff #ifndef	TX_BUF_SIZE
845748Sduboff #define	TX_BUF_SIZE	64
855748Sduboff #endif
865748Sduboff #ifndef	TX_RING_SIZE
875748Sduboff #if MAXTXFRAGS == 1
885748Sduboff #define	TX_RING_SIZE	TX_BUF_SIZE
895748Sduboff #else
905748Sduboff #define	TX_RING_SIZE	(TX_BUF_SIZE * 4)
915748Sduboff #endif
925748Sduboff #endif
935748Sduboff 
945748Sduboff #ifndef	RX_BUF_SIZE
955748Sduboff #define	RX_BUF_SIZE	256
965748Sduboff #endif
975748Sduboff #ifndef	RX_RING_SIZE
985748Sduboff #define	RX_RING_SIZE	RX_BUF_SIZE
995748Sduboff #endif
1005748Sduboff 
1015748Sduboff #define	OUR_INTR_BITS	\
1025748Sduboff 	(ISR_DPERR | ISR_SSERR | ISR_RMABT | ISR_RTABT | ISR_RXSOVR |	\
1035748Sduboff 	ISR_TXURN | ISR_TXDESC | ISR_TXERR |	\
1045748Sduboff 	ISR_RXORN | ISR_RXIDLE | ISR_RXOK | ISR_RXERR)
1055748Sduboff 
1065748Sduboff #define	USE_MULTICAST_HASHTBL
1075748Sduboff 
1085748Sduboff static int	sfe_tx_copy_thresh = 256;
1095748Sduboff static int	sfe_rx_copy_thresh = 256;
1105748Sduboff 
1115748Sduboff /* special PHY registers for SIS900 */
1125748Sduboff #define	MII_CONFIG1	0x0010
1135748Sduboff #define	MII_CONFIG2	0x0011
1145748Sduboff #define	MII_MASK	0x0013
1155748Sduboff #define	MII_RESV	0x0014
1165748Sduboff 
1175748Sduboff #define	PHY_MASK		0xfffffff0
1185748Sduboff #define	PHY_SIS900_INTERNAL	0x001d8000
1195748Sduboff #define	PHY_ICS1893		0x0015f440
1205748Sduboff 
1215748Sduboff 
1225748Sduboff #define	SFE_DESC_SIZE	16	/* including pads rounding up to power of 2 */
1235748Sduboff 
1245748Sduboff /*
1255748Sduboff  * Supported chips
1265748Sduboff  */
1275748Sduboff struct chip_info {
1285748Sduboff 	uint16_t	venid;
1295748Sduboff 	uint16_t	devid;
1305748Sduboff 	char		*chip_name;
1315748Sduboff 	int		chip_type;
1325748Sduboff #define	CHIPTYPE_DP83815	0
1335748Sduboff #define	CHIPTYPE_SIS900		1
1345748Sduboff };
1355748Sduboff 
1365748Sduboff /*
1375748Sduboff  * Chip dependent MAC state
1385748Sduboff  */
1395748Sduboff struct sfe_dev {
1405748Sduboff 	/* misc HW information */
1415748Sduboff 	struct chip_info	*chip;
1425748Sduboff 	uint32_t		our_intr_bits;
143*7116Sduboff 	uint32_t		isr_pended;
1445748Sduboff 	uint32_t		cr;
1455748Sduboff 	uint_t			tx_drain_threshold;
1465748Sduboff 	uint_t			tx_fill_threshold;
1475748Sduboff 	uint_t			rx_drain_threshold;
1485748Sduboff 	uint_t			rx_fill_threshold;
1495748Sduboff 	uint8_t			revid;	/* revision from PCI configuration */
1505748Sduboff 	boolean_t		(*get_mac_addr)(struct gem_dev *);
1515748Sduboff 	uint8_t			mac_addr[ETHERADDRL];
1525748Sduboff 	uint8_t			bridge_revid;
1535748Sduboff };
1545748Sduboff 
1555748Sduboff /*
1565748Sduboff  * Hardware information
1575748Sduboff  */
1585748Sduboff struct chip_info sfe_chiptbl[] = {
1595748Sduboff 	{ 0x1039, 0x0900, "SiS900", CHIPTYPE_SIS900, },
1605748Sduboff 	{ 0x100b, 0x0020, "DP83815/83816", CHIPTYPE_DP83815, },
1615748Sduboff 	{ 0x1039, 0x7016, "SiS7016", CHIPTYPE_SIS900, },
1625748Sduboff };
1635748Sduboff #define	CHIPTABLESIZE (sizeof (sfe_chiptbl)/sizeof (struct chip_info))
1645748Sduboff 
1655748Sduboff /* ======================================================== */
1665748Sduboff 
1675748Sduboff /* mii operations */
1685748Sduboff static void  sfe_mii_sync_dp83815(struct gem_dev *);
1695748Sduboff static void  sfe_mii_sync_sis900(struct gem_dev *);
1705748Sduboff static uint16_t  sfe_mii_read_dp83815(struct gem_dev *, uint_t);
1715748Sduboff static uint16_t  sfe_mii_read_sis900(struct gem_dev *, uint_t);
1725748Sduboff static void sfe_mii_write_dp83815(struct gem_dev *, uint_t, uint16_t);
1735748Sduboff static void sfe_mii_write_sis900(struct gem_dev *, uint_t, uint16_t);
1745748Sduboff static void sfe_set_eq_sis630(struct gem_dev *dp);
1755748Sduboff /* nic operations */
1765748Sduboff static int sfe_reset_chip_sis900(struct gem_dev *);
1775748Sduboff static int sfe_reset_chip_dp83815(struct gem_dev *);
1785748Sduboff static int sfe_init_chip(struct gem_dev *);
1795748Sduboff static int sfe_start_chip(struct gem_dev *);
1805748Sduboff static int sfe_stop_chip(struct gem_dev *);
1815748Sduboff static int sfe_set_media(struct gem_dev *);
1825748Sduboff static int sfe_set_rx_filter_dp83815(struct gem_dev *);
1835748Sduboff static int sfe_set_rx_filter_sis900(struct gem_dev *);
1845748Sduboff static int sfe_get_stats(struct gem_dev *);
1855748Sduboff static int sfe_attach_chip(struct gem_dev *);
1865748Sduboff 
1875748Sduboff /* descriptor operations */
1885748Sduboff static int sfe_tx_desc_write(struct gem_dev *dp, int slot,
1895748Sduboff 		    ddi_dma_cookie_t *dmacookie, int frags, uint64_t flags);
1905748Sduboff static void sfe_tx_start(struct gem_dev *dp, int startslot, int nslot);
1915748Sduboff static void sfe_rx_desc_write(struct gem_dev *dp, int slot,
1925748Sduboff 		    ddi_dma_cookie_t *dmacookie, int frags);
1935748Sduboff static uint_t sfe_tx_desc_stat(struct gem_dev *dp, int slot, int ndesc);
1945748Sduboff static uint64_t sfe_rx_desc_stat(struct gem_dev *dp, int slot, int ndesc);
1955748Sduboff 
1965748Sduboff static void sfe_tx_desc_init(struct gem_dev *dp, int slot);
1975748Sduboff static void sfe_rx_desc_init(struct gem_dev *dp, int slot);
1985748Sduboff static void sfe_tx_desc_clean(struct gem_dev *dp, int slot);
1995748Sduboff static void sfe_rx_desc_clean(struct gem_dev *dp, int slot);
2005748Sduboff 
2015748Sduboff /* interrupt handler */
2025748Sduboff static uint_t sfe_interrupt(struct gem_dev *dp);
2035748Sduboff 
2045748Sduboff /* ======================================================== */
2055748Sduboff 
2065748Sduboff /* mapping attributes */
2075748Sduboff /* Data access requirements. */
2085748Sduboff static struct ddi_device_acc_attr sfe_dev_attr = {
2095748Sduboff 	DDI_DEVICE_ATTR_V0,
2105748Sduboff 	DDI_STRUCTURE_LE_ACC,
2115748Sduboff 	DDI_STRICTORDER_ACC
2125748Sduboff };
2135748Sduboff 
2145748Sduboff /* On sparc, Buffers should be native endian for speed */
2155748Sduboff static struct ddi_device_acc_attr sfe_buf_attr = {
2165748Sduboff 	DDI_DEVICE_ATTR_V0,
2175748Sduboff 	DDI_NEVERSWAP_ACC,	/* native endianness */
2185748Sduboff 	DDI_STRICTORDER_ACC
2195748Sduboff };
2205748Sduboff 
2215748Sduboff static ddi_dma_attr_t sfe_dma_attr_buf = {
2225748Sduboff 	DMA_ATTR_V0,		/* dma_attr_version */
2235748Sduboff 	0,			/* dma_attr_addr_lo */
2245748Sduboff 	0xffffffffull,		/* dma_attr_addr_hi */
2255748Sduboff 	0x00000fffull,		/* dma_attr_count_max */
2265748Sduboff 	0, /* patched later */	/* dma_attr_align */
2275748Sduboff 	0x000003fc,		/* dma_attr_burstsizes */
2285748Sduboff 	1,			/* dma_attr_minxfer */
2295748Sduboff 	0x00000fffull,		/* dma_attr_maxxfer */
2305748Sduboff 	0xffffffffull,		/* dma_attr_seg */
2315748Sduboff 	0, /* patched later */	/* dma_attr_sgllen */
2325748Sduboff 	1,			/* dma_attr_granular */
2335748Sduboff 	0			/* dma_attr_flags */
2345748Sduboff };
2355748Sduboff 
2365748Sduboff static ddi_dma_attr_t sfe_dma_attr_desc = {
2375748Sduboff 	DMA_ATTR_V0,		/* dma_attr_version */
2385748Sduboff 	16,			/* dma_attr_addr_lo */
2395748Sduboff 	0xffffffffull,		/* dma_attr_addr_hi */
2405748Sduboff 	0xffffffffull,		/* dma_attr_count_max */
2415748Sduboff 	16,			/* dma_attr_align */
2425748Sduboff 	0x000003fc,		/* dma_attr_burstsizes */
2435748Sduboff 	1,			/* dma_attr_minxfer */
2445748Sduboff 	0xffffffffull,		/* dma_attr_maxxfer */
2455748Sduboff 	0xffffffffull,		/* dma_attr_seg */
2465748Sduboff 	1,			/* dma_attr_sgllen */
2475748Sduboff 	1,			/* dma_attr_granular */
2485748Sduboff 	0			/* dma_attr_flags */
2495748Sduboff };
2505748Sduboff 
2515748Sduboff uint32_t sfe_use_pcimemspace = 0;
2525748Sduboff 
2535748Sduboff /* ======================================================== */
2545748Sduboff /*
2555748Sduboff  * HW manipulation routines
2565748Sduboff  */
2575748Sduboff /* ======================================================== */
2585748Sduboff 
2595748Sduboff #define	SFE_EEPROM_DELAY(dp)	\
2605748Sduboff 	{ (void) INL(dp, EROMAR); (void) INL(dp, EROMAR); }
2615748Sduboff #define	EE_CMD_READ	6
2625748Sduboff #define	EE_CMD_SHIFT	6
2635748Sduboff 
2645748Sduboff static uint16_t
2655748Sduboff sfe_read_eeprom(struct gem_dev *dp, uint_t offset)
2665748Sduboff {
2675748Sduboff 	int		eedi;
2685748Sduboff 	int		i;
2695748Sduboff 	uint16_t	ret;
2705748Sduboff 
2715748Sduboff 	/* ensure de-assert chip select */
2725748Sduboff 	OUTL(dp, EROMAR, 0);
2735748Sduboff 	SFE_EEPROM_DELAY(dp);
2745748Sduboff 	OUTL(dp, EROMAR, EROMAR_EESK);
2755748Sduboff 	SFE_EEPROM_DELAY(dp);
2765748Sduboff 
2775748Sduboff 	/* assert chip select */
2785748Sduboff 	offset |= EE_CMD_READ << EE_CMD_SHIFT;
2795748Sduboff 
2805748Sduboff 	for (i = 8; i >= 0; i--) {
2815748Sduboff 		/* make command */
2825748Sduboff 		eedi = ((offset >> i) & 1) << EROMAR_EEDI_SHIFT;
2835748Sduboff 
2845748Sduboff 		/* send 1 bit */
2855748Sduboff 		OUTL(dp, EROMAR, EROMAR_EECS | eedi);
2865748Sduboff 		SFE_EEPROM_DELAY(dp);
2875748Sduboff 		OUTL(dp, EROMAR, EROMAR_EECS | eedi | EROMAR_EESK);
2885748Sduboff 		SFE_EEPROM_DELAY(dp);
2895748Sduboff 	}
2905748Sduboff 
2915748Sduboff 	OUTL(dp, EROMAR, EROMAR_EECS);
2925748Sduboff 
2935748Sduboff 	ret = 0;
2945748Sduboff 	for (i = 0; i < 16; i++) {
2955748Sduboff 		/* Get 1 bit */
2965748Sduboff 		OUTL(dp, EROMAR, EROMAR_EECS);
2975748Sduboff 		SFE_EEPROM_DELAY(dp);
2985748Sduboff 		OUTL(dp, EROMAR, EROMAR_EECS | EROMAR_EESK);
2995748Sduboff 		SFE_EEPROM_DELAY(dp);
3005748Sduboff 
3015748Sduboff 		ret = (ret << 1) | ((INL(dp, EROMAR) >> EROMAR_EEDO_SHIFT) & 1);
3025748Sduboff 	}
3035748Sduboff 
3045748Sduboff 	OUTL(dp, EROMAR, 0);
3055748Sduboff 	SFE_EEPROM_DELAY(dp);
3065748Sduboff 
3075748Sduboff 	return (ret);
3085748Sduboff }
3095748Sduboff #undef SFE_EEPROM_DELAY
3105748Sduboff 
3115748Sduboff static boolean_t
3125748Sduboff sfe_get_mac_addr_dp83815(struct gem_dev *dp)
3135748Sduboff {
3145748Sduboff 	uint8_t		*mac;
3155748Sduboff 	uint_t		val;
3165748Sduboff 	int		i;
3175748Sduboff 
3185748Sduboff #define	BITSET(p, ix, v)	(p)[(ix)/8] |= ((v) ? 1 : 0) << ((ix) & 0x7)
3195748Sduboff 
3205748Sduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__));
3215748Sduboff 
3225748Sduboff 	mac = dp->dev_addr.ether_addr_octet;
3235748Sduboff 
3245748Sduboff 	/* first of all, clear MAC address buffer */
3255748Sduboff 	bzero(mac, ETHERADDRL);
3265748Sduboff 
3275748Sduboff 	/* get bit 0 */
3285748Sduboff 	val = sfe_read_eeprom(dp, 0x6);
3295748Sduboff 	BITSET(mac, 0, val & 1);
3305748Sduboff 
3315748Sduboff 	/* get bit 1 - 16 */
3325748Sduboff 	val = sfe_read_eeprom(dp, 0x7);
3335748Sduboff 	for (i = 0; i < 16; i++) {
3345748Sduboff 		BITSET(mac, 1 + i, val & (1 << (15 - i)));
3355748Sduboff 	}
3365748Sduboff 
3375748Sduboff 	/* get bit 17 -  32 */
3385748Sduboff 	val = sfe_read_eeprom(dp, 0x8);
3395748Sduboff 	for (i = 0; i < 16; i++) {
3405748Sduboff 		BITSET(mac, 17 + i, val & (1 << (15 - i)));
3415748Sduboff 	}
3425748Sduboff 
3435748Sduboff 	/* get bit 33 -  47 */
3445748Sduboff 	val = sfe_read_eeprom(dp, 0x9);
3455748Sduboff 	for (i = 0; i < 15; i++) {
3465748Sduboff 		BITSET(mac, 33 + i, val & (1 << (15 - i)));
3475748Sduboff 	}
3485748Sduboff 
3495748Sduboff 	return (B_TRUE);
3505748Sduboff #undef BITSET
3515748Sduboff }
3525748Sduboff 
3535748Sduboff static boolean_t
3545748Sduboff sfe_get_mac_addr_sis900(struct gem_dev *dp)
3555748Sduboff {
3565748Sduboff 	uint_t		val;
3575748Sduboff 	int		i;
3585748Sduboff 	uint8_t		*mac;
3595748Sduboff 
3605748Sduboff 	mac = dp->dev_addr.ether_addr_octet;
3615748Sduboff 
3625748Sduboff 	for (i = 0; i < ETHERADDRL/2; i++) {
3635748Sduboff 		val = sfe_read_eeprom(dp, 0x8 + i);
3645748Sduboff 		*mac++ = (uint8_t)val;
3655748Sduboff 		*mac++ = (uint8_t)(val >> 8);
3665748Sduboff 	}
3675748Sduboff 
3685748Sduboff 	return (B_TRUE);
3695748Sduboff }
3705748Sduboff 
3715748Sduboff static dev_info_t *
3725748Sduboff sfe_search_pci_dev_subr(dev_info_t *cur_node, int vendor_id, int device_id)
3735748Sduboff {
3745748Sduboff 	dev_info_t	*child_id;
3755748Sduboff 	dev_info_t	*ret;
3765748Sduboff 	int		vid, did;
3775748Sduboff 
3785748Sduboff 	if (cur_node == NULL) {
3795748Sduboff 		return (NULL);
3805748Sduboff 	}
3815748Sduboff 
3825748Sduboff 	/* check brothers */
3835748Sduboff 	do {
3845748Sduboff 		vid = ddi_prop_get_int(DDI_DEV_T_ANY, cur_node,
3855748Sduboff 		    DDI_PROP_DONTPASS, "vendor-id", -1);
3865748Sduboff 		did = ddi_prop_get_int(DDI_DEV_T_ANY, cur_node,
3875748Sduboff 		    DDI_PROP_DONTPASS, "device-id", -1);
3885748Sduboff 
3895748Sduboff 		if (vid == vendor_id && did == device_id) {
3905748Sduboff 			/* found */
3915748Sduboff 			return (cur_node);
3925748Sduboff 		}
3935748Sduboff 
3945748Sduboff 		/* check children */
3955748Sduboff 		if ((child_id = ddi_get_child(cur_node)) != NULL) {
3965748Sduboff 			if ((ret = sfe_search_pci_dev_subr(child_id,
3975748Sduboff 			    vendor_id, device_id)) != NULL) {
3985748Sduboff 				return (ret);
3995748Sduboff 			}
4005748Sduboff 		}
4015748Sduboff 
4025748Sduboff 	} while ((cur_node = ddi_get_next_sibling(cur_node)) != NULL);
4035748Sduboff 
4045748Sduboff 	/* not found */
4055748Sduboff 	return (NULL);
4065748Sduboff }
4075748Sduboff 
4085748Sduboff static dev_info_t *
4095748Sduboff sfe_search_pci_dev(int vendor_id, int device_id)
4105748Sduboff {
4115748Sduboff 	return (sfe_search_pci_dev_subr(ddi_root_node(), vendor_id, device_id));
4125748Sduboff }
4135748Sduboff 
4145748Sduboff /* Avoid undefined symbol for non IA architectures */
4155748Sduboff #pragma weak	inb
4165748Sduboff #pragma weak	outb
4175748Sduboff 
4185748Sduboff static boolean_t
4195748Sduboff sfe_get_mac_addr_sis630e(struct gem_dev *dp)
4205748Sduboff {
4215748Sduboff 	int		i;
4225748Sduboff 	dev_info_t	*isa_bridge;
4235748Sduboff 	ddi_acc_handle_t isa_handle;
4245748Sduboff 	int		reg;
4255748Sduboff 
4265748Sduboff 	if (inb == NULL || outb == NULL) {
4275748Sduboff 		/* this is not IA architecture */
4285748Sduboff 		return (B_FALSE);
4295748Sduboff 	}
4305748Sduboff 
4315748Sduboff 	if ((isa_bridge = sfe_search_pci_dev(0x1039, 0x8)) == NULL) {
4325748Sduboff 		cmn_err(CE_WARN, "%s: failed to find isa-bridge pci1039,8",
4335748Sduboff 		    dp->name);
4345748Sduboff 		return (B_FALSE);
4355748Sduboff 	}
4365748Sduboff 
4375748Sduboff 	if (pci_config_setup(isa_bridge, &isa_handle) != DDI_SUCCESS) {
4385748Sduboff 		cmn_err(CE_WARN, "%s: ddi_regs_map_setup failed",
4395748Sduboff 		    dp->name);
4405748Sduboff 		return (B_FALSE);
4415748Sduboff 	}
4425748Sduboff 
4435748Sduboff 	/* enable to access CMOS RAM */
4445748Sduboff 	reg = pci_config_get8(isa_handle, 0x48);
4455748Sduboff 	pci_config_put8(isa_handle, 0x48, reg | 0x40);
4465748Sduboff 
4475748Sduboff 	for (i = 0; i < ETHERADDRL; i++) {
4485748Sduboff 		outb(0x70, 0x09 + i);
4495748Sduboff 		dp->dev_addr.ether_addr_octet[i] = inb(0x71);
4505748Sduboff 	}
4515748Sduboff 
4525748Sduboff 	/* disable to access CMOS RAM */
4535748Sduboff 	pci_config_put8(isa_handle, 0x48, reg);
4545748Sduboff 	pci_config_teardown(&isa_handle);
4555748Sduboff 
4565748Sduboff 	return (B_TRUE);
4575748Sduboff }
4585748Sduboff 
4595748Sduboff static boolean_t
4605748Sduboff sfe_get_mac_addr_sis635(struct gem_dev *dp)
4615748Sduboff {
4625748Sduboff 	int		i;
4635748Sduboff 	uint32_t	rfcr;
4645748Sduboff 	uint16_t	v;
4655748Sduboff 	struct sfe_dev	*lp = dp->private;
4665748Sduboff 
4675748Sduboff 	DPRINTF(2, (CE_CONT, CONS "%s: %s: called", dp->name, __func__));
4685748Sduboff 	rfcr = INL(dp, RFCR);
4695748Sduboff 
4705748Sduboff 	OUTL(dp, CR, lp->cr | CR_RELOAD);
4715748Sduboff 	OUTL(dp, CR, lp->cr);
4725748Sduboff 
4735748Sduboff 	/* disable packet filtering before reading filter */
4745748Sduboff 	OUTL(dp, RFCR, rfcr & ~RFCR_RFEN);
4755748Sduboff 
4765748Sduboff 	/* load MAC addr from filter data register */
4775748Sduboff 	for (i = 0; i < ETHERADDRL; i += 2) {
4785748Sduboff 		OUTL(dp, RFCR,
4795748Sduboff 		    (RFADDR_MAC_SIS900 + (i/2)) << RFCR_RFADDR_SHIFT_SIS900);
4805748Sduboff 		v = INL(dp, RFDR);
4815748Sduboff 		dp->dev_addr.ether_addr_octet[i] = (uint8_t)v;
4825748Sduboff 		dp->dev_addr.ether_addr_octet[i+1] = (uint8_t)(v >> 8);
4835748Sduboff 	}
4845748Sduboff 
4855748Sduboff 	/* re-enable packet filtering */
4865748Sduboff 	OUTL(dp, RFCR, rfcr | RFCR_RFEN);
4875748Sduboff 
4885748Sduboff 	return (B_TRUE);
4895748Sduboff }
4905748Sduboff 
4915748Sduboff static boolean_t
4925748Sduboff sfe_get_mac_addr_sis962(struct gem_dev *dp)
4935748Sduboff {
4945748Sduboff 	boolean_t	ret;
4955748Sduboff 	int		i;
4965748Sduboff 
4975748Sduboff 	ret = B_FALSE;
4985748Sduboff 
4995748Sduboff 	/* rise request signal to access EEPROM */
5005748Sduboff 	OUTL(dp, MEAR, EROMAR_EEREQ);
5015748Sduboff 	for (i = 0; (INL(dp, MEAR) & EROMAR_EEGNT) == 0; i++) {
5025748Sduboff 		if (i > 200) {
5035748Sduboff 			/* failed to acquire eeprom */
5045748Sduboff 			cmn_err(CE_NOTE,
5055748Sduboff 			    CONS "%s: failed to access eeprom", dp->name);
5065748Sduboff 			goto x;
5075748Sduboff 		}
5085748Sduboff 		drv_usecwait(10);
5095748Sduboff 	}
5105748Sduboff 	ret = sfe_get_mac_addr_sis900(dp);
5115748Sduboff x:
5125748Sduboff 	/* release EEPROM */
5135748Sduboff 	OUTL(dp, MEAR, EROMAR_EEDONE);
5145748Sduboff 
5155748Sduboff 	return (ret);
5165748Sduboff }
5175748Sduboff 
5185748Sduboff static int
5195748Sduboff sfe_reset_chip_sis900(struct gem_dev *dp)
5205748Sduboff {
5215748Sduboff 	int		i;
5225748Sduboff 	uint32_t	done;
5235748Sduboff 	uint32_t	val;
5245748Sduboff 	struct sfe_dev	*lp = dp->private;
5255748Sduboff 
5265748Sduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s called", dp->name, __func__));
5275748Sduboff 
5285748Sduboff 	/* invalidate mac addr cache */
5295748Sduboff 	bzero(lp->mac_addr, sizeof (lp->mac_addr));
5305748Sduboff 
5315748Sduboff 	lp->cr = 0;
5325748Sduboff 
5335748Sduboff 	/* inhibit interrupt */
5345748Sduboff 	OUTL(dp, IMR, 0);
535*7116Sduboff 	lp->isr_pended |= INL(dp, ISR) & lp->our_intr_bits;
5365748Sduboff 
5375748Sduboff 	OUTL(dp, RFCR, 0);
5385748Sduboff 
5395748Sduboff 	OUTL(dp, CR, CR_RST | CR_TXR | CR_RXR);
5405748Sduboff 	drv_usecwait(10);
5415748Sduboff 
5425748Sduboff 	done = 0;
5435748Sduboff 	for (i = 0; done != (ISR_TXRCMP | ISR_RXRCMP); i++) {
5445748Sduboff 		if (i > 1000) {
5455748Sduboff 			cmn_err(CE_WARN, "%s: chip reset timeout", dp->name);
5465748Sduboff 			return (GEM_FAILURE);
5475748Sduboff 		}
5485748Sduboff 		done |= INL(dp, ISR) & (ISR_TXRCMP | ISR_RXRCMP);
5495748Sduboff 		drv_usecwait(10);
5505748Sduboff 	}
5515748Sduboff 
5525748Sduboff 	if (lp->revid == SIS630ET_900_REV) {
5535748Sduboff 		lp->cr |= CR_ACCESSMODE;
5545748Sduboff 		OUTL(dp, CR, lp->cr | INL(dp, CR));
5555748Sduboff 	}
5565748Sduboff 
5575748Sduboff 	/* Configuration register: enable PCI parity */
5585748Sduboff 	DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b",
5595748Sduboff 	    dp->name, INL(dp, CFG), CFG_BITS_SIS900));
560*7116Sduboff 	val = 0;
5615748Sduboff 	if (lp->revid >= SIS635A_900_REV ||
5625748Sduboff 	    lp->revid == SIS900B_900_REV) {
5635748Sduboff 		/* what is this ? */
5645748Sduboff 		val |= CFG_RND_CNT;
5655748Sduboff 	}
5665748Sduboff 	OUTL(dp, CFG, val);
5675748Sduboff 	DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b", dp->name,
5685748Sduboff 	    INL(dp, CFG), CFG_BITS_SIS900));
5695748Sduboff 
5705748Sduboff 	return (GEM_SUCCESS);
5715748Sduboff }
5725748Sduboff 
5735748Sduboff static int
5745748Sduboff sfe_reset_chip_dp83815(struct gem_dev *dp)
5755748Sduboff {
5765748Sduboff 	int		i;
577*7116Sduboff 	uint32_t	val;
5785748Sduboff 	struct sfe_dev	*lp = dp->private;
5795748Sduboff 
5805748Sduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s called", dp->name, __func__));
5815748Sduboff 
5825748Sduboff 	/* invalidate mac addr cache */
5835748Sduboff 	bzero(lp->mac_addr, sizeof (lp->mac_addr));
5845748Sduboff 
5855748Sduboff 	lp->cr = 0;
5865748Sduboff 
5875748Sduboff 	/* inhibit interrupts */
5885748Sduboff 	OUTL(dp, IMR, 0);
589*7116Sduboff 	lp->isr_pended |= INL(dp, ISR) & lp->our_intr_bits;
5905748Sduboff 
5915748Sduboff 	OUTL(dp, RFCR, 0);
5925748Sduboff 
5935748Sduboff 	OUTL(dp, CR, CR_RST);
5945748Sduboff 	drv_usecwait(10);
5955748Sduboff 
5965748Sduboff 	for (i = 0; INL(dp, CR) & CR_RST; i++) {
5975748Sduboff 		if (i > 100) {
5985748Sduboff 			cmn_err(CE_WARN, "!%s: chip reset timeout", dp->name);
5995748Sduboff 			return (GEM_FAILURE);
6005748Sduboff 		}
6015748Sduboff 		drv_usecwait(10);
6025748Sduboff 	}
6035748Sduboff 	DPRINTF(0, (CE_CONT, "!%s: chip reset in %duS", dp->name, i*10));
6045748Sduboff 
6055748Sduboff 	OUTL(dp, CCSR, CCSR_PMESTS);
6065748Sduboff 	OUTL(dp, CCSR, 0);
6075748Sduboff 
6085748Sduboff 	/* Configuration register: enable PCI parity */
6095748Sduboff 	DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b",
6105748Sduboff 	    dp->name, INL(dp, CFG), CFG_BITS_DP83815));
611*7116Sduboff 	val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG);
612*7116Sduboff 	OUTL(dp, CFG, val | CFG_PAUSE_ADV);
6135748Sduboff 	DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b", dp->name,
6145748Sduboff 	    INL(dp, CFG), CFG_BITS_DP83815));
6155748Sduboff 
6165748Sduboff 	return (GEM_SUCCESS);
6175748Sduboff }
6185748Sduboff 
6195748Sduboff static int
6205748Sduboff sfe_init_chip(struct gem_dev *dp)
6215748Sduboff {
6225748Sduboff 	/* Configuration register: have been set up in sfe_chip_reset */
6235748Sduboff 
6245748Sduboff 	/* PCI test control register: do nothing */
6255748Sduboff 
6265748Sduboff 	/* Interrupt status register : do nothing */
6275748Sduboff 
6285748Sduboff 	/* Interrupt mask register: clear, but leave lp->our_intr_bits */
6295748Sduboff 	OUTL(dp, IMR, 0);
6305748Sduboff 
6315748Sduboff 	/* Enhanced PHY Access register (sis900): do nothing */
6325748Sduboff 
6335748Sduboff 	/* Transmit Descriptor Pointer register: base addr of TX ring */
6345748Sduboff 	OUTL(dp, TXDP, dp->tx_ring_dma);
6355748Sduboff 
6365748Sduboff 	/* Receive descriptor pointer register: base addr of RX ring */
6375748Sduboff 	OUTL(dp, RXDP, dp->rx_ring_dma);
6385748Sduboff 
6395748Sduboff 	return (GEM_SUCCESS);
6405748Sduboff }
6415748Sduboff 
6425748Sduboff static uint_t
6435748Sduboff sfe_mcast_hash(struct gem_dev *dp, uint8_t *addr)
6445748Sduboff {
6455748Sduboff 	return (gem_ether_crc_be(addr, ETHERADDRL));
6465748Sduboff }
6475748Sduboff 
6485748Sduboff #ifdef DEBUG_LEVEL
6495748Sduboff static void
6505748Sduboff sfe_rxfilter_dump(struct gem_dev *dp, int start, int end)
6515748Sduboff {
6525748Sduboff 	int		i;
6535748Sduboff 	int		j;
6545748Sduboff 	uint16_t	ram[0x10];
6555748Sduboff 
6565748Sduboff 	cmn_err(CE_CONT, "!%s: rx filter ram dump:", dp->name);
6575748Sduboff #define	WORDS_PER_LINE	4
6585748Sduboff 	for (i = start; i < end; i += WORDS_PER_LINE*2) {
6595748Sduboff 		for (j = 0; j < WORDS_PER_LINE; j++) {
6605748Sduboff 			OUTL(dp, RFCR, RFADDR_MAC_DP83815 + i + j*2);
6615748Sduboff 			ram[j] = INL(dp, RFDR);
6625748Sduboff 		}
6635748Sduboff 
6645748Sduboff 		cmn_err(CE_CONT, "!0x%02x: 0x%04x 0x%04x 0x%04x 0x%04x",
6655748Sduboff 		    i, ram[0], ram[1], ram[2], ram[3]);
6665748Sduboff 		}
6675748Sduboff 
6685748Sduboff #undef	WORDS_PER_LINE
6695748Sduboff }
6705748Sduboff #endif
6715748Sduboff 
6725748Sduboff static uint_t	sfe_rf_perfect_base_dp83815[] = {
6735748Sduboff 	RFADDR_PMATCH0_DP83815,
6745748Sduboff 	RFADDR_PMATCH1_DP83815,
6755748Sduboff 	RFADDR_PMATCH2_DP83815,
6765748Sduboff 	RFADDR_PMATCH3_DP83815,
6775748Sduboff };
6785748Sduboff 
6795748Sduboff static int
6805748Sduboff sfe_set_rx_filter_dp83815(struct gem_dev *dp)
6815748Sduboff {
6825748Sduboff 	int		i;
6835748Sduboff 	int		j;
6845748Sduboff 	uint32_t	mode;
6855748Sduboff 	uint8_t		*mac = dp->cur_addr.ether_addr_octet;
6865748Sduboff 	uint16_t	hash_tbl[32];
6875748Sduboff 	struct sfe_dev	*lp = dp->private;
6885748Sduboff 
6895748Sduboff 	DPRINTF(1, (CE_CONT, CONS "%s: %s: called, mc_count:%d, mode:0x%b",
6905748Sduboff 	    dp->name, __func__, dp->mc_count, dp->rxmode, RXMODE_BITS));
6915748Sduboff 
6925748Sduboff #if DEBUG_LEVEL > 0
6935748Sduboff 	for (i = 0; i < dp->mc_count; i++) {
6945748Sduboff 		cmn_err(CE_CONT,
6955748Sduboff 		"!%s: adding mcast(%d) %02x:%02x:%02x:%02x:%02x:%02x",
6965748Sduboff 		    dp->name, i,
6975748Sduboff 		    dp->mc_list[i].addr.ether_addr_octet[0],
6985748Sduboff 		    dp->mc_list[i].addr.ether_addr_octet[1],
6995748Sduboff 		    dp->mc_list[i].addr.ether_addr_octet[2],
7005748Sduboff 		    dp->mc_list[i].addr.ether_addr_octet[3],
7015748Sduboff 		    dp->mc_list[i].addr.ether_addr_octet[4],
7025748Sduboff 		    dp->mc_list[i].addr.ether_addr_octet[5]);
7035748Sduboff 	}
7045748Sduboff #endif
7055748Sduboff 	if ((dp->rxmode & RXMODE_ENABLE) == 0) {
7065748Sduboff 		/* disable rx filter */
7075748Sduboff 		OUTL(dp, RFCR, 0);
7085748Sduboff 		return (GEM_SUCCESS);
7095748Sduboff 	}
7105748Sduboff 
7115748Sduboff 	/*
7125748Sduboff 	 * Set Receive filter control register
7135748Sduboff 	 */
7145748Sduboff 	if (dp->rxmode & RXMODE_PROMISC) {
7155748Sduboff 		/* all broadcast, all multicast, all physical */
7165748Sduboff 		mode = RFCR_AAB | RFCR_AAM | RFCR_AAP;
7175748Sduboff 	} else if ((dp->rxmode & RXMODE_ALLMULTI) || dp->mc_count > 16*32/2) {
7185748Sduboff 		/* all broadcast, all multicast, physical for the chip */
7195748Sduboff 		mode = RFCR_AAB | RFCR_AAM | RFCR_APM_DP83815;
7205748Sduboff 	} else if (dp->mc_count > 4) {
7215748Sduboff 		/*
7225748Sduboff 		 * Use multicast hash table,
7235748Sduboff 		 * accept all broadcast and physical for the chip.
7245748Sduboff 		 */
7255748Sduboff 		mode = RFCR_AAB | RFCR_MHEN_DP83815 | RFCR_APM_DP83815;
7265748Sduboff 
7275748Sduboff 		bzero(hash_tbl, sizeof (hash_tbl));
7285748Sduboff 		for (i = 0; i < dp->mc_count; i++) {
7295748Sduboff 			j = dp->mc_list[i].hash >> (32 - 9);
7305748Sduboff 			hash_tbl[j / 16] |= 1 << (j % 16);
7315748Sduboff 		}
7325748Sduboff 	} else {
7335748Sduboff 		/*
7345748Sduboff 		 * Use pattern mach filter for multicast address,
7355748Sduboff 		 * accept all broadcast and physical for the chip
7365748Sduboff 		 */
7375748Sduboff 		/* need to enable corresponding pattern registers */
7385748Sduboff 		mode = RFCR_AAB | RFCR_APM_DP83815 |
7395748Sduboff 		    (((1 << dp->mc_count) - 1) << RFCR_APAT_SHIFT);
7405748Sduboff 	}
7415748Sduboff 
7425748Sduboff #if DEBUG_LEVEL > 1
7435748Sduboff 	cmn_err(CE_CONT,
7445748Sduboff 	    "!%s: mac %02x:%02x:%02x:%02x:%02x:%02x"
7455748Sduboff 	    "  cache %02x:%02x:%02x:%02x:%02x:%02x",
7465748Sduboff 	    dp->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
7475748Sduboff 	    lp->mac_addr[0], lp->mac_addr[1],
7485748Sduboff 	    lp->mac_addr[2], lp->mac_addr[3],
7495748Sduboff 	    lp->mac_addr[4], lp->mac_addr[5]);
7505748Sduboff #endif
7515748Sduboff 	if (bcmp(mac, lp->mac_addr, ETHERADDRL) != 0) {
7525748Sduboff 		/*
7535748Sduboff 		 * XXX - need to *disable* rx filter to load mac address for
7545748Sduboff 		 * the chip. otherwise, we cannot setup rxfilter correctly.
7555748Sduboff 		 */
7565748Sduboff 		/* setup perfect match register for my station address */
7575748Sduboff 		for (i = 0; i < ETHERADDRL; i += 2) {
7585748Sduboff 			OUTL(dp, RFCR, RFADDR_MAC_DP83815 + i);
7595748Sduboff 			OUTL(dp, RFDR, (mac[i+1] << 8) | mac[i]);
7605748Sduboff 		}
7615748Sduboff 
7625748Sduboff 		bcopy(mac, lp->mac_addr, ETHERADDRL);
7635748Sduboff 	}
7645748Sduboff 
7655748Sduboff #if DEBUG_LEVEL > 3
7665748Sduboff 	/* clear pattern ram */
7675748Sduboff 	for (j = 0x200; j < 0x380; j += 2) {
7685748Sduboff 		OUTL(dp, RFCR, j);
7695748Sduboff 		OUTL(dp, RFDR, 0);
7705748Sduboff 	}
7715748Sduboff #endif
7725748Sduboff 	if (mode & RFCR_APAT_DP83815) {
7735748Sduboff 		/* setup multicast address into pattern match registers */
7745748Sduboff 		for (j = 0; j < dp->mc_count; j++) {
7755748Sduboff 			mac = &dp->mc_list[j].addr.ether_addr_octet[0];
7765748Sduboff 			for (i = 0; i < ETHERADDRL; i += 2) {
7775748Sduboff 				OUTL(dp, RFCR,
7785748Sduboff 				    sfe_rf_perfect_base_dp83815[j] + i*2);
7795748Sduboff 				OUTL(dp, RFDR, (mac[i+1] << 8) | mac[i]);
7805748Sduboff 			}
7815748Sduboff 		}
7825748Sduboff 
7835748Sduboff 		/* setup pattern count registers */
7845748Sduboff 		OUTL(dp, RFCR, RFADDR_PCOUNT01_DP83815);
7855748Sduboff 		OUTL(dp, RFDR, (ETHERADDRL << 8) | ETHERADDRL);
7865748Sduboff 		OUTL(dp, RFCR, RFADDR_PCOUNT23_DP83815);
7875748Sduboff 		OUTL(dp, RFDR, (ETHERADDRL << 8) | ETHERADDRL);
7885748Sduboff 	}
7895748Sduboff 
7905748Sduboff 	if (mode & RFCR_MHEN_DP83815) {
7915748Sduboff 		/* Load Multicast hash table */
7925748Sduboff 		for (i = 0; i < 32; i++) {
7935748Sduboff 			/* for DP83815, index is in byte */
7945748Sduboff 			OUTL(dp, RFCR, RFADDR_MULTICAST_DP83815 + i*2);
7955748Sduboff 			OUTL(dp, RFDR, hash_tbl[i]);
7965748Sduboff 		}
7975748Sduboff 	}
7985748Sduboff #if DEBUG_LEVEL > 2
7995748Sduboff 	sfe_rxfilter_dump(dp, 0, 0x10);
8005748Sduboff 	sfe_rxfilter_dump(dp, 0x200, 0x380);
8015748Sduboff #endif
8025748Sduboff 	/* Set rx filter mode and enable rx filter */
8035748Sduboff 	OUTL(dp, RFCR, RFCR_RFEN | mode);
8045748Sduboff 
8055748Sduboff 	return (GEM_SUCCESS);
8065748Sduboff }
8075748Sduboff 
8085748Sduboff static int
8095748Sduboff sfe_set_rx_filter_sis900(struct gem_dev *dp)
8105748Sduboff {
8115748Sduboff 	int		i;
8125748Sduboff 	uint32_t	mode;
8135748Sduboff 	uint16_t	hash_tbl[16];
8145748Sduboff 	uint8_t		*mac = dp->cur_addr.ether_addr_octet;
8155748Sduboff 	int		hash_size;
8165748Sduboff 	int		hash_shift;
8175748Sduboff 	struct sfe_dev	*lp = dp->private;
8185748Sduboff 
8195748Sduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__));
8205748Sduboff 
8215748Sduboff 	if ((dp->rxmode & RXMODE_ENABLE) == 0) {
8225748Sduboff 		/* disalbe rx filter */
8235748Sduboff 		OUTL(dp, RFCR, 0);
8245748Sduboff 		return (GEM_SUCCESS);
8255748Sduboff 	}
8265748Sduboff 
8275748Sduboff 	/*
8285748Sduboff 	 * determine hardware hash table size in word.
8295748Sduboff 	 */
8305748Sduboff 	hash_shift = 25;
8315748Sduboff 	if (lp->revid >= SIS635A_900_REV || lp->revid == SIS900B_900_REV) {
8325748Sduboff 		hash_shift = 24;
8335748Sduboff 	}
8345748Sduboff 	hash_size = (1 << (32 - hash_shift)) / 16;
8355748Sduboff 	bzero(hash_tbl, sizeof (hash_tbl));
8365748Sduboff 
8375748Sduboff 	/* Set Receive filter control register */
8385748Sduboff 
8395748Sduboff 	if (dp->rxmode & RXMODE_PROMISC) {
8405748Sduboff 		/* all broadcast, all multicast, all physical */
8415748Sduboff 		mode = RFCR_AAB | RFCR_AAM | RFCR_AAP;
8425748Sduboff 	} else if ((dp->rxmode & RXMODE_ALLMULTI) ||
8435748Sduboff 	    dp->mc_count > hash_size*16/2) {
8445748Sduboff 		/* all broadcast, all multicast, physical for the chip */
8455748Sduboff 		mode = RFCR_AAB | RFCR_AAM;
8465748Sduboff 	} else {
8475748Sduboff 		/* all broadcast, physical for the chip */
8485748Sduboff 		mode = RFCR_AAB;
8495748Sduboff 	}
8505748Sduboff 
8515748Sduboff 	/* make hash table */
8525748Sduboff 	for (i = 0; i < dp->mc_count; i++) {
8535748Sduboff 		uint_t	h;
8545748Sduboff 		h = dp->mc_list[i].hash >> hash_shift;
8555748Sduboff 		hash_tbl[h / 16] |= 1 << (h % 16);
8565748Sduboff 	}
8575748Sduboff 
8585748Sduboff 	if (bcmp(mac, lp->mac_addr, ETHERADDRL) != 0) {
8595748Sduboff 		/* Disable Rx filter and load mac address */
8605748Sduboff 		for (i = 0; i < ETHERADDRL/2; i++) {
8615748Sduboff 			/* For sis900, index is in word */
8625748Sduboff 			OUTL(dp, RFCR,
8635748Sduboff 			    (RFADDR_MAC_SIS900+i) << RFCR_RFADDR_SHIFT_SIS900);
8645748Sduboff 			OUTL(dp, RFDR, (mac[i*2+1] << 8) | mac[i*2]);
8655748Sduboff 		}
8665748Sduboff 
8675748Sduboff 		bcopy(mac, lp->mac_addr, ETHERADDRL);
8685748Sduboff 	}
8695748Sduboff 
8705748Sduboff 	/* Load Multicast hash table */
8715748Sduboff 	for (i = 0; i < hash_size; i++) {
8725748Sduboff 		/* For sis900, index is in word */
8735748Sduboff 		OUTL(dp, RFCR,
8745748Sduboff 		    (RFADDR_MULTICAST_SIS900 + i) << RFCR_RFADDR_SHIFT_SIS900);
8755748Sduboff 		OUTL(dp, RFDR, hash_tbl[i]);
8765748Sduboff 	}
8775748Sduboff 
8785748Sduboff 	/* Load rx filter mode and enable rx filter */
8795748Sduboff 	OUTL(dp, RFCR, RFCR_RFEN | mode);
8805748Sduboff 
8815748Sduboff 	return (GEM_SUCCESS);
8825748Sduboff }
8835748Sduboff 
8845748Sduboff static int
8855748Sduboff sfe_start_chip(struct gem_dev *dp)
8865748Sduboff {
8875748Sduboff 	struct sfe_dev	*lp = dp->private;
8885748Sduboff 
8895748Sduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__));
8905748Sduboff 
8915748Sduboff 	/*
8925748Sduboff 	 * setup interrupt mask, which shouldn't include ISR_TOK
8935748Sduboff 	 * to improve performance.
8945748Sduboff 	 */
8955748Sduboff 	lp->our_intr_bits = OUR_INTR_BITS;
8965748Sduboff 
8975748Sduboff 	/* enable interrupt */
8985748Sduboff 	if ((dp->misc_flag & GEM_NOINTR) == 0) {
8995748Sduboff 		OUTL(dp, IER, 1);
9005748Sduboff 		OUTL(dp, IMR, lp->our_intr_bits);
9015748Sduboff 	}
9025748Sduboff 
9035748Sduboff 	/* Kick RX */
9045748Sduboff 	OUTL(dp, CR, lp->cr | CR_RXE);
9055748Sduboff 
9065748Sduboff 	return (GEM_SUCCESS);
9075748Sduboff }
9085748Sduboff 
9095748Sduboff /*
9105748Sduboff  * Stop nic core gracefully.
9115748Sduboff  */
9125748Sduboff static int
9135748Sduboff sfe_stop_chip(struct gem_dev *dp)
9145748Sduboff {
9155748Sduboff 	struct sfe_dev	*lp = dp->private;
9165748Sduboff 	uint32_t	done;
9175748Sduboff 	int		i;
918*7116Sduboff 	uint32_t	val;
9195748Sduboff 
9205748Sduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__));
9215748Sduboff 
9225748Sduboff 	/*
9235748Sduboff 	 * Although we inhibit interrupt here, we don't clear soft copy of
9245748Sduboff 	 * interrupt mask to avoid bogus interrupts.
9255748Sduboff 	 */
9265748Sduboff 	OUTL(dp, IMR, 0);
9275748Sduboff 
9285748Sduboff 	/* stop TX and RX immediately */
9295748Sduboff 	OUTL(dp, CR, lp->cr | CR_TXR | CR_RXR);
9305748Sduboff 
9315748Sduboff 	done = 0;
9325748Sduboff 	for (i = 0; done != (ISR_RXRCMP | ISR_TXRCMP); i++) {
9335748Sduboff 		if (i > 1000) {
9345748Sduboff 			/*
9355748Sduboff 			 * As gem layer will call sfe_reset_chip(),
9365748Sduboff 			 * we don't neet to reset futher
9375748Sduboff 			 */
9385748Sduboff 			cmn_err(CE_NOTE, "!%s: %s: Tx/Rx reset timeout",
9395748Sduboff 			    dp->name, __func__);
9405748Sduboff 
9415748Sduboff 			return (GEM_FAILURE);
9425748Sduboff 		}
943*7116Sduboff 		val = INL(dp, ISR);
944*7116Sduboff 		done |= val & (ISR_RXRCMP | ISR_TXRCMP);
945*7116Sduboff 		lp->isr_pended |= val & lp->our_intr_bits;
9465748Sduboff 		drv_usecwait(10);
9475748Sduboff 	}
9485748Sduboff 
9495748Sduboff 	return (GEM_SUCCESS);
9505748Sduboff }
9515748Sduboff 
9525748Sduboff /*
9535748Sduboff  * Setup media mode
9545748Sduboff  */
9555748Sduboff static uint_t
9565748Sduboff sfe_mxdma_value[] = { 512, 4, 8, 16, 32, 64, 128, 256, };
9575748Sduboff 
9585748Sduboff static uint_t
9595748Sduboff sfe_encode_mxdma(uint_t burstsize)
9605748Sduboff {
9615748Sduboff 	int	i;
9625748Sduboff 
9635748Sduboff 	if (burstsize > 256) {
9645748Sduboff 		/* choose 512 */
9655748Sduboff 		return (0);
9665748Sduboff 	}
9675748Sduboff 
9685748Sduboff 	for (i = 1; i < 8; i++) {
9695748Sduboff 		if (burstsize <= sfe_mxdma_value[i]) {
9705748Sduboff 			break;
9715748Sduboff 		}
9725748Sduboff 	}
9735748Sduboff 	return (i);
9745748Sduboff }
9755748Sduboff 
9765748Sduboff static int
9775748Sduboff sfe_set_media(struct gem_dev *dp)
9785748Sduboff {
9795748Sduboff 	uint32_t	txcfg;
9805748Sduboff 	uint32_t	rxcfg;
9815748Sduboff 	uint32_t	pcr;
9825748Sduboff 	uint32_t	val;
9835748Sduboff 	uint32_t	txmxdma;
9845748Sduboff 	uint32_t	rxmxdma;
9855748Sduboff 	struct sfe_dev	*lp = dp->private;
9865748Sduboff #ifdef DEBUG_LEVEL
9875748Sduboff 	extern int	gem_speed_value[];
9885748Sduboff #endif
9895748Sduboff 	DPRINTF(2, (CE_CONT, CONS "%s: %s: %s duplex, %d Mbps",
9905748Sduboff 	    dp->name, __func__,
9915748Sduboff 	    dp->full_duplex ? "full" : "half", gem_speed_value[dp->speed]));
9925748Sduboff 
9935748Sduboff 	/* initialize txcfg and rxcfg */
9945748Sduboff 	txcfg = TXCFG_ATP;
9955748Sduboff 	if (dp->full_duplex) {
9965748Sduboff 		txcfg |= (TXCFG_CSI | TXCFG_HBI);
9975748Sduboff 	}
998*7116Sduboff 	rxcfg = RXCFG_AEP | RXCFG_ARP;
9995748Sduboff 	if (dp->full_duplex) {
10005748Sduboff 		rxcfg |= RXCFG_ATX;
10015748Sduboff 	}
10025748Sduboff 
10035748Sduboff 	/* select txmxdma and rxmxdma, maxmum burst length */
10045748Sduboff 	if (lp->chip->chip_type == CHIPTYPE_SIS900) {
10055748Sduboff #ifdef DEBUG_SIS900_EDB
10065748Sduboff 		val = CFG_EDB_MASTER;
10075748Sduboff #else
10085748Sduboff 		val = INL(dp, CFG) & CFG_EDB_MASTER;
10095748Sduboff #endif
10105748Sduboff 		if (val) {
10115748Sduboff 			/*
10125748Sduboff 			 * sis900 built-in cores:
10135748Sduboff 			 * max burst length must be fixed to 64
10145748Sduboff 			 */
10155748Sduboff 			txmxdma = 64;
10165748Sduboff 			rxmxdma = 64;
10175748Sduboff 		} else {
10185748Sduboff 			/*
10195748Sduboff 			 * sis900 pci chipset:
10205748Sduboff 			 * the vendor recommended to fix max burst length
10215748Sduboff 			 * to 512
10225748Sduboff 			 */
10235748Sduboff 			txmxdma = 512;
10245748Sduboff 			rxmxdma = 512;
10255748Sduboff 		}
10265748Sduboff 	} else {
10275748Sduboff 		/*
10285748Sduboff 		 * NS dp83815/816:
10295748Sduboff 		 * use user defined or default for tx/rx max burst length
10305748Sduboff 		 */
10315748Sduboff 		txmxdma = max(dp->txmaxdma, 256);
10325748Sduboff 		rxmxdma = max(dp->rxmaxdma, 256);
10335748Sduboff 	}
10345748Sduboff 
10355748Sduboff 
10365748Sduboff 	/* tx high water mark */
10375748Sduboff 	lp->tx_drain_threshold = ROUNDUP2(dp->txthr, TXCFG_FIFO_UNIT);
10385748Sduboff 
10395748Sduboff 	/* determine tx_fill_threshold accroding drain threshold */
10405748Sduboff 	lp->tx_fill_threshold =
10415748Sduboff 	    TXFIFOSIZE - lp->tx_drain_threshold - TXCFG_FIFO_UNIT;
10425748Sduboff 
10435748Sduboff 	/* tune txmxdma not to exceed tx_fill_threshold */
10445748Sduboff 	for (; ; ) {
10455748Sduboff 		/* normalize txmxdma requested */
10465748Sduboff 		val = sfe_encode_mxdma(txmxdma);
10475748Sduboff 		txmxdma = sfe_mxdma_value[val];
10485748Sduboff 
10495748Sduboff 		if (txmxdma <= lp->tx_fill_threshold) {
10505748Sduboff 			break;
10515748Sduboff 		}
10525748Sduboff 		/* select new txmxdma */
10535748Sduboff 		txmxdma = txmxdma / 2;
10545748Sduboff 	}
10555748Sduboff 	txcfg |= val << TXCFG_MXDMA_SHIFT;
10565748Sduboff 
10575748Sduboff 	/* encode rxmxdma, maxmum burst length for rx */
10585748Sduboff 	val = sfe_encode_mxdma(rxmxdma);
1059*7116Sduboff 	rxcfg |= val << RXCFG_MXDMA_SHIFT;
10605748Sduboff 	rxmxdma = sfe_mxdma_value[val];
10615748Sduboff 
10625748Sduboff 	/* receive starting threshold - it have only 5bit-wide field */
10635748Sduboff 	val = ROUNDUP2(max(dp->rxthr, ETHERMIN), RXCFG_FIFO_UNIT);
10645748Sduboff 	lp->rx_drain_threshold =
10655748Sduboff 	    min(val, (RXCFG_DRTH >> RXCFG_DRTH_SHIFT) * RXCFG_FIFO_UNIT);
10665748Sduboff 
10675748Sduboff 	DPRINTF(0, (CE_CONT,
10685748Sduboff 	    "%s: %s: tx: drain:%d(rest %d) fill:%d mxdma:%d,"
10695748Sduboff 	    " rx: drain:%d mxdma:%d",
10705748Sduboff 	    dp->name, __func__,
10715748Sduboff 	    lp->tx_drain_threshold, TXFIFOSIZE - lp->tx_drain_threshold,
10725748Sduboff 	    lp->tx_fill_threshold, txmxdma,
10735748Sduboff 	    lp->rx_drain_threshold, rxmxdma));
10745748Sduboff 
10755748Sduboff 	ASSERT(lp->tx_drain_threshold < 64*TXCFG_FIFO_UNIT);
10765748Sduboff 	ASSERT(lp->tx_fill_threshold < 64*TXCFG_FIFO_UNIT);
10775748Sduboff 	ASSERT(lp->rx_drain_threshold < 32*RXCFG_FIFO_UNIT);
10785748Sduboff 
10795748Sduboff 	txcfg |= ((lp->tx_fill_threshold/TXCFG_FIFO_UNIT) << TXCFG_FLTH_SHIFT)
10805748Sduboff 	    | (lp->tx_drain_threshold/TXCFG_FIFO_UNIT);
10815748Sduboff 	OUTL(dp, TXCFG, txcfg);
10825748Sduboff 
10835748Sduboff 	rxcfg |= ((lp->rx_drain_threshold/RXCFG_FIFO_UNIT) << RXCFG_DRTH_SHIFT);
10845748Sduboff 	if (lp->chip->chip_type == CHIPTYPE_DP83815) {
10855748Sduboff 		rxcfg |= RXCFG_ALP_DP83815;
10865748Sduboff 	}
10875748Sduboff 	OUTL(dp, RXCFG, rxcfg);
10885748Sduboff 
10895748Sduboff 	DPRINTF(0, (CE_CONT, CONS "%s: %s: txcfg:%b rxcfg:%b",
10905748Sduboff 	    dp->name, __func__,
10915748Sduboff 	    txcfg, TXCFG_BITS, rxcfg, RXCFG_BITS));
10925748Sduboff 
10935748Sduboff 	/* Flow control */
10945748Sduboff 	if (lp->chip->chip_type == CHIPTYPE_DP83815) {
10955748Sduboff 		pcr = INL(dp, PCR);
10965748Sduboff 		switch (dp->flow_control) {
10975748Sduboff 		case FLOW_CONTROL_SYMMETRIC:
10985748Sduboff 		case FLOW_CONTROL_RX_PAUSE:
10995748Sduboff 			OUTL(dp, PCR, pcr | PCR_PSEN | PCR_PS_MCAST);
11005748Sduboff 			break;
11015748Sduboff 
11025748Sduboff 		default:
11035748Sduboff 			OUTL(dp, PCR,
11045748Sduboff 			    pcr & ~(PCR_PSEN | PCR_PS_MCAST | PCR_PS_DA));
11055748Sduboff 			break;
11065748Sduboff 		}
11075748Sduboff 		DPRINTF(2, (CE_CONT, CONS "%s: PCR: %b", dp->name,
11085748Sduboff 		    INL(dp, PCR), PCR_BITS));
11095748Sduboff 
11105748Sduboff 	} else if (lp->chip->chip_type == CHIPTYPE_SIS900) {
11115748Sduboff 		switch (dp->flow_control) {
11125748Sduboff 		case FLOW_CONTROL_SYMMETRIC:
11135748Sduboff 		case FLOW_CONTROL_RX_PAUSE:
11145748Sduboff 			OUTL(dp, FLOWCTL, FLOWCTL_FLOWEN);
11155748Sduboff 			break;
11165748Sduboff 		default:
11175748Sduboff 			OUTL(dp, FLOWCTL, 0);
11185748Sduboff 			break;
11195748Sduboff 		}
11205748Sduboff 		DPRINTF(2, (CE_CONT, CONS "%s: FLOWCTL: %b",
11215748Sduboff 		    dp->name, INL(dp, FLOWCTL), FLOWCTL_BITS));
11225748Sduboff 	}
11235748Sduboff 	return (GEM_SUCCESS);
11245748Sduboff }
11255748Sduboff 
11265748Sduboff static int
11275748Sduboff sfe_get_stats(struct gem_dev *dp)
11285748Sduboff {
11295748Sduboff 	/* do nothing */
11305748Sduboff 	return (GEM_SUCCESS);
11315748Sduboff }
11325748Sduboff 
11335748Sduboff /*
11345748Sduboff  * descriptor manipulations
11355748Sduboff  */
11365748Sduboff static int
11375748Sduboff sfe_tx_desc_write(struct gem_dev *dp, int slot,
11385748Sduboff 		ddi_dma_cookie_t *dmacookie, int frags, uint64_t flags)
11395748Sduboff {
11405748Sduboff 	uint32_t		mark;
11415748Sduboff 	struct sfe_desc		*tdp;
11425748Sduboff 	ddi_dma_cookie_t	*dcp;
1143*7116Sduboff 	uint32_t		tmp0;
1144*7116Sduboff #if DEBUG_LEVEL > 2
11455748Sduboff 	int			i;
11465748Sduboff 
11475748Sduboff 	cmn_err(CE_CONT,
11485748Sduboff 	    CONS "%s: time:%d %s seqnum: %d, slot %d, frags: %d flags: %llx",
11495748Sduboff 	    dp->name, ddi_get_lbolt(), __func__,
11505748Sduboff 	    dp->tx_desc_tail, slot, frags, flags);
11515748Sduboff 
11525748Sduboff 	for (i = 0; i < frags; i++) {
11535748Sduboff 		cmn_err(CE_CONT, CONS "%d: addr: 0x%x, len: 0x%x",
11545748Sduboff 		    i, dmacookie[i].dmac_address, dmacookie[i].dmac_size);
1155*7116Sduboff 	}
11565748Sduboff #endif
11575748Sduboff 	/*
11585748Sduboff 	 * write tx descriptor in reversed order.
11595748Sduboff 	 */
11605748Sduboff #if DEBUG_LEVEL > 3
11615748Sduboff 	flags |= GEM_TXFLAG_INTR;
11625748Sduboff #endif
11635748Sduboff 	mark = (flags & GEM_TXFLAG_INTR)
1164*7116Sduboff 	    ? (CMDSTS_OWN | CMDSTS_INTR) : CMDSTS_OWN;
11655748Sduboff 
11665748Sduboff 	ASSERT(frags == 1);
11675748Sduboff 	dcp = &dmacookie[0];
11685748Sduboff 	if (flags & GEM_TXFLAG_HEAD) {
11695748Sduboff 		mark &= ~CMDSTS_OWN;
11705748Sduboff 	}
11715748Sduboff 
11725748Sduboff 	tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot];
1173*7116Sduboff 	tmp0 = (uint32_t)dcp->dmac_address;
1174*7116Sduboff 	mark |= (uint32_t)dcp->dmac_size;
1175*7116Sduboff 	tdp->d_bufptr = LE_32(tmp0);
1176*7116Sduboff 	tdp->d_cmdsts = LE_32(mark);
11775748Sduboff 
11785748Sduboff 	return (frags);
11795748Sduboff }
11805748Sduboff 
11815748Sduboff static void
11825748Sduboff sfe_tx_start(struct gem_dev *dp, int start_slot, int nslot)
11835748Sduboff {
1184*7116Sduboff 	uint_t			tx_ring_size = dp->gc.gc_tx_ring_size;
11855748Sduboff 	struct sfe_desc		*tdp;
11865748Sduboff 	struct sfe_dev		*lp = dp->private;
11875748Sduboff 
11885748Sduboff 	if (nslot > 1) {
11895748Sduboff 		gem_tx_desc_dma_sync(dp,
1190*7116Sduboff 		    SLOT(start_slot + 1, tx_ring_size),
11915748Sduboff 		    nslot - 1, DDI_DMA_SYNC_FORDEV);
11925748Sduboff 	}
11935748Sduboff 
11945748Sduboff 	tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * start_slot];
11955748Sduboff 	tdp->d_cmdsts |= LE_32(CMDSTS_OWN);
11965748Sduboff 
11975748Sduboff 	gem_tx_desc_dma_sync(dp, start_slot, 1, DDI_DMA_SYNC_FORDEV);
11985748Sduboff 
11995748Sduboff 	/*
12005748Sduboff 	 * Let the Transmit Buffer Manager Fill state machine active.
12015748Sduboff 	 */
12025748Sduboff 	if (dp->mac_active) {
12035748Sduboff 		OUTL(dp, CR, lp->cr | CR_TXE);
12045748Sduboff 	}
12055748Sduboff }
12065748Sduboff 
12075748Sduboff static void
12085748Sduboff sfe_rx_desc_write(struct gem_dev *dp, int slot,
12095748Sduboff 	    ddi_dma_cookie_t *dmacookie, int frags)
12105748Sduboff {
12115748Sduboff 	struct sfe_desc		*rdp;
1212*7116Sduboff 	uint32_t		tmp0;
1213*7116Sduboff 	uint32_t		tmp1;
12145748Sduboff #if DEBUG_LEVEL > 2
12155748Sduboff 	int			i;
12165748Sduboff 
12175748Sduboff 	ASSERT(frags == 1);
12185748Sduboff 
12195748Sduboff 	cmn_err(CE_CONT, CONS
12205748Sduboff 	    "%s: %s seqnum: %d, slot %d, frags: %d",
12215748Sduboff 	    dp->name, __func__, dp->rx_active_tail, slot, frags);
12225748Sduboff 	for (i = 0; i < frags; i++) {
12235748Sduboff 		cmn_err(CE_CONT, CONS "  frag: %d addr: 0x%llx, len: 0x%lx",
12245748Sduboff 		    i, dmacookie[i].dmac_address, dmacookie[i].dmac_size);
12255748Sduboff 	}
12265748Sduboff #endif
12275748Sduboff 	/* for the last slot of the packet */
12285748Sduboff 	rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot];
12295748Sduboff 
1230*7116Sduboff 	tmp0 = (uint32_t)dmacookie->dmac_address;
1231*7116Sduboff 	tmp1 = CMDSTS_INTR | (uint32_t)dmacookie->dmac_size;
1232*7116Sduboff 	rdp->d_bufptr = LE_32(tmp0);
1233*7116Sduboff 	rdp->d_cmdsts = LE_32(tmp1);
12345748Sduboff }
12355748Sduboff 
12365748Sduboff static uint_t
12375748Sduboff sfe_tx_desc_stat(struct gem_dev *dp, int slot, int ndesc)
12385748Sduboff {
1239*7116Sduboff 	uint_t			tx_ring_size = dp->gc.gc_tx_ring_size;
12405748Sduboff 	struct sfe_desc		*tdp;
12415748Sduboff 	uint32_t		status;
12425748Sduboff 	int			cols;
1243*7116Sduboff 	struct sfe_dev		*lp = dp->private;
12445748Sduboff #ifdef DEBUG_LEVEL
12455748Sduboff 	int			i;
12465748Sduboff 	clock_t			delay;
12475748Sduboff #endif
12485748Sduboff 	/* check status of the last descriptor */
12495748Sduboff 	tdp = (void *)
1250*7116Sduboff 	    &dp->tx_ring[SFE_DESC_SIZE * SLOT(slot + ndesc - 1, tx_ring_size)];
12515748Sduboff 
1252*7116Sduboff 	/*
1253*7116Sduboff 	 * Don't use LE_32() directly to refer tdp->d_cmdsts.
1254*7116Sduboff 	 * It is not atomic for big endian cpus.
1255*7116Sduboff 	 */
1256*7116Sduboff 	status = tdp->d_cmdsts;
1257*7116Sduboff 	status = LE_32(status);
12585748Sduboff 
12595748Sduboff 	DPRINTF(2, (CE_CONT, CONS "%s: time:%ld %s: slot:%d, status:0x%b",
12605748Sduboff 	    dp->name, ddi_get_lbolt(), __func__,
12615748Sduboff 	    slot, status, TXSTAT_BITS));
12625748Sduboff 
12635748Sduboff 	if (status & CMDSTS_OWN) {
12645748Sduboff 		/*
12655748Sduboff 		 * not yet transmitted
12665748Sduboff 		 */
1267*7116Sduboff 		/* workaround for tx hang */
1268*7116Sduboff 		if (lp->chip->chip_type == CHIPTYPE_DP83815 &&
1269*7116Sduboff 		    dp->mac_active) {
1270*7116Sduboff 			OUTL(dp, CR, lp->cr | CR_TXE);
1271*7116Sduboff 		}
12725748Sduboff 		return (0);
12735748Sduboff 	}
12745748Sduboff 
12755748Sduboff 	if (status & CMDSTS_MORE) {
12765748Sduboff 		/* XXX - the hardware problem but don't panic the system */
12775748Sduboff 		/* avoid lint bug for %b format string including 32nd bit */
12785748Sduboff 		cmn_err(CE_NOTE, CONS
12795748Sduboff 		    "%s: tx status bits incorrect:  slot:%d, status:0x%x",
12805748Sduboff 		    dp->name, slot, status);
12815748Sduboff 	}
12825748Sduboff 
12835748Sduboff #if DEBUG_LEVEL > 3
12845748Sduboff 	delay = (ddi_get_lbolt() - dp->tx_buf_head->txb_stime) * 10;
12855748Sduboff 	if (delay >= 50) {
12865748Sduboff 		DPRINTF(0, (CE_NOTE, "%s: tx deferred %d mS: slot %d",
12875748Sduboff 		    dp->name, delay, slot));
12885748Sduboff 	}
12895748Sduboff #endif
12905748Sduboff 
12915748Sduboff #if DEBUG_LEVEL > 3
12925748Sduboff 	for (i = 0; i < nfrag-1; i++) {
12935748Sduboff 		uint32_t	s;
12945748Sduboff 		int		n;
12955748Sduboff 
1296*7116Sduboff 		n = SLOT(slot + i, tx_ring_size);
12975748Sduboff 		s = LE_32(
12985748Sduboff 		    ((struct sfe_desc *)((void *)
12995748Sduboff 		    &dp->tx_ring[SFE_DESC_SIZE * n]))->d_cmdsts);
13005748Sduboff 
13015748Sduboff 		ASSERT(s & CMDSTS_MORE);
13025748Sduboff 		ASSERT((s & CMDSTS_OWN) == 0);
13035748Sduboff 	}
13045748Sduboff #endif
13055748Sduboff 
13065748Sduboff 	/*
13075748Sduboff 	 *  collect statistics
13085748Sduboff 	 */
13095748Sduboff 	if ((status & CMDSTS_OK) == 0) {
13105748Sduboff 
13115748Sduboff 		/* failed to transmit the packet */
13125748Sduboff 
13135748Sduboff 		DPRINTF(0, (CE_CONT, CONS "%s: Transmit error, Tx status %b",
13145748Sduboff 		    dp->name, status, TXSTAT_BITS));
13155748Sduboff 
13165748Sduboff 		dp->stats.errxmt++;
13175748Sduboff 
13185748Sduboff 		if (status & CMDSTS_TFU) {
13195748Sduboff 			dp->stats.underflow++;
13205748Sduboff 		} else if (status & CMDSTS_CRS) {
13215748Sduboff 			dp->stats.nocarrier++;
13225748Sduboff 		} else if (status & CMDSTS_OWC) {
13235748Sduboff 			dp->stats.xmtlatecoll++;
13245748Sduboff 		} else if ((!dp->full_duplex) && (status & CMDSTS_EC)) {
13255748Sduboff 			dp->stats.excoll++;
13265748Sduboff 			dp->stats.collisions += 16;
13275748Sduboff 		} else {
13285748Sduboff 			dp->stats.xmit_internal_err++;
13295748Sduboff 		}
13305748Sduboff 	} else if (!dp->full_duplex) {
13315748Sduboff 		cols = (status >> CMDSTS_CCNT_SHIFT) & CCNT_MASK;
13325748Sduboff 
13335748Sduboff 		if (cols > 0) {
13345748Sduboff 			if (cols == 1) {
13355748Sduboff 				dp->stats.first_coll++;
13365748Sduboff 			} else /* (cols > 1) */ {
13375748Sduboff 				dp->stats.multi_coll++;
13385748Sduboff 			}
13395748Sduboff 			dp->stats.collisions += cols;
13405748Sduboff 		} else if (status & CMDSTS_TD) {
13415748Sduboff 			dp->stats.defer++;
13425748Sduboff 		}
13435748Sduboff 	}
13445748Sduboff 	return (GEM_TX_DONE);
13455748Sduboff }
13465748Sduboff 
13475748Sduboff static uint64_t
13485748Sduboff sfe_rx_desc_stat(struct gem_dev *dp, int slot, int ndesc)
13495748Sduboff {
13505748Sduboff 	struct sfe_desc		*rdp;
13515748Sduboff 	uint_t			len;
13525748Sduboff 	uint_t			flag;
13535748Sduboff 	uint32_t		status;
13545748Sduboff 
13555748Sduboff 	flag = GEM_RX_DONE;
13565748Sduboff 
13575748Sduboff 	/* Dont read ISR because we cannot ack only to rx interrupt. */
13585748Sduboff 
13595748Sduboff 	rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot];
13605748Sduboff 
1361*7116Sduboff 	/*
1362*7116Sduboff 	 * Don't use LE_32() directly to refer rdp->d_cmdsts.
1363*7116Sduboff 	 * It is not atomic for big endian cpus.
1364*7116Sduboff 	 */
1365*7116Sduboff 	status = rdp->d_cmdsts;
1366*7116Sduboff 	status = LE_32(status);
13675748Sduboff 
13685748Sduboff 	DPRINTF(2, (CE_CONT, CONS "%s: time:%ld %s: slot:%d, status:0x%b",
13695748Sduboff 	    dp->name, ddi_get_lbolt(), __func__,
13705748Sduboff 	    slot, status, RXSTAT_BITS));
13715748Sduboff 
13725748Sduboff 	if ((status & CMDSTS_OWN) == 0) {
13735748Sduboff 		/*
13745748Sduboff 		 * No more received packets because
13755748Sduboff 		 * this buffer is owned by NIC.
13765748Sduboff 		 */
13775748Sduboff 		return (0);
13785748Sduboff 	}
13795748Sduboff 
13805748Sduboff #define	RX_ERR_BITS \
13815748Sduboff 	(CMDSTS_RXA | CMDSTS_RXO | CMDSTS_LONG | CMDSTS_RUNT | \
13825748Sduboff 		CMDSTS_ISE | CMDSTS_CRCE | CMDSTS_FAE | CMDSTS_MORE)
13835748Sduboff 
13845748Sduboff 	if (status & RX_ERR_BITS) {
13855748Sduboff 		/*
13865748Sduboff 		 * Packet with error received
13875748Sduboff 		 */
13885748Sduboff 		DPRINTF(0, (CE_CONT, CONS "%s: Corrupted packet "
13895748Sduboff 		    "received, buffer status: %b",
13905748Sduboff 		    dp->name, status, RXSTAT_BITS));
13915748Sduboff 
13925748Sduboff 		/* collect statistics information */
13935748Sduboff 		dp->stats.errrcv++;
13945748Sduboff 
13955748Sduboff 		if (status & CMDSTS_RXO) {
13965748Sduboff 			dp->stats.overflow++;
13975748Sduboff 		} else if (status & (CMDSTS_LONG | CMDSTS_MORE)) {
13985748Sduboff 			dp->stats.frame_too_long++;
13995748Sduboff 		} else if (status & CMDSTS_RUNT) {
14005748Sduboff 			dp->stats.runt++;
14015748Sduboff 		} else if (status & (CMDSTS_ISE | CMDSTS_FAE)) {
14025748Sduboff 			dp->stats.frame++;
14035748Sduboff 		} else if (status & CMDSTS_CRCE) {
14045748Sduboff 			dp->stats.crc++;
14055748Sduboff 		} else {
14065748Sduboff 			dp->stats.rcv_internal_err++;
14075748Sduboff 		}
14085748Sduboff 
14095748Sduboff 		return (flag | GEM_RX_ERR);
14105748Sduboff 	}
14115748Sduboff 
14125748Sduboff 	/*
14135748Sduboff 	 * this packet was received without errors
14145748Sduboff 	 */
14155748Sduboff 	if ((len = (status & CMDSTS_SIZE)) >= ETHERFCSL) {
14165748Sduboff 		len -= ETHERFCSL;
14175748Sduboff 	}
14185748Sduboff 
14195748Sduboff #if DEBUG_LEVEL > 10
14205748Sduboff {
14215748Sduboff 	int	i;
14225748Sduboff 	uint8_t	*bp = dp->rx_buf_head->rxb_buf;
14235748Sduboff 
14245748Sduboff 	cmn_err(CE_CONT, CONS "%s: len:%d", dp->name, len);
14255748Sduboff 
14265748Sduboff 	for (i = 0; i < 60; i += 10) {
14275748Sduboff 		cmn_err(CE_CONT, CONS
14285748Sduboff 		    "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
14295748Sduboff 		    bp[0], bp[1], bp[2], bp[3], bp[4],
14305748Sduboff 		    bp[5], bp[6], bp[7], bp[8], bp[9]);
14315748Sduboff 	}
14325748Sduboff 	bp += 10;
14335748Sduboff }
14345748Sduboff #endif
14355748Sduboff 	return (flag | (len & GEM_RX_LEN));
14365748Sduboff }
14375748Sduboff 
14385748Sduboff static void
14395748Sduboff sfe_tx_desc_init(struct gem_dev *dp, int slot)
14405748Sduboff {
1441*7116Sduboff 	uint_t			tx_ring_size = dp->gc.gc_tx_ring_size;
14425748Sduboff 	struct sfe_desc		*tdp;
14435748Sduboff 	uint32_t		here;
14445748Sduboff 
14455748Sduboff 	tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot];
14465748Sduboff 
14475748Sduboff 	/* don't clear d_link field, which have a valid pointer */
14485748Sduboff 	tdp->d_cmdsts = 0;
14495748Sduboff 
14505748Sduboff 	/* make a link to this from the previous descriptor */
14515748Sduboff 	here = ((uint32_t)dp->tx_ring_dma) + SFE_DESC_SIZE*slot;
14525748Sduboff 
14535748Sduboff 	tdp = (void *)
1454*7116Sduboff 	    &dp->tx_ring[SFE_DESC_SIZE * SLOT(slot - 1, tx_ring_size)];
14555748Sduboff 	tdp->d_link = LE_32(here);
14565748Sduboff }
14575748Sduboff 
14585748Sduboff static void
14595748Sduboff sfe_rx_desc_init(struct gem_dev *dp, int slot)
14605748Sduboff {
1461*7116Sduboff 	uint_t			rx_ring_size = dp->gc.gc_rx_ring_size;
14625748Sduboff 	struct sfe_desc		*rdp;
14635748Sduboff 	uint32_t		here;
14645748Sduboff 
14655748Sduboff 	rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot];
14665748Sduboff 
14675748Sduboff 	/* don't clear d_link field, which have a valid pointer */
14685748Sduboff 	rdp->d_cmdsts = LE_32(CMDSTS_OWN);
14695748Sduboff 
14705748Sduboff 	/* make a link to this from the previous descriptor */
14715748Sduboff 	here = ((uint32_t)dp->rx_ring_dma) + SFE_DESC_SIZE*slot;
14725748Sduboff 
14735748Sduboff 	rdp = (void *)
1474*7116Sduboff 	    &dp->rx_ring[SFE_DESC_SIZE * SLOT(slot - 1, rx_ring_size)];
14755748Sduboff 	rdp->d_link = LE_32(here);
14765748Sduboff }
14775748Sduboff 
14785748Sduboff static void
14795748Sduboff sfe_tx_desc_clean(struct gem_dev *dp, int slot)
14805748Sduboff {
14815748Sduboff 	struct sfe_desc		*tdp;
14825748Sduboff 
14835748Sduboff 	tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot];
14845748Sduboff 	tdp->d_cmdsts = 0;
14855748Sduboff }
14865748Sduboff 
14875748Sduboff static void
14885748Sduboff sfe_rx_desc_clean(struct gem_dev *dp, int slot)
14895748Sduboff {
14905748Sduboff 	struct sfe_desc		*rdp;
14915748Sduboff 
14925748Sduboff 	rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot];
14935748Sduboff 	rdp->d_cmdsts = LE_32(CMDSTS_OWN);
14945748Sduboff }
14955748Sduboff 
14965748Sduboff /*
14975748Sduboff  * Device depend interrupt handler
14985748Sduboff  */
14995748Sduboff static uint_t
15005748Sduboff sfe_interrupt(struct gem_dev *dp)
15015748Sduboff {
1502*7116Sduboff 	uint_t		rx_ring_size = dp->gc.gc_rx_ring_size;
15035748Sduboff 	uint32_t	isr;
1504*7116Sduboff 	uint32_t	isr_bogus;
15055748Sduboff 	uint_t		flags = 0;
15065748Sduboff 	boolean_t	need_to_reset = B_FALSE;
15075748Sduboff 	struct sfe_dev	*lp = dp->private;
15085748Sduboff 
15095748Sduboff 	/* read reason and clear interrupt */
15105748Sduboff 	isr = INL(dp, ISR);
15115748Sduboff 
1512*7116Sduboff 	isr_bogus = lp->isr_pended;
1513*7116Sduboff 	lp->isr_pended = 0;
1514*7116Sduboff 
1515*7116Sduboff 	if (((isr | isr_bogus) & lp->our_intr_bits) == 0) {
15165748Sduboff 		/* we are not the interrupt source */
15175748Sduboff 		return (DDI_INTR_UNCLAIMED);
15185748Sduboff 	}
15195748Sduboff 
15205748Sduboff 	DPRINTF(3, (CE_CONT,
15215748Sduboff 	    CONS "%s: time:%ld %s:called: isr:0x%b rx_active_head: %d",
15225748Sduboff 	    dp->name, ddi_get_lbolt(), __func__,
15235748Sduboff 	    isr, INTR_BITS, dp->rx_active_head));
15245748Sduboff 
15255748Sduboff 	if (!dp->mac_active) {
15265748Sduboff 		/* the device is going to stop */
15275748Sduboff 		lp->our_intr_bits = 0;
15285748Sduboff 		return (DDI_INTR_CLAIMED);
15295748Sduboff 	}
15305748Sduboff 
15315748Sduboff 	isr &= lp->our_intr_bits;
15325748Sduboff 
15335748Sduboff 	if (isr & (ISR_RXSOVR | ISR_RXORN | ISR_RXIDLE | ISR_RXERR |
15345748Sduboff 	    ISR_RXDESC | ISR_RXOK)) {
15355748Sduboff 		(void) gem_receive(dp);
15365748Sduboff 
15375748Sduboff 		if (isr & (ISR_RXSOVR | ISR_RXORN)) {
15385748Sduboff 			DPRINTF(0, (CE_CONT,
15395748Sduboff 			    CONS "%s: rx fifo overrun: isr %b",
15405748Sduboff 			    dp->name, isr, INTR_BITS));
15415748Sduboff 			/* no need restart rx */
15425748Sduboff 			dp->stats.overflow++;
15435748Sduboff 		}
15445748Sduboff 
15455748Sduboff 		if (isr & ISR_RXIDLE) {
15465748Sduboff 			DPRINTF(0, (CE_CONT,
15475748Sduboff 			    CONS "%s: rx buffer ran out: isr %b",
15485748Sduboff 			    dp->name, isr, INTR_BITS));
15495748Sduboff 
15505748Sduboff 			dp->stats.norcvbuf++;
15515748Sduboff 
15525748Sduboff 			/*
15535748Sduboff 			 * Make RXDP points the head of receive
15545748Sduboff 			 * buffer list.
15555748Sduboff 			 */
15565748Sduboff 			OUTL(dp, RXDP, dp->rx_ring_dma +
15575748Sduboff 			    SFE_DESC_SIZE *
1558*7116Sduboff 			    SLOT(dp->rx_active_head, rx_ring_size));
15595748Sduboff 
15605748Sduboff 			/* Restart the receive engine */
15615748Sduboff 			OUTL(dp, CR, lp->cr | CR_RXE);
15625748Sduboff 		}
15635748Sduboff 	}
15645748Sduboff 
15655748Sduboff 	if (isr & (ISR_TXURN | ISR_TXERR | ISR_TXDESC |
15665748Sduboff 	    ISR_TXIDLE | ISR_TXOK)) {
15675748Sduboff 		/* need to reclaim tx buffers */
15685748Sduboff 		if (gem_tx_done(dp)) {
15695748Sduboff 			flags |= INTR_RESTART_TX;
15705748Sduboff 		}
15715748Sduboff 		/*
15725748Sduboff 		 * XXX - tx error statistics will be counted in
15735748Sduboff 		 * sfe_tx_desc_stat() and no need to restart tx on errors.
15745748Sduboff 		 */
15755748Sduboff 	}
15765748Sduboff 
15775748Sduboff 	if (isr & (ISR_DPERR | ISR_SSERR | ISR_RMABT | ISR_RTABT)) {
15785748Sduboff 		cmn_err(CE_WARN, "%s: ERROR interrupt: isr %b.",
15795748Sduboff 		    dp->name, isr, INTR_BITS);
15805748Sduboff 		need_to_reset = B_TRUE;
15815748Sduboff 	}
15825748Sduboff reset:
15835748Sduboff 	if (need_to_reset) {
15845748Sduboff 		(void) gem_restart_nic(dp, GEM_RESTART_KEEP_BUF);
15855748Sduboff 		flags |= INTR_RESTART_TX;
15865748Sduboff 	}
15875748Sduboff 
15885748Sduboff 	DPRINTF(5, (CE_CONT, CONS "%s: %s: return: isr: %b",
15895748Sduboff 	    dp->name, __func__, isr, INTR_BITS));
15905748Sduboff 
15915748Sduboff 	return (DDI_INTR_CLAIMED | flags);
15925748Sduboff }
15935748Sduboff 
15945748Sduboff /* ======================================================== */
15955748Sduboff /*
15965748Sduboff  * HW depend MII routine
15975748Sduboff  */
15985748Sduboff /* ======================================================== */
15995748Sduboff 
16005748Sduboff /*
16015748Sduboff  * MII routines for NS DP83815
16025748Sduboff  */
16035748Sduboff static void
16045748Sduboff sfe_mii_sync_dp83815(struct gem_dev *dp)
16055748Sduboff {
16065748Sduboff 	/* do nothing */
16075748Sduboff }
16085748Sduboff 
16095748Sduboff static uint16_t
16105748Sduboff sfe_mii_read_dp83815(struct gem_dev *dp, uint_t offset)
16115748Sduboff {
16125748Sduboff 	DPRINTF(4, (CE_CONT, CONS"%s: %s: offset 0x%x",
16135748Sduboff 	    dp->name, __func__, offset));
16145748Sduboff 	return ((uint16_t)INL(dp, MII_REGS_BASE + offset*4));
16155748Sduboff }
16165748Sduboff 
16175748Sduboff static void
16185748Sduboff sfe_mii_write_dp83815(struct gem_dev *dp, uint_t offset, uint16_t val)
16195748Sduboff {
16205748Sduboff 	DPRINTF(4, (CE_CONT, CONS"%s: %s: offset 0x%x 0x%x",
16215748Sduboff 	    dp->name, __func__, offset, val));
16225748Sduboff 	OUTL(dp, MII_REGS_BASE + offset*4, val);
16235748Sduboff }
16245748Sduboff 
16255748Sduboff static int
16265748Sduboff sfe_mii_config_dp83815(struct gem_dev *dp)
16275748Sduboff {
16285748Sduboff 	uint32_t	srr;
16295748Sduboff 
16305748Sduboff 	srr = INL(dp, SRR) & SRR_REV;
16315748Sduboff 
16325748Sduboff 	DPRINTF(0, (CE_CONT, CONS "%s: srr:0x%04x %04x %04x %04x %04x %04x",
16335748Sduboff 	    dp->name, srr,
16345748Sduboff 	    INW(dp, 0x00cc),	/* PGSEL */
16355748Sduboff 	    INW(dp, 0x00e4),	/* PMDCSR */
16365748Sduboff 	    INW(dp, 0x00fc),	/* TSTDAT */
16375748Sduboff 	    INW(dp, 0x00f4),	/* DSPCFG */
16385748Sduboff 	    INW(dp, 0x00f8)));	/* SDCFG */
16395748Sduboff 
1640*7116Sduboff 	if (srr == SRR_REV_DP83815CVNG) {
16415748Sduboff 		/*
16425748Sduboff 		 * NS datasheet says that DP83815CVNG needs following
16435748Sduboff 		 * registers to be patched for optimizing its performance.
1644*7116Sduboff 		 * A report said that CRC errors on RX disappeared
16455748Sduboff 		 * with the patch.
16465748Sduboff 		 */
16475748Sduboff 		OUTW(dp, 0x00cc, 0x0001);	/* PGSEL */
16485748Sduboff 		OUTW(dp, 0x00e4, 0x189c);	/* PMDCSR */
16495748Sduboff 		OUTW(dp, 0x00fc, 0x0000);	/* TSTDAT */
16505748Sduboff 		OUTW(dp, 0x00f4, 0x5040);	/* DSPCFG */
16515748Sduboff 		OUTW(dp, 0x00f8, 0x008c);	/* SDCFG */
1652*7116Sduboff 		OUTW(dp, 0x00cc, 0x0000);	/* PGSEL */
16535748Sduboff 
16545748Sduboff 		DPRINTF(0, (CE_CONT,
16555748Sduboff 		    CONS "%s: PHY patched %04x %04x %04x %04x %04x",
16565748Sduboff 		    dp->name,
16575748Sduboff 		    INW(dp, 0x00cc),	/* PGSEL */
16585748Sduboff 		    INW(dp, 0x00e4),	/* PMDCSR */
16595748Sduboff 		    INW(dp, 0x00fc),	/* TSTDAT */
16605748Sduboff 		    INW(dp, 0x00f4),	/* DSPCFG */
16615748Sduboff 		    INW(dp, 0x00f8)));	/* SDCFG */
1662*7116Sduboff 	} else if (((srr ^ SRR_REV_DP83815DVNG) & 0xff00) == 0 ||
1663*7116Sduboff 	    ((srr ^ SRR_REV_DP83816AVNG) & 0xff00) == 0) {
1664*7116Sduboff 		/*
1665*7116Sduboff 		 * Additional packets for later chipset
1666*7116Sduboff 		 */
1667*7116Sduboff 		OUTW(dp, 0x00cc, 0x0001);	/* PGSEL */
1668*7116Sduboff 		OUTW(dp, 0x00e4, 0x189c);	/* PMDCSR */
1669*7116Sduboff 		OUTW(dp, 0x00cc, 0x0000);	/* PGSEL */
1670*7116Sduboff 
1671*7116Sduboff 		DPRINTF(0, (CE_CONT,
1672*7116Sduboff 		    CONS "%s: PHY patched %04x %04x",
1673*7116Sduboff 		    dp->name,
1674*7116Sduboff 		    INW(dp, 0x00cc),	/* PGSEL */
1675*7116Sduboff 		    INW(dp, 0x00e4)));	/* PMDCSR */
16765748Sduboff 	}
16775748Sduboff 
16785748Sduboff 	return (gem_mii_config_default(dp));
16795748Sduboff }
16805748Sduboff 
1681*7116Sduboff static int
1682*7116Sduboff sfe_mii_probe_dp83815(struct gem_dev *dp)
1683*7116Sduboff {
1684*7116Sduboff 	uint32_t	val;
1685*7116Sduboff 
1686*7116Sduboff 	/* try external phy first */
1687*7116Sduboff 	DPRINTF(0, (CE_CONT, CONS "%s: %s: trying external phy",
1688*7116Sduboff 	    dp->name, __func__));
1689*7116Sduboff 	dp->mii_phy_addr = 0;
1690*7116Sduboff 	dp->gc.gc_mii_sync = &sfe_mii_sync_sis900;
1691*7116Sduboff 	dp->gc.gc_mii_read = &sfe_mii_read_sis900;
1692*7116Sduboff 	dp->gc.gc_mii_write = &sfe_mii_write_sis900;
1693*7116Sduboff 
1694*7116Sduboff 	val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG);
1695*7116Sduboff 	OUTL(dp, CFG, val | CFG_EXT_PHY | CFG_PHY_DIS);
1696*7116Sduboff 
1697*7116Sduboff 	if (gem_mii_probe_default(dp) == GEM_SUCCESS) {
1698*7116Sduboff 		return (GEM_SUCCESS);
1699*7116Sduboff 	}
1700*7116Sduboff 
1701*7116Sduboff 	/* switch to internal phy */
1702*7116Sduboff 	DPRINTF(0, (CE_CONT, CONS "%s: %s: switching to internal phy",
1703*7116Sduboff 	    dp->name, __func__));
1704*7116Sduboff 	dp->mii_phy_addr = -1;
1705*7116Sduboff 	dp->gc.gc_mii_sync = &sfe_mii_sync_dp83815;
1706*7116Sduboff 	dp->gc.gc_mii_read = &sfe_mii_read_dp83815;
1707*7116Sduboff 	dp->gc.gc_mii_write = &sfe_mii_write_dp83815;
1708*7116Sduboff 
1709*7116Sduboff 	val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG);
1710*7116Sduboff 	OUTL(dp, CFG, val | CFG_PAUSE_ADV | CFG_PHY_RST);
1711*7116Sduboff 	drv_usecwait(100);	/* keep to assert RST bit for a while */
1712*7116Sduboff 	OUTL(dp, CFG, val | CFG_PAUSE_ADV);
1713*7116Sduboff 
1714*7116Sduboff 	/* wait for PHY reset */
1715*7116Sduboff 	delay(drv_usectohz(10000));
1716*7116Sduboff 
1717*7116Sduboff 	return (gem_mii_probe_default(dp));
1718*7116Sduboff }
1719*7116Sduboff 
1720*7116Sduboff static int
1721*7116Sduboff sfe_mii_init_dp83815(struct gem_dev *dp)
1722*7116Sduboff {
1723*7116Sduboff 	uint32_t	val;
1724*7116Sduboff 
1725*7116Sduboff 	val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG);
1726*7116Sduboff 
1727*7116Sduboff 	if (dp->mii_phy_addr == -1) {
1728*7116Sduboff 		/* select internal phy */
1729*7116Sduboff 		OUTL(dp, CFG, val | CFG_PAUSE_ADV);
1730*7116Sduboff 	} else {
1731*7116Sduboff 		/* select external phy */
1732*7116Sduboff 		OUTL(dp, CFG, val | CFG_EXT_PHY | CFG_PHY_DIS);
1733*7116Sduboff 	}
1734*7116Sduboff 
1735*7116Sduboff 	return (GEM_SUCCESS);
1736*7116Sduboff }
17375748Sduboff 
17385748Sduboff /*
17395748Sduboff  * MII routines for SiS900
17405748Sduboff  */
1741*7116Sduboff #define	MDIO_DELAY(dp)	{(void) INL(dp, MEAR); (void) INL(dp, MEAR); }
17425748Sduboff static void
17435748Sduboff sfe_mii_sync_sis900(struct gem_dev *dp)
17445748Sduboff {
17455748Sduboff 	int	i;
17465748Sduboff 
1747*7116Sduboff 	/* send 32 ONE's to make MII line idle */
17485748Sduboff 	for (i = 0; i < 32; i++) {
17495748Sduboff 		OUTL(dp, MEAR, MEAR_MDDIR | MEAR_MDIO);
17505748Sduboff 		MDIO_DELAY(dp);
17515748Sduboff 		OUTL(dp, MEAR, MEAR_MDDIR | MEAR_MDIO | MEAR_MDC);
17525748Sduboff 		MDIO_DELAY(dp);
17535748Sduboff 	}
17545748Sduboff }
17555748Sduboff 
17565748Sduboff static int
17575748Sduboff sfe_mii_config_sis900(struct gem_dev *dp)
17585748Sduboff {
17595748Sduboff 	struct sfe_dev	*lp = dp->private;
17605748Sduboff 
17615748Sduboff 	/* Do chip depend setup */
17625748Sduboff 	if ((dp->mii_phy_id & PHY_MASK) == PHY_ICS1893) {
17635748Sduboff 		/* workaround for ICS1893 PHY */
17645748Sduboff 		gem_mii_write(dp, 0x0018, 0xD200);
17655748Sduboff 	}
17665748Sduboff 
17675748Sduboff 	if (lp->revid == SIS630E_900_REV) {
17685748Sduboff 		/*
17695748Sduboff 		 * SiS 630E has bugs on default values
17705748Sduboff 		 * of PHY registers
17715748Sduboff 		 */
17725748Sduboff 		gem_mii_write(dp, MII_AN_ADVERT, 0x05e1);
17735748Sduboff 		gem_mii_write(dp, MII_CONFIG1, 0x0022);
17745748Sduboff 		gem_mii_write(dp, MII_CONFIG2, 0xff00);
17755748Sduboff 		gem_mii_write(dp, MII_MASK,    0xffc0);
17765748Sduboff 	}
17775748Sduboff 	sfe_set_eq_sis630(dp);
17785748Sduboff 
17795748Sduboff 	return (gem_mii_config_default(dp));
17805748Sduboff }
17815748Sduboff 
17825748Sduboff static uint16_t
17835748Sduboff sfe_mii_read_sis900(struct gem_dev *dp, uint_t reg)
17845748Sduboff {
17855748Sduboff 	uint32_t	cmd;
17865748Sduboff 	uint16_t	ret;
17875748Sduboff 	int		i;
17885748Sduboff 	uint32_t	data;
17895748Sduboff 
17905748Sduboff 	cmd = MII_READ_CMD(dp->mii_phy_addr, reg);
17915748Sduboff 
17925748Sduboff 	for (i = 31; i >= 18; i--) {
17935748Sduboff 		data = ((cmd >> i) & 1) <<  MEAR_MDIO_SHIFT;
17945748Sduboff 		OUTL(dp, MEAR, data | MEAR_MDDIR);
17955748Sduboff 		MDIO_DELAY(dp);
17965748Sduboff 		OUTL(dp, MEAR, data | MEAR_MDDIR | MEAR_MDC);
17975748Sduboff 		MDIO_DELAY(dp);
17985748Sduboff 	}
17995748Sduboff 
18005748Sduboff 	/* turn around cycle */
1801*7116Sduboff 	OUTL(dp, MEAR, 0);
18025748Sduboff 	MDIO_DELAY(dp);
18035748Sduboff 
18045748Sduboff 	/* get response from PHY */
18055748Sduboff 	OUTL(dp, MEAR, MEAR_MDC);
18065748Sduboff 	MDIO_DELAY(dp);
1807*7116Sduboff 
18085748Sduboff 	OUTL(dp, MEAR, 0);
18095748Sduboff #if DEBUG_LEBEL > 0
1810*7116Sduboff 	(void) INL(dp, MEAR);	/* delay */
18115748Sduboff 	if (INL(dp, MEAR) & MEAR_MDIO) {
18125748Sduboff 		cmn_err(CE_WARN, "%s: PHY@%d not responded",
18135748Sduboff 		    dp->name, dp->mii_phy_addr);
18145748Sduboff 	}
1815*7116Sduboff #else
1816*7116Sduboff 	MDIO_DELAY(dp);
18175748Sduboff #endif
18185748Sduboff 	/* terminate response cycle */
18195748Sduboff 	OUTL(dp, MEAR, MEAR_MDC);
1820*7116Sduboff 	MDIO_DELAY(dp);
18215748Sduboff 
18225748Sduboff 	ret = 0;	/* to avoid lint errors */
18235748Sduboff 	for (i = 16; i > 0; i--) {
18245748Sduboff 		OUTL(dp, MEAR, 0);
1825*7116Sduboff 		(void) INL(dp, MEAR);	/* delay */
18265748Sduboff 		ret = (ret << 1) | ((INL(dp, MEAR) >> MEAR_MDIO_SHIFT) & 1);
18275748Sduboff 		OUTL(dp, MEAR, MEAR_MDC);
18285748Sduboff 		MDIO_DELAY(dp);
18295748Sduboff 	}
18305748Sduboff 
1831*7116Sduboff 	/* send two idle(Z) bits to terminate the read cycle */
1832*7116Sduboff 	for (i = 0; i < 2; i++) {
1833*7116Sduboff 		OUTL(dp, MEAR, 0);
1834*7116Sduboff 		MDIO_DELAY(dp);
1835*7116Sduboff 		OUTL(dp, MEAR, MEAR_MDC);
1836*7116Sduboff 		MDIO_DELAY(dp);
1837*7116Sduboff 	}
18385748Sduboff 
18395748Sduboff 	return (ret);
18405748Sduboff }
18415748Sduboff 
18425748Sduboff static void
18435748Sduboff sfe_mii_write_sis900(struct gem_dev *dp, uint_t reg, uint16_t val)
18445748Sduboff {
18455748Sduboff 	uint32_t	cmd;
18465748Sduboff 	int		i;
18475748Sduboff 	uint32_t	data;
18485748Sduboff 
18495748Sduboff 	cmd = MII_WRITE_CMD(dp->mii_phy_addr, reg, val);
18505748Sduboff 
18515748Sduboff 	for (i = 31; i >= 0; i--) {
18525748Sduboff 		data = ((cmd >> i) & 1) << MEAR_MDIO_SHIFT;
18535748Sduboff 		OUTL(dp, MEAR, data | MEAR_MDDIR);
18545748Sduboff 		MDIO_DELAY(dp);
18555748Sduboff 		OUTL(dp, MEAR, data | MEAR_MDDIR | MEAR_MDC);
18565748Sduboff 		MDIO_DELAY(dp);
18575748Sduboff 	}
18585748Sduboff 
1859*7116Sduboff 	/* send two idle(Z) bits to terminate the write cycle. */
18605748Sduboff 	for (i = 0; i < 2; i++) {
1861*7116Sduboff 		OUTL(dp, MEAR, 0);
18625748Sduboff 		MDIO_DELAY(dp);
1863*7116Sduboff 		OUTL(dp, MEAR, MEAR_MDC);
18645748Sduboff 		MDIO_DELAY(dp);
18655748Sduboff 	}
18665748Sduboff }
18675748Sduboff #undef MDIO_DELAY
18685748Sduboff 
18695748Sduboff static void
18705748Sduboff sfe_set_eq_sis630(struct gem_dev *dp)
18715748Sduboff {
18725748Sduboff 	uint16_t	reg14h;
18735748Sduboff 	uint16_t	eq_value;
18745748Sduboff 	uint16_t	max_value;
18755748Sduboff 	uint16_t	min_value;
18765748Sduboff 	int		i;
18775748Sduboff 	uint8_t		rev;
18785748Sduboff 	struct sfe_dev	*lp = dp->private;
18795748Sduboff 
18805748Sduboff 	rev = lp->revid;
18815748Sduboff 
18825748Sduboff 	if (!(rev == SIS630E_900_REV || rev == SIS630EA1_900_REV ||
18835748Sduboff 	    rev == SIS630A_900_REV || rev == SIS630ET_900_REV)) {
18845748Sduboff 		/* it doesn't have a internal PHY */
18855748Sduboff 		return;
18865748Sduboff 	}
18875748Sduboff 
18885748Sduboff 	if (dp->mii_state == MII_STATE_LINKUP) {
18895748Sduboff 		reg14h = gem_mii_read(dp, MII_RESV);
18905748Sduboff 		gem_mii_write(dp, MII_RESV, (0x2200 | reg14h) & 0xBFFF);
18915748Sduboff 
18925748Sduboff 		eq_value = (0x00f8 & gem_mii_read(dp, MII_RESV)) >> 3;
18935748Sduboff 		max_value = min_value = eq_value;
18945748Sduboff 		for (i = 1; i < 10; i++) {
18955748Sduboff 			eq_value = (0x00f8 & gem_mii_read(dp, MII_RESV)) >> 3;
18965748Sduboff 			max_value = max(eq_value, max_value);
18975748Sduboff 			min_value = min(eq_value, min_value);
18985748Sduboff 		}
18995748Sduboff 
19005748Sduboff 		/* for 630E, rule to determine the equalizer value */
19015748Sduboff 		if (rev == SIS630E_900_REV || rev == SIS630EA1_900_REV ||
19025748Sduboff 		    rev == SIS630ET_900_REV) {
19035748Sduboff 			if (max_value < 5) {
19045748Sduboff 				eq_value = max_value;
19055748Sduboff 			} else if (5 <= max_value && max_value < 15) {
19065748Sduboff 				eq_value =
19075748Sduboff 				    max(max_value + 1,
19085748Sduboff 				    min_value + 2);
19095748Sduboff 			} else if (15 <= max_value) {
19105748Sduboff 				eq_value =
19115748Sduboff 				    max(max_value + 5,
19125748Sduboff 				    min_value + 6);
19135748Sduboff 			}
19145748Sduboff 		}
19155748Sduboff 		/* for 630B0&B1, rule to determine the equalizer value */
19165748Sduboff 		else
19175748Sduboff 		if (rev == SIS630A_900_REV &&
19185748Sduboff 		    (lp->bridge_revid == SIS630B0 ||
19195748Sduboff 		    lp->bridge_revid == SIS630B1)) {
19205748Sduboff 
19215748Sduboff 			if (max_value == 0) {
19225748Sduboff 				eq_value = 3;
19235748Sduboff 			} else {
19245748Sduboff 				eq_value = (max_value + min_value + 1)/2;
19255748Sduboff 			}
19265748Sduboff 		}
19275748Sduboff 		/* write equalizer value and setting */
19285748Sduboff 		reg14h = gem_mii_read(dp, MII_RESV) & ~0x02f8;
19295748Sduboff 		reg14h |= 0x6000 | (eq_value << 3);
19305748Sduboff 		gem_mii_write(dp, MII_RESV, reg14h);
19315748Sduboff 	} else {
19325748Sduboff 		reg14h = (gem_mii_read(dp, MII_RESV) & ~0x4000) | 0x2000;
19335748Sduboff 		if (rev == SIS630A_900_REV &&
19345748Sduboff 		    (lp->bridge_revid == SIS630B0 ||
19355748Sduboff 		    lp->bridge_revid == SIS630B1)) {
19365748Sduboff 
19375748Sduboff 			reg14h |= 0x0200;
19385748Sduboff 		}
19395748Sduboff 		gem_mii_write(dp, MII_RESV, reg14h);
19405748Sduboff 	}
19415748Sduboff }
19425748Sduboff 
19435748Sduboff /* ======================================================== */
19445748Sduboff /*
19455748Sduboff  * OS depend (device driver) routine
19465748Sduboff  */
19475748Sduboff /* ======================================================== */
19485748Sduboff static void
19495748Sduboff sfe_chipinfo_init_sis900(struct gem_dev *dp)
19505748Sduboff {
19515748Sduboff 	int		rev;
19525748Sduboff 	struct sfe_dev	*lp = (struct sfe_dev *)dp->private;
19535748Sduboff 
19545748Sduboff 	rev = lp->revid;
19555748Sduboff 
19565748Sduboff 	if (rev == SIS630E_900_REV /* 0x81 */) {
19575748Sduboff 		/* sis630E */
19585748Sduboff 		lp->get_mac_addr = &sfe_get_mac_addr_sis630e;
19595748Sduboff 	} else if (rev > 0x81 && rev <= 0x90) {
19605748Sduboff 		/* 630S, 630EA1, 630ET, 635A */
19615748Sduboff 		lp->get_mac_addr = &sfe_get_mac_addr_sis635;
19625748Sduboff 	} else if (rev == SIS962_900_REV /* 0x91 */) {
19635748Sduboff 		/* sis962 or later */
19645748Sduboff 		lp->get_mac_addr = &sfe_get_mac_addr_sis962;
19655748Sduboff 	} else {
19665748Sduboff 		/* sis900 */
19675748Sduboff 		lp->get_mac_addr = &sfe_get_mac_addr_sis900;
19685748Sduboff 	}
19695748Sduboff 
19705748Sduboff 	lp->bridge_revid = 0;
19715748Sduboff 
19725748Sduboff 	if (rev == SIS630E_900_REV || rev == SIS630EA1_900_REV ||
19735748Sduboff 	    rev == SIS630A_900_REV || rev ==  SIS630ET_900_REV) {
19745748Sduboff 		/*
19755748Sduboff 		 * read host bridge revision
19765748Sduboff 		 */
19775748Sduboff 		dev_info_t	*bridge;
19785748Sduboff 		ddi_acc_handle_t bridge_handle;
19795748Sduboff 
19805748Sduboff 		if ((bridge = sfe_search_pci_dev(0x1039, 0x630)) == NULL) {
19815748Sduboff 			cmn_err(CE_WARN,
19825748Sduboff 			    "%s: cannot find host bridge (pci1039,630)",
19835748Sduboff 			    dp->name);
19845748Sduboff 			return;
19855748Sduboff 		}
19865748Sduboff 
19875748Sduboff 		if (pci_config_setup(bridge, &bridge_handle) != DDI_SUCCESS) {
19885748Sduboff 			cmn_err(CE_WARN, "%s: pci_config_setup failed",
19895748Sduboff 			    dp->name);
19905748Sduboff 			return;
19915748Sduboff 		}
19925748Sduboff 
19935748Sduboff 		lp->bridge_revid =
19945748Sduboff 		    pci_config_get8(bridge_handle, PCI_CONF_REVID);
19955748Sduboff 		pci_config_teardown(&bridge_handle);
19965748Sduboff 	}
19975748Sduboff }
19985748Sduboff 
19995748Sduboff static int
20005748Sduboff sfe_attach_chip(struct gem_dev *dp)
20015748Sduboff {
20025748Sduboff 	struct sfe_dev		*lp = (struct sfe_dev *)dp->private;
20035748Sduboff 
20045748Sduboff 	DPRINTF(4, (CE_CONT, CONS "!%s: %s called", dp->name, __func__));
20055748Sduboff 
20065748Sduboff 	/* setup chip-depend get_mac_address function */
20075748Sduboff 	if (lp->chip->chip_type == CHIPTYPE_SIS900) {
20085748Sduboff 		sfe_chipinfo_init_sis900(dp);
20095748Sduboff 	} else {
20105748Sduboff 		lp->get_mac_addr = &sfe_get_mac_addr_dp83815;
20115748Sduboff 	}
20125748Sduboff 
20135748Sduboff 	/* read MAC address */
20145748Sduboff 	if (!(lp->get_mac_addr)(dp)) {
20155748Sduboff 		cmn_err(CE_WARN,
20165748Sduboff 		    "!%s: %s: failed to get factory mac address"
20175748Sduboff 		    " please specify a mac address in sfe.conf",
20185748Sduboff 		    dp->name, __func__);
20195748Sduboff 		return (GEM_FAILURE);
20205748Sduboff 	}
20215748Sduboff 
20225748Sduboff 	if (lp->chip->chip_type == CHIPTYPE_DP83815) {
20235748Sduboff 		dp->mii_phy_addr = -1;	/* no need to scan PHY */
20245748Sduboff 		dp->misc_flag |= GEM_VLAN_SOFT;
20255748Sduboff 		dp->txthr += 4; /* VTAG_SIZE */
20265748Sduboff 	}
20275748Sduboff 	dp->txthr = min(dp->txthr, TXFIFOSIZE - 2);
20285748Sduboff 
20295748Sduboff 	return (GEM_SUCCESS);
20305748Sduboff }
20315748Sduboff 
20325748Sduboff static int
20335748Sduboff sfeattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
20345748Sduboff {
20355748Sduboff 	int			unit;
20365748Sduboff 	const char		*drv_name;
20375748Sduboff 	int			i;
20385748Sduboff 	ddi_acc_handle_t	conf_handle;
20395748Sduboff 	uint16_t		vid;
20405748Sduboff 	uint16_t		did;
20415748Sduboff 	uint8_t			rev;
20425748Sduboff #ifdef DEBUG_LEVEL
20435748Sduboff 	uint32_t		iline;
20445748Sduboff 	uint8_t			latim;
20455748Sduboff #endif
20465748Sduboff 	struct chip_info	*p;
20475748Sduboff 	struct gem_dev		*dp;
20485748Sduboff 	struct sfe_dev		*lp;
20495748Sduboff 	caddr_t			base;
20505748Sduboff 	ddi_acc_handle_t	regs_ha;
20515748Sduboff 	struct gem_conf		*gcp;
20525748Sduboff 
20535748Sduboff 	unit = ddi_get_instance(dip);
20545748Sduboff 	drv_name = ddi_driver_name(dip);
20555748Sduboff 
20565748Sduboff 	DPRINTF(3, (CE_CONT, CONS "%s%d: sfeattach: called", drv_name, unit));
20575748Sduboff 
20585748Sduboff 	/*
20595748Sduboff 	 * Common codes after power-up
20605748Sduboff 	 */
20615748Sduboff 	if (pci_config_setup(dip, &conf_handle) != DDI_SUCCESS) {
20625748Sduboff 		cmn_err(CE_WARN, "%s%d: ddi_regs_map_setup failed",
20635748Sduboff 		    drv_name, unit);
20645748Sduboff 		goto err;
20655748Sduboff 	}
20665748Sduboff 
20675748Sduboff 	vid  = pci_config_get16(conf_handle, PCI_CONF_VENID);
20685748Sduboff 	did  = pci_config_get16(conf_handle, PCI_CONF_DEVID);
20695748Sduboff 	rev  = pci_config_get16(conf_handle, PCI_CONF_REVID);
20705748Sduboff #ifdef DEBUG_LEVEL
2071*7116Sduboff 	iline = pci_config_get32(conf_handle, PCI_CONF_ILINE);
2072*7116Sduboff 	latim = pci_config_get8(conf_handle, PCI_CONF_LATENCY_TIMER);
20735748Sduboff #endif
20745748Sduboff #ifdef DEBUG_BUILT_IN_SIS900
20755748Sduboff 	rev  = SIS630E_900_REV;
20765748Sduboff #endif
20775748Sduboff 	for (i = 0, p = sfe_chiptbl; i < CHIPTABLESIZE; i++, p++) {
20785748Sduboff 		if (p->venid == vid && p->devid == did) {
20795748Sduboff 			/* found */
20805748Sduboff 			goto chip_found;
20815748Sduboff 		}
20825748Sduboff 	}
20835748Sduboff 
20845748Sduboff 	/* Not found */
20855748Sduboff 	cmn_err(CE_WARN,
20865748Sduboff 	    "%s%d: sfe_attach: wrong PCI venid/devid (0x%x, 0x%x)",
20875748Sduboff 	    drv_name, unit, vid, did);
20885748Sduboff 	pci_config_teardown(&conf_handle);
20895748Sduboff 	goto err;
20905748Sduboff 
20915748Sduboff chip_found:
20925748Sduboff 	pci_config_put16(conf_handle, PCI_CONF_COMM,
20935748Sduboff 	    PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME |
20945748Sduboff 	    pci_config_get16(conf_handle, PCI_CONF_COMM));
20955748Sduboff 
20965748Sduboff 	/* ensure D0 mode */
20975748Sduboff 	(void) gem_pci_set_power_state(dip, conf_handle, PCI_PMCSR_D0);
20985748Sduboff 
20995748Sduboff 	pci_config_teardown(&conf_handle);
21005748Sduboff 
21015748Sduboff 	switch (cmd) {
21025748Sduboff 	case DDI_RESUME:
21035748Sduboff 		return (gem_resume(dip));
21045748Sduboff 
21055748Sduboff 	case DDI_ATTACH:
21065748Sduboff 
21075748Sduboff 		DPRINTF(0, (CE_CONT,
21085748Sduboff 		    CONS "%s%d: ilr 0x%08x, latency_timer:0x%02x",
21095748Sduboff 		    drv_name, unit, iline, latim));
21105748Sduboff 
21115748Sduboff 		/*
21125748Sduboff 		 * Map in the device registers.
21135748Sduboff 		 */
21145748Sduboff 		if (gem_pci_regs_map_setup(dip,
21155748Sduboff 		    (sfe_use_pcimemspace && p->chip_type == CHIPTYPE_DP83815)
21165748Sduboff 		    ? PCI_ADDR_MEM32 : PCI_ADDR_IO, PCI_ADDR_MASK,
21175748Sduboff 		    &sfe_dev_attr, &base, &regs_ha) != DDI_SUCCESS) {
21185748Sduboff 			cmn_err(CE_WARN,
21195748Sduboff 			    "%s%d: ddi_regs_map_setup failed",
21205748Sduboff 			    drv_name, unit);
21215748Sduboff 			goto err;
21225748Sduboff 		}
21235748Sduboff 
21245748Sduboff 		/*
21255748Sduboff 		 * construct gem configuration
21265748Sduboff 		 */
21275748Sduboff 		gcp = kmem_zalloc(sizeof (*gcp), KM_SLEEP);
21285748Sduboff 
21295748Sduboff 		/* name */
21305748Sduboff 		(void) sprintf(gcp->gc_name, "%s%d", drv_name, unit);
21315748Sduboff 
21325748Sduboff 		/* consistency on tx and rx */
21335748Sduboff 		gcp->gc_tx_buf_align = sizeof (uint8_t) - 1;
21345748Sduboff 		gcp->gc_tx_max_frags = MAXTXFRAGS;
21355748Sduboff 		gcp->gc_tx_max_descs_per_pkt = gcp->gc_tx_max_frags;
21365748Sduboff 		gcp->gc_tx_desc_unit_shift = 4;	/* 16 byte */
21375748Sduboff 		gcp->gc_tx_buf_size  = TX_BUF_SIZE;
21385748Sduboff 		gcp->gc_tx_buf_limit = gcp->gc_tx_buf_size;
21395748Sduboff 		gcp->gc_tx_ring_size = TX_RING_SIZE;
21405748Sduboff 		gcp->gc_tx_ring_limit = gcp->gc_tx_ring_size;
21415748Sduboff 		gcp->gc_tx_auto_pad  = B_TRUE;
21425748Sduboff 		gcp->gc_tx_copy_thresh = sfe_tx_copy_thresh;
21435748Sduboff 		gcp->gc_tx_desc_write_oo = B_TRUE;
21445748Sduboff 
21455748Sduboff 		gcp->gc_rx_buf_align = sizeof (uint8_t) - 1;
21465748Sduboff 		gcp->gc_rx_max_frags = MAXRXFRAGS;
21475748Sduboff 		gcp->gc_rx_desc_unit_shift = 4;
21485748Sduboff 		gcp->gc_rx_ring_size = RX_RING_SIZE;
21495748Sduboff 		gcp->gc_rx_buf_max   = RX_BUF_SIZE;
21505748Sduboff 		gcp->gc_rx_copy_thresh = sfe_rx_copy_thresh;
21515748Sduboff 
21525748Sduboff 		/* map attributes */
21535748Sduboff 		gcp->gc_dev_attr = sfe_dev_attr;
21545748Sduboff 		gcp->gc_buf_attr = sfe_buf_attr;
21555748Sduboff 		gcp->gc_desc_attr = sfe_buf_attr;
21565748Sduboff 
21575748Sduboff 		/* dma attributes */
21585748Sduboff 		gcp->gc_dma_attr_desc = sfe_dma_attr_desc;
21595748Sduboff 
21605748Sduboff 		gcp->gc_dma_attr_txbuf = sfe_dma_attr_buf;
21615748Sduboff 		gcp->gc_dma_attr_txbuf.dma_attr_align = gcp->gc_tx_buf_align+1;
21625748Sduboff 		gcp->gc_dma_attr_txbuf.dma_attr_sgllen = gcp->gc_tx_max_frags;
21635748Sduboff 
21645748Sduboff 		gcp->gc_dma_attr_rxbuf = sfe_dma_attr_buf;
21655748Sduboff 		gcp->gc_dma_attr_rxbuf.dma_attr_align = gcp->gc_rx_buf_align+1;
21665748Sduboff 		gcp->gc_dma_attr_rxbuf.dma_attr_sgllen = gcp->gc_rx_max_frags;
21675748Sduboff 
21685748Sduboff 		/* time out parameters */
21695748Sduboff 		gcp->gc_tx_timeout = 3*ONESEC;
21705748Sduboff 		gcp->gc_tx_timeout_interval = ONESEC;
2171*7116Sduboff 		if (p->chip_type == CHIPTYPE_DP83815) {
2172*7116Sduboff 			/* workaround for tx hang */
2173*7116Sduboff 			gcp->gc_tx_timeout_interval = ONESEC/20; /* 50mS */
2174*7116Sduboff 		}
21755748Sduboff 
21765748Sduboff 		/* MII timeout parameters */
21775748Sduboff 		gcp->gc_mii_link_watch_interval = ONESEC;
21785748Sduboff 		gcp->gc_mii_an_watch_interval   = ONESEC/5;
21795748Sduboff 		gcp->gc_mii_reset_timeout = MII_RESET_TIMEOUT;	/* 1 sec */
21805748Sduboff 		gcp->gc_mii_an_timeout = MII_AN_TIMEOUT;	/* 5 sec */
21815748Sduboff 		gcp->gc_mii_an_wait = 0;
21825748Sduboff 		gcp->gc_mii_linkdown_timeout = MII_LINKDOWN_TIMEOUT;
21835748Sduboff 
21845748Sduboff 		/* setting for general PHY */
21855748Sduboff 		gcp->gc_mii_an_delay = 0;
21865748Sduboff 		gcp->gc_mii_linkdown_action = MII_ACTION_RSA;
21875748Sduboff 		gcp->gc_mii_linkdown_timeout_action = MII_ACTION_RESET;
21885748Sduboff 		gcp->gc_mii_dont_reset = B_FALSE;
21895748Sduboff 
21905748Sduboff 
21915748Sduboff 		/* I/O methods */
21925748Sduboff 
21935748Sduboff 		/* mac operation */
21945748Sduboff 		gcp->gc_attach_chip = &sfe_attach_chip;
21955748Sduboff 		if (p->chip_type == CHIPTYPE_DP83815) {
21965748Sduboff 			gcp->gc_reset_chip = &sfe_reset_chip_dp83815;
21975748Sduboff 		} else {
21985748Sduboff 			gcp->gc_reset_chip = &sfe_reset_chip_sis900;
21995748Sduboff 		}
22005748Sduboff 		gcp->gc_init_chip  = &sfe_init_chip;
22015748Sduboff 		gcp->gc_start_chip = &sfe_start_chip;
22025748Sduboff 		gcp->gc_stop_chip  = &sfe_stop_chip;
22035748Sduboff #ifdef USE_MULTICAST_HASHTBL
22045748Sduboff 		gcp->gc_multicast_hash = &sfe_mcast_hash;
22055748Sduboff #endif
22065748Sduboff 		if (p->chip_type == CHIPTYPE_DP83815) {
22075748Sduboff 			gcp->gc_set_rx_filter = &sfe_set_rx_filter_dp83815;
22085748Sduboff 		} else {
22095748Sduboff 			gcp->gc_set_rx_filter = &sfe_set_rx_filter_sis900;
22105748Sduboff 		}
22115748Sduboff 		gcp->gc_set_media = &sfe_set_media;
22125748Sduboff 		gcp->gc_get_stats = &sfe_get_stats;
22135748Sduboff 		gcp->gc_interrupt = &sfe_interrupt;
22145748Sduboff 
22155748Sduboff 		/* descriptor operation */
22165748Sduboff 		gcp->gc_tx_desc_write = &sfe_tx_desc_write;
22175748Sduboff 		gcp->gc_tx_start = &sfe_tx_start;
22185748Sduboff 		gcp->gc_rx_desc_write = &sfe_rx_desc_write;
22195748Sduboff 		gcp->gc_rx_start = NULL;
22205748Sduboff 
22215748Sduboff 		gcp->gc_tx_desc_stat = &sfe_tx_desc_stat;
22225748Sduboff 		gcp->gc_rx_desc_stat = &sfe_rx_desc_stat;
22235748Sduboff 		gcp->gc_tx_desc_init = &sfe_tx_desc_init;
22245748Sduboff 		gcp->gc_rx_desc_init = &sfe_rx_desc_init;
22255748Sduboff 		gcp->gc_tx_desc_clean = &sfe_tx_desc_clean;
22265748Sduboff 		gcp->gc_rx_desc_clean = &sfe_rx_desc_clean;
22275748Sduboff 
22285748Sduboff 		/* mii operations */
22295748Sduboff 		if (p->chip_type == CHIPTYPE_DP83815) {
2230*7116Sduboff 			gcp->gc_mii_probe = &sfe_mii_probe_dp83815;
2231*7116Sduboff 			gcp->gc_mii_init = &sfe_mii_init_dp83815;
22325748Sduboff 			gcp->gc_mii_config = &sfe_mii_config_dp83815;
22335748Sduboff 			gcp->gc_mii_sync = &sfe_mii_sync_dp83815;
22345748Sduboff 			gcp->gc_mii_read = &sfe_mii_read_dp83815;
22355748Sduboff 			gcp->gc_mii_write = &sfe_mii_write_dp83815;
22365748Sduboff 			gcp->gc_mii_tune_phy = NULL;
22375748Sduboff 			gcp->gc_flow_control = FLOW_CONTROL_NONE;
22385748Sduboff 		} else {
22395748Sduboff 			gcp->gc_mii_probe = &gem_mii_probe_default;
22405748Sduboff 			gcp->gc_mii_init = NULL;
22415748Sduboff 			gcp->gc_mii_config = &sfe_mii_config_sis900;
22425748Sduboff 			gcp->gc_mii_sync = &sfe_mii_sync_sis900;
22435748Sduboff 			gcp->gc_mii_read = &sfe_mii_read_sis900;
22445748Sduboff 			gcp->gc_mii_write = &sfe_mii_write_sis900;
22455748Sduboff 			gcp->gc_mii_tune_phy = &sfe_set_eq_sis630;
22465748Sduboff 			gcp->gc_flow_control = FLOW_CONTROL_RX_PAUSE;
22475748Sduboff 		}
22485748Sduboff 
22495748Sduboff 		lp = kmem_zalloc(sizeof (*lp), KM_SLEEP);
22505748Sduboff 		lp->chip = p;
22515748Sduboff 		lp->revid = rev;
2252*7116Sduboff 		lp->our_intr_bits = 0;
2253*7116Sduboff 		lp->isr_pended = 0;
22545748Sduboff 
22555748Sduboff 		cmn_err(CE_CONT, CONS "%s%d: chip:%s rev:0x%02x",
22565748Sduboff 		    drv_name, unit, p->chip_name, rev);
22575748Sduboff 
22585748Sduboff 		dp = gem_do_attach(dip, 0, gcp, base, &regs_ha,
22595748Sduboff 		    lp, sizeof (*lp));
22605748Sduboff 		kmem_free(gcp, sizeof (*gcp));
22615748Sduboff 
22625748Sduboff 		if (dp == NULL) {
22635748Sduboff 			goto err_freelp;
22645748Sduboff 		}
22655748Sduboff 
22665748Sduboff 		return (DDI_SUCCESS);
22675748Sduboff 
22685748Sduboff err_freelp:
22695748Sduboff 		kmem_free(lp, sizeof (struct sfe_dev));
22705748Sduboff err:
22715748Sduboff 		return (DDI_FAILURE);
22725748Sduboff 	}
22735748Sduboff 	return (DDI_FAILURE);
22745748Sduboff }
22755748Sduboff 
22765748Sduboff static int
22775748Sduboff sfedetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
22785748Sduboff {
22795748Sduboff 	switch (cmd) {
22805748Sduboff 	case DDI_SUSPEND:
22815748Sduboff 		return (gem_suspend(dip));
22825748Sduboff 
22835748Sduboff 	case DDI_DETACH:
22845748Sduboff 		return (gem_do_detach(dip));
22855748Sduboff 	}
22865748Sduboff 	return (DDI_FAILURE);
22875748Sduboff }
22885748Sduboff 
22895748Sduboff /* ======================================================== */
22905748Sduboff /*
22915748Sduboff  * OS depend (loadable streams driver) routine
22925748Sduboff  */
22935748Sduboff /* ======================================================== */
22945748Sduboff DDI_DEFINE_STREAM_OPS(sfe_ops, nulldev, nulldev, sfeattach, sfedetach,
22955748Sduboff     nodev, NULL, D_MP, NULL);
22965748Sduboff 
22975748Sduboff static struct modldrv modldrv = {
22985748Sduboff 	&mod_driverops,	/* Type of module.  This one is a driver */
22995748Sduboff 	ident,
23005748Sduboff 	&sfe_ops,	/* driver ops */
23015748Sduboff };
23025748Sduboff 
23035748Sduboff static struct modlinkage modlinkage = {
23045748Sduboff 	MODREV_1, &modldrv, NULL
23055748Sduboff };
23065748Sduboff 
23075748Sduboff /* ======================================================== */
23085748Sduboff /*
23095748Sduboff  * Loadable module support
23105748Sduboff  */
23115748Sduboff /* ======================================================== */
23125748Sduboff int
23135748Sduboff _init(void)
23145748Sduboff {
23155748Sduboff 	int 	status;
23165748Sduboff 
23175748Sduboff 	DPRINTF(2, (CE_CONT, CONS "sfe: _init: called"));
23185748Sduboff 	gem_mod_init(&sfe_ops, "sfe");
23195748Sduboff 	status = mod_install(&modlinkage);
23205748Sduboff 	if (status != DDI_SUCCESS) {
23215748Sduboff 		gem_mod_fini(&sfe_ops);
23225748Sduboff 	}
23235748Sduboff 	return (status);
23245748Sduboff }
23255748Sduboff 
23265748Sduboff /*
23275748Sduboff  * _fini : done
23285748Sduboff  */
23295748Sduboff int
23305748Sduboff _fini(void)
23315748Sduboff {
23325748Sduboff 	int	status;
23335748Sduboff 
23345748Sduboff 	DPRINTF(2, (CE_CONT, CONS "sfe: _fini: called"));
23355748Sduboff 	status = mod_remove(&modlinkage);
23365748Sduboff 	if (status == DDI_SUCCESS) {
23375748Sduboff 		gem_mod_fini(&sfe_ops);
23385748Sduboff 	}
23395748Sduboff 	return (status);
23405748Sduboff }
23415748Sduboff 
23425748Sduboff int
23435748Sduboff _info(struct modinfo *modinfop)
23445748Sduboff {
23455748Sduboff 	return (mod_info(&modlinkage, modinfop));
23465748Sduboff }
2347