xref: /onnv-gate/usr/src/uts/common/io/sfe/sfe.c (revision 9694:78fafb281255)
15748Sduboff /*
25748Sduboff  *  sfe.c : DP83815/DP83816/SiS900 Fast Ethernet MAC driver for Solaris
35748Sduboff  *
47116Sduboff  * 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 
34*9694SScott.Rotondo@Sun.COM /* Avoid undefined symbol for non IA architectures */
35*9694SScott.Rotondo@Sun.COM #pragma weak	inb
36*9694SScott.Rotondo@Sun.COM #pragma weak	outb
37*9694SScott.Rotondo@Sun.COM 
387656SSherry.Moore@Sun.COM /*
398611SSherry.Moore@Sun.COM  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
407656SSherry.Moore@Sun.COM  * Use is subject to license terms.
417656SSherry.Moore@Sun.COM  */
425748Sduboff 
435748Sduboff /*
445748Sduboff  * System Header files.
455748Sduboff  */
465748Sduboff #include <sys/types.h>
475748Sduboff #include <sys/conf.h>
485748Sduboff #include <sys/debug.h>
495748Sduboff #include <sys/kmem.h>
505748Sduboff #include <sys/modctl.h>
515748Sduboff #include <sys/errno.h>
525748Sduboff #include <sys/ddi.h>
535748Sduboff #include <sys/sunddi.h>
545748Sduboff #include <sys/byteorder.h>
555748Sduboff #include <sys/ethernet.h>
565748Sduboff #include <sys/pci.h>
575748Sduboff 
585748Sduboff #include "sfe_mii.h"
595748Sduboff #include "sfe_util.h"
605748Sduboff #include "sfereg.h"
615748Sduboff 
628611SSherry.Moore@Sun.COM char	ident[] = "sis900/dp83815 driver v" "2.6.1t30os";
635748Sduboff 
645748Sduboff /* Debugging support */
655748Sduboff #ifdef DEBUG_LEVEL
665748Sduboff static int sfe_debug = DEBUG_LEVEL;
675748Sduboff #if DEBUG_LEVEL > 4
685748Sduboff #define	CONS	"^"
695748Sduboff #else
705748Sduboff #define	CONS	"!"
715748Sduboff #endif
725748Sduboff #define	DPRINTF(n, args)	if (sfe_debug > (n)) cmn_err args
735748Sduboff #else
745748Sduboff #define	CONS	"!"
755748Sduboff #define	DPRINTF(n, args)
765748Sduboff #endif
775748Sduboff 
785748Sduboff /*
795748Sduboff  * Useful macros and typedefs
805748Sduboff  */
815748Sduboff #define	ONESEC		(drv_usectohz(1*1000000))
825748Sduboff #define	ROUNDUP2(x, a)	(((x) + (a) - 1) & ~((a) - 1))
835748Sduboff 
845748Sduboff /*
855748Sduboff  * Our configuration
865748Sduboff  */
875748Sduboff #define	MAXTXFRAGS	1
885748Sduboff #define	MAXRXFRAGS	1
895748Sduboff 
905748Sduboff #ifndef	TX_BUF_SIZE
915748Sduboff #define	TX_BUF_SIZE	64
925748Sduboff #endif
935748Sduboff #ifndef	TX_RING_SIZE
945748Sduboff #if MAXTXFRAGS == 1
955748Sduboff #define	TX_RING_SIZE	TX_BUF_SIZE
965748Sduboff #else
975748Sduboff #define	TX_RING_SIZE	(TX_BUF_SIZE * 4)
985748Sduboff #endif
995748Sduboff #endif
1005748Sduboff 
1015748Sduboff #ifndef	RX_BUF_SIZE
1025748Sduboff #define	RX_BUF_SIZE	256
1035748Sduboff #endif
1045748Sduboff #ifndef	RX_RING_SIZE
1055748Sduboff #define	RX_RING_SIZE	RX_BUF_SIZE
1065748Sduboff #endif
1075748Sduboff 
1085748Sduboff #define	OUR_INTR_BITS	\
1095748Sduboff 	(ISR_DPERR | ISR_SSERR | ISR_RMABT | ISR_RTABT | ISR_RXSOVR |	\
1105748Sduboff 	ISR_TXURN | ISR_TXDESC | ISR_TXERR |	\
1115748Sduboff 	ISR_RXORN | ISR_RXIDLE | ISR_RXOK | ISR_RXERR)
1125748Sduboff 
1135748Sduboff #define	USE_MULTICAST_HASHTBL
1145748Sduboff 
1155748Sduboff static int	sfe_tx_copy_thresh = 256;
1165748Sduboff static int	sfe_rx_copy_thresh = 256;
1175748Sduboff 
1185748Sduboff /* special PHY registers for SIS900 */
1195748Sduboff #define	MII_CONFIG1	0x0010
1205748Sduboff #define	MII_CONFIG2	0x0011
1215748Sduboff #define	MII_MASK	0x0013
1225748Sduboff #define	MII_RESV	0x0014
1235748Sduboff 
1245748Sduboff #define	PHY_MASK		0xfffffff0
1255748Sduboff #define	PHY_SIS900_INTERNAL	0x001d8000
1265748Sduboff #define	PHY_ICS1893		0x0015f440
1275748Sduboff 
1285748Sduboff 
1295748Sduboff #define	SFE_DESC_SIZE	16	/* including pads rounding up to power of 2 */
1305748Sduboff 
1315748Sduboff /*
1325748Sduboff  * Supported chips
1335748Sduboff  */
1345748Sduboff struct chip_info {
1355748Sduboff 	uint16_t	venid;
1365748Sduboff 	uint16_t	devid;
1375748Sduboff 	char		*chip_name;
1385748Sduboff 	int		chip_type;
1395748Sduboff #define	CHIPTYPE_DP83815	0
1405748Sduboff #define	CHIPTYPE_SIS900		1
1415748Sduboff };
1425748Sduboff 
1435748Sduboff /*
1445748Sduboff  * Chip dependent MAC state
1455748Sduboff  */
1465748Sduboff struct sfe_dev {
1475748Sduboff 	/* misc HW information */
1485748Sduboff 	struct chip_info	*chip;
1495748Sduboff 	uint32_t		our_intr_bits;
1507116Sduboff 	uint32_t		isr_pended;
1515748Sduboff 	uint32_t		cr;
1525748Sduboff 	uint_t			tx_drain_threshold;
1535748Sduboff 	uint_t			tx_fill_threshold;
1545748Sduboff 	uint_t			rx_drain_threshold;
1555748Sduboff 	uint_t			rx_fill_threshold;
1565748Sduboff 	uint8_t			revid;	/* revision from PCI configuration */
1575748Sduboff 	boolean_t		(*get_mac_addr)(struct gem_dev *);
1585748Sduboff 	uint8_t			mac_addr[ETHERADDRL];
1595748Sduboff 	uint8_t			bridge_revid;
1605748Sduboff };
1615748Sduboff 
1625748Sduboff /*
1635748Sduboff  * Hardware information
1645748Sduboff  */
1655748Sduboff struct chip_info sfe_chiptbl[] = {
1665748Sduboff 	{ 0x1039, 0x0900, "SiS900", CHIPTYPE_SIS900, },
1675748Sduboff 	{ 0x100b, 0x0020, "DP83815/83816", CHIPTYPE_DP83815, },
1685748Sduboff 	{ 0x1039, 0x7016, "SiS7016", CHIPTYPE_SIS900, },
1695748Sduboff };
1705748Sduboff #define	CHIPTABLESIZE (sizeof (sfe_chiptbl)/sizeof (struct chip_info))
1715748Sduboff 
1725748Sduboff /* ======================================================== */
1735748Sduboff 
1745748Sduboff /* mii operations */
1755748Sduboff static void  sfe_mii_sync_dp83815(struct gem_dev *);
1765748Sduboff static void  sfe_mii_sync_sis900(struct gem_dev *);
1775748Sduboff static uint16_t  sfe_mii_read_dp83815(struct gem_dev *, uint_t);
1785748Sduboff static uint16_t  sfe_mii_read_sis900(struct gem_dev *, uint_t);
1795748Sduboff static void sfe_mii_write_dp83815(struct gem_dev *, uint_t, uint16_t);
1805748Sduboff static void sfe_mii_write_sis900(struct gem_dev *, uint_t, uint16_t);
1815748Sduboff static void sfe_set_eq_sis630(struct gem_dev *dp);
1825748Sduboff /* nic operations */
1835748Sduboff static int sfe_reset_chip_sis900(struct gem_dev *);
1845748Sduboff static int sfe_reset_chip_dp83815(struct gem_dev *);
1855748Sduboff static int sfe_init_chip(struct gem_dev *);
1865748Sduboff static int sfe_start_chip(struct gem_dev *);
1875748Sduboff static int sfe_stop_chip(struct gem_dev *);
1885748Sduboff static int sfe_set_media(struct gem_dev *);
1895748Sduboff static int sfe_set_rx_filter_dp83815(struct gem_dev *);
1905748Sduboff static int sfe_set_rx_filter_sis900(struct gem_dev *);
1915748Sduboff static int sfe_get_stats(struct gem_dev *);
1925748Sduboff static int sfe_attach_chip(struct gem_dev *);
1935748Sduboff 
1945748Sduboff /* descriptor operations */
1955748Sduboff static int sfe_tx_desc_write(struct gem_dev *dp, int slot,
1965748Sduboff 		    ddi_dma_cookie_t *dmacookie, int frags, uint64_t flags);
1975748Sduboff static void sfe_tx_start(struct gem_dev *dp, int startslot, int nslot);
1985748Sduboff static void sfe_rx_desc_write(struct gem_dev *dp, int slot,
1995748Sduboff 		    ddi_dma_cookie_t *dmacookie, int frags);
2005748Sduboff static uint_t sfe_tx_desc_stat(struct gem_dev *dp, int slot, int ndesc);
2015748Sduboff static uint64_t sfe_rx_desc_stat(struct gem_dev *dp, int slot, int ndesc);
2025748Sduboff 
2035748Sduboff static void sfe_tx_desc_init(struct gem_dev *dp, int slot);
2045748Sduboff static void sfe_rx_desc_init(struct gem_dev *dp, int slot);
2055748Sduboff static void sfe_tx_desc_clean(struct gem_dev *dp, int slot);
2065748Sduboff static void sfe_rx_desc_clean(struct gem_dev *dp, int slot);
2075748Sduboff 
2085748Sduboff /* interrupt handler */
2095748Sduboff static uint_t sfe_interrupt(struct gem_dev *dp);
2105748Sduboff 
2115748Sduboff /* ======================================================== */
2125748Sduboff 
2135748Sduboff /* mapping attributes */
2145748Sduboff /* Data access requirements. */
2155748Sduboff static struct ddi_device_acc_attr sfe_dev_attr = {
2165748Sduboff 	DDI_DEVICE_ATTR_V0,
2175748Sduboff 	DDI_STRUCTURE_LE_ACC,
2185748Sduboff 	DDI_STRICTORDER_ACC
2195748Sduboff };
2205748Sduboff 
2215748Sduboff /* On sparc, Buffers should be native endian for speed */
2225748Sduboff static struct ddi_device_acc_attr sfe_buf_attr = {
2235748Sduboff 	DDI_DEVICE_ATTR_V0,
2245748Sduboff 	DDI_NEVERSWAP_ACC,	/* native endianness */
2255748Sduboff 	DDI_STRICTORDER_ACC
2265748Sduboff };
2275748Sduboff 
2285748Sduboff static ddi_dma_attr_t sfe_dma_attr_buf = {
2295748Sduboff 	DMA_ATTR_V0,		/* dma_attr_version */
2305748Sduboff 	0,			/* dma_attr_addr_lo */
2315748Sduboff 	0xffffffffull,		/* dma_attr_addr_hi */
2325748Sduboff 	0x00000fffull,		/* dma_attr_count_max */
2335748Sduboff 	0, /* patched later */	/* dma_attr_align */
2345748Sduboff 	0x000003fc,		/* dma_attr_burstsizes */
2355748Sduboff 	1,			/* dma_attr_minxfer */
2365748Sduboff 	0x00000fffull,		/* dma_attr_maxxfer */
2375748Sduboff 	0xffffffffull,		/* dma_attr_seg */
2385748Sduboff 	0, /* patched later */	/* dma_attr_sgllen */
2395748Sduboff 	1,			/* dma_attr_granular */
2405748Sduboff 	0			/* dma_attr_flags */
2415748Sduboff };
2425748Sduboff 
2435748Sduboff static ddi_dma_attr_t sfe_dma_attr_desc = {
2445748Sduboff 	DMA_ATTR_V0,		/* dma_attr_version */
2455748Sduboff 	16,			/* dma_attr_addr_lo */
2465748Sduboff 	0xffffffffull,		/* dma_attr_addr_hi */
2475748Sduboff 	0xffffffffull,		/* dma_attr_count_max */
2485748Sduboff 	16,			/* dma_attr_align */
2495748Sduboff 	0x000003fc,		/* dma_attr_burstsizes */
2505748Sduboff 	1,			/* dma_attr_minxfer */
2515748Sduboff 	0xffffffffull,		/* dma_attr_maxxfer */
2525748Sduboff 	0xffffffffull,		/* dma_attr_seg */
2535748Sduboff 	1,			/* dma_attr_sgllen */
2545748Sduboff 	1,			/* dma_attr_granular */
2555748Sduboff 	0			/* dma_attr_flags */
2565748Sduboff };
2575748Sduboff 
2585748Sduboff uint32_t sfe_use_pcimemspace = 0;
2595748Sduboff 
2605748Sduboff /* ======================================================== */
2615748Sduboff /*
2625748Sduboff  * HW manipulation routines
2635748Sduboff  */
2645748Sduboff /* ======================================================== */
2655748Sduboff 
2665748Sduboff #define	SFE_EEPROM_DELAY(dp)	\
2675748Sduboff 	{ (void) INL(dp, EROMAR); (void) INL(dp, EROMAR); }
2685748Sduboff #define	EE_CMD_READ	6
2695748Sduboff #define	EE_CMD_SHIFT	6
2705748Sduboff 
2715748Sduboff static uint16_t
sfe_read_eeprom(struct gem_dev * dp,uint_t offset)2725748Sduboff sfe_read_eeprom(struct gem_dev *dp, uint_t offset)
2735748Sduboff {
2745748Sduboff 	int		eedi;
2755748Sduboff 	int		i;
2765748Sduboff 	uint16_t	ret;
2775748Sduboff 
2785748Sduboff 	/* ensure de-assert chip select */
2795748Sduboff 	OUTL(dp, EROMAR, 0);
2805748Sduboff 	SFE_EEPROM_DELAY(dp);
2815748Sduboff 	OUTL(dp, EROMAR, EROMAR_EESK);
2825748Sduboff 	SFE_EEPROM_DELAY(dp);
2835748Sduboff 
2845748Sduboff 	/* assert chip select */
2855748Sduboff 	offset |= EE_CMD_READ << EE_CMD_SHIFT;
2865748Sduboff 
2875748Sduboff 	for (i = 8; i >= 0; i--) {
2885748Sduboff 		/* make command */
2895748Sduboff 		eedi = ((offset >> i) & 1) << EROMAR_EEDI_SHIFT;
2905748Sduboff 
2915748Sduboff 		/* send 1 bit */
2925748Sduboff 		OUTL(dp, EROMAR, EROMAR_EECS | eedi);
2935748Sduboff 		SFE_EEPROM_DELAY(dp);
2945748Sduboff 		OUTL(dp, EROMAR, EROMAR_EECS | eedi | EROMAR_EESK);
2955748Sduboff 		SFE_EEPROM_DELAY(dp);
2965748Sduboff 	}
2975748Sduboff 
2985748Sduboff 	OUTL(dp, EROMAR, EROMAR_EECS);
2995748Sduboff 
3005748Sduboff 	ret = 0;
3015748Sduboff 	for (i = 0; i < 16; i++) {
3025748Sduboff 		/* Get 1 bit */
3035748Sduboff 		OUTL(dp, EROMAR, EROMAR_EECS);
3045748Sduboff 		SFE_EEPROM_DELAY(dp);
3055748Sduboff 		OUTL(dp, EROMAR, EROMAR_EECS | EROMAR_EESK);
3065748Sduboff 		SFE_EEPROM_DELAY(dp);
3075748Sduboff 
3085748Sduboff 		ret = (ret << 1) | ((INL(dp, EROMAR) >> EROMAR_EEDO_SHIFT) & 1);
3095748Sduboff 	}
3105748Sduboff 
3115748Sduboff 	OUTL(dp, EROMAR, 0);
3125748Sduboff 	SFE_EEPROM_DELAY(dp);
3135748Sduboff 
3145748Sduboff 	return (ret);
3155748Sduboff }
3165748Sduboff #undef SFE_EEPROM_DELAY
3175748Sduboff 
3185748Sduboff static boolean_t
sfe_get_mac_addr_dp83815(struct gem_dev * dp)3195748Sduboff sfe_get_mac_addr_dp83815(struct gem_dev *dp)
3205748Sduboff {
3215748Sduboff 	uint8_t		*mac;
3225748Sduboff 	uint_t		val;
3235748Sduboff 	int		i;
3245748Sduboff 
3255748Sduboff #define	BITSET(p, ix, v)	(p)[(ix)/8] |= ((v) ? 1 : 0) << ((ix) & 0x7)
3265748Sduboff 
3275748Sduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__));
3285748Sduboff 
3295748Sduboff 	mac = dp->dev_addr.ether_addr_octet;
3305748Sduboff 
3315748Sduboff 	/* first of all, clear MAC address buffer */
3325748Sduboff 	bzero(mac, ETHERADDRL);
3335748Sduboff 
3345748Sduboff 	/* get bit 0 */
3355748Sduboff 	val = sfe_read_eeprom(dp, 0x6);
3365748Sduboff 	BITSET(mac, 0, val & 1);
3375748Sduboff 
3385748Sduboff 	/* get bit 1 - 16 */
3395748Sduboff 	val = sfe_read_eeprom(dp, 0x7);
3405748Sduboff 	for (i = 0; i < 16; i++) {
3415748Sduboff 		BITSET(mac, 1 + i, val & (1 << (15 - i)));
3425748Sduboff 	}
3435748Sduboff 
3445748Sduboff 	/* get bit 17 -  32 */
3455748Sduboff 	val = sfe_read_eeprom(dp, 0x8);
3465748Sduboff 	for (i = 0; i < 16; i++) {
3475748Sduboff 		BITSET(mac, 17 + i, val & (1 << (15 - i)));
3485748Sduboff 	}
3495748Sduboff 
3505748Sduboff 	/* get bit 33 -  47 */
3515748Sduboff 	val = sfe_read_eeprom(dp, 0x9);
3525748Sduboff 	for (i = 0; i < 15; i++) {
3535748Sduboff 		BITSET(mac, 33 + i, val & (1 << (15 - i)));
3545748Sduboff 	}
3555748Sduboff 
3565748Sduboff 	return (B_TRUE);
3575748Sduboff #undef BITSET
3585748Sduboff }
3595748Sduboff 
3605748Sduboff static boolean_t
sfe_get_mac_addr_sis900(struct gem_dev * dp)3615748Sduboff sfe_get_mac_addr_sis900(struct gem_dev *dp)
3625748Sduboff {
3635748Sduboff 	uint_t		val;
3645748Sduboff 	int		i;
3655748Sduboff 	uint8_t		*mac;
3665748Sduboff 
3675748Sduboff 	mac = dp->dev_addr.ether_addr_octet;
3685748Sduboff 
3695748Sduboff 	for (i = 0; i < ETHERADDRL/2; i++) {
3705748Sduboff 		val = sfe_read_eeprom(dp, 0x8 + i);
3715748Sduboff 		*mac++ = (uint8_t)val;
3725748Sduboff 		*mac++ = (uint8_t)(val >> 8);
3735748Sduboff 	}
3745748Sduboff 
3755748Sduboff 	return (B_TRUE);
3765748Sduboff }
3775748Sduboff 
3785748Sduboff static dev_info_t *
sfe_search_pci_dev_subr(dev_info_t * cur_node,int vendor_id,int device_id)3795748Sduboff sfe_search_pci_dev_subr(dev_info_t *cur_node, int vendor_id, int device_id)
3805748Sduboff {
3815748Sduboff 	dev_info_t	*child_id;
3825748Sduboff 	dev_info_t	*ret;
3835748Sduboff 	int		vid, did;
3845748Sduboff 
3855748Sduboff 	if (cur_node == NULL) {
3865748Sduboff 		return (NULL);
3875748Sduboff 	}
3885748Sduboff 
3895748Sduboff 	/* check brothers */
3905748Sduboff 	do {
3915748Sduboff 		vid = ddi_prop_get_int(DDI_DEV_T_ANY, cur_node,
3925748Sduboff 		    DDI_PROP_DONTPASS, "vendor-id", -1);
3935748Sduboff 		did = ddi_prop_get_int(DDI_DEV_T_ANY, cur_node,
3945748Sduboff 		    DDI_PROP_DONTPASS, "device-id", -1);
3955748Sduboff 
3965748Sduboff 		if (vid == vendor_id && did == device_id) {
3975748Sduboff 			/* found */
3985748Sduboff 			return (cur_node);
3995748Sduboff 		}
4005748Sduboff 
4015748Sduboff 		/* check children */
4025748Sduboff 		if ((child_id = ddi_get_child(cur_node)) != NULL) {
4035748Sduboff 			if ((ret = sfe_search_pci_dev_subr(child_id,
4045748Sduboff 			    vendor_id, device_id)) != NULL) {
4055748Sduboff 				return (ret);
4065748Sduboff 			}
4075748Sduboff 		}
4085748Sduboff 
4095748Sduboff 	} while ((cur_node = ddi_get_next_sibling(cur_node)) != NULL);
4105748Sduboff 
4115748Sduboff 	/* not found */
4125748Sduboff 	return (NULL);
4135748Sduboff }
4145748Sduboff 
4155748Sduboff static dev_info_t *
sfe_search_pci_dev(int vendor_id,int device_id)4165748Sduboff sfe_search_pci_dev(int vendor_id, int device_id)
4175748Sduboff {
4185748Sduboff 	return (sfe_search_pci_dev_subr(ddi_root_node(), vendor_id, device_id));
4195748Sduboff }
4205748Sduboff 
4215748Sduboff static boolean_t
sfe_get_mac_addr_sis630e(struct gem_dev * dp)4225748Sduboff sfe_get_mac_addr_sis630e(struct gem_dev *dp)
4235748Sduboff {
4245748Sduboff 	int		i;
4255748Sduboff 	dev_info_t	*isa_bridge;
4265748Sduboff 	ddi_acc_handle_t isa_handle;
4275748Sduboff 	int		reg;
4285748Sduboff 
4295748Sduboff 	if (inb == NULL || outb == NULL) {
4305748Sduboff 		/* this is not IA architecture */
4315748Sduboff 		return (B_FALSE);
4325748Sduboff 	}
4335748Sduboff 
4345748Sduboff 	if ((isa_bridge = sfe_search_pci_dev(0x1039, 0x8)) == NULL) {
4355748Sduboff 		cmn_err(CE_WARN, "%s: failed to find isa-bridge pci1039,8",
4365748Sduboff 		    dp->name);
4375748Sduboff 		return (B_FALSE);
4385748Sduboff 	}
4395748Sduboff 
4405748Sduboff 	if (pci_config_setup(isa_bridge, &isa_handle) != DDI_SUCCESS) {
4415748Sduboff 		cmn_err(CE_WARN, "%s: ddi_regs_map_setup failed",
4425748Sduboff 		    dp->name);
4435748Sduboff 		return (B_FALSE);
4445748Sduboff 	}
4455748Sduboff 
4465748Sduboff 	/* enable to access CMOS RAM */
4475748Sduboff 	reg = pci_config_get8(isa_handle, 0x48);
4485748Sduboff 	pci_config_put8(isa_handle, 0x48, reg | 0x40);
4495748Sduboff 
4505748Sduboff 	for (i = 0; i < ETHERADDRL; i++) {
4515748Sduboff 		outb(0x70, 0x09 + i);
4525748Sduboff 		dp->dev_addr.ether_addr_octet[i] = inb(0x71);
4535748Sduboff 	}
4545748Sduboff 
4555748Sduboff 	/* disable to access CMOS RAM */
4565748Sduboff 	pci_config_put8(isa_handle, 0x48, reg);
4575748Sduboff 	pci_config_teardown(&isa_handle);
4585748Sduboff 
4595748Sduboff 	return (B_TRUE);
4605748Sduboff }
4615748Sduboff 
4625748Sduboff static boolean_t
sfe_get_mac_addr_sis635(struct gem_dev * dp)4635748Sduboff sfe_get_mac_addr_sis635(struct gem_dev *dp)
4645748Sduboff {
4655748Sduboff 	int		i;
4665748Sduboff 	uint32_t	rfcr;
4675748Sduboff 	uint16_t	v;
4685748Sduboff 	struct sfe_dev	*lp = dp->private;
4695748Sduboff 
4705748Sduboff 	DPRINTF(2, (CE_CONT, CONS "%s: %s: called", dp->name, __func__));
4715748Sduboff 	rfcr = INL(dp, RFCR);
4725748Sduboff 
4735748Sduboff 	OUTL(dp, CR, lp->cr | CR_RELOAD);
4745748Sduboff 	OUTL(dp, CR, lp->cr);
4755748Sduboff 
4765748Sduboff 	/* disable packet filtering before reading filter */
4775748Sduboff 	OUTL(dp, RFCR, rfcr & ~RFCR_RFEN);
4785748Sduboff 
4795748Sduboff 	/* load MAC addr from filter data register */
4805748Sduboff 	for (i = 0; i < ETHERADDRL; i += 2) {
4815748Sduboff 		OUTL(dp, RFCR,
4825748Sduboff 		    (RFADDR_MAC_SIS900 + (i/2)) << RFCR_RFADDR_SHIFT_SIS900);
4835748Sduboff 		v = INL(dp, RFDR);
4845748Sduboff 		dp->dev_addr.ether_addr_octet[i] = (uint8_t)v;
4855748Sduboff 		dp->dev_addr.ether_addr_octet[i+1] = (uint8_t)(v >> 8);
4865748Sduboff 	}
4875748Sduboff 
4885748Sduboff 	/* re-enable packet filtering */
4895748Sduboff 	OUTL(dp, RFCR, rfcr | RFCR_RFEN);
4905748Sduboff 
4915748Sduboff 	return (B_TRUE);
4925748Sduboff }
4935748Sduboff 
4945748Sduboff static boolean_t
sfe_get_mac_addr_sis962(struct gem_dev * dp)4955748Sduboff sfe_get_mac_addr_sis962(struct gem_dev *dp)
4965748Sduboff {
4975748Sduboff 	boolean_t	ret;
4985748Sduboff 	int		i;
4995748Sduboff 
5005748Sduboff 	ret = B_FALSE;
5015748Sduboff 
5025748Sduboff 	/* rise request signal to access EEPROM */
5035748Sduboff 	OUTL(dp, MEAR, EROMAR_EEREQ);
5045748Sduboff 	for (i = 0; (INL(dp, MEAR) & EROMAR_EEGNT) == 0; i++) {
5055748Sduboff 		if (i > 200) {
5065748Sduboff 			/* failed to acquire eeprom */
5075748Sduboff 			cmn_err(CE_NOTE,
5085748Sduboff 			    CONS "%s: failed to access eeprom", dp->name);
5095748Sduboff 			goto x;
5105748Sduboff 		}
5115748Sduboff 		drv_usecwait(10);
5125748Sduboff 	}
5135748Sduboff 	ret = sfe_get_mac_addr_sis900(dp);
5145748Sduboff x:
5155748Sduboff 	/* release EEPROM */
5165748Sduboff 	OUTL(dp, MEAR, EROMAR_EEDONE);
5175748Sduboff 
5185748Sduboff 	return (ret);
5195748Sduboff }
5205748Sduboff 
5215748Sduboff static int
sfe_reset_chip_sis900(struct gem_dev * dp)5225748Sduboff sfe_reset_chip_sis900(struct gem_dev *dp)
5235748Sduboff {
5245748Sduboff 	int		i;
5255748Sduboff 	uint32_t	done;
5265748Sduboff 	uint32_t	val;
5275748Sduboff 	struct sfe_dev	*lp = dp->private;
5285748Sduboff 
5295748Sduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s called", dp->name, __func__));
5305748Sduboff 
5315748Sduboff 	/* invalidate mac addr cache */
5325748Sduboff 	bzero(lp->mac_addr, sizeof (lp->mac_addr));
5335748Sduboff 
5345748Sduboff 	lp->cr = 0;
5355748Sduboff 
5365748Sduboff 	/* inhibit interrupt */
5375748Sduboff 	OUTL(dp, IMR, 0);
5387116Sduboff 	lp->isr_pended |= INL(dp, ISR) & lp->our_intr_bits;
5395748Sduboff 
5407893SAlan.Duboff@Sun.COM 	OUTLINL(dp, RFCR, 0);
5415748Sduboff 
5425748Sduboff 	OUTL(dp, CR, CR_RST | CR_TXR | CR_RXR);
5435748Sduboff 	drv_usecwait(10);
5445748Sduboff 
5455748Sduboff 	done = 0;
5465748Sduboff 	for (i = 0; done != (ISR_TXRCMP | ISR_RXRCMP); i++) {
5475748Sduboff 		if (i > 1000) {
5485748Sduboff 			cmn_err(CE_WARN, "%s: chip reset timeout", dp->name);
5495748Sduboff 			return (GEM_FAILURE);
5505748Sduboff 		}
5515748Sduboff 		done |= INL(dp, ISR) & (ISR_TXRCMP | ISR_RXRCMP);
5525748Sduboff 		drv_usecwait(10);
5535748Sduboff 	}
5545748Sduboff 
5555748Sduboff 	if (lp->revid == SIS630ET_900_REV) {
5565748Sduboff 		lp->cr |= CR_ACCESSMODE;
5575748Sduboff 		OUTL(dp, CR, lp->cr | INL(dp, CR));
5585748Sduboff 	}
5595748Sduboff 
5605748Sduboff 	/* Configuration register: enable PCI parity */
5615748Sduboff 	DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b",
5625748Sduboff 	    dp->name, INL(dp, CFG), CFG_BITS_SIS900));
5637116Sduboff 	val = 0;
5645748Sduboff 	if (lp->revid >= SIS635A_900_REV ||
5655748Sduboff 	    lp->revid == SIS900B_900_REV) {
5665748Sduboff 		/* what is this ? */
5675748Sduboff 		val |= CFG_RND_CNT;
5685748Sduboff 	}
5695748Sduboff 	OUTL(dp, CFG, val);
5705748Sduboff 	DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b", dp->name,
5715748Sduboff 	    INL(dp, CFG), CFG_BITS_SIS900));
5725748Sduboff 
5735748Sduboff 	return (GEM_SUCCESS);
5745748Sduboff }
5755748Sduboff 
5765748Sduboff static int
sfe_reset_chip_dp83815(struct gem_dev * dp)5775748Sduboff sfe_reset_chip_dp83815(struct gem_dev *dp)
5785748Sduboff {
5795748Sduboff 	int		i;
5807116Sduboff 	uint32_t	val;
5815748Sduboff 	struct sfe_dev	*lp = dp->private;
5825748Sduboff 
5835748Sduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s called", dp->name, __func__));
5845748Sduboff 
5855748Sduboff 	/* invalidate mac addr cache */
5865748Sduboff 	bzero(lp->mac_addr, sizeof (lp->mac_addr));
5875748Sduboff 
5885748Sduboff 	lp->cr = 0;
5895748Sduboff 
5905748Sduboff 	/* inhibit interrupts */
5915748Sduboff 	OUTL(dp, IMR, 0);
5927116Sduboff 	lp->isr_pended |= INL(dp, ISR) & lp->our_intr_bits;
5935748Sduboff 
5945748Sduboff 	OUTL(dp, RFCR, 0);
5955748Sduboff 
5965748Sduboff 	OUTL(dp, CR, CR_RST);
5975748Sduboff 	drv_usecwait(10);
5985748Sduboff 
5995748Sduboff 	for (i = 0; INL(dp, CR) & CR_RST; i++) {
6005748Sduboff 		if (i > 100) {
6015748Sduboff 			cmn_err(CE_WARN, "!%s: chip reset timeout", dp->name);
6025748Sduboff 			return (GEM_FAILURE);
6035748Sduboff 		}
6045748Sduboff 		drv_usecwait(10);
6055748Sduboff 	}
6065748Sduboff 	DPRINTF(0, (CE_CONT, "!%s: chip reset in %duS", dp->name, i*10));
6075748Sduboff 
6085748Sduboff 	OUTL(dp, CCSR, CCSR_PMESTS);
6095748Sduboff 	OUTL(dp, CCSR, 0);
6105748Sduboff 
6115748Sduboff 	/* Configuration register: enable PCI parity */
6125748Sduboff 	DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b",
6135748Sduboff 	    dp->name, INL(dp, CFG), CFG_BITS_DP83815));
6147116Sduboff 	val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG);
6157116Sduboff 	OUTL(dp, CFG, val | CFG_PAUSE_ADV);
6165748Sduboff 	DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b", dp->name,
6175748Sduboff 	    INL(dp, CFG), CFG_BITS_DP83815));
6185748Sduboff 
6195748Sduboff 	return (GEM_SUCCESS);
6205748Sduboff }
6215748Sduboff 
6225748Sduboff static int
sfe_init_chip(struct gem_dev * dp)6235748Sduboff sfe_init_chip(struct gem_dev *dp)
6245748Sduboff {
6255748Sduboff 	/* Configuration register: have been set up in sfe_chip_reset */
6265748Sduboff 
6275748Sduboff 	/* PCI test control register: do nothing */
6285748Sduboff 
6295748Sduboff 	/* Interrupt status register : do nothing */
6305748Sduboff 
6315748Sduboff 	/* Interrupt mask register: clear, but leave lp->our_intr_bits */
6325748Sduboff 	OUTL(dp, IMR, 0);
6335748Sduboff 
6345748Sduboff 	/* Enhanced PHY Access register (sis900): do nothing */
6355748Sduboff 
6365748Sduboff 	/* Transmit Descriptor Pointer register: base addr of TX ring */
6375748Sduboff 	OUTL(dp, TXDP, dp->tx_ring_dma);
6385748Sduboff 
6395748Sduboff 	/* Receive descriptor pointer register: base addr of RX ring */
6405748Sduboff 	OUTL(dp, RXDP, dp->rx_ring_dma);
6415748Sduboff 
6425748Sduboff 	return (GEM_SUCCESS);
6435748Sduboff }
6445748Sduboff 
6455748Sduboff static uint_t
sfe_mcast_hash(struct gem_dev * dp,uint8_t * addr)6465748Sduboff sfe_mcast_hash(struct gem_dev *dp, uint8_t *addr)
6475748Sduboff {
6485748Sduboff 	return (gem_ether_crc_be(addr, ETHERADDRL));
6495748Sduboff }
6505748Sduboff 
6515748Sduboff #ifdef DEBUG_LEVEL
6525748Sduboff static void
sfe_rxfilter_dump(struct gem_dev * dp,int start,int end)6535748Sduboff sfe_rxfilter_dump(struct gem_dev *dp, int start, int end)
6545748Sduboff {
6555748Sduboff 	int		i;
6565748Sduboff 	int		j;
6575748Sduboff 	uint16_t	ram[0x10];
6585748Sduboff 
6595748Sduboff 	cmn_err(CE_CONT, "!%s: rx filter ram dump:", dp->name);
6605748Sduboff #define	WORDS_PER_LINE	4
6615748Sduboff 	for (i = start; i < end; i += WORDS_PER_LINE*2) {
6625748Sduboff 		for (j = 0; j < WORDS_PER_LINE; j++) {
6635748Sduboff 			OUTL(dp, RFCR, RFADDR_MAC_DP83815 + i + j*2);
6645748Sduboff 			ram[j] = INL(dp, RFDR);
6655748Sduboff 		}
6665748Sduboff 
6675748Sduboff 		cmn_err(CE_CONT, "!0x%02x: 0x%04x 0x%04x 0x%04x 0x%04x",
6685748Sduboff 		    i, ram[0], ram[1], ram[2], ram[3]);
6695748Sduboff 		}
6705748Sduboff 
6715748Sduboff #undef	WORDS_PER_LINE
6725748Sduboff }
6735748Sduboff #endif
6745748Sduboff 
6755748Sduboff static uint_t	sfe_rf_perfect_base_dp83815[] = {
6765748Sduboff 	RFADDR_PMATCH0_DP83815,
6775748Sduboff 	RFADDR_PMATCH1_DP83815,
6785748Sduboff 	RFADDR_PMATCH2_DP83815,
6795748Sduboff 	RFADDR_PMATCH3_DP83815,
6805748Sduboff };
6815748Sduboff 
6825748Sduboff static int
sfe_set_rx_filter_dp83815(struct gem_dev * dp)6835748Sduboff sfe_set_rx_filter_dp83815(struct gem_dev *dp)
6845748Sduboff {
6855748Sduboff 	int		i;
6865748Sduboff 	int		j;
6875748Sduboff 	uint32_t	mode;
6885748Sduboff 	uint8_t		*mac = dp->cur_addr.ether_addr_octet;
6895748Sduboff 	uint16_t	hash_tbl[32];
6905748Sduboff 	struct sfe_dev	*lp = dp->private;
6915748Sduboff 
6925748Sduboff 	DPRINTF(1, (CE_CONT, CONS "%s: %s: called, mc_count:%d, mode:0x%b",
6935748Sduboff 	    dp->name, __func__, dp->mc_count, dp->rxmode, RXMODE_BITS));
6945748Sduboff 
6955748Sduboff #if DEBUG_LEVEL > 0
6965748Sduboff 	for (i = 0; i < dp->mc_count; i++) {
6975748Sduboff 		cmn_err(CE_CONT,
6985748Sduboff 		"!%s: adding mcast(%d) %02x:%02x:%02x:%02x:%02x:%02x",
6995748Sduboff 		    dp->name, i,
7005748Sduboff 		    dp->mc_list[i].addr.ether_addr_octet[0],
7015748Sduboff 		    dp->mc_list[i].addr.ether_addr_octet[1],
7025748Sduboff 		    dp->mc_list[i].addr.ether_addr_octet[2],
7035748Sduboff 		    dp->mc_list[i].addr.ether_addr_octet[3],
7045748Sduboff 		    dp->mc_list[i].addr.ether_addr_octet[4],
7055748Sduboff 		    dp->mc_list[i].addr.ether_addr_octet[5]);
7065748Sduboff 	}
7075748Sduboff #endif
7085748Sduboff 	if ((dp->rxmode & RXMODE_ENABLE) == 0) {
7095748Sduboff 		/* disable rx filter */
7105748Sduboff 		OUTL(dp, RFCR, 0);
7115748Sduboff 		return (GEM_SUCCESS);
7125748Sduboff 	}
7135748Sduboff 
7145748Sduboff 	/*
7155748Sduboff 	 * Set Receive filter control register
7165748Sduboff 	 */
7175748Sduboff 	if (dp->rxmode & RXMODE_PROMISC) {
7185748Sduboff 		/* all broadcast, all multicast, all physical */
7195748Sduboff 		mode = RFCR_AAB | RFCR_AAM | RFCR_AAP;
7205748Sduboff 	} else if ((dp->rxmode & RXMODE_ALLMULTI) || dp->mc_count > 16*32/2) {
7215748Sduboff 		/* all broadcast, all multicast, physical for the chip */
7225748Sduboff 		mode = RFCR_AAB | RFCR_AAM | RFCR_APM_DP83815;
7235748Sduboff 	} else if (dp->mc_count > 4) {
7245748Sduboff 		/*
7255748Sduboff 		 * Use multicast hash table,
7265748Sduboff 		 * accept all broadcast and physical for the chip.
7275748Sduboff 		 */
7285748Sduboff 		mode = RFCR_AAB | RFCR_MHEN_DP83815 | RFCR_APM_DP83815;
7295748Sduboff 
7305748Sduboff 		bzero(hash_tbl, sizeof (hash_tbl));
7315748Sduboff 		for (i = 0; i < dp->mc_count; i++) {
7325748Sduboff 			j = dp->mc_list[i].hash >> (32 - 9);
7335748Sduboff 			hash_tbl[j / 16] |= 1 << (j % 16);
7345748Sduboff 		}
7355748Sduboff 	} else {
7365748Sduboff 		/*
7375748Sduboff 		 * Use pattern mach filter for multicast address,
7385748Sduboff 		 * accept all broadcast and physical for the chip
7395748Sduboff 		 */
7405748Sduboff 		/* need to enable corresponding pattern registers */
7415748Sduboff 		mode = RFCR_AAB | RFCR_APM_DP83815 |
7425748Sduboff 		    (((1 << dp->mc_count) - 1) << RFCR_APAT_SHIFT);
7435748Sduboff 	}
7445748Sduboff 
7455748Sduboff #if DEBUG_LEVEL > 1
7465748Sduboff 	cmn_err(CE_CONT,
7475748Sduboff 	    "!%s: mac %02x:%02x:%02x:%02x:%02x:%02x"
7485748Sduboff 	    "  cache %02x:%02x:%02x:%02x:%02x:%02x",
7495748Sduboff 	    dp->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
7505748Sduboff 	    lp->mac_addr[0], lp->mac_addr[1],
7515748Sduboff 	    lp->mac_addr[2], lp->mac_addr[3],
7525748Sduboff 	    lp->mac_addr[4], lp->mac_addr[5]);
7535748Sduboff #endif
7545748Sduboff 	if (bcmp(mac, lp->mac_addr, ETHERADDRL) != 0) {
7555748Sduboff 		/*
7565748Sduboff 		 * XXX - need to *disable* rx filter to load mac address for
7575748Sduboff 		 * the chip. otherwise, we cannot setup rxfilter correctly.
7585748Sduboff 		 */
7595748Sduboff 		/* setup perfect match register for my station address */
7605748Sduboff 		for (i = 0; i < ETHERADDRL; i += 2) {
7615748Sduboff 			OUTL(dp, RFCR, RFADDR_MAC_DP83815 + i);
7625748Sduboff 			OUTL(dp, RFDR, (mac[i+1] << 8) | mac[i]);
7635748Sduboff 		}
7645748Sduboff 
7655748Sduboff 		bcopy(mac, lp->mac_addr, ETHERADDRL);
7665748Sduboff 	}
7675748Sduboff 
7685748Sduboff #if DEBUG_LEVEL > 3
7695748Sduboff 	/* clear pattern ram */
7705748Sduboff 	for (j = 0x200; j < 0x380; j += 2) {
7715748Sduboff 		OUTL(dp, RFCR, j);
7725748Sduboff 		OUTL(dp, RFDR, 0);
7735748Sduboff 	}
7745748Sduboff #endif
7755748Sduboff 	if (mode & RFCR_APAT_DP83815) {
7765748Sduboff 		/* setup multicast address into pattern match registers */
7775748Sduboff 		for (j = 0; j < dp->mc_count; j++) {
7785748Sduboff 			mac = &dp->mc_list[j].addr.ether_addr_octet[0];
7795748Sduboff 			for (i = 0; i < ETHERADDRL; i += 2) {
7805748Sduboff 				OUTL(dp, RFCR,
7815748Sduboff 				    sfe_rf_perfect_base_dp83815[j] + i*2);
7825748Sduboff 				OUTL(dp, RFDR, (mac[i+1] << 8) | mac[i]);
7835748Sduboff 			}
7845748Sduboff 		}
7855748Sduboff 
7865748Sduboff 		/* setup pattern count registers */
7875748Sduboff 		OUTL(dp, RFCR, RFADDR_PCOUNT01_DP83815);
7885748Sduboff 		OUTL(dp, RFDR, (ETHERADDRL << 8) | ETHERADDRL);
7895748Sduboff 		OUTL(dp, RFCR, RFADDR_PCOUNT23_DP83815);
7905748Sduboff 		OUTL(dp, RFDR, (ETHERADDRL << 8) | ETHERADDRL);
7915748Sduboff 	}
7925748Sduboff 
7935748Sduboff 	if (mode & RFCR_MHEN_DP83815) {
7945748Sduboff 		/* Load Multicast hash table */
7955748Sduboff 		for (i = 0; i < 32; i++) {
7965748Sduboff 			/* for DP83815, index is in byte */
7975748Sduboff 			OUTL(dp, RFCR, RFADDR_MULTICAST_DP83815 + i*2);
7985748Sduboff 			OUTL(dp, RFDR, hash_tbl[i]);
7995748Sduboff 		}
8005748Sduboff 	}
8015748Sduboff #if DEBUG_LEVEL > 2
8025748Sduboff 	sfe_rxfilter_dump(dp, 0, 0x10);
8035748Sduboff 	sfe_rxfilter_dump(dp, 0x200, 0x380);
8045748Sduboff #endif
8055748Sduboff 	/* Set rx filter mode and enable rx filter */
8065748Sduboff 	OUTL(dp, RFCR, RFCR_RFEN | mode);
8075748Sduboff 
8085748Sduboff 	return (GEM_SUCCESS);
8095748Sduboff }
8105748Sduboff 
8115748Sduboff static int
sfe_set_rx_filter_sis900(struct gem_dev * dp)8125748Sduboff sfe_set_rx_filter_sis900(struct gem_dev *dp)
8135748Sduboff {
8145748Sduboff 	int		i;
8155748Sduboff 	uint32_t	mode;
8165748Sduboff 	uint16_t	hash_tbl[16];
8175748Sduboff 	uint8_t		*mac = dp->cur_addr.ether_addr_octet;
8185748Sduboff 	int		hash_size;
8195748Sduboff 	int		hash_shift;
8205748Sduboff 	struct sfe_dev	*lp = dp->private;
8215748Sduboff 
8225748Sduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__));
8235748Sduboff 
8245748Sduboff 	if ((dp->rxmode & RXMODE_ENABLE) == 0) {
8257893SAlan.Duboff@Sun.COM 		/* disable rx filter */
8267893SAlan.Duboff@Sun.COM 		OUTLINL(dp, RFCR, 0);
8275748Sduboff 		return (GEM_SUCCESS);
8285748Sduboff 	}
8295748Sduboff 
8305748Sduboff 	/*
8315748Sduboff 	 * determine hardware hash table size in word.
8325748Sduboff 	 */
8335748Sduboff 	hash_shift = 25;
8345748Sduboff 	if (lp->revid >= SIS635A_900_REV || lp->revid == SIS900B_900_REV) {
8355748Sduboff 		hash_shift = 24;
8365748Sduboff 	}
8375748Sduboff 	hash_size = (1 << (32 - hash_shift)) / 16;
8385748Sduboff 	bzero(hash_tbl, sizeof (hash_tbl));
8395748Sduboff 
8405748Sduboff 	/* Set Receive filter control register */
8415748Sduboff 
8425748Sduboff 	if (dp->rxmode & RXMODE_PROMISC) {
8435748Sduboff 		/* all broadcast, all multicast, all physical */
8445748Sduboff 		mode = RFCR_AAB | RFCR_AAM | RFCR_AAP;
8455748Sduboff 	} else if ((dp->rxmode & RXMODE_ALLMULTI) ||
8465748Sduboff 	    dp->mc_count > hash_size*16/2) {
8475748Sduboff 		/* all broadcast, all multicast, physical for the chip */
8485748Sduboff 		mode = RFCR_AAB | RFCR_AAM;
8495748Sduboff 	} else {
8505748Sduboff 		/* all broadcast, physical for the chip */
8515748Sduboff 		mode = RFCR_AAB;
8525748Sduboff 	}
8535748Sduboff 
8545748Sduboff 	/* make hash table */
8555748Sduboff 	for (i = 0; i < dp->mc_count; i++) {
8565748Sduboff 		uint_t	h;
8575748Sduboff 		h = dp->mc_list[i].hash >> hash_shift;
8585748Sduboff 		hash_tbl[h / 16] |= 1 << (h % 16);
8595748Sduboff 	}
8605748Sduboff 
8615748Sduboff 	if (bcmp(mac, lp->mac_addr, ETHERADDRL) != 0) {
8625748Sduboff 		/* Disable Rx filter and load mac address */
8635748Sduboff 		for (i = 0; i < ETHERADDRL/2; i++) {
8645748Sduboff 			/* For sis900, index is in word */
8657893SAlan.Duboff@Sun.COM 			OUTLINL(dp, RFCR,
8665748Sduboff 			    (RFADDR_MAC_SIS900+i) << RFCR_RFADDR_SHIFT_SIS900);
8677893SAlan.Duboff@Sun.COM 			OUTLINL(dp, RFDR, (mac[i*2+1] << 8) | mac[i*2]);
8685748Sduboff 		}
8695748Sduboff 
8705748Sduboff 		bcopy(mac, lp->mac_addr, ETHERADDRL);
8715748Sduboff 	}
8725748Sduboff 
8735748Sduboff 	/* Load Multicast hash table */
8745748Sduboff 	for (i = 0; i < hash_size; i++) {
8755748Sduboff 		/* For sis900, index is in word */
8767893SAlan.Duboff@Sun.COM 		OUTLINL(dp, RFCR,
8775748Sduboff 		    (RFADDR_MULTICAST_SIS900 + i) << RFCR_RFADDR_SHIFT_SIS900);
8787893SAlan.Duboff@Sun.COM 		OUTLINL(dp, RFDR, hash_tbl[i]);
8795748Sduboff 	}
8805748Sduboff 
8815748Sduboff 	/* Load rx filter mode and enable rx filter */
8827893SAlan.Duboff@Sun.COM 	OUTLINL(dp, RFCR, RFCR_RFEN | mode);
8835748Sduboff 
8845748Sduboff 	return (GEM_SUCCESS);
8855748Sduboff }
8865748Sduboff 
8875748Sduboff static int
sfe_start_chip(struct gem_dev * dp)8885748Sduboff sfe_start_chip(struct gem_dev *dp)
8895748Sduboff {
8905748Sduboff 	struct sfe_dev	*lp = dp->private;
8915748Sduboff 
8925748Sduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__));
8935748Sduboff 
8945748Sduboff 	/*
8955748Sduboff 	 * setup interrupt mask, which shouldn't include ISR_TOK
8965748Sduboff 	 * to improve performance.
8975748Sduboff 	 */
8985748Sduboff 	lp->our_intr_bits = OUR_INTR_BITS;
8995748Sduboff 
9005748Sduboff 	/* enable interrupt */
9015748Sduboff 	if ((dp->misc_flag & GEM_NOINTR) == 0) {
9025748Sduboff 		OUTL(dp, IER, 1);
9035748Sduboff 		OUTL(dp, IMR, lp->our_intr_bits);
9045748Sduboff 	}
9055748Sduboff 
9065748Sduboff 	/* Kick RX */
9075748Sduboff 	OUTL(dp, CR, lp->cr | CR_RXE);
9085748Sduboff 
9095748Sduboff 	return (GEM_SUCCESS);
9105748Sduboff }
9115748Sduboff 
9125748Sduboff /*
9135748Sduboff  * Stop nic core gracefully.
9145748Sduboff  */
9155748Sduboff static int
sfe_stop_chip(struct gem_dev * dp)9165748Sduboff sfe_stop_chip(struct gem_dev *dp)
9175748Sduboff {
9185748Sduboff 	struct sfe_dev	*lp = dp->private;
9195748Sduboff 	uint32_t	done;
9205748Sduboff 	int		i;
9217116Sduboff 	uint32_t	val;
9225748Sduboff 
9235748Sduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__));
9245748Sduboff 
9255748Sduboff 	/*
9265748Sduboff 	 * Although we inhibit interrupt here, we don't clear soft copy of
9275748Sduboff 	 * interrupt mask to avoid bogus interrupts.
9285748Sduboff 	 */
9295748Sduboff 	OUTL(dp, IMR, 0);
9305748Sduboff 
9315748Sduboff 	/* stop TX and RX immediately */
9325748Sduboff 	OUTL(dp, CR, lp->cr | CR_TXR | CR_RXR);
9335748Sduboff 
9345748Sduboff 	done = 0;
9355748Sduboff 	for (i = 0; done != (ISR_RXRCMP | ISR_TXRCMP); i++) {
9365748Sduboff 		if (i > 1000) {
9375748Sduboff 			/*
9385748Sduboff 			 * As gem layer will call sfe_reset_chip(),
9395748Sduboff 			 * we don't neet to reset futher
9405748Sduboff 			 */
9415748Sduboff 			cmn_err(CE_NOTE, "!%s: %s: Tx/Rx reset timeout",
9425748Sduboff 			    dp->name, __func__);
9435748Sduboff 
9445748Sduboff 			return (GEM_FAILURE);
9455748Sduboff 		}
9467116Sduboff 		val = INL(dp, ISR);
9477116Sduboff 		done |= val & (ISR_RXRCMP | ISR_TXRCMP);
9487116Sduboff 		lp->isr_pended |= val & lp->our_intr_bits;
9495748Sduboff 		drv_usecwait(10);
9505748Sduboff 	}
9515748Sduboff 
9525748Sduboff 	return (GEM_SUCCESS);
9535748Sduboff }
9545748Sduboff 
9558611SSherry.Moore@Sun.COM #ifndef	__sparc
9568611SSherry.Moore@Sun.COM /*
9578611SSherry.Moore@Sun.COM  * Stop nic core gracefully for quiesce
9588611SSherry.Moore@Sun.COM  */
9598611SSherry.Moore@Sun.COM static int
sfe_stop_chip_quiesce(struct gem_dev * dp)9608611SSherry.Moore@Sun.COM sfe_stop_chip_quiesce(struct gem_dev *dp)
9618611SSherry.Moore@Sun.COM {
9628611SSherry.Moore@Sun.COM 	struct sfe_dev	*lp = dp->private;
9638611SSherry.Moore@Sun.COM 	uint32_t	done;
9648611SSherry.Moore@Sun.COM 	int		i;
9658611SSherry.Moore@Sun.COM 	uint32_t	val;
9668611SSherry.Moore@Sun.COM 
9678611SSherry.Moore@Sun.COM 	/*
9688611SSherry.Moore@Sun.COM 	 * Although we inhibit interrupt here, we don't clear soft copy of
9698611SSherry.Moore@Sun.COM 	 * interrupt mask to avoid bogus interrupts.
9708611SSherry.Moore@Sun.COM 	 */
9718611SSherry.Moore@Sun.COM 	OUTL(dp, IMR, 0);
9728611SSherry.Moore@Sun.COM 
9738611SSherry.Moore@Sun.COM 	/* stop TX and RX immediately */
9748611SSherry.Moore@Sun.COM 	OUTL(dp, CR, CR_TXR | CR_RXR);
9758611SSherry.Moore@Sun.COM 
9768611SSherry.Moore@Sun.COM 	done = 0;
9778611SSherry.Moore@Sun.COM 	for (i = 0; done != (ISR_RXRCMP | ISR_TXRCMP); i++) {
9788611SSherry.Moore@Sun.COM 		if (i > 1000) {
9798611SSherry.Moore@Sun.COM 			/*
9808611SSherry.Moore@Sun.COM 			 * As gem layer will call sfe_reset_chip(),
9818611SSherry.Moore@Sun.COM 			 * we don't neet to reset futher
9828611SSherry.Moore@Sun.COM 			 */
9838611SSherry.Moore@Sun.COM 
9848611SSherry.Moore@Sun.COM 			return (DDI_FAILURE);
9858611SSherry.Moore@Sun.COM 		}
9868611SSherry.Moore@Sun.COM 		val = INL(dp, ISR);
9878611SSherry.Moore@Sun.COM 		done |= val & (ISR_RXRCMP | ISR_TXRCMP);
9888611SSherry.Moore@Sun.COM 		lp->isr_pended |= val & lp->our_intr_bits;
9898611SSherry.Moore@Sun.COM 		drv_usecwait(10);
9908611SSherry.Moore@Sun.COM 	}
9918611SSherry.Moore@Sun.COM 	return (DDI_SUCCESS);
9928611SSherry.Moore@Sun.COM }
9938611SSherry.Moore@Sun.COM #endif
9948611SSherry.Moore@Sun.COM 
9955748Sduboff /*
9965748Sduboff  * Setup media mode
9975748Sduboff  */
9985748Sduboff static uint_t
9995748Sduboff sfe_mxdma_value[] = { 512, 4, 8, 16, 32, 64, 128, 256, };
10005748Sduboff 
10015748Sduboff static uint_t
sfe_encode_mxdma(uint_t burstsize)10025748Sduboff sfe_encode_mxdma(uint_t burstsize)
10035748Sduboff {
10045748Sduboff 	int	i;
10055748Sduboff 
10065748Sduboff 	if (burstsize > 256) {
10075748Sduboff 		/* choose 512 */
10085748Sduboff 		return (0);
10095748Sduboff 	}
10105748Sduboff 
10115748Sduboff 	for (i = 1; i < 8; i++) {
10125748Sduboff 		if (burstsize <= sfe_mxdma_value[i]) {
10135748Sduboff 			break;
10145748Sduboff 		}
10155748Sduboff 	}
10165748Sduboff 	return (i);
10175748Sduboff }
10185748Sduboff 
10195748Sduboff static int
sfe_set_media(struct gem_dev * dp)10205748Sduboff sfe_set_media(struct gem_dev *dp)
10215748Sduboff {
10225748Sduboff 	uint32_t	txcfg;
10235748Sduboff 	uint32_t	rxcfg;
10245748Sduboff 	uint32_t	pcr;
10255748Sduboff 	uint32_t	val;
10265748Sduboff 	uint32_t	txmxdma;
10275748Sduboff 	uint32_t	rxmxdma;
10285748Sduboff 	struct sfe_dev	*lp = dp->private;
10295748Sduboff #ifdef DEBUG_LEVEL
10305748Sduboff 	extern int	gem_speed_value[];
10315748Sduboff #endif
10325748Sduboff 	DPRINTF(2, (CE_CONT, CONS "%s: %s: %s duplex, %d Mbps",
10335748Sduboff 	    dp->name, __func__,
10345748Sduboff 	    dp->full_duplex ? "full" : "half", gem_speed_value[dp->speed]));
10355748Sduboff 
10365748Sduboff 	/* initialize txcfg and rxcfg */
10375748Sduboff 	txcfg = TXCFG_ATP;
10385748Sduboff 	if (dp->full_duplex) {
10395748Sduboff 		txcfg |= (TXCFG_CSI | TXCFG_HBI);
10405748Sduboff 	}
10417116Sduboff 	rxcfg = RXCFG_AEP | RXCFG_ARP;
10425748Sduboff 	if (dp->full_duplex) {
10435748Sduboff 		rxcfg |= RXCFG_ATX;
10445748Sduboff 	}
10455748Sduboff 
10465748Sduboff 	/* select txmxdma and rxmxdma, maxmum burst length */
10475748Sduboff 	if (lp->chip->chip_type == CHIPTYPE_SIS900) {
10485748Sduboff #ifdef DEBUG_SIS900_EDB
10495748Sduboff 		val = CFG_EDB_MASTER;
10505748Sduboff #else
10515748Sduboff 		val = INL(dp, CFG) & CFG_EDB_MASTER;
10525748Sduboff #endif
10535748Sduboff 		if (val) {
10545748Sduboff 			/*
10555748Sduboff 			 * sis900 built-in cores:
10565748Sduboff 			 * max burst length must be fixed to 64
10575748Sduboff 			 */
10585748Sduboff 			txmxdma = 64;
10595748Sduboff 			rxmxdma = 64;
10605748Sduboff 		} else {
10615748Sduboff 			/*
10625748Sduboff 			 * sis900 pci chipset:
10635748Sduboff 			 * the vendor recommended to fix max burst length
10645748Sduboff 			 * to 512
10655748Sduboff 			 */
10665748Sduboff 			txmxdma = 512;
10675748Sduboff 			rxmxdma = 512;
10685748Sduboff 		}
10695748Sduboff 	} else {
10705748Sduboff 		/*
10715748Sduboff 		 * NS dp83815/816:
10725748Sduboff 		 * use user defined or default for tx/rx max burst length
10735748Sduboff 		 */
10745748Sduboff 		txmxdma = max(dp->txmaxdma, 256);
10755748Sduboff 		rxmxdma = max(dp->rxmaxdma, 256);
10765748Sduboff 	}
10775748Sduboff 
10785748Sduboff 
10795748Sduboff 	/* tx high water mark */
10805748Sduboff 	lp->tx_drain_threshold = ROUNDUP2(dp->txthr, TXCFG_FIFO_UNIT);
10815748Sduboff 
10825748Sduboff 	/* determine tx_fill_threshold accroding drain threshold */
10835748Sduboff 	lp->tx_fill_threshold =
10845748Sduboff 	    TXFIFOSIZE - lp->tx_drain_threshold - TXCFG_FIFO_UNIT;
10855748Sduboff 
10865748Sduboff 	/* tune txmxdma not to exceed tx_fill_threshold */
10875748Sduboff 	for (; ; ) {
10885748Sduboff 		/* normalize txmxdma requested */
10895748Sduboff 		val = sfe_encode_mxdma(txmxdma);
10905748Sduboff 		txmxdma = sfe_mxdma_value[val];
10915748Sduboff 
10925748Sduboff 		if (txmxdma <= lp->tx_fill_threshold) {
10935748Sduboff 			break;
10945748Sduboff 		}
10955748Sduboff 		/* select new txmxdma */
10965748Sduboff 		txmxdma = txmxdma / 2;
10975748Sduboff 	}
10985748Sduboff 	txcfg |= val << TXCFG_MXDMA_SHIFT;
10995748Sduboff 
11005748Sduboff 	/* encode rxmxdma, maxmum burst length for rx */
11015748Sduboff 	val = sfe_encode_mxdma(rxmxdma);
11027116Sduboff 	rxcfg |= val << RXCFG_MXDMA_SHIFT;
11035748Sduboff 	rxmxdma = sfe_mxdma_value[val];
11045748Sduboff 
11055748Sduboff 	/* receive starting threshold - it have only 5bit-wide field */
11065748Sduboff 	val = ROUNDUP2(max(dp->rxthr, ETHERMIN), RXCFG_FIFO_UNIT);
11075748Sduboff 	lp->rx_drain_threshold =
11085748Sduboff 	    min(val, (RXCFG_DRTH >> RXCFG_DRTH_SHIFT) * RXCFG_FIFO_UNIT);
11095748Sduboff 
11105748Sduboff 	DPRINTF(0, (CE_CONT,
11115748Sduboff 	    "%s: %s: tx: drain:%d(rest %d) fill:%d mxdma:%d,"
11125748Sduboff 	    " rx: drain:%d mxdma:%d",
11135748Sduboff 	    dp->name, __func__,
11145748Sduboff 	    lp->tx_drain_threshold, TXFIFOSIZE - lp->tx_drain_threshold,
11155748Sduboff 	    lp->tx_fill_threshold, txmxdma,
11165748Sduboff 	    lp->rx_drain_threshold, rxmxdma));
11175748Sduboff 
11185748Sduboff 	ASSERT(lp->tx_drain_threshold < 64*TXCFG_FIFO_UNIT);
11195748Sduboff 	ASSERT(lp->tx_fill_threshold < 64*TXCFG_FIFO_UNIT);
11205748Sduboff 	ASSERT(lp->rx_drain_threshold < 32*RXCFG_FIFO_UNIT);
11215748Sduboff 
11225748Sduboff 	txcfg |= ((lp->tx_fill_threshold/TXCFG_FIFO_UNIT) << TXCFG_FLTH_SHIFT)
11235748Sduboff 	    | (lp->tx_drain_threshold/TXCFG_FIFO_UNIT);
11245748Sduboff 	OUTL(dp, TXCFG, txcfg);
11255748Sduboff 
11265748Sduboff 	rxcfg |= ((lp->rx_drain_threshold/RXCFG_FIFO_UNIT) << RXCFG_DRTH_SHIFT);
11275748Sduboff 	if (lp->chip->chip_type == CHIPTYPE_DP83815) {
11285748Sduboff 		rxcfg |= RXCFG_ALP_DP83815;
11295748Sduboff 	}
11305748Sduboff 	OUTL(dp, RXCFG, rxcfg);
11315748Sduboff 
11325748Sduboff 	DPRINTF(0, (CE_CONT, CONS "%s: %s: txcfg:%b rxcfg:%b",
11335748Sduboff 	    dp->name, __func__,
11345748Sduboff 	    txcfg, TXCFG_BITS, rxcfg, RXCFG_BITS));
11355748Sduboff 
11365748Sduboff 	/* Flow control */
11375748Sduboff 	if (lp->chip->chip_type == CHIPTYPE_DP83815) {
11385748Sduboff 		pcr = INL(dp, PCR);
11395748Sduboff 		switch (dp->flow_control) {
11405748Sduboff 		case FLOW_CONTROL_SYMMETRIC:
11415748Sduboff 		case FLOW_CONTROL_RX_PAUSE:
11425748Sduboff 			OUTL(dp, PCR, pcr | PCR_PSEN | PCR_PS_MCAST);
11435748Sduboff 			break;
11445748Sduboff 
11455748Sduboff 		default:
11465748Sduboff 			OUTL(dp, PCR,
11475748Sduboff 			    pcr & ~(PCR_PSEN | PCR_PS_MCAST | PCR_PS_DA));
11485748Sduboff 			break;
11495748Sduboff 		}
11505748Sduboff 		DPRINTF(2, (CE_CONT, CONS "%s: PCR: %b", dp->name,
11515748Sduboff 		    INL(dp, PCR), PCR_BITS));
11525748Sduboff 
11535748Sduboff 	} else if (lp->chip->chip_type == CHIPTYPE_SIS900) {
11545748Sduboff 		switch (dp->flow_control) {
11555748Sduboff 		case FLOW_CONTROL_SYMMETRIC:
11565748Sduboff 		case FLOW_CONTROL_RX_PAUSE:
11575748Sduboff 			OUTL(dp, FLOWCTL, FLOWCTL_FLOWEN);
11585748Sduboff 			break;
11595748Sduboff 		default:
11605748Sduboff 			OUTL(dp, FLOWCTL, 0);
11615748Sduboff 			break;
11625748Sduboff 		}
11635748Sduboff 		DPRINTF(2, (CE_CONT, CONS "%s: FLOWCTL: %b",
11645748Sduboff 		    dp->name, INL(dp, FLOWCTL), FLOWCTL_BITS));
11655748Sduboff 	}
11665748Sduboff 	return (GEM_SUCCESS);
11675748Sduboff }
11685748Sduboff 
11695748Sduboff static int
sfe_get_stats(struct gem_dev * dp)11705748Sduboff sfe_get_stats(struct gem_dev *dp)
11715748Sduboff {
11725748Sduboff 	/* do nothing */
11735748Sduboff 	return (GEM_SUCCESS);
11745748Sduboff }
11755748Sduboff 
11765748Sduboff /*
11775748Sduboff  * descriptor manipulations
11785748Sduboff  */
11795748Sduboff static int
sfe_tx_desc_write(struct gem_dev * dp,int slot,ddi_dma_cookie_t * dmacookie,int frags,uint64_t flags)11805748Sduboff sfe_tx_desc_write(struct gem_dev *dp, int slot,
11815748Sduboff 		ddi_dma_cookie_t *dmacookie, int frags, uint64_t flags)
11825748Sduboff {
11835748Sduboff 	uint32_t		mark;
11845748Sduboff 	struct sfe_desc		*tdp;
11855748Sduboff 	ddi_dma_cookie_t	*dcp;
11867116Sduboff 	uint32_t		tmp0;
11877116Sduboff #if DEBUG_LEVEL > 2
11885748Sduboff 	int			i;
11895748Sduboff 
11905748Sduboff 	cmn_err(CE_CONT,
11915748Sduboff 	    CONS "%s: time:%d %s seqnum: %d, slot %d, frags: %d flags: %llx",
11925748Sduboff 	    dp->name, ddi_get_lbolt(), __func__,
11935748Sduboff 	    dp->tx_desc_tail, slot, frags, flags);
11945748Sduboff 
11955748Sduboff 	for (i = 0; i < frags; i++) {
11965748Sduboff 		cmn_err(CE_CONT, CONS "%d: addr: 0x%x, len: 0x%x",
11975748Sduboff 		    i, dmacookie[i].dmac_address, dmacookie[i].dmac_size);
11987116Sduboff 	}
11995748Sduboff #endif
12005748Sduboff 	/*
12015748Sduboff 	 * write tx descriptor in reversed order.
12025748Sduboff 	 */
12035748Sduboff #if DEBUG_LEVEL > 3
12045748Sduboff 	flags |= GEM_TXFLAG_INTR;
12055748Sduboff #endif
12065748Sduboff 	mark = (flags & GEM_TXFLAG_INTR)
12077116Sduboff 	    ? (CMDSTS_OWN | CMDSTS_INTR) : CMDSTS_OWN;
12085748Sduboff 
12095748Sduboff 	ASSERT(frags == 1);
12105748Sduboff 	dcp = &dmacookie[0];
12115748Sduboff 	if (flags & GEM_TXFLAG_HEAD) {
12125748Sduboff 		mark &= ~CMDSTS_OWN;
12135748Sduboff 	}
12145748Sduboff 
12155748Sduboff 	tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot];
12167116Sduboff 	tmp0 = (uint32_t)dcp->dmac_address;
12177116Sduboff 	mark |= (uint32_t)dcp->dmac_size;
12187116Sduboff 	tdp->d_bufptr = LE_32(tmp0);
12197116Sduboff 	tdp->d_cmdsts = LE_32(mark);
12205748Sduboff 
12215748Sduboff 	return (frags);
12225748Sduboff }
12235748Sduboff 
12245748Sduboff static void
sfe_tx_start(struct gem_dev * dp,int start_slot,int nslot)12255748Sduboff sfe_tx_start(struct gem_dev *dp, int start_slot, int nslot)
12265748Sduboff {
12277116Sduboff 	uint_t			tx_ring_size = dp->gc.gc_tx_ring_size;
12285748Sduboff 	struct sfe_desc		*tdp;
12295748Sduboff 	struct sfe_dev		*lp = dp->private;
12305748Sduboff 
12315748Sduboff 	if (nslot > 1) {
12325748Sduboff 		gem_tx_desc_dma_sync(dp,
12337116Sduboff 		    SLOT(start_slot + 1, tx_ring_size),
12345748Sduboff 		    nslot - 1, DDI_DMA_SYNC_FORDEV);
12355748Sduboff 	}
12365748Sduboff 
12375748Sduboff 	tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * start_slot];
12385748Sduboff 	tdp->d_cmdsts |= LE_32(CMDSTS_OWN);
12395748Sduboff 
12405748Sduboff 	gem_tx_desc_dma_sync(dp, start_slot, 1, DDI_DMA_SYNC_FORDEV);
12415748Sduboff 
12425748Sduboff 	/*
12435748Sduboff 	 * Let the Transmit Buffer Manager Fill state machine active.
12445748Sduboff 	 */
12455748Sduboff 	if (dp->mac_active) {
12465748Sduboff 		OUTL(dp, CR, lp->cr | CR_TXE);
12475748Sduboff 	}
12485748Sduboff }
12495748Sduboff 
12505748Sduboff static void
sfe_rx_desc_write(struct gem_dev * dp,int slot,ddi_dma_cookie_t * dmacookie,int frags)12515748Sduboff sfe_rx_desc_write(struct gem_dev *dp, int slot,
12525748Sduboff 	    ddi_dma_cookie_t *dmacookie, int frags)
12535748Sduboff {
12545748Sduboff 	struct sfe_desc		*rdp;
12557116Sduboff 	uint32_t		tmp0;
12567116Sduboff 	uint32_t		tmp1;
12575748Sduboff #if DEBUG_LEVEL > 2
12585748Sduboff 	int			i;
12595748Sduboff 
12605748Sduboff 	ASSERT(frags == 1);
12615748Sduboff 
12625748Sduboff 	cmn_err(CE_CONT, CONS
12635748Sduboff 	    "%s: %s seqnum: %d, slot %d, frags: %d",
12645748Sduboff 	    dp->name, __func__, dp->rx_active_tail, slot, frags);
12655748Sduboff 	for (i = 0; i < frags; i++) {
12665748Sduboff 		cmn_err(CE_CONT, CONS "  frag: %d addr: 0x%llx, len: 0x%lx",
12675748Sduboff 		    i, dmacookie[i].dmac_address, dmacookie[i].dmac_size);
12685748Sduboff 	}
12695748Sduboff #endif
12705748Sduboff 	/* for the last slot of the packet */
12715748Sduboff 	rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot];
12725748Sduboff 
12737116Sduboff 	tmp0 = (uint32_t)dmacookie->dmac_address;
12747116Sduboff 	tmp1 = CMDSTS_INTR | (uint32_t)dmacookie->dmac_size;
12757116Sduboff 	rdp->d_bufptr = LE_32(tmp0);
12767116Sduboff 	rdp->d_cmdsts = LE_32(tmp1);
12775748Sduboff }
12785748Sduboff 
12795748Sduboff static uint_t
sfe_tx_desc_stat(struct gem_dev * dp,int slot,int ndesc)12805748Sduboff sfe_tx_desc_stat(struct gem_dev *dp, int slot, int ndesc)
12815748Sduboff {
12827116Sduboff 	uint_t			tx_ring_size = dp->gc.gc_tx_ring_size;
12835748Sduboff 	struct sfe_desc		*tdp;
12845748Sduboff 	uint32_t		status;
12855748Sduboff 	int			cols;
12867116Sduboff 	struct sfe_dev		*lp = dp->private;
12875748Sduboff #ifdef DEBUG_LEVEL
12885748Sduboff 	int			i;
12895748Sduboff 	clock_t			delay;
12905748Sduboff #endif
12915748Sduboff 	/* check status of the last descriptor */
12925748Sduboff 	tdp = (void *)
12937116Sduboff 	    &dp->tx_ring[SFE_DESC_SIZE * SLOT(slot + ndesc - 1, tx_ring_size)];
12945748Sduboff 
12957116Sduboff 	/*
12967116Sduboff 	 * Don't use LE_32() directly to refer tdp->d_cmdsts.
12977116Sduboff 	 * It is not atomic for big endian cpus.
12987116Sduboff 	 */
12997116Sduboff 	status = tdp->d_cmdsts;
13007116Sduboff 	status = LE_32(status);
13015748Sduboff 
13025748Sduboff 	DPRINTF(2, (CE_CONT, CONS "%s: time:%ld %s: slot:%d, status:0x%b",
13035748Sduboff 	    dp->name, ddi_get_lbolt(), __func__,
13045748Sduboff 	    slot, status, TXSTAT_BITS));
13055748Sduboff 
13065748Sduboff 	if (status & CMDSTS_OWN) {
13075748Sduboff 		/*
13085748Sduboff 		 * not yet transmitted
13095748Sduboff 		 */
13107116Sduboff 		/* workaround for tx hang */
13117116Sduboff 		if (lp->chip->chip_type == CHIPTYPE_DP83815 &&
13127116Sduboff 		    dp->mac_active) {
13137116Sduboff 			OUTL(dp, CR, lp->cr | CR_TXE);
13147116Sduboff 		}
13155748Sduboff 		return (0);
13165748Sduboff 	}
13175748Sduboff 
13185748Sduboff 	if (status & CMDSTS_MORE) {
13195748Sduboff 		/* XXX - the hardware problem but don't panic the system */
13205748Sduboff 		/* avoid lint bug for %b format string including 32nd bit */
13215748Sduboff 		cmn_err(CE_NOTE, CONS
13225748Sduboff 		    "%s: tx status bits incorrect:  slot:%d, status:0x%x",
13235748Sduboff 		    dp->name, slot, status);
13245748Sduboff 	}
13255748Sduboff 
13265748Sduboff #if DEBUG_LEVEL > 3
13275748Sduboff 	delay = (ddi_get_lbolt() - dp->tx_buf_head->txb_stime) * 10;
13285748Sduboff 	if (delay >= 50) {
13295748Sduboff 		DPRINTF(0, (CE_NOTE, "%s: tx deferred %d mS: slot %d",
13305748Sduboff 		    dp->name, delay, slot));
13315748Sduboff 	}
13325748Sduboff #endif
13335748Sduboff 
13345748Sduboff #if DEBUG_LEVEL > 3
13355748Sduboff 	for (i = 0; i < nfrag-1; i++) {
13365748Sduboff 		uint32_t	s;
13375748Sduboff 		int		n;
13385748Sduboff 
13397116Sduboff 		n = SLOT(slot + i, tx_ring_size);
13405748Sduboff 		s = LE_32(
13415748Sduboff 		    ((struct sfe_desc *)((void *)
13425748Sduboff 		    &dp->tx_ring[SFE_DESC_SIZE * n]))->d_cmdsts);
13435748Sduboff 
13445748Sduboff 		ASSERT(s & CMDSTS_MORE);
13455748Sduboff 		ASSERT((s & CMDSTS_OWN) == 0);
13465748Sduboff 	}
13475748Sduboff #endif
13485748Sduboff 
13495748Sduboff 	/*
13505748Sduboff 	 *  collect statistics
13515748Sduboff 	 */
13525748Sduboff 	if ((status & CMDSTS_OK) == 0) {
13535748Sduboff 
13545748Sduboff 		/* failed to transmit the packet */
13555748Sduboff 
13565748Sduboff 		DPRINTF(0, (CE_CONT, CONS "%s: Transmit error, Tx status %b",
13575748Sduboff 		    dp->name, status, TXSTAT_BITS));
13585748Sduboff 
13595748Sduboff 		dp->stats.errxmt++;
13605748Sduboff 
13615748Sduboff 		if (status & CMDSTS_TFU) {
13625748Sduboff 			dp->stats.underflow++;
13635748Sduboff 		} else if (status & CMDSTS_CRS) {
13645748Sduboff 			dp->stats.nocarrier++;
13655748Sduboff 		} else if (status & CMDSTS_OWC) {
13665748Sduboff 			dp->stats.xmtlatecoll++;
13675748Sduboff 		} else if ((!dp->full_duplex) && (status & CMDSTS_EC)) {
13685748Sduboff 			dp->stats.excoll++;
13695748Sduboff 			dp->stats.collisions += 16;
13705748Sduboff 		} else {
13715748Sduboff 			dp->stats.xmit_internal_err++;
13725748Sduboff 		}
13735748Sduboff 	} else if (!dp->full_duplex) {
13745748Sduboff 		cols = (status >> CMDSTS_CCNT_SHIFT) & CCNT_MASK;
13755748Sduboff 
13765748Sduboff 		if (cols > 0) {
13775748Sduboff 			if (cols == 1) {
13785748Sduboff 				dp->stats.first_coll++;
13795748Sduboff 			} else /* (cols > 1) */ {
13805748Sduboff 				dp->stats.multi_coll++;
13815748Sduboff 			}
13825748Sduboff 			dp->stats.collisions += cols;
13835748Sduboff 		} else if (status & CMDSTS_TD) {
13845748Sduboff 			dp->stats.defer++;
13855748Sduboff 		}
13865748Sduboff 	}
13875748Sduboff 	return (GEM_TX_DONE);
13885748Sduboff }
13895748Sduboff 
13905748Sduboff static uint64_t
sfe_rx_desc_stat(struct gem_dev * dp,int slot,int ndesc)13915748Sduboff sfe_rx_desc_stat(struct gem_dev *dp, int slot, int ndesc)
13925748Sduboff {
13935748Sduboff 	struct sfe_desc		*rdp;
13945748Sduboff 	uint_t			len;
13955748Sduboff 	uint_t			flag;
13965748Sduboff 	uint32_t		status;
13975748Sduboff 
13985748Sduboff 	flag = GEM_RX_DONE;
13995748Sduboff 
14005748Sduboff 	/* Dont read ISR because we cannot ack only to rx interrupt. */
14015748Sduboff 
14025748Sduboff 	rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot];
14035748Sduboff 
14047116Sduboff 	/*
14057116Sduboff 	 * Don't use LE_32() directly to refer rdp->d_cmdsts.
14067116Sduboff 	 * It is not atomic for big endian cpus.
14077116Sduboff 	 */
14087116Sduboff 	status = rdp->d_cmdsts;
14097116Sduboff 	status = LE_32(status);
14105748Sduboff 
14115748Sduboff 	DPRINTF(2, (CE_CONT, CONS "%s: time:%ld %s: slot:%d, status:0x%b",
14125748Sduboff 	    dp->name, ddi_get_lbolt(), __func__,
14135748Sduboff 	    slot, status, RXSTAT_BITS));
14145748Sduboff 
14155748Sduboff 	if ((status & CMDSTS_OWN) == 0) {
14165748Sduboff 		/*
14175748Sduboff 		 * No more received packets because
14185748Sduboff 		 * this buffer is owned by NIC.
14195748Sduboff 		 */
14205748Sduboff 		return (0);
14215748Sduboff 	}
14225748Sduboff 
14235748Sduboff #define	RX_ERR_BITS \
14245748Sduboff 	(CMDSTS_RXA | CMDSTS_RXO | CMDSTS_LONG | CMDSTS_RUNT | \
14255748Sduboff 		CMDSTS_ISE | CMDSTS_CRCE | CMDSTS_FAE | CMDSTS_MORE)
14265748Sduboff 
14275748Sduboff 	if (status & RX_ERR_BITS) {
14285748Sduboff 		/*
14295748Sduboff 		 * Packet with error received
14305748Sduboff 		 */
14315748Sduboff 		DPRINTF(0, (CE_CONT, CONS "%s: Corrupted packet "
14325748Sduboff 		    "received, buffer status: %b",
14335748Sduboff 		    dp->name, status, RXSTAT_BITS));
14345748Sduboff 
14355748Sduboff 		/* collect statistics information */
14365748Sduboff 		dp->stats.errrcv++;
14375748Sduboff 
14385748Sduboff 		if (status & CMDSTS_RXO) {
14395748Sduboff 			dp->stats.overflow++;
14405748Sduboff 		} else if (status & (CMDSTS_LONG | CMDSTS_MORE)) {
14415748Sduboff 			dp->stats.frame_too_long++;
14425748Sduboff 		} else if (status & CMDSTS_RUNT) {
14435748Sduboff 			dp->stats.runt++;
14445748Sduboff 		} else if (status & (CMDSTS_ISE | CMDSTS_FAE)) {
14455748Sduboff 			dp->stats.frame++;
14465748Sduboff 		} else if (status & CMDSTS_CRCE) {
14475748Sduboff 			dp->stats.crc++;
14485748Sduboff 		} else {
14495748Sduboff 			dp->stats.rcv_internal_err++;
14505748Sduboff 		}
14515748Sduboff 
14525748Sduboff 		return (flag | GEM_RX_ERR);
14535748Sduboff 	}
14545748Sduboff 
14555748Sduboff 	/*
14565748Sduboff 	 * this packet was received without errors
14575748Sduboff 	 */
14585748Sduboff 	if ((len = (status & CMDSTS_SIZE)) >= ETHERFCSL) {
14595748Sduboff 		len -= ETHERFCSL;
14605748Sduboff 	}
14615748Sduboff 
14625748Sduboff #if DEBUG_LEVEL > 10
14635748Sduboff {
14645748Sduboff 	int	i;
14655748Sduboff 	uint8_t	*bp = dp->rx_buf_head->rxb_buf;
14665748Sduboff 
14675748Sduboff 	cmn_err(CE_CONT, CONS "%s: len:%d", dp->name, len);
14685748Sduboff 
14695748Sduboff 	for (i = 0; i < 60; i += 10) {
14705748Sduboff 		cmn_err(CE_CONT, CONS
14715748Sduboff 		    "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
14725748Sduboff 		    bp[0], bp[1], bp[2], bp[3], bp[4],
14735748Sduboff 		    bp[5], bp[6], bp[7], bp[8], bp[9]);
14745748Sduboff 	}
14755748Sduboff 	bp += 10;
14765748Sduboff }
14775748Sduboff #endif
14785748Sduboff 	return (flag | (len & GEM_RX_LEN));
14795748Sduboff }
14805748Sduboff 
14815748Sduboff static void
sfe_tx_desc_init(struct gem_dev * dp,int slot)14825748Sduboff sfe_tx_desc_init(struct gem_dev *dp, int slot)
14835748Sduboff {
14847116Sduboff 	uint_t			tx_ring_size = dp->gc.gc_tx_ring_size;
14855748Sduboff 	struct sfe_desc		*tdp;
14865748Sduboff 	uint32_t		here;
14875748Sduboff 
14885748Sduboff 	tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot];
14895748Sduboff 
14905748Sduboff 	/* don't clear d_link field, which have a valid pointer */
14915748Sduboff 	tdp->d_cmdsts = 0;
14925748Sduboff 
14935748Sduboff 	/* make a link to this from the previous descriptor */
14945748Sduboff 	here = ((uint32_t)dp->tx_ring_dma) + SFE_DESC_SIZE*slot;
14955748Sduboff 
14965748Sduboff 	tdp = (void *)
14977116Sduboff 	    &dp->tx_ring[SFE_DESC_SIZE * SLOT(slot - 1, tx_ring_size)];
14985748Sduboff 	tdp->d_link = LE_32(here);
14995748Sduboff }
15005748Sduboff 
15015748Sduboff static void
sfe_rx_desc_init(struct gem_dev * dp,int slot)15025748Sduboff sfe_rx_desc_init(struct gem_dev *dp, int slot)
15035748Sduboff {
15047116Sduboff 	uint_t			rx_ring_size = dp->gc.gc_rx_ring_size;
15055748Sduboff 	struct sfe_desc		*rdp;
15065748Sduboff 	uint32_t		here;
15075748Sduboff 
15085748Sduboff 	rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot];
15095748Sduboff 
15105748Sduboff 	/* don't clear d_link field, which have a valid pointer */
15115748Sduboff 	rdp->d_cmdsts = LE_32(CMDSTS_OWN);
15125748Sduboff 
15135748Sduboff 	/* make a link to this from the previous descriptor */
15145748Sduboff 	here = ((uint32_t)dp->rx_ring_dma) + SFE_DESC_SIZE*slot;
15155748Sduboff 
15165748Sduboff 	rdp = (void *)
15177116Sduboff 	    &dp->rx_ring[SFE_DESC_SIZE * SLOT(slot - 1, rx_ring_size)];
15185748Sduboff 	rdp->d_link = LE_32(here);
15195748Sduboff }
15205748Sduboff 
15215748Sduboff static void
sfe_tx_desc_clean(struct gem_dev * dp,int slot)15225748Sduboff sfe_tx_desc_clean(struct gem_dev *dp, int slot)
15235748Sduboff {
15245748Sduboff 	struct sfe_desc		*tdp;
15255748Sduboff 
15265748Sduboff 	tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot];
15275748Sduboff 	tdp->d_cmdsts = 0;
15285748Sduboff }
15295748Sduboff 
15305748Sduboff static void
sfe_rx_desc_clean(struct gem_dev * dp,int slot)15315748Sduboff sfe_rx_desc_clean(struct gem_dev *dp, int slot)
15325748Sduboff {
15335748Sduboff 	struct sfe_desc		*rdp;
15345748Sduboff 
15355748Sduboff 	rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot];
15365748Sduboff 	rdp->d_cmdsts = LE_32(CMDSTS_OWN);
15375748Sduboff }
15385748Sduboff 
15395748Sduboff /*
15405748Sduboff  * Device depend interrupt handler
15415748Sduboff  */
15425748Sduboff static uint_t
sfe_interrupt(struct gem_dev * dp)15435748Sduboff sfe_interrupt(struct gem_dev *dp)
15445748Sduboff {
15457116Sduboff 	uint_t		rx_ring_size = dp->gc.gc_rx_ring_size;
15465748Sduboff 	uint32_t	isr;
15477116Sduboff 	uint32_t	isr_bogus;
15485748Sduboff 	uint_t		flags = 0;
15495748Sduboff 	boolean_t	need_to_reset = B_FALSE;
15505748Sduboff 	struct sfe_dev	*lp = dp->private;
15515748Sduboff 
15525748Sduboff 	/* read reason and clear interrupt */
15535748Sduboff 	isr = INL(dp, ISR);
15545748Sduboff 
15557116Sduboff 	isr_bogus = lp->isr_pended;
15567116Sduboff 	lp->isr_pended = 0;
15577116Sduboff 
15587116Sduboff 	if (((isr | isr_bogus) & lp->our_intr_bits) == 0) {
15595748Sduboff 		/* we are not the interrupt source */
15605748Sduboff 		return (DDI_INTR_UNCLAIMED);
15615748Sduboff 	}
15625748Sduboff 
15635748Sduboff 	DPRINTF(3, (CE_CONT,
15645748Sduboff 	    CONS "%s: time:%ld %s:called: isr:0x%b rx_active_head: %d",
15655748Sduboff 	    dp->name, ddi_get_lbolt(), __func__,
15665748Sduboff 	    isr, INTR_BITS, dp->rx_active_head));
15675748Sduboff 
15685748Sduboff 	if (!dp->mac_active) {
15695748Sduboff 		/* the device is going to stop */
15705748Sduboff 		lp->our_intr_bits = 0;
15715748Sduboff 		return (DDI_INTR_CLAIMED);
15725748Sduboff 	}
15735748Sduboff 
15745748Sduboff 	isr &= lp->our_intr_bits;
15755748Sduboff 
15765748Sduboff 	if (isr & (ISR_RXSOVR | ISR_RXORN | ISR_RXIDLE | ISR_RXERR |
15775748Sduboff 	    ISR_RXDESC | ISR_RXOK)) {
15785748Sduboff 		(void) gem_receive(dp);
15795748Sduboff 
15805748Sduboff 		if (isr & (ISR_RXSOVR | ISR_RXORN)) {
15815748Sduboff 			DPRINTF(0, (CE_CONT,
15825748Sduboff 			    CONS "%s: rx fifo overrun: isr %b",
15835748Sduboff 			    dp->name, isr, INTR_BITS));
15845748Sduboff 			/* no need restart rx */
15855748Sduboff 			dp->stats.overflow++;
15865748Sduboff 		}
15875748Sduboff 
15885748Sduboff 		if (isr & ISR_RXIDLE) {
15895748Sduboff 			DPRINTF(0, (CE_CONT,
15905748Sduboff 			    CONS "%s: rx buffer ran out: isr %b",
15915748Sduboff 			    dp->name, isr, INTR_BITS));
15925748Sduboff 
15935748Sduboff 			dp->stats.norcvbuf++;
15945748Sduboff 
15955748Sduboff 			/*
15965748Sduboff 			 * Make RXDP points the head of receive
15975748Sduboff 			 * buffer list.
15985748Sduboff 			 */
15995748Sduboff 			OUTL(dp, RXDP, dp->rx_ring_dma +
16005748Sduboff 			    SFE_DESC_SIZE *
16017116Sduboff 			    SLOT(dp->rx_active_head, rx_ring_size));
16025748Sduboff 
16035748Sduboff 			/* Restart the receive engine */
16045748Sduboff 			OUTL(dp, CR, lp->cr | CR_RXE);
16055748Sduboff 		}
16065748Sduboff 	}
16075748Sduboff 
16085748Sduboff 	if (isr & (ISR_TXURN | ISR_TXERR | ISR_TXDESC |
16095748Sduboff 	    ISR_TXIDLE | ISR_TXOK)) {
16105748Sduboff 		/* need to reclaim tx buffers */
16115748Sduboff 		if (gem_tx_done(dp)) {
16125748Sduboff 			flags |= INTR_RESTART_TX;
16135748Sduboff 		}
16145748Sduboff 		/*
16155748Sduboff 		 * XXX - tx error statistics will be counted in
16165748Sduboff 		 * sfe_tx_desc_stat() and no need to restart tx on errors.
16175748Sduboff 		 */
16185748Sduboff 	}
16195748Sduboff 
16205748Sduboff 	if (isr & (ISR_DPERR | ISR_SSERR | ISR_RMABT | ISR_RTABT)) {
16215748Sduboff 		cmn_err(CE_WARN, "%s: ERROR interrupt: isr %b.",
16225748Sduboff 		    dp->name, isr, INTR_BITS);
16235748Sduboff 		need_to_reset = B_TRUE;
16245748Sduboff 	}
16255748Sduboff reset:
16265748Sduboff 	if (need_to_reset) {
16275748Sduboff 		(void) gem_restart_nic(dp, GEM_RESTART_KEEP_BUF);
16285748Sduboff 		flags |= INTR_RESTART_TX;
16295748Sduboff 	}
16305748Sduboff 
16315748Sduboff 	DPRINTF(5, (CE_CONT, CONS "%s: %s: return: isr: %b",
16325748Sduboff 	    dp->name, __func__, isr, INTR_BITS));
16335748Sduboff 
16345748Sduboff 	return (DDI_INTR_CLAIMED | flags);
16355748Sduboff }
16365748Sduboff 
16375748Sduboff /* ======================================================== */
16385748Sduboff /*
16395748Sduboff  * HW depend MII routine
16405748Sduboff  */
16415748Sduboff /* ======================================================== */
16425748Sduboff 
16435748Sduboff /*
16445748Sduboff  * MII routines for NS DP83815
16455748Sduboff  */
16465748Sduboff static void
sfe_mii_sync_dp83815(struct gem_dev * dp)16475748Sduboff sfe_mii_sync_dp83815(struct gem_dev *dp)
16485748Sduboff {
16495748Sduboff 	/* do nothing */
16505748Sduboff }
16515748Sduboff 
16525748Sduboff static uint16_t
sfe_mii_read_dp83815(struct gem_dev * dp,uint_t offset)16535748Sduboff sfe_mii_read_dp83815(struct gem_dev *dp, uint_t offset)
16545748Sduboff {
16555748Sduboff 	DPRINTF(4, (CE_CONT, CONS"%s: %s: offset 0x%x",
16565748Sduboff 	    dp->name, __func__, offset));
16575748Sduboff 	return ((uint16_t)INL(dp, MII_REGS_BASE + offset*4));
16585748Sduboff }
16595748Sduboff 
16605748Sduboff static void
sfe_mii_write_dp83815(struct gem_dev * dp,uint_t offset,uint16_t val)16615748Sduboff sfe_mii_write_dp83815(struct gem_dev *dp, uint_t offset, uint16_t val)
16625748Sduboff {
16635748Sduboff 	DPRINTF(4, (CE_CONT, CONS"%s: %s: offset 0x%x 0x%x",
16645748Sduboff 	    dp->name, __func__, offset, val));
16655748Sduboff 	OUTL(dp, MII_REGS_BASE + offset*4, val);
16665748Sduboff }
16675748Sduboff 
16685748Sduboff static int
sfe_mii_config_dp83815(struct gem_dev * dp)16695748Sduboff sfe_mii_config_dp83815(struct gem_dev *dp)
16705748Sduboff {
16715748Sduboff 	uint32_t	srr;
16725748Sduboff 
16735748Sduboff 	srr = INL(dp, SRR) & SRR_REV;
16745748Sduboff 
16755748Sduboff 	DPRINTF(0, (CE_CONT, CONS "%s: srr:0x%04x %04x %04x %04x %04x %04x",
16765748Sduboff 	    dp->name, srr,
16775748Sduboff 	    INW(dp, 0x00cc),	/* PGSEL */
16785748Sduboff 	    INW(dp, 0x00e4),	/* PMDCSR */
16795748Sduboff 	    INW(dp, 0x00fc),	/* TSTDAT */
16805748Sduboff 	    INW(dp, 0x00f4),	/* DSPCFG */
16815748Sduboff 	    INW(dp, 0x00f8)));	/* SDCFG */
16825748Sduboff 
16837116Sduboff 	if (srr == SRR_REV_DP83815CVNG) {
16845748Sduboff 		/*
16855748Sduboff 		 * NS datasheet says that DP83815CVNG needs following
16865748Sduboff 		 * registers to be patched for optimizing its performance.
16877116Sduboff 		 * A report said that CRC errors on RX disappeared
16885748Sduboff 		 * with the patch.
16895748Sduboff 		 */
16905748Sduboff 		OUTW(dp, 0x00cc, 0x0001);	/* PGSEL */
16915748Sduboff 		OUTW(dp, 0x00e4, 0x189c);	/* PMDCSR */
16925748Sduboff 		OUTW(dp, 0x00fc, 0x0000);	/* TSTDAT */
16935748Sduboff 		OUTW(dp, 0x00f4, 0x5040);	/* DSPCFG */
16945748Sduboff 		OUTW(dp, 0x00f8, 0x008c);	/* SDCFG */
16957116Sduboff 		OUTW(dp, 0x00cc, 0x0000);	/* PGSEL */
16965748Sduboff 
16975748Sduboff 		DPRINTF(0, (CE_CONT,
16985748Sduboff 		    CONS "%s: PHY patched %04x %04x %04x %04x %04x",
16995748Sduboff 		    dp->name,
17005748Sduboff 		    INW(dp, 0x00cc),	/* PGSEL */
17015748Sduboff 		    INW(dp, 0x00e4),	/* PMDCSR */
17025748Sduboff 		    INW(dp, 0x00fc),	/* TSTDAT */
17035748Sduboff 		    INW(dp, 0x00f4),	/* DSPCFG */
17045748Sduboff 		    INW(dp, 0x00f8)));	/* SDCFG */
17057116Sduboff 	} else if (((srr ^ SRR_REV_DP83815DVNG) & 0xff00) == 0 ||
17067116Sduboff 	    ((srr ^ SRR_REV_DP83816AVNG) & 0xff00) == 0) {
17077116Sduboff 		/*
17087116Sduboff 		 * Additional packets for later chipset
17097116Sduboff 		 */
17107116Sduboff 		OUTW(dp, 0x00cc, 0x0001);	/* PGSEL */
17117116Sduboff 		OUTW(dp, 0x00e4, 0x189c);	/* PMDCSR */
17127116Sduboff 		OUTW(dp, 0x00cc, 0x0000);	/* PGSEL */
17137116Sduboff 
17147116Sduboff 		DPRINTF(0, (CE_CONT,
17157116Sduboff 		    CONS "%s: PHY patched %04x %04x",
17167116Sduboff 		    dp->name,
17177116Sduboff 		    INW(dp, 0x00cc),	/* PGSEL */
17187116Sduboff 		    INW(dp, 0x00e4)));	/* PMDCSR */
17195748Sduboff 	}
17205748Sduboff 
17215748Sduboff 	return (gem_mii_config_default(dp));
17225748Sduboff }
17235748Sduboff 
17247116Sduboff static int
sfe_mii_probe_dp83815(struct gem_dev * dp)17257116Sduboff sfe_mii_probe_dp83815(struct gem_dev *dp)
17267116Sduboff {
17277116Sduboff 	uint32_t	val;
17287116Sduboff 
17297116Sduboff 	/* try external phy first */
17307116Sduboff 	DPRINTF(0, (CE_CONT, CONS "%s: %s: trying external phy",
17317116Sduboff 	    dp->name, __func__));
17327116Sduboff 	dp->mii_phy_addr = 0;
17337116Sduboff 	dp->gc.gc_mii_sync = &sfe_mii_sync_sis900;
17347116Sduboff 	dp->gc.gc_mii_read = &sfe_mii_read_sis900;
17357116Sduboff 	dp->gc.gc_mii_write = &sfe_mii_write_sis900;
17367116Sduboff 
17377116Sduboff 	val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG);
17387116Sduboff 	OUTL(dp, CFG, val | CFG_EXT_PHY | CFG_PHY_DIS);
17397116Sduboff 
17407116Sduboff 	if (gem_mii_probe_default(dp) == GEM_SUCCESS) {
17417116Sduboff 		return (GEM_SUCCESS);
17427116Sduboff 	}
17437116Sduboff 
17447116Sduboff 	/* switch to internal phy */
17457116Sduboff 	DPRINTF(0, (CE_CONT, CONS "%s: %s: switching to internal phy",
17467116Sduboff 	    dp->name, __func__));
17477116Sduboff 	dp->mii_phy_addr = -1;
17487116Sduboff 	dp->gc.gc_mii_sync = &sfe_mii_sync_dp83815;
17497116Sduboff 	dp->gc.gc_mii_read = &sfe_mii_read_dp83815;
17507116Sduboff 	dp->gc.gc_mii_write = &sfe_mii_write_dp83815;
17517116Sduboff 
17527116Sduboff 	val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG);
17537116Sduboff 	OUTL(dp, CFG, val | CFG_PAUSE_ADV | CFG_PHY_RST);
17547116Sduboff 	drv_usecwait(100);	/* keep to assert RST bit for a while */
17557116Sduboff 	OUTL(dp, CFG, val | CFG_PAUSE_ADV);
17567116Sduboff 
17577116Sduboff 	/* wait for PHY reset */
17587116Sduboff 	delay(drv_usectohz(10000));
17597116Sduboff 
17607116Sduboff 	return (gem_mii_probe_default(dp));
17617116Sduboff }
17627116Sduboff 
17637116Sduboff static int
sfe_mii_init_dp83815(struct gem_dev * dp)17647116Sduboff sfe_mii_init_dp83815(struct gem_dev *dp)
17657116Sduboff {
17667116Sduboff 	uint32_t	val;
17677116Sduboff 
17687116Sduboff 	val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG);
17697116Sduboff 
17707116Sduboff 	if (dp->mii_phy_addr == -1) {
17717116Sduboff 		/* select internal phy */
17727116Sduboff 		OUTL(dp, CFG, val | CFG_PAUSE_ADV);
17737116Sduboff 	} else {
17747116Sduboff 		/* select external phy */
17757116Sduboff 		OUTL(dp, CFG, val | CFG_EXT_PHY | CFG_PHY_DIS);
17767116Sduboff 	}
17777116Sduboff 
17787116Sduboff 	return (GEM_SUCCESS);
17797116Sduboff }
17805748Sduboff 
17815748Sduboff /*
17825748Sduboff  * MII routines for SiS900
17835748Sduboff  */
17847116Sduboff #define	MDIO_DELAY(dp)	{(void) INL(dp, MEAR); (void) INL(dp, MEAR); }
17855748Sduboff static void
sfe_mii_sync_sis900(struct gem_dev * dp)17865748Sduboff sfe_mii_sync_sis900(struct gem_dev *dp)
17875748Sduboff {
17885748Sduboff 	int	i;
17895748Sduboff 
17907116Sduboff 	/* send 32 ONE's to make MII line idle */
17915748Sduboff 	for (i = 0; i < 32; i++) {
17925748Sduboff 		OUTL(dp, MEAR, MEAR_MDDIR | MEAR_MDIO);
17935748Sduboff 		MDIO_DELAY(dp);
17945748Sduboff 		OUTL(dp, MEAR, MEAR_MDDIR | MEAR_MDIO | MEAR_MDC);
17955748Sduboff 		MDIO_DELAY(dp);
17965748Sduboff 	}
17975748Sduboff }
17985748Sduboff 
17995748Sduboff static int
sfe_mii_config_sis900(struct gem_dev * dp)18005748Sduboff sfe_mii_config_sis900(struct gem_dev *dp)
18015748Sduboff {
18025748Sduboff 	struct sfe_dev	*lp = dp->private;
18035748Sduboff 
18045748Sduboff 	/* Do chip depend setup */
18055748Sduboff 	if ((dp->mii_phy_id & PHY_MASK) == PHY_ICS1893) {
18065748Sduboff 		/* workaround for ICS1893 PHY */
18075748Sduboff 		gem_mii_write(dp, 0x0018, 0xD200);
18085748Sduboff 	}
18095748Sduboff 
18105748Sduboff 	if (lp->revid == SIS630E_900_REV) {
18115748Sduboff 		/*
18125748Sduboff 		 * SiS 630E has bugs on default values
18135748Sduboff 		 * of PHY registers
18145748Sduboff 		 */
18155748Sduboff 		gem_mii_write(dp, MII_AN_ADVERT, 0x05e1);
18165748Sduboff 		gem_mii_write(dp, MII_CONFIG1, 0x0022);
18175748Sduboff 		gem_mii_write(dp, MII_CONFIG2, 0xff00);
18185748Sduboff 		gem_mii_write(dp, MII_MASK,    0xffc0);
18195748Sduboff 	}
18205748Sduboff 	sfe_set_eq_sis630(dp);
18215748Sduboff 
18225748Sduboff 	return (gem_mii_config_default(dp));
18235748Sduboff }
18245748Sduboff 
18255748Sduboff static uint16_t
sfe_mii_read_sis900(struct gem_dev * dp,uint_t reg)18265748Sduboff sfe_mii_read_sis900(struct gem_dev *dp, uint_t reg)
18275748Sduboff {
18285748Sduboff 	uint32_t	cmd;
18295748Sduboff 	uint16_t	ret;
18305748Sduboff 	int		i;
18315748Sduboff 	uint32_t	data;
18325748Sduboff 
18335748Sduboff 	cmd = MII_READ_CMD(dp->mii_phy_addr, reg);
18345748Sduboff 
18355748Sduboff 	for (i = 31; i >= 18; i--) {
18365748Sduboff 		data = ((cmd >> i) & 1) <<  MEAR_MDIO_SHIFT;
18375748Sduboff 		OUTL(dp, MEAR, data | MEAR_MDDIR);
18385748Sduboff 		MDIO_DELAY(dp);
18395748Sduboff 		OUTL(dp, MEAR, data | MEAR_MDDIR | MEAR_MDC);
18405748Sduboff 		MDIO_DELAY(dp);
18415748Sduboff 	}
18425748Sduboff 
18435748Sduboff 	/* turn around cycle */
18447116Sduboff 	OUTL(dp, MEAR, 0);
18455748Sduboff 	MDIO_DELAY(dp);
18465748Sduboff 
18475748Sduboff 	/* get response from PHY */
18485748Sduboff 	OUTL(dp, MEAR, MEAR_MDC);
18495748Sduboff 	MDIO_DELAY(dp);
18507116Sduboff 
18515748Sduboff 	OUTL(dp, MEAR, 0);
18525748Sduboff #if DEBUG_LEBEL > 0
18537116Sduboff 	(void) INL(dp, MEAR);	/* delay */
18545748Sduboff 	if (INL(dp, MEAR) & MEAR_MDIO) {
18555748Sduboff 		cmn_err(CE_WARN, "%s: PHY@%d not responded",
18565748Sduboff 		    dp->name, dp->mii_phy_addr);
18575748Sduboff 	}
18587116Sduboff #else
18597116Sduboff 	MDIO_DELAY(dp);
18605748Sduboff #endif
18615748Sduboff 	/* terminate response cycle */
18625748Sduboff 	OUTL(dp, MEAR, MEAR_MDC);
18637116Sduboff 	MDIO_DELAY(dp);
18645748Sduboff 
18655748Sduboff 	ret = 0;	/* to avoid lint errors */
18665748Sduboff 	for (i = 16; i > 0; i--) {
18675748Sduboff 		OUTL(dp, MEAR, 0);
18687116Sduboff 		(void) INL(dp, MEAR);	/* delay */
18695748Sduboff 		ret = (ret << 1) | ((INL(dp, MEAR) >> MEAR_MDIO_SHIFT) & 1);
18705748Sduboff 		OUTL(dp, MEAR, MEAR_MDC);
18715748Sduboff 		MDIO_DELAY(dp);
18725748Sduboff 	}
18735748Sduboff 
18747116Sduboff 	/* send two idle(Z) bits to terminate the read cycle */
18757116Sduboff 	for (i = 0; i < 2; i++) {
18767116Sduboff 		OUTL(dp, MEAR, 0);
18777116Sduboff 		MDIO_DELAY(dp);
18787116Sduboff 		OUTL(dp, MEAR, MEAR_MDC);
18797116Sduboff 		MDIO_DELAY(dp);
18807116Sduboff 	}
18815748Sduboff 
18825748Sduboff 	return (ret);
18835748Sduboff }
18845748Sduboff 
18855748Sduboff static void
sfe_mii_write_sis900(struct gem_dev * dp,uint_t reg,uint16_t val)18865748Sduboff sfe_mii_write_sis900(struct gem_dev *dp, uint_t reg, uint16_t val)
18875748Sduboff {
18885748Sduboff 	uint32_t	cmd;
18895748Sduboff 	int		i;
18905748Sduboff 	uint32_t	data;
18915748Sduboff 
18925748Sduboff 	cmd = MII_WRITE_CMD(dp->mii_phy_addr, reg, val);
18935748Sduboff 
18945748Sduboff 	for (i = 31; i >= 0; i--) {
18955748Sduboff 		data = ((cmd >> i) & 1) << MEAR_MDIO_SHIFT;
18965748Sduboff 		OUTL(dp, MEAR, data | MEAR_MDDIR);
18975748Sduboff 		MDIO_DELAY(dp);
18985748Sduboff 		OUTL(dp, MEAR, data | MEAR_MDDIR | MEAR_MDC);
18995748Sduboff 		MDIO_DELAY(dp);
19005748Sduboff 	}
19015748Sduboff 
19027116Sduboff 	/* send two idle(Z) bits to terminate the write cycle. */
19035748Sduboff 	for (i = 0; i < 2; i++) {
19047116Sduboff 		OUTL(dp, MEAR, 0);
19055748Sduboff 		MDIO_DELAY(dp);
19067116Sduboff 		OUTL(dp, MEAR, MEAR_MDC);
19075748Sduboff 		MDIO_DELAY(dp);
19085748Sduboff 	}
19095748Sduboff }
19105748Sduboff #undef MDIO_DELAY
19115748Sduboff 
19125748Sduboff static void
sfe_set_eq_sis630(struct gem_dev * dp)19135748Sduboff sfe_set_eq_sis630(struct gem_dev *dp)
19145748Sduboff {
19155748Sduboff 	uint16_t	reg14h;
19165748Sduboff 	uint16_t	eq_value;
19175748Sduboff 	uint16_t	max_value;
19185748Sduboff 	uint16_t	min_value;
19195748Sduboff 	int		i;
19205748Sduboff 	uint8_t		rev;
19215748Sduboff 	struct sfe_dev	*lp = dp->private;
19225748Sduboff 
19235748Sduboff 	rev = lp->revid;
19245748Sduboff 
19255748Sduboff 	if (!(rev == SIS630E_900_REV || rev == SIS630EA1_900_REV ||
19265748Sduboff 	    rev == SIS630A_900_REV || rev == SIS630ET_900_REV)) {
19275748Sduboff 		/* it doesn't have a internal PHY */
19285748Sduboff 		return;
19295748Sduboff 	}
19305748Sduboff 
19315748Sduboff 	if (dp->mii_state == MII_STATE_LINKUP) {
19325748Sduboff 		reg14h = gem_mii_read(dp, MII_RESV);
19335748Sduboff 		gem_mii_write(dp, MII_RESV, (0x2200 | reg14h) & 0xBFFF);
19345748Sduboff 
19355748Sduboff 		eq_value = (0x00f8 & gem_mii_read(dp, MII_RESV)) >> 3;
19365748Sduboff 		max_value = min_value = eq_value;
19375748Sduboff 		for (i = 1; i < 10; i++) {
19385748Sduboff 			eq_value = (0x00f8 & gem_mii_read(dp, MII_RESV)) >> 3;
19395748Sduboff 			max_value = max(eq_value, max_value);
19405748Sduboff 			min_value = min(eq_value, min_value);
19415748Sduboff 		}
19425748Sduboff 
19435748Sduboff 		/* for 630E, rule to determine the equalizer value */
19445748Sduboff 		if (rev == SIS630E_900_REV || rev == SIS630EA1_900_REV ||
19455748Sduboff 		    rev == SIS630ET_900_REV) {
19465748Sduboff 			if (max_value < 5) {
19475748Sduboff 				eq_value = max_value;
19485748Sduboff 			} else if (5 <= max_value && max_value < 15) {
19495748Sduboff 				eq_value =
19505748Sduboff 				    max(max_value + 1,
19515748Sduboff 				    min_value + 2);
19525748Sduboff 			} else if (15 <= max_value) {
19535748Sduboff 				eq_value =
19545748Sduboff 				    max(max_value + 5,
19555748Sduboff 				    min_value + 6);
19565748Sduboff 			}
19575748Sduboff 		}
19585748Sduboff 		/* for 630B0&B1, rule to determine the equalizer value */
19595748Sduboff 		else
19605748Sduboff 		if (rev == SIS630A_900_REV &&
19615748Sduboff 		    (lp->bridge_revid == SIS630B0 ||
19625748Sduboff 		    lp->bridge_revid == SIS630B1)) {
19635748Sduboff 
19645748Sduboff 			if (max_value == 0) {
19655748Sduboff 				eq_value = 3;
19665748Sduboff 			} else {
19675748Sduboff 				eq_value = (max_value + min_value + 1)/2;
19685748Sduboff 			}
19695748Sduboff 		}
19705748Sduboff 		/* write equalizer value and setting */
19715748Sduboff 		reg14h = gem_mii_read(dp, MII_RESV) & ~0x02f8;
19725748Sduboff 		reg14h |= 0x6000 | (eq_value << 3);
19735748Sduboff 		gem_mii_write(dp, MII_RESV, reg14h);
19745748Sduboff 	} else {
19755748Sduboff 		reg14h = (gem_mii_read(dp, MII_RESV) & ~0x4000) | 0x2000;
19765748Sduboff 		if (rev == SIS630A_900_REV &&
19775748Sduboff 		    (lp->bridge_revid == SIS630B0 ||
19785748Sduboff 		    lp->bridge_revid == SIS630B1)) {
19795748Sduboff 
19805748Sduboff 			reg14h |= 0x0200;
19815748Sduboff 		}
19825748Sduboff 		gem_mii_write(dp, MII_RESV, reg14h);
19835748Sduboff 	}
19845748Sduboff }
19855748Sduboff 
19865748Sduboff /* ======================================================== */
19875748Sduboff /*
19885748Sduboff  * OS depend (device driver) routine
19895748Sduboff  */
19905748Sduboff /* ======================================================== */
19915748Sduboff static void
sfe_chipinfo_init_sis900(struct gem_dev * dp)19925748Sduboff sfe_chipinfo_init_sis900(struct gem_dev *dp)
19935748Sduboff {
19945748Sduboff 	int		rev;
19955748Sduboff 	struct sfe_dev	*lp = (struct sfe_dev *)dp->private;
19965748Sduboff 
19975748Sduboff 	rev = lp->revid;
19985748Sduboff 
19995748Sduboff 	if (rev == SIS630E_900_REV /* 0x81 */) {
20005748Sduboff 		/* sis630E */
20015748Sduboff 		lp->get_mac_addr = &sfe_get_mac_addr_sis630e;
20025748Sduboff 	} else if (rev > 0x81 && rev <= 0x90) {
20035748Sduboff 		/* 630S, 630EA1, 630ET, 635A */
20045748Sduboff 		lp->get_mac_addr = &sfe_get_mac_addr_sis635;
20055748Sduboff 	} else if (rev == SIS962_900_REV /* 0x91 */) {
20065748Sduboff 		/* sis962 or later */
20075748Sduboff 		lp->get_mac_addr = &sfe_get_mac_addr_sis962;
20085748Sduboff 	} else {
20095748Sduboff 		/* sis900 */
20105748Sduboff 		lp->get_mac_addr = &sfe_get_mac_addr_sis900;
20115748Sduboff 	}
20125748Sduboff 
20135748Sduboff 	lp->bridge_revid = 0;
20145748Sduboff 
20155748Sduboff 	if (rev == SIS630E_900_REV || rev == SIS630EA1_900_REV ||
20165748Sduboff 	    rev == SIS630A_900_REV || rev ==  SIS630ET_900_REV) {
20175748Sduboff 		/*
20185748Sduboff 		 * read host bridge revision
20195748Sduboff 		 */
20205748Sduboff 		dev_info_t	*bridge;
20215748Sduboff 		ddi_acc_handle_t bridge_handle;
20225748Sduboff 
20235748Sduboff 		if ((bridge = sfe_search_pci_dev(0x1039, 0x630)) == NULL) {
20245748Sduboff 			cmn_err(CE_WARN,
20255748Sduboff 			    "%s: cannot find host bridge (pci1039,630)",
20265748Sduboff 			    dp->name);
20275748Sduboff 			return;
20285748Sduboff 		}
20295748Sduboff 
20305748Sduboff 		if (pci_config_setup(bridge, &bridge_handle) != DDI_SUCCESS) {
20315748Sduboff 			cmn_err(CE_WARN, "%s: pci_config_setup failed",
20325748Sduboff 			    dp->name);
20335748Sduboff 			return;
20345748Sduboff 		}
20355748Sduboff 
20365748Sduboff 		lp->bridge_revid =
20375748Sduboff 		    pci_config_get8(bridge_handle, PCI_CONF_REVID);
20385748Sduboff 		pci_config_teardown(&bridge_handle);
20395748Sduboff 	}
20405748Sduboff }
20415748Sduboff 
20425748Sduboff static int
sfe_attach_chip(struct gem_dev * dp)20435748Sduboff sfe_attach_chip(struct gem_dev *dp)
20445748Sduboff {
20455748Sduboff 	struct sfe_dev		*lp = (struct sfe_dev *)dp->private;
20465748Sduboff 
20475748Sduboff 	DPRINTF(4, (CE_CONT, CONS "!%s: %s called", dp->name, __func__));
20485748Sduboff 
20495748Sduboff 	/* setup chip-depend get_mac_address function */
20505748Sduboff 	if (lp->chip->chip_type == CHIPTYPE_SIS900) {
20515748Sduboff 		sfe_chipinfo_init_sis900(dp);
20525748Sduboff 	} else {
20535748Sduboff 		lp->get_mac_addr = &sfe_get_mac_addr_dp83815;
20545748Sduboff 	}
20555748Sduboff 
20565748Sduboff 	/* read MAC address */
20575748Sduboff 	if (!(lp->get_mac_addr)(dp)) {
20585748Sduboff 		cmn_err(CE_WARN,
20595748Sduboff 		    "!%s: %s: failed to get factory mac address"
20605748Sduboff 		    " please specify a mac address in sfe.conf",
20615748Sduboff 		    dp->name, __func__);
20625748Sduboff 		return (GEM_FAILURE);
20635748Sduboff 	}
20645748Sduboff 
20655748Sduboff 	if (lp->chip->chip_type == CHIPTYPE_DP83815) {
20665748Sduboff 		dp->mii_phy_addr = -1;	/* no need to scan PHY */
20675748Sduboff 		dp->misc_flag |= GEM_VLAN_SOFT;
20685748Sduboff 		dp->txthr += 4; /* VTAG_SIZE */
20695748Sduboff 	}
20705748Sduboff 	dp->txthr = min(dp->txthr, TXFIFOSIZE - 2);
20715748Sduboff 
20725748Sduboff 	return (GEM_SUCCESS);
20735748Sduboff }
20745748Sduboff 
20755748Sduboff static int
sfeattach(dev_info_t * dip,ddi_attach_cmd_t cmd)20765748Sduboff sfeattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
20775748Sduboff {
20785748Sduboff 	int			unit;
20795748Sduboff 	const char		*drv_name;
20805748Sduboff 	int			i;
20815748Sduboff 	ddi_acc_handle_t	conf_handle;
20825748Sduboff 	uint16_t		vid;
20835748Sduboff 	uint16_t		did;
20845748Sduboff 	uint8_t			rev;
20855748Sduboff #ifdef DEBUG_LEVEL
20865748Sduboff 	uint32_t		iline;
20875748Sduboff 	uint8_t			latim;
20885748Sduboff #endif
20895748Sduboff 	struct chip_info	*p;
20905748Sduboff 	struct gem_dev		*dp;
20915748Sduboff 	struct sfe_dev		*lp;
20925748Sduboff 	caddr_t			base;
20935748Sduboff 	ddi_acc_handle_t	regs_ha;
20945748Sduboff 	struct gem_conf		*gcp;
20955748Sduboff 
20965748Sduboff 	unit = ddi_get_instance(dip);
20975748Sduboff 	drv_name = ddi_driver_name(dip);
20985748Sduboff 
20995748Sduboff 	DPRINTF(3, (CE_CONT, CONS "%s%d: sfeattach: called", drv_name, unit));
21005748Sduboff 
21015748Sduboff 	/*
21025748Sduboff 	 * Common codes after power-up
21035748Sduboff 	 */
21045748Sduboff 	if (pci_config_setup(dip, &conf_handle) != DDI_SUCCESS) {
21055748Sduboff 		cmn_err(CE_WARN, "%s%d: ddi_regs_map_setup failed",
21065748Sduboff 		    drv_name, unit);
21075748Sduboff 		goto err;
21085748Sduboff 	}
21095748Sduboff 
21105748Sduboff 	vid  = pci_config_get16(conf_handle, PCI_CONF_VENID);
21115748Sduboff 	did  = pci_config_get16(conf_handle, PCI_CONF_DEVID);
21125748Sduboff 	rev  = pci_config_get16(conf_handle, PCI_CONF_REVID);
21135748Sduboff #ifdef DEBUG_LEVEL
21147116Sduboff 	iline = pci_config_get32(conf_handle, PCI_CONF_ILINE);
21157116Sduboff 	latim = pci_config_get8(conf_handle, PCI_CONF_LATENCY_TIMER);
21165748Sduboff #endif
21175748Sduboff #ifdef DEBUG_BUILT_IN_SIS900
21185748Sduboff 	rev  = SIS630E_900_REV;
21195748Sduboff #endif
21205748Sduboff 	for (i = 0, p = sfe_chiptbl; i < CHIPTABLESIZE; i++, p++) {
21215748Sduboff 		if (p->venid == vid && p->devid == did) {
21225748Sduboff 			/* found */
21235748Sduboff 			goto chip_found;
21245748Sduboff 		}
21255748Sduboff 	}
21265748Sduboff 
21275748Sduboff 	/* Not found */
21285748Sduboff 	cmn_err(CE_WARN,
21295748Sduboff 	    "%s%d: sfe_attach: wrong PCI venid/devid (0x%x, 0x%x)",
21305748Sduboff 	    drv_name, unit, vid, did);
21315748Sduboff 	pci_config_teardown(&conf_handle);
21325748Sduboff 	goto err;
21335748Sduboff 
21345748Sduboff chip_found:
21355748Sduboff 	pci_config_put16(conf_handle, PCI_CONF_COMM,
21365748Sduboff 	    PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME |
21375748Sduboff 	    pci_config_get16(conf_handle, PCI_CONF_COMM));
21385748Sduboff 
21395748Sduboff 	/* ensure D0 mode */
21405748Sduboff 	(void) gem_pci_set_power_state(dip, conf_handle, PCI_PMCSR_D0);
21415748Sduboff 
21425748Sduboff 	pci_config_teardown(&conf_handle);
21435748Sduboff 
21445748Sduboff 	switch (cmd) {
21455748Sduboff 	case DDI_RESUME:
21465748Sduboff 		return (gem_resume(dip));
21475748Sduboff 
21485748Sduboff 	case DDI_ATTACH:
21495748Sduboff 
21505748Sduboff 		DPRINTF(0, (CE_CONT,
21515748Sduboff 		    CONS "%s%d: ilr 0x%08x, latency_timer:0x%02x",
21525748Sduboff 		    drv_name, unit, iline, latim));
21535748Sduboff 
21545748Sduboff 		/*
21555748Sduboff 		 * Map in the device registers.
21565748Sduboff 		 */
21575748Sduboff 		if (gem_pci_regs_map_setup(dip,
21585748Sduboff 		    (sfe_use_pcimemspace && p->chip_type == CHIPTYPE_DP83815)
21595748Sduboff 		    ? PCI_ADDR_MEM32 : PCI_ADDR_IO, PCI_ADDR_MASK,
21605748Sduboff 		    &sfe_dev_attr, &base, &regs_ha) != DDI_SUCCESS) {
21615748Sduboff 			cmn_err(CE_WARN,
21625748Sduboff 			    "%s%d: ddi_regs_map_setup failed",
21635748Sduboff 			    drv_name, unit);
21645748Sduboff 			goto err;
21655748Sduboff 		}
21665748Sduboff 
21675748Sduboff 		/*
21685748Sduboff 		 * construct gem configuration
21695748Sduboff 		 */
21705748Sduboff 		gcp = kmem_zalloc(sizeof (*gcp), KM_SLEEP);
21715748Sduboff 
21725748Sduboff 		/* name */
21735748Sduboff 		(void) sprintf(gcp->gc_name, "%s%d", drv_name, unit);
21745748Sduboff 
21755748Sduboff 		/* consistency on tx and rx */
21765748Sduboff 		gcp->gc_tx_buf_align = sizeof (uint8_t) - 1;
21775748Sduboff 		gcp->gc_tx_max_frags = MAXTXFRAGS;
21785748Sduboff 		gcp->gc_tx_max_descs_per_pkt = gcp->gc_tx_max_frags;
21795748Sduboff 		gcp->gc_tx_desc_unit_shift = 4;	/* 16 byte */
21805748Sduboff 		gcp->gc_tx_buf_size  = TX_BUF_SIZE;
21815748Sduboff 		gcp->gc_tx_buf_limit = gcp->gc_tx_buf_size;
21825748Sduboff 		gcp->gc_tx_ring_size = TX_RING_SIZE;
21835748Sduboff 		gcp->gc_tx_ring_limit = gcp->gc_tx_ring_size;
21845748Sduboff 		gcp->gc_tx_auto_pad  = B_TRUE;
21855748Sduboff 		gcp->gc_tx_copy_thresh = sfe_tx_copy_thresh;
21865748Sduboff 		gcp->gc_tx_desc_write_oo = B_TRUE;
21875748Sduboff 
21885748Sduboff 		gcp->gc_rx_buf_align = sizeof (uint8_t) - 1;
21895748Sduboff 		gcp->gc_rx_max_frags = MAXRXFRAGS;
21905748Sduboff 		gcp->gc_rx_desc_unit_shift = 4;
21915748Sduboff 		gcp->gc_rx_ring_size = RX_RING_SIZE;
21925748Sduboff 		gcp->gc_rx_buf_max   = RX_BUF_SIZE;
21935748Sduboff 		gcp->gc_rx_copy_thresh = sfe_rx_copy_thresh;
21945748Sduboff 
21955748Sduboff 		/* map attributes */
21965748Sduboff 		gcp->gc_dev_attr = sfe_dev_attr;
21975748Sduboff 		gcp->gc_buf_attr = sfe_buf_attr;
21985748Sduboff 		gcp->gc_desc_attr = sfe_buf_attr;
21995748Sduboff 
22005748Sduboff 		/* dma attributes */
22015748Sduboff 		gcp->gc_dma_attr_desc = sfe_dma_attr_desc;
22025748Sduboff 
22035748Sduboff 		gcp->gc_dma_attr_txbuf = sfe_dma_attr_buf;
22045748Sduboff 		gcp->gc_dma_attr_txbuf.dma_attr_align = gcp->gc_tx_buf_align+1;
22055748Sduboff 		gcp->gc_dma_attr_txbuf.dma_attr_sgllen = gcp->gc_tx_max_frags;
22065748Sduboff 
22075748Sduboff 		gcp->gc_dma_attr_rxbuf = sfe_dma_attr_buf;
22085748Sduboff 		gcp->gc_dma_attr_rxbuf.dma_attr_align = gcp->gc_rx_buf_align+1;
22095748Sduboff 		gcp->gc_dma_attr_rxbuf.dma_attr_sgllen = gcp->gc_rx_max_frags;
22105748Sduboff 
22115748Sduboff 		/* time out parameters */
22125748Sduboff 		gcp->gc_tx_timeout = 3*ONESEC;
22135748Sduboff 		gcp->gc_tx_timeout_interval = ONESEC;
22147116Sduboff 		if (p->chip_type == CHIPTYPE_DP83815) {
22157116Sduboff 			/* workaround for tx hang */
22167116Sduboff 			gcp->gc_tx_timeout_interval = ONESEC/20; /* 50mS */
22177116Sduboff 		}
22185748Sduboff 
22195748Sduboff 		/* MII timeout parameters */
22205748Sduboff 		gcp->gc_mii_link_watch_interval = ONESEC;
22215748Sduboff 		gcp->gc_mii_an_watch_interval   = ONESEC/5;
22225748Sduboff 		gcp->gc_mii_reset_timeout = MII_RESET_TIMEOUT;	/* 1 sec */
22235748Sduboff 		gcp->gc_mii_an_timeout = MII_AN_TIMEOUT;	/* 5 sec */
22245748Sduboff 		gcp->gc_mii_an_wait = 0;
22255748Sduboff 		gcp->gc_mii_linkdown_timeout = MII_LINKDOWN_TIMEOUT;
22265748Sduboff 
22275748Sduboff 		/* setting for general PHY */
22285748Sduboff 		gcp->gc_mii_an_delay = 0;
22295748Sduboff 		gcp->gc_mii_linkdown_action = MII_ACTION_RSA;
22305748Sduboff 		gcp->gc_mii_linkdown_timeout_action = MII_ACTION_RESET;
22315748Sduboff 		gcp->gc_mii_dont_reset = B_FALSE;
22325748Sduboff 
22335748Sduboff 
22345748Sduboff 		/* I/O methods */
22355748Sduboff 
22365748Sduboff 		/* mac operation */
22375748Sduboff 		gcp->gc_attach_chip = &sfe_attach_chip;
22385748Sduboff 		if (p->chip_type == CHIPTYPE_DP83815) {
22395748Sduboff 			gcp->gc_reset_chip = &sfe_reset_chip_dp83815;
22405748Sduboff 		} else {
22415748Sduboff 			gcp->gc_reset_chip = &sfe_reset_chip_sis900;
22425748Sduboff 		}
22435748Sduboff 		gcp->gc_init_chip  = &sfe_init_chip;
22445748Sduboff 		gcp->gc_start_chip = &sfe_start_chip;
22455748Sduboff 		gcp->gc_stop_chip  = &sfe_stop_chip;
22465748Sduboff #ifdef USE_MULTICAST_HASHTBL
22475748Sduboff 		gcp->gc_multicast_hash = &sfe_mcast_hash;
22485748Sduboff #endif
22495748Sduboff 		if (p->chip_type == CHIPTYPE_DP83815) {
22505748Sduboff 			gcp->gc_set_rx_filter = &sfe_set_rx_filter_dp83815;
22515748Sduboff 		} else {
22525748Sduboff 			gcp->gc_set_rx_filter = &sfe_set_rx_filter_sis900;
22535748Sduboff 		}
22545748Sduboff 		gcp->gc_set_media = &sfe_set_media;
22555748Sduboff 		gcp->gc_get_stats = &sfe_get_stats;
22565748Sduboff 		gcp->gc_interrupt = &sfe_interrupt;
22575748Sduboff 
22585748Sduboff 		/* descriptor operation */
22595748Sduboff 		gcp->gc_tx_desc_write = &sfe_tx_desc_write;
22605748Sduboff 		gcp->gc_tx_start = &sfe_tx_start;
22615748Sduboff 		gcp->gc_rx_desc_write = &sfe_rx_desc_write;
22625748Sduboff 		gcp->gc_rx_start = NULL;
22635748Sduboff 
22645748Sduboff 		gcp->gc_tx_desc_stat = &sfe_tx_desc_stat;
22655748Sduboff 		gcp->gc_rx_desc_stat = &sfe_rx_desc_stat;
22665748Sduboff 		gcp->gc_tx_desc_init = &sfe_tx_desc_init;
22675748Sduboff 		gcp->gc_rx_desc_init = &sfe_rx_desc_init;
22685748Sduboff 		gcp->gc_tx_desc_clean = &sfe_tx_desc_clean;
22695748Sduboff 		gcp->gc_rx_desc_clean = &sfe_rx_desc_clean;
22705748Sduboff 
22715748Sduboff 		/* mii operations */
22725748Sduboff 		if (p->chip_type == CHIPTYPE_DP83815) {
22737116Sduboff 			gcp->gc_mii_probe = &sfe_mii_probe_dp83815;
22747116Sduboff 			gcp->gc_mii_init = &sfe_mii_init_dp83815;
22755748Sduboff 			gcp->gc_mii_config = &sfe_mii_config_dp83815;
22765748Sduboff 			gcp->gc_mii_sync = &sfe_mii_sync_dp83815;
22775748Sduboff 			gcp->gc_mii_read = &sfe_mii_read_dp83815;
22785748Sduboff 			gcp->gc_mii_write = &sfe_mii_write_dp83815;
22795748Sduboff 			gcp->gc_mii_tune_phy = NULL;
22805748Sduboff 			gcp->gc_flow_control = FLOW_CONTROL_NONE;
22815748Sduboff 		} else {
22825748Sduboff 			gcp->gc_mii_probe = &gem_mii_probe_default;
22835748Sduboff 			gcp->gc_mii_init = NULL;
22845748Sduboff 			gcp->gc_mii_config = &sfe_mii_config_sis900;
22855748Sduboff 			gcp->gc_mii_sync = &sfe_mii_sync_sis900;
22865748Sduboff 			gcp->gc_mii_read = &sfe_mii_read_sis900;
22875748Sduboff 			gcp->gc_mii_write = &sfe_mii_write_sis900;
22885748Sduboff 			gcp->gc_mii_tune_phy = &sfe_set_eq_sis630;
22895748Sduboff 			gcp->gc_flow_control = FLOW_CONTROL_RX_PAUSE;
22905748Sduboff 		}
22915748Sduboff 
22925748Sduboff 		lp = kmem_zalloc(sizeof (*lp), KM_SLEEP);
22935748Sduboff 		lp->chip = p;
22945748Sduboff 		lp->revid = rev;
22957116Sduboff 		lp->our_intr_bits = 0;
22967116Sduboff 		lp->isr_pended = 0;
22975748Sduboff 
22985748Sduboff 		cmn_err(CE_CONT, CONS "%s%d: chip:%s rev:0x%02x",
22995748Sduboff 		    drv_name, unit, p->chip_name, rev);
23005748Sduboff 
23015748Sduboff 		dp = gem_do_attach(dip, 0, gcp, base, &regs_ha,
23025748Sduboff 		    lp, sizeof (*lp));
23035748Sduboff 		kmem_free(gcp, sizeof (*gcp));
23045748Sduboff 
23055748Sduboff 		if (dp == NULL) {
23065748Sduboff 			goto err_freelp;
23075748Sduboff 		}
23085748Sduboff 
23095748Sduboff 		return (DDI_SUCCESS);
23105748Sduboff 
23115748Sduboff err_freelp:
23125748Sduboff 		kmem_free(lp, sizeof (struct sfe_dev));
23135748Sduboff err:
23145748Sduboff 		return (DDI_FAILURE);
23155748Sduboff 	}
23165748Sduboff 	return (DDI_FAILURE);
23175748Sduboff }
23185748Sduboff 
23195748Sduboff static int
sfedetach(dev_info_t * dip,ddi_detach_cmd_t cmd)23205748Sduboff sfedetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
23215748Sduboff {
23225748Sduboff 	switch (cmd) {
23235748Sduboff 	case DDI_SUSPEND:
23245748Sduboff 		return (gem_suspend(dip));
23255748Sduboff 
23265748Sduboff 	case DDI_DETACH:
23275748Sduboff 		return (gem_do_detach(dip));
23285748Sduboff 	}
23295748Sduboff 	return (DDI_FAILURE);
23305748Sduboff }
23315748Sduboff 
23328611SSherry.Moore@Sun.COM /*
23338611SSherry.Moore@Sun.COM  * quiesce(9E) entry point.
23348611SSherry.Moore@Sun.COM  *
23358611SSherry.Moore@Sun.COM  * This function is called when the system is single-threaded at high
23368611SSherry.Moore@Sun.COM  * PIL with preemption disabled. Therefore, this function must not be
23378611SSherry.Moore@Sun.COM  * blocked.
23388611SSherry.Moore@Sun.COM  *
23398611SSherry.Moore@Sun.COM  * This function returns DDI_SUCCESS on success, or DDI_FAILURE on failure.
23408611SSherry.Moore@Sun.COM  * DDI_FAILURE indicates an error condition and should almost never happen.
23418611SSherry.Moore@Sun.COM  */
23428611SSherry.Moore@Sun.COM #ifdef	__sparc
23438611SSherry.Moore@Sun.COM #define	sfe_quiesce	ddi_quiesce_not_supported
23448611SSherry.Moore@Sun.COM #else
23458611SSherry.Moore@Sun.COM static int
sfe_quiesce(dev_info_t * dip)23468611SSherry.Moore@Sun.COM sfe_quiesce(dev_info_t *dip)
23478611SSherry.Moore@Sun.COM {
23488611SSherry.Moore@Sun.COM 	struct gem_dev	*dp;
23498611SSherry.Moore@Sun.COM 	int	ret = 0;
23508611SSherry.Moore@Sun.COM 
23518611SSherry.Moore@Sun.COM 	dp = GEM_GET_DEV(dip);
23528611SSherry.Moore@Sun.COM 
23538611SSherry.Moore@Sun.COM 	if (dp == NULL)
23548611SSherry.Moore@Sun.COM 		return (DDI_FAILURE);
23558611SSherry.Moore@Sun.COM 
23568611SSherry.Moore@Sun.COM 	ret = sfe_stop_chip_quiesce(dp);
23578611SSherry.Moore@Sun.COM 
23588611SSherry.Moore@Sun.COM 	return (ret);
23598611SSherry.Moore@Sun.COM }
23608611SSherry.Moore@Sun.COM #endif
23618611SSherry.Moore@Sun.COM 
23625748Sduboff /* ======================================================== */
23635748Sduboff /*
23645748Sduboff  * OS depend (loadable streams driver) routine
23655748Sduboff  */
23665748Sduboff /* ======================================================== */
23675748Sduboff DDI_DEFINE_STREAM_OPS(sfe_ops, nulldev, nulldev, sfeattach, sfedetach,
23688611SSherry.Moore@Sun.COM 	nodev, NULL, D_MP, NULL, sfe_quiesce);
23695748Sduboff 
23705748Sduboff static struct modldrv modldrv = {
23715748Sduboff 	&mod_driverops,	/* Type of module.  This one is a driver */
23725748Sduboff 	ident,
23735748Sduboff 	&sfe_ops,	/* driver ops */
23745748Sduboff };
23755748Sduboff 
23765748Sduboff static struct modlinkage modlinkage = {
23775748Sduboff 	MODREV_1, &modldrv, NULL
23785748Sduboff };
23795748Sduboff 
23805748Sduboff /* ======================================================== */
23815748Sduboff /*
23825748Sduboff  * Loadable module support
23835748Sduboff  */
23845748Sduboff /* ======================================================== */
23855748Sduboff int
_init(void)23865748Sduboff _init(void)
23875748Sduboff {
23885748Sduboff 	int 	status;
23895748Sduboff 
23905748Sduboff 	DPRINTF(2, (CE_CONT, CONS "sfe: _init: called"));
23915748Sduboff 	gem_mod_init(&sfe_ops, "sfe");
23925748Sduboff 	status = mod_install(&modlinkage);
23935748Sduboff 	if (status != DDI_SUCCESS) {
23945748Sduboff 		gem_mod_fini(&sfe_ops);
23955748Sduboff 	}
23965748Sduboff 	return (status);
23975748Sduboff }
23985748Sduboff 
23995748Sduboff /*
24005748Sduboff  * _fini : done
24015748Sduboff  */
24025748Sduboff int
_fini(void)24035748Sduboff _fini(void)
24045748Sduboff {
24055748Sduboff 	int	status;
24065748Sduboff 
24075748Sduboff 	DPRINTF(2, (CE_CONT, CONS "sfe: _fini: called"));
24085748Sduboff 	status = mod_remove(&modlinkage);
24095748Sduboff 	if (status == DDI_SUCCESS) {
24105748Sduboff 		gem_mod_fini(&sfe_ops);
24115748Sduboff 	}
24125748Sduboff 	return (status);
24135748Sduboff }
24145748Sduboff 
24155748Sduboff int
_info(struct modinfo * modinfop)24165748Sduboff _info(struct modinfo *modinfop)
24175748Sduboff {
24185748Sduboff 	return (mod_info(&modlinkage, modinfop));
24195748Sduboff }
2420