xref: /illumos-gate/usr/src/uts/common/io/sfe/sfe.c (revision 23d366e3)
1f8919bdaSduboff /*
2f8919bdaSduboff  *  sfe.c : DP83815/DP83816/SiS900 Fast Ethernet MAC driver for Solaris
3f8919bdaSduboff  *
4*23d366e3Sduboff  * Copyright (c) 2002-2008 Masayuki Murayama.  All rights reserved.
5f8919bdaSduboff  *
6f8919bdaSduboff  * Redistribution and use in source and binary forms, with or without
7f8919bdaSduboff  * modification, are permitted provided that the following conditions are met:
8f8919bdaSduboff  *
9f8919bdaSduboff  * 1. Redistributions of source code must retain the above copyright notice,
10f8919bdaSduboff  *    this list of conditions and the following disclaimer.
11f8919bdaSduboff  *
12f8919bdaSduboff  * 2. Redistributions in binary form must reproduce the above copyright notice,
13f8919bdaSduboff  *    this list of conditions and the following disclaimer in the documentation
14f8919bdaSduboff  *    and/or other materials provided with the distribution.
15f8919bdaSduboff  *
16f8919bdaSduboff  * 3. Neither the name of the author nor the names of its contributors may be
17f8919bdaSduboff  *    used to endorse or promote products derived from this software without
18f8919bdaSduboff  *    specific prior written permission.
19f8919bdaSduboff  *
20f8919bdaSduboff  * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21f8919bdaSduboff  * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22f8919bdaSduboff  * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
23f8919bdaSduboff  * FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
24f8919bdaSduboff  * COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
25f8919bdaSduboff  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
26f8919bdaSduboff  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
27f8919bdaSduboff  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
28f8919bdaSduboff  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
29f8919bdaSduboff  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
30f8919bdaSduboff  * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
31f8919bdaSduboff  * DAMAGE.
32f8919bdaSduboff  */
33f8919bdaSduboff 
34f8919bdaSduboff #pragma ident	"%Z%%M%	%I%	%E% SMI"	/* sfe device driver */
35f8919bdaSduboff 
36f8919bdaSduboff /*
37f8919bdaSduboff  * System Header files.
38f8919bdaSduboff  */
39f8919bdaSduboff #include <sys/types.h>
40f8919bdaSduboff #include <sys/conf.h>
41f8919bdaSduboff #include <sys/debug.h>
42f8919bdaSduboff #include <sys/kmem.h>
43f8919bdaSduboff #include <sys/modctl.h>
44f8919bdaSduboff #include <sys/errno.h>
45f8919bdaSduboff #include <sys/ddi.h>
46f8919bdaSduboff #include <sys/sunddi.h>
47f8919bdaSduboff #include <sys/byteorder.h>
48f8919bdaSduboff #include <sys/ethernet.h>
49f8919bdaSduboff #include <sys/pci.h>
50f8919bdaSduboff 
51f8919bdaSduboff #include "sfe_mii.h"
52f8919bdaSduboff #include "sfe_util.h"
53f8919bdaSduboff #include "sfereg.h"
54f8919bdaSduboff 
55*23d366e3Sduboff char	ident[] = "sis900/dp83815 driver v" "2.6.1t27os";
56f8919bdaSduboff 
57f8919bdaSduboff /* Debugging support */
58f8919bdaSduboff #ifdef DEBUG_LEVEL
59f8919bdaSduboff static int sfe_debug = DEBUG_LEVEL;
60f8919bdaSduboff #if DEBUG_LEVEL > 4
61f8919bdaSduboff #define	CONS	"^"
62f8919bdaSduboff #else
63f8919bdaSduboff #define	CONS	"!"
64f8919bdaSduboff #endif
65f8919bdaSduboff #define	DPRINTF(n, args)	if (sfe_debug > (n)) cmn_err args
66f8919bdaSduboff #else
67f8919bdaSduboff #define	CONS	"!"
68f8919bdaSduboff #define	DPRINTF(n, args)
69f8919bdaSduboff #endif
70f8919bdaSduboff 
71f8919bdaSduboff /*
72f8919bdaSduboff  * Useful macros and typedefs
73f8919bdaSduboff  */
74f8919bdaSduboff #define	ONESEC		(drv_usectohz(1*1000000))
75f8919bdaSduboff #define	ROUNDUP2(x, a)	(((x) + (a) - 1) & ~((a) - 1))
76f8919bdaSduboff 
77f8919bdaSduboff /*
78f8919bdaSduboff  * Our configuration
79f8919bdaSduboff  */
80f8919bdaSduboff #define	MAXTXFRAGS	1
81f8919bdaSduboff #define	MAXRXFRAGS	1
82f8919bdaSduboff 
83f8919bdaSduboff #ifndef	TX_BUF_SIZE
84f8919bdaSduboff #define	TX_BUF_SIZE	64
85f8919bdaSduboff #endif
86f8919bdaSduboff #ifndef	TX_RING_SIZE
87f8919bdaSduboff #if MAXTXFRAGS == 1
88f8919bdaSduboff #define	TX_RING_SIZE	TX_BUF_SIZE
89f8919bdaSduboff #else
90f8919bdaSduboff #define	TX_RING_SIZE	(TX_BUF_SIZE * 4)
91f8919bdaSduboff #endif
92f8919bdaSduboff #endif
93f8919bdaSduboff 
94f8919bdaSduboff #ifndef	RX_BUF_SIZE
95f8919bdaSduboff #define	RX_BUF_SIZE	256
96f8919bdaSduboff #endif
97f8919bdaSduboff #ifndef	RX_RING_SIZE
98f8919bdaSduboff #define	RX_RING_SIZE	RX_BUF_SIZE
99f8919bdaSduboff #endif
100f8919bdaSduboff 
101f8919bdaSduboff #define	OUR_INTR_BITS	\
102f8919bdaSduboff 	(ISR_DPERR | ISR_SSERR | ISR_RMABT | ISR_RTABT | ISR_RXSOVR |	\
103f8919bdaSduboff 	ISR_TXURN | ISR_TXDESC | ISR_TXERR |	\
104f8919bdaSduboff 	ISR_RXORN | ISR_RXIDLE | ISR_RXOK | ISR_RXERR)
105f8919bdaSduboff 
106f8919bdaSduboff #define	USE_MULTICAST_HASHTBL
107f8919bdaSduboff 
108f8919bdaSduboff static int	sfe_tx_copy_thresh = 256;
109f8919bdaSduboff static int	sfe_rx_copy_thresh = 256;
110f8919bdaSduboff 
111f8919bdaSduboff /* special PHY registers for SIS900 */
112f8919bdaSduboff #define	MII_CONFIG1	0x0010
113f8919bdaSduboff #define	MII_CONFIG2	0x0011
114f8919bdaSduboff #define	MII_MASK	0x0013
115f8919bdaSduboff #define	MII_RESV	0x0014
116f8919bdaSduboff 
117f8919bdaSduboff #define	PHY_MASK		0xfffffff0
118f8919bdaSduboff #define	PHY_SIS900_INTERNAL	0x001d8000
119f8919bdaSduboff #define	PHY_ICS1893		0x0015f440
120f8919bdaSduboff 
121f8919bdaSduboff 
122f8919bdaSduboff #define	SFE_DESC_SIZE	16	/* including pads rounding up to power of 2 */
123f8919bdaSduboff 
124f8919bdaSduboff /*
125f8919bdaSduboff  * Supported chips
126f8919bdaSduboff  */
127f8919bdaSduboff struct chip_info {
128f8919bdaSduboff 	uint16_t	venid;
129f8919bdaSduboff 	uint16_t	devid;
130f8919bdaSduboff 	char		*chip_name;
131f8919bdaSduboff 	int		chip_type;
132f8919bdaSduboff #define	CHIPTYPE_DP83815	0
133f8919bdaSduboff #define	CHIPTYPE_SIS900		1
134f8919bdaSduboff };
135f8919bdaSduboff 
136f8919bdaSduboff /*
137f8919bdaSduboff  * Chip dependent MAC state
138f8919bdaSduboff  */
139f8919bdaSduboff struct sfe_dev {
140f8919bdaSduboff 	/* misc HW information */
141f8919bdaSduboff 	struct chip_info	*chip;
142f8919bdaSduboff 	uint32_t		our_intr_bits;
143*23d366e3Sduboff 	uint32_t		isr_pended;
144f8919bdaSduboff 	uint32_t		cr;
145f8919bdaSduboff 	uint_t			tx_drain_threshold;
146f8919bdaSduboff 	uint_t			tx_fill_threshold;
147f8919bdaSduboff 	uint_t			rx_drain_threshold;
148f8919bdaSduboff 	uint_t			rx_fill_threshold;
149f8919bdaSduboff 	uint8_t			revid;	/* revision from PCI configuration */
150f8919bdaSduboff 	boolean_t		(*get_mac_addr)(struct gem_dev *);
151f8919bdaSduboff 	uint8_t			mac_addr[ETHERADDRL];
152f8919bdaSduboff 	uint8_t			bridge_revid;
153f8919bdaSduboff };
154f8919bdaSduboff 
155f8919bdaSduboff /*
156f8919bdaSduboff  * Hardware information
157f8919bdaSduboff  */
158f8919bdaSduboff struct chip_info sfe_chiptbl[] = {
159f8919bdaSduboff 	{ 0x1039, 0x0900, "SiS900", CHIPTYPE_SIS900, },
160f8919bdaSduboff 	{ 0x100b, 0x0020, "DP83815/83816", CHIPTYPE_DP83815, },
161f8919bdaSduboff 	{ 0x1039, 0x7016, "SiS7016", CHIPTYPE_SIS900, },
162f8919bdaSduboff };
163f8919bdaSduboff #define	CHIPTABLESIZE (sizeof (sfe_chiptbl)/sizeof (struct chip_info))
164f8919bdaSduboff 
165f8919bdaSduboff /* ======================================================== */
166f8919bdaSduboff 
167f8919bdaSduboff /* mii operations */
168f8919bdaSduboff static void  sfe_mii_sync_dp83815(struct gem_dev *);
169f8919bdaSduboff static void  sfe_mii_sync_sis900(struct gem_dev *);
170f8919bdaSduboff static uint16_t  sfe_mii_read_dp83815(struct gem_dev *, uint_t);
171f8919bdaSduboff static uint16_t  sfe_mii_read_sis900(struct gem_dev *, uint_t);
172f8919bdaSduboff static void sfe_mii_write_dp83815(struct gem_dev *, uint_t, uint16_t);
173f8919bdaSduboff static void sfe_mii_write_sis900(struct gem_dev *, uint_t, uint16_t);
174f8919bdaSduboff static void sfe_set_eq_sis630(struct gem_dev *dp);
175f8919bdaSduboff /* nic operations */
176f8919bdaSduboff static int sfe_reset_chip_sis900(struct gem_dev *);
177f8919bdaSduboff static int sfe_reset_chip_dp83815(struct gem_dev *);
178f8919bdaSduboff static int sfe_init_chip(struct gem_dev *);
179f8919bdaSduboff static int sfe_start_chip(struct gem_dev *);
180f8919bdaSduboff static int sfe_stop_chip(struct gem_dev *);
181f8919bdaSduboff static int sfe_set_media(struct gem_dev *);
182f8919bdaSduboff static int sfe_set_rx_filter_dp83815(struct gem_dev *);
183f8919bdaSduboff static int sfe_set_rx_filter_sis900(struct gem_dev *);
184f8919bdaSduboff static int sfe_get_stats(struct gem_dev *);
185f8919bdaSduboff static int sfe_attach_chip(struct gem_dev *);
186f8919bdaSduboff 
187f8919bdaSduboff /* descriptor operations */
188f8919bdaSduboff static int sfe_tx_desc_write(struct gem_dev *dp, int slot,
189f8919bdaSduboff 		    ddi_dma_cookie_t *dmacookie, int frags, uint64_t flags);
190f8919bdaSduboff static void sfe_tx_start(struct gem_dev *dp, int startslot, int nslot);
191f8919bdaSduboff static void sfe_rx_desc_write(struct gem_dev *dp, int slot,
192f8919bdaSduboff 		    ddi_dma_cookie_t *dmacookie, int frags);
193f8919bdaSduboff static uint_t sfe_tx_desc_stat(struct gem_dev *dp, int slot, int ndesc);
194f8919bdaSduboff static uint64_t sfe_rx_desc_stat(struct gem_dev *dp, int slot, int ndesc);
195f8919bdaSduboff 
196f8919bdaSduboff static void sfe_tx_desc_init(struct gem_dev *dp, int slot);
197f8919bdaSduboff static void sfe_rx_desc_init(struct gem_dev *dp, int slot);
198f8919bdaSduboff static void sfe_tx_desc_clean(struct gem_dev *dp, int slot);
199f8919bdaSduboff static void sfe_rx_desc_clean(struct gem_dev *dp, int slot);
200f8919bdaSduboff 
201f8919bdaSduboff /* interrupt handler */
202f8919bdaSduboff static uint_t sfe_interrupt(struct gem_dev *dp);
203f8919bdaSduboff 
204f8919bdaSduboff /* ======================================================== */
205f8919bdaSduboff 
206f8919bdaSduboff /* mapping attributes */
207f8919bdaSduboff /* Data access requirements. */
208f8919bdaSduboff static struct ddi_device_acc_attr sfe_dev_attr = {
209f8919bdaSduboff 	DDI_DEVICE_ATTR_V0,
210f8919bdaSduboff 	DDI_STRUCTURE_LE_ACC,
211f8919bdaSduboff 	DDI_STRICTORDER_ACC
212f8919bdaSduboff };
213f8919bdaSduboff 
214f8919bdaSduboff /* On sparc, Buffers should be native endian for speed */
215f8919bdaSduboff static struct ddi_device_acc_attr sfe_buf_attr = {
216f8919bdaSduboff 	DDI_DEVICE_ATTR_V0,
217f8919bdaSduboff 	DDI_NEVERSWAP_ACC,	/* native endianness */
218f8919bdaSduboff 	DDI_STRICTORDER_ACC
219f8919bdaSduboff };
220f8919bdaSduboff 
221f8919bdaSduboff static ddi_dma_attr_t sfe_dma_attr_buf = {
222f8919bdaSduboff 	DMA_ATTR_V0,		/* dma_attr_version */
223f8919bdaSduboff 	0,			/* dma_attr_addr_lo */
224f8919bdaSduboff 	0xffffffffull,		/* dma_attr_addr_hi */
225f8919bdaSduboff 	0x00000fffull,		/* dma_attr_count_max */
226f8919bdaSduboff 	0, /* patched later */	/* dma_attr_align */
227f8919bdaSduboff 	0x000003fc,		/* dma_attr_burstsizes */
228f8919bdaSduboff 	1,			/* dma_attr_minxfer */
229f8919bdaSduboff 	0x00000fffull,		/* dma_attr_maxxfer */
230f8919bdaSduboff 	0xffffffffull,		/* dma_attr_seg */
231f8919bdaSduboff 	0, /* patched later */	/* dma_attr_sgllen */
232f8919bdaSduboff 	1,			/* dma_attr_granular */
233f8919bdaSduboff 	0			/* dma_attr_flags */
234f8919bdaSduboff };
235f8919bdaSduboff 
236f8919bdaSduboff static ddi_dma_attr_t sfe_dma_attr_desc = {
237f8919bdaSduboff 	DMA_ATTR_V0,		/* dma_attr_version */
238f8919bdaSduboff 	16,			/* dma_attr_addr_lo */
239f8919bdaSduboff 	0xffffffffull,		/* dma_attr_addr_hi */
240f8919bdaSduboff 	0xffffffffull,		/* dma_attr_count_max */
241f8919bdaSduboff 	16,			/* dma_attr_align */
242f8919bdaSduboff 	0x000003fc,		/* dma_attr_burstsizes */
243f8919bdaSduboff 	1,			/* dma_attr_minxfer */
244f8919bdaSduboff 	0xffffffffull,		/* dma_attr_maxxfer */
245f8919bdaSduboff 	0xffffffffull,		/* dma_attr_seg */
246f8919bdaSduboff 	1,			/* dma_attr_sgllen */
247f8919bdaSduboff 	1,			/* dma_attr_granular */
248f8919bdaSduboff 	0			/* dma_attr_flags */
249f8919bdaSduboff };
250f8919bdaSduboff 
251f8919bdaSduboff uint32_t sfe_use_pcimemspace = 0;
252f8919bdaSduboff 
253f8919bdaSduboff /* ======================================================== */
254f8919bdaSduboff /*
255f8919bdaSduboff  * HW manipulation routines
256f8919bdaSduboff  */
257f8919bdaSduboff /* ======================================================== */
258f8919bdaSduboff 
259f8919bdaSduboff #define	SFE_EEPROM_DELAY(dp)	\
260f8919bdaSduboff 	{ (void) INL(dp, EROMAR); (void) INL(dp, EROMAR); }
261f8919bdaSduboff #define	EE_CMD_READ	6
262f8919bdaSduboff #define	EE_CMD_SHIFT	6
263f8919bdaSduboff 
264f8919bdaSduboff static uint16_t
265f8919bdaSduboff sfe_read_eeprom(struct gem_dev *dp, uint_t offset)
266f8919bdaSduboff {
267f8919bdaSduboff 	int		eedi;
268f8919bdaSduboff 	int		i;
269f8919bdaSduboff 	uint16_t	ret;
270f8919bdaSduboff 
271f8919bdaSduboff 	/* ensure de-assert chip select */
272f8919bdaSduboff 	OUTL(dp, EROMAR, 0);
273f8919bdaSduboff 	SFE_EEPROM_DELAY(dp);
274f8919bdaSduboff 	OUTL(dp, EROMAR, EROMAR_EESK);
275f8919bdaSduboff 	SFE_EEPROM_DELAY(dp);
276f8919bdaSduboff 
277f8919bdaSduboff 	/* assert chip select */
278f8919bdaSduboff 	offset |= EE_CMD_READ << EE_CMD_SHIFT;
279f8919bdaSduboff 
280f8919bdaSduboff 	for (i = 8; i >= 0; i--) {
281f8919bdaSduboff 		/* make command */
282f8919bdaSduboff 		eedi = ((offset >> i) & 1) << EROMAR_EEDI_SHIFT;
283f8919bdaSduboff 
284f8919bdaSduboff 		/* send 1 bit */
285f8919bdaSduboff 		OUTL(dp, EROMAR, EROMAR_EECS | eedi);
286f8919bdaSduboff 		SFE_EEPROM_DELAY(dp);
287f8919bdaSduboff 		OUTL(dp, EROMAR, EROMAR_EECS | eedi | EROMAR_EESK);
288f8919bdaSduboff 		SFE_EEPROM_DELAY(dp);
289f8919bdaSduboff 	}
290f8919bdaSduboff 
291f8919bdaSduboff 	OUTL(dp, EROMAR, EROMAR_EECS);
292f8919bdaSduboff 
293f8919bdaSduboff 	ret = 0;
294f8919bdaSduboff 	for (i = 0; i < 16; i++) {
295f8919bdaSduboff 		/* Get 1 bit */
296f8919bdaSduboff 		OUTL(dp, EROMAR, EROMAR_EECS);
297f8919bdaSduboff 		SFE_EEPROM_DELAY(dp);
298f8919bdaSduboff 		OUTL(dp, EROMAR, EROMAR_EECS | EROMAR_EESK);
299f8919bdaSduboff 		SFE_EEPROM_DELAY(dp);
300f8919bdaSduboff 
301f8919bdaSduboff 		ret = (ret << 1) | ((INL(dp, EROMAR) >> EROMAR_EEDO_SHIFT) & 1);
302f8919bdaSduboff 	}
303f8919bdaSduboff 
304f8919bdaSduboff 	OUTL(dp, EROMAR, 0);
305f8919bdaSduboff 	SFE_EEPROM_DELAY(dp);
306f8919bdaSduboff 
307f8919bdaSduboff 	return (ret);
308f8919bdaSduboff }
309f8919bdaSduboff #undef SFE_EEPROM_DELAY
310f8919bdaSduboff 
311f8919bdaSduboff static boolean_t
312f8919bdaSduboff sfe_get_mac_addr_dp83815(struct gem_dev *dp)
313f8919bdaSduboff {
314f8919bdaSduboff 	uint8_t		*mac;
315f8919bdaSduboff 	uint_t		val;
316f8919bdaSduboff 	int		i;
317f8919bdaSduboff 
318f8919bdaSduboff #define	BITSET(p, ix, v)	(p)[(ix)/8] |= ((v) ? 1 : 0) << ((ix) & 0x7)
319f8919bdaSduboff 
320f8919bdaSduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__));
321f8919bdaSduboff 
322f8919bdaSduboff 	mac = dp->dev_addr.ether_addr_octet;
323f8919bdaSduboff 
324f8919bdaSduboff 	/* first of all, clear MAC address buffer */
325f8919bdaSduboff 	bzero(mac, ETHERADDRL);
326f8919bdaSduboff 
327f8919bdaSduboff 	/* get bit 0 */
328f8919bdaSduboff 	val = sfe_read_eeprom(dp, 0x6);
329f8919bdaSduboff 	BITSET(mac, 0, val & 1);
330f8919bdaSduboff 
331f8919bdaSduboff 	/* get bit 1 - 16 */
332f8919bdaSduboff 	val = sfe_read_eeprom(dp, 0x7);
333f8919bdaSduboff 	for (i = 0; i < 16; i++) {
334f8919bdaSduboff 		BITSET(mac, 1 + i, val & (1 << (15 - i)));
335f8919bdaSduboff 	}
336f8919bdaSduboff 
337f8919bdaSduboff 	/* get bit 17 -  32 */
338f8919bdaSduboff 	val = sfe_read_eeprom(dp, 0x8);
339f8919bdaSduboff 	for (i = 0; i < 16; i++) {
340f8919bdaSduboff 		BITSET(mac, 17 + i, val & (1 << (15 - i)));
341f8919bdaSduboff 	}
342f8919bdaSduboff 
343f8919bdaSduboff 	/* get bit 33 -  47 */
344f8919bdaSduboff 	val = sfe_read_eeprom(dp, 0x9);
345f8919bdaSduboff 	for (i = 0; i < 15; i++) {
346f8919bdaSduboff 		BITSET(mac, 33 + i, val & (1 << (15 - i)));
347f8919bdaSduboff 	}
348f8919bdaSduboff 
349f8919bdaSduboff 	return (B_TRUE);
350f8919bdaSduboff #undef BITSET
351f8919bdaSduboff }
352f8919bdaSduboff 
353f8919bdaSduboff static boolean_t
354f8919bdaSduboff sfe_get_mac_addr_sis900(struct gem_dev *dp)
355f8919bdaSduboff {
356f8919bdaSduboff 	uint_t		val;
357f8919bdaSduboff 	int		i;
358f8919bdaSduboff 	uint8_t		*mac;
359f8919bdaSduboff 
360f8919bdaSduboff 	mac = dp->dev_addr.ether_addr_octet;
361f8919bdaSduboff 
362f8919bdaSduboff 	for (i = 0; i < ETHERADDRL/2; i++) {
363f8919bdaSduboff 		val = sfe_read_eeprom(dp, 0x8 + i);
364f8919bdaSduboff 		*mac++ = (uint8_t)val;
365f8919bdaSduboff 		*mac++ = (uint8_t)(val >> 8);
366f8919bdaSduboff 	}
367f8919bdaSduboff 
368f8919bdaSduboff 	return (B_TRUE);
369f8919bdaSduboff }
370f8919bdaSduboff 
371f8919bdaSduboff static dev_info_t *
372f8919bdaSduboff sfe_search_pci_dev_subr(dev_info_t *cur_node, int vendor_id, int device_id)
373f8919bdaSduboff {
374f8919bdaSduboff 	dev_info_t	*child_id;
375f8919bdaSduboff 	dev_info_t	*ret;
376f8919bdaSduboff 	int		vid, did;
377f8919bdaSduboff 
378f8919bdaSduboff 	if (cur_node == NULL) {
379f8919bdaSduboff 		return (NULL);
380f8919bdaSduboff 	}
381f8919bdaSduboff 
382f8919bdaSduboff 	/* check brothers */
383f8919bdaSduboff 	do {
384f8919bdaSduboff 		vid = ddi_prop_get_int(DDI_DEV_T_ANY, cur_node,
385f8919bdaSduboff 		    DDI_PROP_DONTPASS, "vendor-id", -1);
386f8919bdaSduboff 		did = ddi_prop_get_int(DDI_DEV_T_ANY, cur_node,
387f8919bdaSduboff 		    DDI_PROP_DONTPASS, "device-id", -1);
388f8919bdaSduboff 
389f8919bdaSduboff 		if (vid == vendor_id && did == device_id) {
390f8919bdaSduboff 			/* found */
391f8919bdaSduboff 			return (cur_node);
392f8919bdaSduboff 		}
393f8919bdaSduboff 
394f8919bdaSduboff 		/* check children */
395f8919bdaSduboff 		if ((child_id = ddi_get_child(cur_node)) != NULL) {
396f8919bdaSduboff 			if ((ret = sfe_search_pci_dev_subr(child_id,
397f8919bdaSduboff 			    vendor_id, device_id)) != NULL) {
398f8919bdaSduboff 				return (ret);
399f8919bdaSduboff 			}
400f8919bdaSduboff 		}
401f8919bdaSduboff 
402f8919bdaSduboff 	} while ((cur_node = ddi_get_next_sibling(cur_node)) != NULL);
403f8919bdaSduboff 
404f8919bdaSduboff 	/* not found */
405f8919bdaSduboff 	return (NULL);
406f8919bdaSduboff }
407f8919bdaSduboff 
408f8919bdaSduboff static dev_info_t *
409f8919bdaSduboff sfe_search_pci_dev(int vendor_id, int device_id)
410f8919bdaSduboff {
411f8919bdaSduboff 	return (sfe_search_pci_dev_subr(ddi_root_node(), vendor_id, device_id));
412f8919bdaSduboff }
413f8919bdaSduboff 
414f8919bdaSduboff /* Avoid undefined symbol for non IA architectures */
415f8919bdaSduboff #pragma weak	inb
416f8919bdaSduboff #pragma weak	outb
417f8919bdaSduboff 
418f8919bdaSduboff static boolean_t
419f8919bdaSduboff sfe_get_mac_addr_sis630e(struct gem_dev *dp)
420f8919bdaSduboff {
421f8919bdaSduboff 	int		i;
422f8919bdaSduboff 	dev_info_t	*isa_bridge;
423f8919bdaSduboff 	ddi_acc_handle_t isa_handle;
424f8919bdaSduboff 	int		reg;
425f8919bdaSduboff 
426f8919bdaSduboff 	if (inb == NULL || outb == NULL) {
427f8919bdaSduboff 		/* this is not IA architecture */
428f8919bdaSduboff 		return (B_FALSE);
429f8919bdaSduboff 	}
430f8919bdaSduboff 
431f8919bdaSduboff 	if ((isa_bridge = sfe_search_pci_dev(0x1039, 0x8)) == NULL) {
432f8919bdaSduboff 		cmn_err(CE_WARN, "%s: failed to find isa-bridge pci1039,8",
433f8919bdaSduboff 		    dp->name);
434f8919bdaSduboff 		return (B_FALSE);
435f8919bdaSduboff 	}
436f8919bdaSduboff 
437f8919bdaSduboff 	if (pci_config_setup(isa_bridge, &isa_handle) != DDI_SUCCESS) {
438f8919bdaSduboff 		cmn_err(CE_WARN, "%s: ddi_regs_map_setup failed",
439f8919bdaSduboff 		    dp->name);
440f8919bdaSduboff 		return (B_FALSE);
441f8919bdaSduboff 	}
442f8919bdaSduboff 
443f8919bdaSduboff 	/* enable to access CMOS RAM */
444f8919bdaSduboff 	reg = pci_config_get8(isa_handle, 0x48);
445f8919bdaSduboff 	pci_config_put8(isa_handle, 0x48, reg | 0x40);
446f8919bdaSduboff 
447f8919bdaSduboff 	for (i = 0; i < ETHERADDRL; i++) {
448f8919bdaSduboff 		outb(0x70, 0x09 + i);
449f8919bdaSduboff 		dp->dev_addr.ether_addr_octet[i] = inb(0x71);
450f8919bdaSduboff 	}
451f8919bdaSduboff 
452f8919bdaSduboff 	/* disable to access CMOS RAM */
453f8919bdaSduboff 	pci_config_put8(isa_handle, 0x48, reg);
454f8919bdaSduboff 	pci_config_teardown(&isa_handle);
455f8919bdaSduboff 
456f8919bdaSduboff 	return (B_TRUE);
457f8919bdaSduboff }
458f8919bdaSduboff 
459f8919bdaSduboff static boolean_t
460f8919bdaSduboff sfe_get_mac_addr_sis635(struct gem_dev *dp)
461f8919bdaSduboff {
462f8919bdaSduboff 	int		i;
463f8919bdaSduboff 	uint32_t	rfcr;
464f8919bdaSduboff 	uint16_t	v;
465f8919bdaSduboff 	struct sfe_dev	*lp = dp->private;
466f8919bdaSduboff 
467f8919bdaSduboff 	DPRINTF(2, (CE_CONT, CONS "%s: %s: called", dp->name, __func__));
468f8919bdaSduboff 	rfcr = INL(dp, RFCR);
469f8919bdaSduboff 
470f8919bdaSduboff 	OUTL(dp, CR, lp->cr | CR_RELOAD);
471f8919bdaSduboff 	OUTL(dp, CR, lp->cr);
472f8919bdaSduboff 
473f8919bdaSduboff 	/* disable packet filtering before reading filter */
474f8919bdaSduboff 	OUTL(dp, RFCR, rfcr & ~RFCR_RFEN);
475f8919bdaSduboff 
476f8919bdaSduboff 	/* load MAC addr from filter data register */
477f8919bdaSduboff 	for (i = 0; i < ETHERADDRL; i += 2) {
478f8919bdaSduboff 		OUTL(dp, RFCR,
479f8919bdaSduboff 		    (RFADDR_MAC_SIS900 + (i/2)) << RFCR_RFADDR_SHIFT_SIS900);
480f8919bdaSduboff 		v = INL(dp, RFDR);
481f8919bdaSduboff 		dp->dev_addr.ether_addr_octet[i] = (uint8_t)v;
482f8919bdaSduboff 		dp->dev_addr.ether_addr_octet[i+1] = (uint8_t)(v >> 8);
483f8919bdaSduboff 	}
484f8919bdaSduboff 
485f8919bdaSduboff 	/* re-enable packet filtering */
486f8919bdaSduboff 	OUTL(dp, RFCR, rfcr | RFCR_RFEN);
487f8919bdaSduboff 
488f8919bdaSduboff 	return (B_TRUE);
489f8919bdaSduboff }
490f8919bdaSduboff 
491f8919bdaSduboff static boolean_t
492f8919bdaSduboff sfe_get_mac_addr_sis962(struct gem_dev *dp)
493f8919bdaSduboff {
494f8919bdaSduboff 	boolean_t	ret;
495f8919bdaSduboff 	int		i;
496f8919bdaSduboff 
497f8919bdaSduboff 	ret = B_FALSE;
498f8919bdaSduboff 
499f8919bdaSduboff 	/* rise request signal to access EEPROM */
500f8919bdaSduboff 	OUTL(dp, MEAR, EROMAR_EEREQ);
501f8919bdaSduboff 	for (i = 0; (INL(dp, MEAR) & EROMAR_EEGNT) == 0; i++) {
502f8919bdaSduboff 		if (i > 200) {
503f8919bdaSduboff 			/* failed to acquire eeprom */
504f8919bdaSduboff 			cmn_err(CE_NOTE,
505f8919bdaSduboff 			    CONS "%s: failed to access eeprom", dp->name);
506f8919bdaSduboff 			goto x;
507f8919bdaSduboff 		}
508f8919bdaSduboff 		drv_usecwait(10);
509f8919bdaSduboff 	}
510f8919bdaSduboff 	ret = sfe_get_mac_addr_sis900(dp);
511f8919bdaSduboff x:
512f8919bdaSduboff 	/* release EEPROM */
513f8919bdaSduboff 	OUTL(dp, MEAR, EROMAR_EEDONE);
514f8919bdaSduboff 
515f8919bdaSduboff 	return (ret);
516f8919bdaSduboff }
517f8919bdaSduboff 
518f8919bdaSduboff static int
519f8919bdaSduboff sfe_reset_chip_sis900(struct gem_dev *dp)
520f8919bdaSduboff {
521f8919bdaSduboff 	int		i;
522f8919bdaSduboff 	uint32_t	done;
523f8919bdaSduboff 	uint32_t	val;
524f8919bdaSduboff 	struct sfe_dev	*lp = dp->private;
525f8919bdaSduboff 
526f8919bdaSduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s called", dp->name, __func__));
527f8919bdaSduboff 
528f8919bdaSduboff 	/* invalidate mac addr cache */
529f8919bdaSduboff 	bzero(lp->mac_addr, sizeof (lp->mac_addr));
530f8919bdaSduboff 
531f8919bdaSduboff 	lp->cr = 0;
532f8919bdaSduboff 
533f8919bdaSduboff 	/* inhibit interrupt */
534f8919bdaSduboff 	OUTL(dp, IMR, 0);
535*23d366e3Sduboff 	lp->isr_pended |= INL(dp, ISR) & lp->our_intr_bits;
536f8919bdaSduboff 
537f8919bdaSduboff 	OUTL(dp, RFCR, 0);
538f8919bdaSduboff 
539f8919bdaSduboff 	OUTL(dp, CR, CR_RST | CR_TXR | CR_RXR);
540f8919bdaSduboff 	drv_usecwait(10);
541f8919bdaSduboff 
542f8919bdaSduboff 	done = 0;
543f8919bdaSduboff 	for (i = 0; done != (ISR_TXRCMP | ISR_RXRCMP); i++) {
544f8919bdaSduboff 		if (i > 1000) {
545f8919bdaSduboff 			cmn_err(CE_WARN, "%s: chip reset timeout", dp->name);
546f8919bdaSduboff 			return (GEM_FAILURE);
547f8919bdaSduboff 		}
548f8919bdaSduboff 		done |= INL(dp, ISR) & (ISR_TXRCMP | ISR_RXRCMP);
549f8919bdaSduboff 		drv_usecwait(10);
550f8919bdaSduboff 	}
551f8919bdaSduboff 
552f8919bdaSduboff 	if (lp->revid == SIS630ET_900_REV) {
553f8919bdaSduboff 		lp->cr |= CR_ACCESSMODE;
554f8919bdaSduboff 		OUTL(dp, CR, lp->cr | INL(dp, CR));
555f8919bdaSduboff 	}
556f8919bdaSduboff 
557f8919bdaSduboff 	/* Configuration register: enable PCI parity */
558f8919bdaSduboff 	DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b",
559f8919bdaSduboff 	    dp->name, INL(dp, CFG), CFG_BITS_SIS900));
560*23d366e3Sduboff 	val = 0;
561f8919bdaSduboff 	if (lp->revid >= SIS635A_900_REV ||
562f8919bdaSduboff 	    lp->revid == SIS900B_900_REV) {
563f8919bdaSduboff 		/* what is this ? */
564f8919bdaSduboff 		val |= CFG_RND_CNT;
565f8919bdaSduboff 	}
566f8919bdaSduboff 	OUTL(dp, CFG, val);
567f8919bdaSduboff 	DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b", dp->name,
568f8919bdaSduboff 	    INL(dp, CFG), CFG_BITS_SIS900));
569f8919bdaSduboff 
570f8919bdaSduboff 	return (GEM_SUCCESS);
571f8919bdaSduboff }
572f8919bdaSduboff 
573f8919bdaSduboff static int
574f8919bdaSduboff sfe_reset_chip_dp83815(struct gem_dev *dp)
575f8919bdaSduboff {
576f8919bdaSduboff 	int		i;
577*23d366e3Sduboff 	uint32_t	val;
578f8919bdaSduboff 	struct sfe_dev	*lp = dp->private;
579f8919bdaSduboff 
580f8919bdaSduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s called", dp->name, __func__));
581f8919bdaSduboff 
582f8919bdaSduboff 	/* invalidate mac addr cache */
583f8919bdaSduboff 	bzero(lp->mac_addr, sizeof (lp->mac_addr));
584f8919bdaSduboff 
585f8919bdaSduboff 	lp->cr = 0;
586f8919bdaSduboff 
587f8919bdaSduboff 	/* inhibit interrupts */
588f8919bdaSduboff 	OUTL(dp, IMR, 0);
589*23d366e3Sduboff 	lp->isr_pended |= INL(dp, ISR) & lp->our_intr_bits;
590f8919bdaSduboff 
591f8919bdaSduboff 	OUTL(dp, RFCR, 0);
592f8919bdaSduboff 
593f8919bdaSduboff 	OUTL(dp, CR, CR_RST);
594f8919bdaSduboff 	drv_usecwait(10);
595f8919bdaSduboff 
596f8919bdaSduboff 	for (i = 0; INL(dp, CR) & CR_RST; i++) {
597f8919bdaSduboff 		if (i > 100) {
598f8919bdaSduboff 			cmn_err(CE_WARN, "!%s: chip reset timeout", dp->name);
599f8919bdaSduboff 			return (GEM_FAILURE);
600f8919bdaSduboff 		}
601f8919bdaSduboff 		drv_usecwait(10);
602f8919bdaSduboff 	}
603f8919bdaSduboff 	DPRINTF(0, (CE_CONT, "!%s: chip reset in %duS", dp->name, i*10));
604f8919bdaSduboff 
605f8919bdaSduboff 	OUTL(dp, CCSR, CCSR_PMESTS);
606f8919bdaSduboff 	OUTL(dp, CCSR, 0);
607f8919bdaSduboff 
608f8919bdaSduboff 	/* Configuration register: enable PCI parity */
609f8919bdaSduboff 	DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b",
610f8919bdaSduboff 	    dp->name, INL(dp, CFG), CFG_BITS_DP83815));
611*23d366e3Sduboff 	val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG);
612*23d366e3Sduboff 	OUTL(dp, CFG, val | CFG_PAUSE_ADV);
613f8919bdaSduboff 	DPRINTF(2, (CE_CONT, CONS "%s: cfg:%b", dp->name,
614f8919bdaSduboff 	    INL(dp, CFG), CFG_BITS_DP83815));
615f8919bdaSduboff 
616f8919bdaSduboff 	return (GEM_SUCCESS);
617f8919bdaSduboff }
618f8919bdaSduboff 
619f8919bdaSduboff static int
620f8919bdaSduboff sfe_init_chip(struct gem_dev *dp)
621f8919bdaSduboff {
622f8919bdaSduboff 	/* Configuration register: have been set up in sfe_chip_reset */
623f8919bdaSduboff 
624f8919bdaSduboff 	/* PCI test control register: do nothing */
625f8919bdaSduboff 
626f8919bdaSduboff 	/* Interrupt status register : do nothing */
627f8919bdaSduboff 
628f8919bdaSduboff 	/* Interrupt mask register: clear, but leave lp->our_intr_bits */
629f8919bdaSduboff 	OUTL(dp, IMR, 0);
630f8919bdaSduboff 
631f8919bdaSduboff 	/* Enhanced PHY Access register (sis900): do nothing */
632f8919bdaSduboff 
633f8919bdaSduboff 	/* Transmit Descriptor Pointer register: base addr of TX ring */
634f8919bdaSduboff 	OUTL(dp, TXDP, dp->tx_ring_dma);
635f8919bdaSduboff 
636f8919bdaSduboff 	/* Receive descriptor pointer register: base addr of RX ring */
637f8919bdaSduboff 	OUTL(dp, RXDP, dp->rx_ring_dma);
638f8919bdaSduboff 
639f8919bdaSduboff 	return (GEM_SUCCESS);
640f8919bdaSduboff }
641f8919bdaSduboff 
642f8919bdaSduboff static uint_t
643f8919bdaSduboff sfe_mcast_hash(struct gem_dev *dp, uint8_t *addr)
644f8919bdaSduboff {
645f8919bdaSduboff 	return (gem_ether_crc_be(addr, ETHERADDRL));
646f8919bdaSduboff }
647f8919bdaSduboff 
648f8919bdaSduboff #ifdef DEBUG_LEVEL
649f8919bdaSduboff static void
650f8919bdaSduboff sfe_rxfilter_dump(struct gem_dev *dp, int start, int end)
651f8919bdaSduboff {
652f8919bdaSduboff 	int		i;
653f8919bdaSduboff 	int		j;
654f8919bdaSduboff 	uint16_t	ram[0x10];
655f8919bdaSduboff 
656f8919bdaSduboff 	cmn_err(CE_CONT, "!%s: rx filter ram dump:", dp->name);
657f8919bdaSduboff #define	WORDS_PER_LINE	4
658f8919bdaSduboff 	for (i = start; i < end; i += WORDS_PER_LINE*2) {
659f8919bdaSduboff 		for (j = 0; j < WORDS_PER_LINE; j++) {
660f8919bdaSduboff 			OUTL(dp, RFCR, RFADDR_MAC_DP83815 + i + j*2);
661f8919bdaSduboff 			ram[j] = INL(dp, RFDR);
662f8919bdaSduboff 		}
663f8919bdaSduboff 
664f8919bdaSduboff 		cmn_err(CE_CONT, "!0x%02x: 0x%04x 0x%04x 0x%04x 0x%04x",
665f8919bdaSduboff 		    i, ram[0], ram[1], ram[2], ram[3]);
666f8919bdaSduboff 		}
667f8919bdaSduboff 
668f8919bdaSduboff #undef	WORDS_PER_LINE
669f8919bdaSduboff }
670f8919bdaSduboff #endif
671f8919bdaSduboff 
672f8919bdaSduboff static uint_t	sfe_rf_perfect_base_dp83815[] = {
673f8919bdaSduboff 	RFADDR_PMATCH0_DP83815,
674f8919bdaSduboff 	RFADDR_PMATCH1_DP83815,
675f8919bdaSduboff 	RFADDR_PMATCH2_DP83815,
676f8919bdaSduboff 	RFADDR_PMATCH3_DP83815,
677f8919bdaSduboff };
678f8919bdaSduboff 
679f8919bdaSduboff static int
680f8919bdaSduboff sfe_set_rx_filter_dp83815(struct gem_dev *dp)
681f8919bdaSduboff {
682f8919bdaSduboff 	int		i;
683f8919bdaSduboff 	int		j;
684f8919bdaSduboff 	uint32_t	mode;
685f8919bdaSduboff 	uint8_t		*mac = dp->cur_addr.ether_addr_octet;
686f8919bdaSduboff 	uint16_t	hash_tbl[32];
687f8919bdaSduboff 	struct sfe_dev	*lp = dp->private;
688f8919bdaSduboff 
689f8919bdaSduboff 	DPRINTF(1, (CE_CONT, CONS "%s: %s: called, mc_count:%d, mode:0x%b",
690f8919bdaSduboff 	    dp->name, __func__, dp->mc_count, dp->rxmode, RXMODE_BITS));
691f8919bdaSduboff 
692f8919bdaSduboff #if DEBUG_LEVEL > 0
693f8919bdaSduboff 	for (i = 0; i < dp->mc_count; i++) {
694f8919bdaSduboff 		cmn_err(CE_CONT,
695f8919bdaSduboff 		"!%s: adding mcast(%d) %02x:%02x:%02x:%02x:%02x:%02x",
696f8919bdaSduboff 		    dp->name, i,
697f8919bdaSduboff 		    dp->mc_list[i].addr.ether_addr_octet[0],
698f8919bdaSduboff 		    dp->mc_list[i].addr.ether_addr_octet[1],
699f8919bdaSduboff 		    dp->mc_list[i].addr.ether_addr_octet[2],
700f8919bdaSduboff 		    dp->mc_list[i].addr.ether_addr_octet[3],
701f8919bdaSduboff 		    dp->mc_list[i].addr.ether_addr_octet[4],
702f8919bdaSduboff 		    dp->mc_list[i].addr.ether_addr_octet[5]);
703f8919bdaSduboff 	}
704f8919bdaSduboff #endif
705f8919bdaSduboff 	if ((dp->rxmode & RXMODE_ENABLE) == 0) {
706f8919bdaSduboff 		/* disable rx filter */
707f8919bdaSduboff 		OUTL(dp, RFCR, 0);
708f8919bdaSduboff 		return (GEM_SUCCESS);
709f8919bdaSduboff 	}
710f8919bdaSduboff 
711f8919bdaSduboff 	/*
712f8919bdaSduboff 	 * Set Receive filter control register
713f8919bdaSduboff 	 */
714f8919bdaSduboff 	if (dp->rxmode & RXMODE_PROMISC) {
715f8919bdaSduboff 		/* all broadcast, all multicast, all physical */
716f8919bdaSduboff 		mode = RFCR_AAB | RFCR_AAM | RFCR_AAP;
717f8919bdaSduboff 	} else if ((dp->rxmode & RXMODE_ALLMULTI) || dp->mc_count > 16*32/2) {
718f8919bdaSduboff 		/* all broadcast, all multicast, physical for the chip */
719f8919bdaSduboff 		mode = RFCR_AAB | RFCR_AAM | RFCR_APM_DP83815;
720f8919bdaSduboff 	} else if (dp->mc_count > 4) {
721f8919bdaSduboff 		/*
722f8919bdaSduboff 		 * Use multicast hash table,
723f8919bdaSduboff 		 * accept all broadcast and physical for the chip.
724f8919bdaSduboff 		 */
725f8919bdaSduboff 		mode = RFCR_AAB | RFCR_MHEN_DP83815 | RFCR_APM_DP83815;
726f8919bdaSduboff 
727f8919bdaSduboff 		bzero(hash_tbl, sizeof (hash_tbl));
728f8919bdaSduboff 		for (i = 0; i < dp->mc_count; i++) {
729f8919bdaSduboff 			j = dp->mc_list[i].hash >> (32 - 9);
730f8919bdaSduboff 			hash_tbl[j / 16] |= 1 << (j % 16);
731f8919bdaSduboff 		}
732f8919bdaSduboff 	} else {
733f8919bdaSduboff 		/*
734f8919bdaSduboff 		 * Use pattern mach filter for multicast address,
735f8919bdaSduboff 		 * accept all broadcast and physical for the chip
736f8919bdaSduboff 		 */
737f8919bdaSduboff 		/* need to enable corresponding pattern registers */
738f8919bdaSduboff 		mode = RFCR_AAB | RFCR_APM_DP83815 |
739f8919bdaSduboff 		    (((1 << dp->mc_count) - 1) << RFCR_APAT_SHIFT);
740f8919bdaSduboff 	}
741f8919bdaSduboff 
742f8919bdaSduboff #if DEBUG_LEVEL > 1
743f8919bdaSduboff 	cmn_err(CE_CONT,
744f8919bdaSduboff 	    "!%s: mac %02x:%02x:%02x:%02x:%02x:%02x"
745f8919bdaSduboff 	    "  cache %02x:%02x:%02x:%02x:%02x:%02x",
746f8919bdaSduboff 	    dp->name, mac[0], mac[1], mac[2], mac[3], mac[4], mac[5],
747f8919bdaSduboff 	    lp->mac_addr[0], lp->mac_addr[1],
748f8919bdaSduboff 	    lp->mac_addr[2], lp->mac_addr[3],
749f8919bdaSduboff 	    lp->mac_addr[4], lp->mac_addr[5]);
750f8919bdaSduboff #endif
751f8919bdaSduboff 	if (bcmp(mac, lp->mac_addr, ETHERADDRL) != 0) {
752f8919bdaSduboff 		/*
753f8919bdaSduboff 		 * XXX - need to *disable* rx filter to load mac address for
754f8919bdaSduboff 		 * the chip. otherwise, we cannot setup rxfilter correctly.
755f8919bdaSduboff 		 */
756f8919bdaSduboff 		/* setup perfect match register for my station address */
757f8919bdaSduboff 		for (i = 0; i < ETHERADDRL; i += 2) {
758f8919bdaSduboff 			OUTL(dp, RFCR, RFADDR_MAC_DP83815 + i);
759f8919bdaSduboff 			OUTL(dp, RFDR, (mac[i+1] << 8) | mac[i]);
760f8919bdaSduboff 		}
761f8919bdaSduboff 
762f8919bdaSduboff 		bcopy(mac, lp->mac_addr, ETHERADDRL);
763f8919bdaSduboff 	}
764f8919bdaSduboff 
765f8919bdaSduboff #if DEBUG_LEVEL > 3
766f8919bdaSduboff 	/* clear pattern ram */
767f8919bdaSduboff 	for (j = 0x200; j < 0x380; j += 2) {
768f8919bdaSduboff 		OUTL(dp, RFCR, j);
769f8919bdaSduboff 		OUTL(dp, RFDR, 0);
770f8919bdaSduboff 	}
771f8919bdaSduboff #endif
772f8919bdaSduboff 	if (mode & RFCR_APAT_DP83815) {
773f8919bdaSduboff 		/* setup multicast address into pattern match registers */
774f8919bdaSduboff 		for (j = 0; j < dp->mc_count; j++) {
775f8919bdaSduboff 			mac = &dp->mc_list[j].addr.ether_addr_octet[0];
776f8919bdaSduboff 			for (i = 0; i < ETHERADDRL; i += 2) {
777f8919bdaSduboff 				OUTL(dp, RFCR,
778f8919bdaSduboff 				    sfe_rf_perfect_base_dp83815[j] + i*2);
779f8919bdaSduboff 				OUTL(dp, RFDR, (mac[i+1] << 8) | mac[i]);
780f8919bdaSduboff 			}
781f8919bdaSduboff 		}
782f8919bdaSduboff 
783f8919bdaSduboff 		/* setup pattern count registers */
784f8919bdaSduboff 		OUTL(dp, RFCR, RFADDR_PCOUNT01_DP83815);
785f8919bdaSduboff 		OUTL(dp, RFDR, (ETHERADDRL << 8) | ETHERADDRL);
786f8919bdaSduboff 		OUTL(dp, RFCR, RFADDR_PCOUNT23_DP83815);
787f8919bdaSduboff 		OUTL(dp, RFDR, (ETHERADDRL << 8) | ETHERADDRL);
788f8919bdaSduboff 	}
789f8919bdaSduboff 
790f8919bdaSduboff 	if (mode & RFCR_MHEN_DP83815) {
791f8919bdaSduboff 		/* Load Multicast hash table */
792f8919bdaSduboff 		for (i = 0; i < 32; i++) {
793f8919bdaSduboff 			/* for DP83815, index is in byte */
794f8919bdaSduboff 			OUTL(dp, RFCR, RFADDR_MULTICAST_DP83815 + i*2);
795f8919bdaSduboff 			OUTL(dp, RFDR, hash_tbl[i]);
796f8919bdaSduboff 		}
797f8919bdaSduboff 	}
798f8919bdaSduboff #if DEBUG_LEVEL > 2
799f8919bdaSduboff 	sfe_rxfilter_dump(dp, 0, 0x10);
800f8919bdaSduboff 	sfe_rxfilter_dump(dp, 0x200, 0x380);
801f8919bdaSduboff #endif
802f8919bdaSduboff 	/* Set rx filter mode and enable rx filter */
803f8919bdaSduboff 	OUTL(dp, RFCR, RFCR_RFEN | mode);
804f8919bdaSduboff 
805f8919bdaSduboff 	return (GEM_SUCCESS);
806f8919bdaSduboff }
807f8919bdaSduboff 
808f8919bdaSduboff static int
809f8919bdaSduboff sfe_set_rx_filter_sis900(struct gem_dev *dp)
810f8919bdaSduboff {
811f8919bdaSduboff 	int		i;
812f8919bdaSduboff 	uint32_t	mode;
813f8919bdaSduboff 	uint16_t	hash_tbl[16];
814f8919bdaSduboff 	uint8_t		*mac = dp->cur_addr.ether_addr_octet;
815f8919bdaSduboff 	int		hash_size;
816f8919bdaSduboff 	int		hash_shift;
817f8919bdaSduboff 	struct sfe_dev	*lp = dp->private;
818f8919bdaSduboff 
819f8919bdaSduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__));
820f8919bdaSduboff 
821f8919bdaSduboff 	if ((dp->rxmode & RXMODE_ENABLE) == 0) {
822f8919bdaSduboff 		/* disalbe rx filter */
823f8919bdaSduboff 		OUTL(dp, RFCR, 0);
824f8919bdaSduboff 		return (GEM_SUCCESS);
825f8919bdaSduboff 	}
826f8919bdaSduboff 
827f8919bdaSduboff 	/*
828f8919bdaSduboff 	 * determine hardware hash table size in word.
829f8919bdaSduboff 	 */
830f8919bdaSduboff 	hash_shift = 25;
831f8919bdaSduboff 	if (lp->revid >= SIS635A_900_REV || lp->revid == SIS900B_900_REV) {
832f8919bdaSduboff 		hash_shift = 24;
833f8919bdaSduboff 	}
834f8919bdaSduboff 	hash_size = (1 << (32 - hash_shift)) / 16;
835f8919bdaSduboff 	bzero(hash_tbl, sizeof (hash_tbl));
836f8919bdaSduboff 
837f8919bdaSduboff 	/* Set Receive filter control register */
838f8919bdaSduboff 
839f8919bdaSduboff 	if (dp->rxmode & RXMODE_PROMISC) {
840f8919bdaSduboff 		/* all broadcast, all multicast, all physical */
841f8919bdaSduboff 		mode = RFCR_AAB | RFCR_AAM | RFCR_AAP;
842f8919bdaSduboff 	} else if ((dp->rxmode & RXMODE_ALLMULTI) ||
843f8919bdaSduboff 	    dp->mc_count > hash_size*16/2) {
844f8919bdaSduboff 		/* all broadcast, all multicast, physical for the chip */
845f8919bdaSduboff 		mode = RFCR_AAB | RFCR_AAM;
846f8919bdaSduboff 	} else {
847f8919bdaSduboff 		/* all broadcast, physical for the chip */
848f8919bdaSduboff 		mode = RFCR_AAB;
849f8919bdaSduboff 	}
850f8919bdaSduboff 
851f8919bdaSduboff 	/* make hash table */
852f8919bdaSduboff 	for (i = 0; i < dp->mc_count; i++) {
853f8919bdaSduboff 		uint_t	h;
854f8919bdaSduboff 		h = dp->mc_list[i].hash >> hash_shift;
855f8919bdaSduboff 		hash_tbl[h / 16] |= 1 << (h % 16);
856f8919bdaSduboff 	}
857f8919bdaSduboff 
858f8919bdaSduboff 	if (bcmp(mac, lp->mac_addr, ETHERADDRL) != 0) {
859f8919bdaSduboff 		/* Disable Rx filter and load mac address */
860f8919bdaSduboff 		for (i = 0; i < ETHERADDRL/2; i++) {
861f8919bdaSduboff 			/* For sis900, index is in word */
862f8919bdaSduboff 			OUTL(dp, RFCR,
863f8919bdaSduboff 			    (RFADDR_MAC_SIS900+i) << RFCR_RFADDR_SHIFT_SIS900);
864f8919bdaSduboff 			OUTL(dp, RFDR, (mac[i*2+1] << 8) | mac[i*2]);
865f8919bdaSduboff 		}
866f8919bdaSduboff 
867f8919bdaSduboff 		bcopy(mac, lp->mac_addr, ETHERADDRL);
868f8919bdaSduboff 	}
869f8919bdaSduboff 
870f8919bdaSduboff 	/* Load Multicast hash table */
871f8919bdaSduboff 	for (i = 0; i < hash_size; i++) {
872f8919bdaSduboff 		/* For sis900, index is in word */
873f8919bdaSduboff 		OUTL(dp, RFCR,
874f8919bdaSduboff 		    (RFADDR_MULTICAST_SIS900 + i) << RFCR_RFADDR_SHIFT_SIS900);
875f8919bdaSduboff 		OUTL(dp, RFDR, hash_tbl[i]);
876f8919bdaSduboff 	}
877f8919bdaSduboff 
878f8919bdaSduboff 	/* Load rx filter mode and enable rx filter */
879f8919bdaSduboff 	OUTL(dp, RFCR, RFCR_RFEN | mode);
880f8919bdaSduboff 
881f8919bdaSduboff 	return (GEM_SUCCESS);
882f8919bdaSduboff }
883f8919bdaSduboff 
884f8919bdaSduboff static int
885f8919bdaSduboff sfe_start_chip(struct gem_dev *dp)
886f8919bdaSduboff {
887f8919bdaSduboff 	struct sfe_dev	*lp = dp->private;
888f8919bdaSduboff 
889f8919bdaSduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__));
890f8919bdaSduboff 
891f8919bdaSduboff 	/*
892f8919bdaSduboff 	 * setup interrupt mask, which shouldn't include ISR_TOK
893f8919bdaSduboff 	 * to improve performance.
894f8919bdaSduboff 	 */
895f8919bdaSduboff 	lp->our_intr_bits = OUR_INTR_BITS;
896f8919bdaSduboff 
897f8919bdaSduboff 	/* enable interrupt */
898f8919bdaSduboff 	if ((dp->misc_flag & GEM_NOINTR) == 0) {
899f8919bdaSduboff 		OUTL(dp, IER, 1);
900f8919bdaSduboff 		OUTL(dp, IMR, lp->our_intr_bits);
901f8919bdaSduboff 	}
902f8919bdaSduboff 
903f8919bdaSduboff 	/* Kick RX */
904f8919bdaSduboff 	OUTL(dp, CR, lp->cr | CR_RXE);
905f8919bdaSduboff 
906f8919bdaSduboff 	return (GEM_SUCCESS);
907f8919bdaSduboff }
908f8919bdaSduboff 
909f8919bdaSduboff /*
910f8919bdaSduboff  * Stop nic core gracefully.
911f8919bdaSduboff  */
912f8919bdaSduboff static int
913f8919bdaSduboff sfe_stop_chip(struct gem_dev *dp)
914f8919bdaSduboff {
915f8919bdaSduboff 	struct sfe_dev	*lp = dp->private;
916f8919bdaSduboff 	uint32_t	done;
917f8919bdaSduboff 	int		i;
918*23d366e3Sduboff 	uint32_t	val;
919f8919bdaSduboff 
920f8919bdaSduboff 	DPRINTF(4, (CE_CONT, CONS "%s: %s: called", dp->name, __func__));
921f8919bdaSduboff 
922f8919bdaSduboff 	/*
923f8919bdaSduboff 	 * Although we inhibit interrupt here, we don't clear soft copy of
924f8919bdaSduboff 	 * interrupt mask to avoid bogus interrupts.
925f8919bdaSduboff 	 */
926f8919bdaSduboff 	OUTL(dp, IMR, 0);
927f8919bdaSduboff 
928f8919bdaSduboff 	/* stop TX and RX immediately */
929f8919bdaSduboff 	OUTL(dp, CR, lp->cr | CR_TXR | CR_RXR);
930f8919bdaSduboff 
931f8919bdaSduboff 	done = 0;
932f8919bdaSduboff 	for (i = 0; done != (ISR_RXRCMP | ISR_TXRCMP); i++) {
933f8919bdaSduboff 		if (i > 1000) {
934f8919bdaSduboff 			/*
935f8919bdaSduboff 			 * As gem layer will call sfe_reset_chip(),
936f8919bdaSduboff 			 * we don't neet to reset futher
937f8919bdaSduboff 			 */
938f8919bdaSduboff 			cmn_err(CE_NOTE, "!%s: %s: Tx/Rx reset timeout",
939f8919bdaSduboff 			    dp->name, __func__);
940f8919bdaSduboff 
941f8919bdaSduboff 			return (GEM_FAILURE);
942f8919bdaSduboff 		}
943*23d366e3Sduboff 		val = INL(dp, ISR);
944*23d366e3Sduboff 		done |= val & (ISR_RXRCMP | ISR_TXRCMP);
945*23d366e3Sduboff 		lp->isr_pended |= val & lp->our_intr_bits;
946f8919bdaSduboff 		drv_usecwait(10);
947f8919bdaSduboff 	}
948f8919bdaSduboff 
949f8919bdaSduboff 	return (GEM_SUCCESS);
950f8919bdaSduboff }
951f8919bdaSduboff 
952f8919bdaSduboff /*
953f8919bdaSduboff  * Setup media mode
954f8919bdaSduboff  */
955f8919bdaSduboff static uint_t
956f8919bdaSduboff sfe_mxdma_value[] = { 512, 4, 8, 16, 32, 64, 128, 256, };
957f8919bdaSduboff 
958f8919bdaSduboff static uint_t
959f8919bdaSduboff sfe_encode_mxdma(uint_t burstsize)
960f8919bdaSduboff {
961f8919bdaSduboff 	int	i;
962f8919bdaSduboff 
963f8919bdaSduboff 	if (burstsize > 256) {
964f8919bdaSduboff 		/* choose 512 */
965f8919bdaSduboff 		return (0);
966f8919bdaSduboff 	}
967f8919bdaSduboff 
968f8919bdaSduboff 	for (i = 1; i < 8; i++) {
969f8919bdaSduboff 		if (burstsize <= sfe_mxdma_value[i]) {
970f8919bdaSduboff 			break;
971f8919bdaSduboff 		}
972f8919bdaSduboff 	}
973f8919bdaSduboff 	return (i);
974f8919bdaSduboff }
975f8919bdaSduboff 
976f8919bdaSduboff static int
977f8919bdaSduboff sfe_set_media(struct gem_dev *dp)
978f8919bdaSduboff {
979f8919bdaSduboff 	uint32_t	txcfg;
980f8919bdaSduboff 	uint32_t	rxcfg;
981f8919bdaSduboff 	uint32_t	pcr;
982f8919bdaSduboff 	uint32_t	val;
983f8919bdaSduboff 	uint32_t	txmxdma;
984f8919bdaSduboff 	uint32_t	rxmxdma;
985f8919bdaSduboff 	struct sfe_dev	*lp = dp->private;
986f8919bdaSduboff #ifdef DEBUG_LEVEL
987f8919bdaSduboff 	extern int	gem_speed_value[];
988f8919bdaSduboff #endif
989f8919bdaSduboff 	DPRINTF(2, (CE_CONT, CONS "%s: %s: %s duplex, %d Mbps",
990f8919bdaSduboff 	    dp->name, __func__,
991f8919bdaSduboff 	    dp->full_duplex ? "full" : "half", gem_speed_value[dp->speed]));
992f8919bdaSduboff 
993f8919bdaSduboff 	/* initialize txcfg and rxcfg */
994f8919bdaSduboff 	txcfg = TXCFG_ATP;
995f8919bdaSduboff 	if (dp->full_duplex) {
996f8919bdaSduboff 		txcfg |= (TXCFG_CSI | TXCFG_HBI);
997f8919bdaSduboff 	}
998*23d366e3Sduboff 	rxcfg = RXCFG_AEP | RXCFG_ARP;
999f8919bdaSduboff 	if (dp->full_duplex) {
1000f8919bdaSduboff 		rxcfg |= RXCFG_ATX;
1001f8919bdaSduboff 	}
1002f8919bdaSduboff 
1003f8919bdaSduboff 	/* select txmxdma and rxmxdma, maxmum burst length */
1004f8919bdaSduboff 	if (lp->chip->chip_type == CHIPTYPE_SIS900) {
1005f8919bdaSduboff #ifdef DEBUG_SIS900_EDB
1006f8919bdaSduboff 		val = CFG_EDB_MASTER;
1007f8919bdaSduboff #else
1008f8919bdaSduboff 		val = INL(dp, CFG) & CFG_EDB_MASTER;
1009f8919bdaSduboff #endif
1010f8919bdaSduboff 		if (val) {
1011f8919bdaSduboff 			/*
1012f8919bdaSduboff 			 * sis900 built-in cores:
1013f8919bdaSduboff 			 * max burst length must be fixed to 64
1014f8919bdaSduboff 			 */
1015f8919bdaSduboff 			txmxdma = 64;
1016f8919bdaSduboff 			rxmxdma = 64;
1017f8919bdaSduboff 		} else {
1018f8919bdaSduboff 			/*
1019f8919bdaSduboff 			 * sis900 pci chipset:
1020f8919bdaSduboff 			 * the vendor recommended to fix max burst length
1021f8919bdaSduboff 			 * to 512
1022f8919bdaSduboff 			 */
1023f8919bdaSduboff 			txmxdma = 512;
1024f8919bdaSduboff 			rxmxdma = 512;
1025f8919bdaSduboff 		}
1026f8919bdaSduboff 	} else {
1027f8919bdaSduboff 		/*
1028f8919bdaSduboff 		 * NS dp83815/816:
1029f8919bdaSduboff 		 * use user defined or default for tx/rx max burst length
1030f8919bdaSduboff 		 */
1031f8919bdaSduboff 		txmxdma = max(dp->txmaxdma, 256);
1032f8919bdaSduboff 		rxmxdma = max(dp->rxmaxdma, 256);
1033f8919bdaSduboff 	}
1034f8919bdaSduboff 
1035f8919bdaSduboff 
1036f8919bdaSduboff 	/* tx high water mark */
1037f8919bdaSduboff 	lp->tx_drain_threshold = ROUNDUP2(dp->txthr, TXCFG_FIFO_UNIT);
1038f8919bdaSduboff 
1039f8919bdaSduboff 	/* determine tx_fill_threshold accroding drain threshold */
1040f8919bdaSduboff 	lp->tx_fill_threshold =
1041f8919bdaSduboff 	    TXFIFOSIZE - lp->tx_drain_threshold - TXCFG_FIFO_UNIT;
1042f8919bdaSduboff 
1043f8919bdaSduboff 	/* tune txmxdma not to exceed tx_fill_threshold */
1044f8919bdaSduboff 	for (; ; ) {
1045f8919bdaSduboff 		/* normalize txmxdma requested */
1046f8919bdaSduboff 		val = sfe_encode_mxdma(txmxdma);
1047f8919bdaSduboff 		txmxdma = sfe_mxdma_value[val];
1048f8919bdaSduboff 
1049f8919bdaSduboff 		if (txmxdma <= lp->tx_fill_threshold) {
1050f8919bdaSduboff 			break;
1051f8919bdaSduboff 		}
1052f8919bdaSduboff 		/* select new txmxdma */
1053f8919bdaSduboff 		txmxdma = txmxdma / 2;
1054f8919bdaSduboff 	}
1055f8919bdaSduboff 	txcfg |= val << TXCFG_MXDMA_SHIFT;
1056f8919bdaSduboff 
1057f8919bdaSduboff 	/* encode rxmxdma, maxmum burst length for rx */
1058f8919bdaSduboff 	val = sfe_encode_mxdma(rxmxdma);
1059*23d366e3Sduboff 	rxcfg |= val << RXCFG_MXDMA_SHIFT;
1060f8919bdaSduboff 	rxmxdma = sfe_mxdma_value[val];
1061f8919bdaSduboff 
1062f8919bdaSduboff 	/* receive starting threshold - it have only 5bit-wide field */
1063f8919bdaSduboff 	val = ROUNDUP2(max(dp->rxthr, ETHERMIN), RXCFG_FIFO_UNIT);
1064f8919bdaSduboff 	lp->rx_drain_threshold =
1065f8919bdaSduboff 	    min(val, (RXCFG_DRTH >> RXCFG_DRTH_SHIFT) * RXCFG_FIFO_UNIT);
1066f8919bdaSduboff 
1067f8919bdaSduboff 	DPRINTF(0, (CE_CONT,
1068f8919bdaSduboff 	    "%s: %s: tx: drain:%d(rest %d) fill:%d mxdma:%d,"
1069f8919bdaSduboff 	    " rx: drain:%d mxdma:%d",
1070f8919bdaSduboff 	    dp->name, __func__,
1071f8919bdaSduboff 	    lp->tx_drain_threshold, TXFIFOSIZE - lp->tx_drain_threshold,
1072f8919bdaSduboff 	    lp->tx_fill_threshold, txmxdma,
1073f8919bdaSduboff 	    lp->rx_drain_threshold, rxmxdma));
1074f8919bdaSduboff 
1075f8919bdaSduboff 	ASSERT(lp->tx_drain_threshold < 64*TXCFG_FIFO_UNIT);
1076f8919bdaSduboff 	ASSERT(lp->tx_fill_threshold < 64*TXCFG_FIFO_UNIT);
1077f8919bdaSduboff 	ASSERT(lp->rx_drain_threshold < 32*RXCFG_FIFO_UNIT);
1078f8919bdaSduboff 
1079f8919bdaSduboff 	txcfg |= ((lp->tx_fill_threshold/TXCFG_FIFO_UNIT) << TXCFG_FLTH_SHIFT)
1080f8919bdaSduboff 	    | (lp->tx_drain_threshold/TXCFG_FIFO_UNIT);
1081f8919bdaSduboff 	OUTL(dp, TXCFG, txcfg);
1082f8919bdaSduboff 
1083f8919bdaSduboff 	rxcfg |= ((lp->rx_drain_threshold/RXCFG_FIFO_UNIT) << RXCFG_DRTH_SHIFT);
1084f8919bdaSduboff 	if (lp->chip->chip_type == CHIPTYPE_DP83815) {
1085f8919bdaSduboff 		rxcfg |= RXCFG_ALP_DP83815;
1086f8919bdaSduboff 	}
1087f8919bdaSduboff 	OUTL(dp, RXCFG, rxcfg);
1088f8919bdaSduboff 
1089f8919bdaSduboff 	DPRINTF(0, (CE_CONT, CONS "%s: %s: txcfg:%b rxcfg:%b",
1090f8919bdaSduboff 	    dp->name, __func__,
1091f8919bdaSduboff 	    txcfg, TXCFG_BITS, rxcfg, RXCFG_BITS));
1092f8919bdaSduboff 
1093f8919bdaSduboff 	/* Flow control */
1094f8919bdaSduboff 	if (lp->chip->chip_type == CHIPTYPE_DP83815) {
1095f8919bdaSduboff 		pcr = INL(dp, PCR);
1096f8919bdaSduboff 		switch (dp->flow_control) {
1097f8919bdaSduboff 		case FLOW_CONTROL_SYMMETRIC:
1098f8919bdaSduboff 		case FLOW_CONTROL_RX_PAUSE:
1099f8919bdaSduboff 			OUTL(dp, PCR, pcr | PCR_PSEN | PCR_PS_MCAST);
1100f8919bdaSduboff 			break;
1101f8919bdaSduboff 
1102f8919bdaSduboff 		default:
1103f8919bdaSduboff 			OUTL(dp, PCR,
1104f8919bdaSduboff 			    pcr & ~(PCR_PSEN | PCR_PS_MCAST | PCR_PS_DA));
1105f8919bdaSduboff 			break;
1106f8919bdaSduboff 		}
1107f8919bdaSduboff 		DPRINTF(2, (CE_CONT, CONS "%s: PCR: %b", dp->name,
1108f8919bdaSduboff 		    INL(dp, PCR), PCR_BITS));
1109f8919bdaSduboff 
1110f8919bdaSduboff 	} else if (lp->chip->chip_type == CHIPTYPE_SIS900) {
1111f8919bdaSduboff 		switch (dp->flow_control) {
1112f8919bdaSduboff 		case FLOW_CONTROL_SYMMETRIC:
1113f8919bdaSduboff 		case FLOW_CONTROL_RX_PAUSE:
1114f8919bdaSduboff 			OUTL(dp, FLOWCTL, FLOWCTL_FLOWEN);
1115f8919bdaSduboff 			break;
1116f8919bdaSduboff 		default:
1117f8919bdaSduboff 			OUTL(dp, FLOWCTL, 0);
1118f8919bdaSduboff 			break;
1119f8919bdaSduboff 		}
1120f8919bdaSduboff 		DPRINTF(2, (CE_CONT, CONS "%s: FLOWCTL: %b",
1121f8919bdaSduboff 		    dp->name, INL(dp, FLOWCTL), FLOWCTL_BITS));
1122f8919bdaSduboff 	}
1123f8919bdaSduboff 	return (GEM_SUCCESS);
1124f8919bdaSduboff }
1125f8919bdaSduboff 
1126f8919bdaSduboff static int
1127f8919bdaSduboff sfe_get_stats(struct gem_dev *dp)
1128f8919bdaSduboff {
1129f8919bdaSduboff 	/* do nothing */
1130f8919bdaSduboff 	return (GEM_SUCCESS);
1131f8919bdaSduboff }
1132f8919bdaSduboff 
1133f8919bdaSduboff /*
1134f8919bdaSduboff  * descriptor manipulations
1135f8919bdaSduboff  */
1136f8919bdaSduboff static int
1137f8919bdaSduboff sfe_tx_desc_write(struct gem_dev *dp, int slot,
1138f8919bdaSduboff 		ddi_dma_cookie_t *dmacookie, int frags, uint64_t flags)
1139f8919bdaSduboff {
1140f8919bdaSduboff 	uint32_t		mark;
1141f8919bdaSduboff 	struct sfe_desc		*tdp;
1142f8919bdaSduboff 	ddi_dma_cookie_t	*dcp;
1143*23d366e3Sduboff 	uint32_t		tmp0;
1144*23d366e3Sduboff #if DEBUG_LEVEL > 2
1145f8919bdaSduboff 	int			i;
1146f8919bdaSduboff 
1147f8919bdaSduboff 	cmn_err(CE_CONT,
1148f8919bdaSduboff 	    CONS "%s: time:%d %s seqnum: %d, slot %d, frags: %d flags: %llx",
1149f8919bdaSduboff 	    dp->name, ddi_get_lbolt(), __func__,
1150f8919bdaSduboff 	    dp->tx_desc_tail, slot, frags, flags);
1151f8919bdaSduboff 
1152f8919bdaSduboff 	for (i = 0; i < frags; i++) {
1153f8919bdaSduboff 		cmn_err(CE_CONT, CONS "%d: addr: 0x%x, len: 0x%x",
1154f8919bdaSduboff 		    i, dmacookie[i].dmac_address, dmacookie[i].dmac_size);
1155*23d366e3Sduboff 	}
1156f8919bdaSduboff #endif
1157f8919bdaSduboff 	/*
1158f8919bdaSduboff 	 * write tx descriptor in reversed order.
1159f8919bdaSduboff 	 */
1160f8919bdaSduboff #if DEBUG_LEVEL > 3
1161f8919bdaSduboff 	flags |= GEM_TXFLAG_INTR;
1162f8919bdaSduboff #endif
1163f8919bdaSduboff 	mark = (flags & GEM_TXFLAG_INTR)
1164*23d366e3Sduboff 	    ? (CMDSTS_OWN | CMDSTS_INTR) : CMDSTS_OWN;
1165f8919bdaSduboff 
1166f8919bdaSduboff 	ASSERT(frags == 1);
1167f8919bdaSduboff 	dcp = &dmacookie[0];
1168f8919bdaSduboff 	if (flags & GEM_TXFLAG_HEAD) {
1169f8919bdaSduboff 		mark &= ~CMDSTS_OWN;
1170f8919bdaSduboff 	}
1171f8919bdaSduboff 
1172f8919bdaSduboff 	tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot];
1173*23d366e3Sduboff 	tmp0 = (uint32_t)dcp->dmac_address;
1174*23d366e3Sduboff 	mark |= (uint32_t)dcp->dmac_size;
1175*23d366e3Sduboff 	tdp->d_bufptr = LE_32(tmp0);
1176*23d366e3Sduboff 	tdp->d_cmdsts = LE_32(mark);
1177f8919bdaSduboff 
1178f8919bdaSduboff 	return (frags);
1179f8919bdaSduboff }
1180f8919bdaSduboff 
1181f8919bdaSduboff static void
1182f8919bdaSduboff sfe_tx_start(struct gem_dev *dp, int start_slot, int nslot)
1183f8919bdaSduboff {
1184*23d366e3Sduboff 	uint_t			tx_ring_size = dp->gc.gc_tx_ring_size;
1185f8919bdaSduboff 	struct sfe_desc		*tdp;
1186f8919bdaSduboff 	struct sfe_dev		*lp = dp->private;
1187f8919bdaSduboff 
1188f8919bdaSduboff 	if (nslot > 1) {
1189f8919bdaSduboff 		gem_tx_desc_dma_sync(dp,
1190*23d366e3Sduboff 		    SLOT(start_slot + 1, tx_ring_size),
1191f8919bdaSduboff 		    nslot - 1, DDI_DMA_SYNC_FORDEV);
1192f8919bdaSduboff 	}
1193f8919bdaSduboff 
1194f8919bdaSduboff 	tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * start_slot];
1195f8919bdaSduboff 	tdp->d_cmdsts |= LE_32(CMDSTS_OWN);
1196f8919bdaSduboff 
1197f8919bdaSduboff 	gem_tx_desc_dma_sync(dp, start_slot, 1, DDI_DMA_SYNC_FORDEV);
1198f8919bdaSduboff 
1199f8919bdaSduboff 	/*
1200f8919bdaSduboff 	 * Let the Transmit Buffer Manager Fill state machine active.
1201f8919bdaSduboff 	 */
1202f8919bdaSduboff 	if (dp->mac_active) {
1203f8919bdaSduboff 		OUTL(dp, CR, lp->cr | CR_TXE);
1204f8919bdaSduboff 	}
1205f8919bdaSduboff }
1206f8919bdaSduboff 
1207f8919bdaSduboff static void
1208f8919bdaSduboff sfe_rx_desc_write(struct gem_dev *dp, int slot,
1209f8919bdaSduboff 	    ddi_dma_cookie_t *dmacookie, int frags)
1210f8919bdaSduboff {
1211f8919bdaSduboff 	struct sfe_desc		*rdp;
1212*23d366e3Sduboff 	uint32_t		tmp0;
1213*23d366e3Sduboff 	uint32_t		tmp1;
1214f8919bdaSduboff #if DEBUG_LEVEL > 2
1215f8919bdaSduboff 	int			i;
1216f8919bdaSduboff 
1217f8919bdaSduboff 	ASSERT(frags == 1);
1218f8919bdaSduboff 
1219f8919bdaSduboff 	cmn_err(CE_CONT, CONS
1220f8919bdaSduboff 	    "%s: %s seqnum: %d, slot %d, frags: %d",
1221f8919bdaSduboff 	    dp->name, __func__, dp->rx_active_tail, slot, frags);
1222f8919bdaSduboff 	for (i = 0; i < frags; i++) {
1223f8919bdaSduboff 		cmn_err(CE_CONT, CONS "  frag: %d addr: 0x%llx, len: 0x%lx",
1224f8919bdaSduboff 		    i, dmacookie[i].dmac_address, dmacookie[i].dmac_size);
1225f8919bdaSduboff 	}
1226f8919bdaSduboff #endif
1227f8919bdaSduboff 	/* for the last slot of the packet */
1228f8919bdaSduboff 	rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot];
1229f8919bdaSduboff 
1230*23d366e3Sduboff 	tmp0 = (uint32_t)dmacookie->dmac_address;
1231*23d366e3Sduboff 	tmp1 = CMDSTS_INTR | (uint32_t)dmacookie->dmac_size;
1232*23d366e3Sduboff 	rdp->d_bufptr = LE_32(tmp0);
1233*23d366e3Sduboff 	rdp->d_cmdsts = LE_32(tmp1);
1234f8919bdaSduboff }
1235f8919bdaSduboff 
1236f8919bdaSduboff static uint_t
1237f8919bdaSduboff sfe_tx_desc_stat(struct gem_dev *dp, int slot, int ndesc)
1238f8919bdaSduboff {
1239*23d366e3Sduboff 	uint_t			tx_ring_size = dp->gc.gc_tx_ring_size;
1240f8919bdaSduboff 	struct sfe_desc		*tdp;
1241f8919bdaSduboff 	uint32_t		status;
1242f8919bdaSduboff 	int			cols;
1243*23d366e3Sduboff 	struct sfe_dev		*lp = dp->private;
1244f8919bdaSduboff #ifdef DEBUG_LEVEL
1245f8919bdaSduboff 	int			i;
1246f8919bdaSduboff 	clock_t			delay;
1247f8919bdaSduboff #endif
1248f8919bdaSduboff 	/* check status of the last descriptor */
1249f8919bdaSduboff 	tdp = (void *)
1250*23d366e3Sduboff 	    &dp->tx_ring[SFE_DESC_SIZE * SLOT(slot + ndesc - 1, tx_ring_size)];
1251f8919bdaSduboff 
1252*23d366e3Sduboff 	/*
1253*23d366e3Sduboff 	 * Don't use LE_32() directly to refer tdp->d_cmdsts.
1254*23d366e3Sduboff 	 * It is not atomic for big endian cpus.
1255*23d366e3Sduboff 	 */
1256*23d366e3Sduboff 	status = tdp->d_cmdsts;
1257*23d366e3Sduboff 	status = LE_32(status);
1258f8919bdaSduboff 
1259f8919bdaSduboff 	DPRINTF(2, (CE_CONT, CONS "%s: time:%ld %s: slot:%d, status:0x%b",
1260f8919bdaSduboff 	    dp->name, ddi_get_lbolt(), __func__,
1261f8919bdaSduboff 	    slot, status, TXSTAT_BITS));
1262f8919bdaSduboff 
1263f8919bdaSduboff 	if (status & CMDSTS_OWN) {
1264f8919bdaSduboff 		/*
1265f8919bdaSduboff 		 * not yet transmitted
1266f8919bdaSduboff 		 */
1267*23d366e3Sduboff 		/* workaround for tx hang */
1268*23d366e3Sduboff 		if (lp->chip->chip_type == CHIPTYPE_DP83815 &&
1269*23d366e3Sduboff 		    dp->mac_active) {
1270*23d366e3Sduboff 			OUTL(dp, CR, lp->cr | CR_TXE);
1271*23d366e3Sduboff 		}
1272f8919bdaSduboff 		return (0);
1273f8919bdaSduboff 	}
1274f8919bdaSduboff 
1275f8919bdaSduboff 	if (status & CMDSTS_MORE) {
1276f8919bdaSduboff 		/* XXX - the hardware problem but don't panic the system */
1277f8919bdaSduboff 		/* avoid lint bug for %b format string including 32nd bit */
1278f8919bdaSduboff 		cmn_err(CE_NOTE, CONS
1279f8919bdaSduboff 		    "%s: tx status bits incorrect:  slot:%d, status:0x%x",
1280f8919bdaSduboff 		    dp->name, slot, status);
1281f8919bdaSduboff 	}
1282f8919bdaSduboff 
1283f8919bdaSduboff #if DEBUG_LEVEL > 3
1284f8919bdaSduboff 	delay = (ddi_get_lbolt() - dp->tx_buf_head->txb_stime) * 10;
1285f8919bdaSduboff 	if (delay >= 50) {
1286f8919bdaSduboff 		DPRINTF(0, (CE_NOTE, "%s: tx deferred %d mS: slot %d",
1287f8919bdaSduboff 		    dp->name, delay, slot));
1288f8919bdaSduboff 	}
1289f8919bdaSduboff #endif
1290f8919bdaSduboff 
1291f8919bdaSduboff #if DEBUG_LEVEL > 3
1292f8919bdaSduboff 	for (i = 0; i < nfrag-1; i++) {
1293f8919bdaSduboff 		uint32_t	s;
1294f8919bdaSduboff 		int		n;
1295f8919bdaSduboff 
1296*23d366e3Sduboff 		n = SLOT(slot + i, tx_ring_size);
1297f8919bdaSduboff 		s = LE_32(
1298f8919bdaSduboff 		    ((struct sfe_desc *)((void *)
1299f8919bdaSduboff 		    &dp->tx_ring[SFE_DESC_SIZE * n]))->d_cmdsts);
1300f8919bdaSduboff 
1301f8919bdaSduboff 		ASSERT(s & CMDSTS_MORE);
1302f8919bdaSduboff 		ASSERT((s & CMDSTS_OWN) == 0);
1303f8919bdaSduboff 	}
1304f8919bdaSduboff #endif
1305f8919bdaSduboff 
1306f8919bdaSduboff 	/*
1307f8919bdaSduboff 	 *  collect statistics
1308f8919bdaSduboff 	 */
1309f8919bdaSduboff 	if ((status & CMDSTS_OK) == 0) {
1310f8919bdaSduboff 
1311f8919bdaSduboff 		/* failed to transmit the packet */
1312f8919bdaSduboff 
1313f8919bdaSduboff 		DPRINTF(0, (CE_CONT, CONS "%s: Transmit error, Tx status %b",
1314f8919bdaSduboff 		    dp->name, status, TXSTAT_BITS));
1315f8919bdaSduboff 
1316f8919bdaSduboff 		dp->stats.errxmt++;
1317f8919bdaSduboff 
1318f8919bdaSduboff 		if (status & CMDSTS_TFU) {
1319f8919bdaSduboff 			dp->stats.underflow++;
1320f8919bdaSduboff 		} else if (status & CMDSTS_CRS) {
1321f8919bdaSduboff 			dp->stats.nocarrier++;
1322f8919bdaSduboff 		} else if (status & CMDSTS_OWC) {
1323f8919bdaSduboff 			dp->stats.xmtlatecoll++;
1324f8919bdaSduboff 		} else if ((!dp->full_duplex) && (status & CMDSTS_EC)) {
1325f8919bdaSduboff 			dp->stats.excoll++;
1326f8919bdaSduboff 			dp->stats.collisions += 16;
1327f8919bdaSduboff 		} else {
1328f8919bdaSduboff 			dp->stats.xmit_internal_err++;
1329f8919bdaSduboff 		}
1330f8919bdaSduboff 	} else if (!dp->full_duplex) {
1331f8919bdaSduboff 		cols = (status >> CMDSTS_CCNT_SHIFT) & CCNT_MASK;
1332f8919bdaSduboff 
1333f8919bdaSduboff 		if (cols > 0) {
1334f8919bdaSduboff 			if (cols == 1) {
1335f8919bdaSduboff 				dp->stats.first_coll++;
1336f8919bdaSduboff 			} else /* (cols > 1) */ {
1337f8919bdaSduboff 				dp->stats.multi_coll++;
1338f8919bdaSduboff 			}
1339f8919bdaSduboff 			dp->stats.collisions += cols;
1340f8919bdaSduboff 		} else if (status & CMDSTS_TD) {
1341f8919bdaSduboff 			dp->stats.defer++;
1342f8919bdaSduboff 		}
1343f8919bdaSduboff 	}
1344f8919bdaSduboff 	return (GEM_TX_DONE);
1345f8919bdaSduboff }
1346f8919bdaSduboff 
1347f8919bdaSduboff static uint64_t
1348f8919bdaSduboff sfe_rx_desc_stat(struct gem_dev *dp, int slot, int ndesc)
1349f8919bdaSduboff {
1350f8919bdaSduboff 	struct sfe_desc		*rdp;
1351f8919bdaSduboff 	uint_t			len;
1352f8919bdaSduboff 	uint_t			flag;
1353f8919bdaSduboff 	uint32_t		status;
1354f8919bdaSduboff 
1355f8919bdaSduboff 	flag = GEM_RX_DONE;
1356f8919bdaSduboff 
1357f8919bdaSduboff 	/* Dont read ISR because we cannot ack only to rx interrupt. */
1358f8919bdaSduboff 
1359f8919bdaSduboff 	rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot];
1360f8919bdaSduboff 
1361*23d366e3Sduboff 	/*
1362*23d366e3Sduboff 	 * Don't use LE_32() directly to refer rdp->d_cmdsts.
1363*23d366e3Sduboff 	 * It is not atomic for big endian cpus.
1364*23d366e3Sduboff 	 */
1365*23d366e3Sduboff 	status = rdp->d_cmdsts;
1366*23d366e3Sduboff 	status = LE_32(status);
1367f8919bdaSduboff 
1368f8919bdaSduboff 	DPRINTF(2, (CE_CONT, CONS "%s: time:%ld %s: slot:%d, status:0x%b",
1369f8919bdaSduboff 	    dp->name, ddi_get_lbolt(), __func__,
1370f8919bdaSduboff 	    slot, status, RXSTAT_BITS));
1371f8919bdaSduboff 
1372f8919bdaSduboff 	if ((status & CMDSTS_OWN) == 0) {
1373f8919bdaSduboff 		/*
1374f8919bdaSduboff 		 * No more received packets because
1375f8919bdaSduboff 		 * this buffer is owned by NIC.
1376f8919bdaSduboff 		 */
1377f8919bdaSduboff 		return (0);
1378f8919bdaSduboff 	}
1379f8919bdaSduboff 
1380f8919bdaSduboff #define	RX_ERR_BITS \
1381f8919bdaSduboff 	(CMDSTS_RXA | CMDSTS_RXO | CMDSTS_LONG | CMDSTS_RUNT | \
1382f8919bdaSduboff 		CMDSTS_ISE | CMDSTS_CRCE | CMDSTS_FAE | CMDSTS_MORE)
1383f8919bdaSduboff 
1384f8919bdaSduboff 	if (status & RX_ERR_BITS) {
1385f8919bdaSduboff 		/*
1386f8919bdaSduboff 		 * Packet with error received
1387f8919bdaSduboff 		 */
1388f8919bdaSduboff 		DPRINTF(0, (CE_CONT, CONS "%s: Corrupted packet "
1389f8919bdaSduboff 		    "received, buffer status: %b",
1390f8919bdaSduboff 		    dp->name, status, RXSTAT_BITS));
1391f8919bdaSduboff 
1392f8919bdaSduboff 		/* collect statistics information */
1393f8919bdaSduboff 		dp->stats.errrcv++;
1394f8919bdaSduboff 
1395f8919bdaSduboff 		if (status & CMDSTS_RXO) {
1396f8919bdaSduboff 			dp->stats.overflow++;
1397f8919bdaSduboff 		} else if (status & (CMDSTS_LONG | CMDSTS_MORE)) {
1398f8919bdaSduboff 			dp->stats.frame_too_long++;
1399f8919bdaSduboff 		} else if (status & CMDSTS_RUNT) {
1400f8919bdaSduboff 			dp->stats.runt++;
1401f8919bdaSduboff 		} else if (status & (CMDSTS_ISE | CMDSTS_FAE)) {
1402f8919bdaSduboff 			dp->stats.frame++;
1403f8919bdaSduboff 		} else if (status & CMDSTS_CRCE) {
1404f8919bdaSduboff 			dp->stats.crc++;
1405f8919bdaSduboff 		} else {
1406f8919bdaSduboff 			dp->stats.rcv_internal_err++;
1407f8919bdaSduboff 		}
1408f8919bdaSduboff 
1409f8919bdaSduboff 		return (flag | GEM_RX_ERR);
1410f8919bdaSduboff 	}
1411f8919bdaSduboff 
1412f8919bdaSduboff 	/*
1413f8919bdaSduboff 	 * this packet was received without errors
1414f8919bdaSduboff 	 */
1415f8919bdaSduboff 	if ((len = (status & CMDSTS_SIZE)) >= ETHERFCSL) {
1416f8919bdaSduboff 		len -= ETHERFCSL;
1417f8919bdaSduboff 	}
1418f8919bdaSduboff 
1419f8919bdaSduboff #if DEBUG_LEVEL > 10
1420f8919bdaSduboff {
1421f8919bdaSduboff 	int	i;
1422f8919bdaSduboff 	uint8_t	*bp = dp->rx_buf_head->rxb_buf;
1423f8919bdaSduboff 
1424f8919bdaSduboff 	cmn_err(CE_CONT, CONS "%s: len:%d", dp->name, len);
1425f8919bdaSduboff 
1426f8919bdaSduboff 	for (i = 0; i < 60; i += 10) {
1427f8919bdaSduboff 		cmn_err(CE_CONT, CONS
1428f8919bdaSduboff 		    "%02x %02x %02x %02x %02x %02x %02x %02x %02x %02x",
1429f8919bdaSduboff 		    bp[0], bp[1], bp[2], bp[3], bp[4],
1430f8919bdaSduboff 		    bp[5], bp[6], bp[7], bp[8], bp[9]);
1431f8919bdaSduboff 	}
1432f8919bdaSduboff 	bp += 10;
1433f8919bdaSduboff }
1434f8919bdaSduboff #endif
1435f8919bdaSduboff 	return (flag | (len & GEM_RX_LEN));
1436f8919bdaSduboff }
1437f8919bdaSduboff 
1438f8919bdaSduboff static void
1439f8919bdaSduboff sfe_tx_desc_init(struct gem_dev *dp, int slot)
1440f8919bdaSduboff {
1441*23d366e3Sduboff 	uint_t			tx_ring_size = dp->gc.gc_tx_ring_size;
1442f8919bdaSduboff 	struct sfe_desc		*tdp;
1443f8919bdaSduboff 	uint32_t		here;
1444f8919bdaSduboff 
1445f8919bdaSduboff 	tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot];
1446f8919bdaSduboff 
1447f8919bdaSduboff 	/* don't clear d_link field, which have a valid pointer */
1448f8919bdaSduboff 	tdp->d_cmdsts = 0;
1449f8919bdaSduboff 
1450f8919bdaSduboff 	/* make a link to this from the previous descriptor */
1451f8919bdaSduboff 	here = ((uint32_t)dp->tx_ring_dma) + SFE_DESC_SIZE*slot;
1452f8919bdaSduboff 
1453f8919bdaSduboff 	tdp = (void *)
1454*23d366e3Sduboff 	    &dp->tx_ring[SFE_DESC_SIZE * SLOT(slot - 1, tx_ring_size)];
1455f8919bdaSduboff 	tdp->d_link = LE_32(here);
1456f8919bdaSduboff }
1457f8919bdaSduboff 
1458f8919bdaSduboff static void
1459f8919bdaSduboff sfe_rx_desc_init(struct gem_dev *dp, int slot)
1460f8919bdaSduboff {
1461*23d366e3Sduboff 	uint_t			rx_ring_size = dp->gc.gc_rx_ring_size;
1462f8919bdaSduboff 	struct sfe_desc		*rdp;
1463f8919bdaSduboff 	uint32_t		here;
1464f8919bdaSduboff 
1465f8919bdaSduboff 	rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot];
1466f8919bdaSduboff 
1467f8919bdaSduboff 	/* don't clear d_link field, which have a valid pointer */
1468f8919bdaSduboff 	rdp->d_cmdsts = LE_32(CMDSTS_OWN);
1469f8919bdaSduboff 
1470f8919bdaSduboff 	/* make a link to this from the previous descriptor */
1471f8919bdaSduboff 	here = ((uint32_t)dp->rx_ring_dma) + SFE_DESC_SIZE*slot;
1472f8919bdaSduboff 
1473f8919bdaSduboff 	rdp = (void *)
1474*23d366e3Sduboff 	    &dp->rx_ring[SFE_DESC_SIZE * SLOT(slot - 1, rx_ring_size)];
1475f8919bdaSduboff 	rdp->d_link = LE_32(here);
1476f8919bdaSduboff }
1477f8919bdaSduboff 
1478f8919bdaSduboff static void
1479f8919bdaSduboff sfe_tx_desc_clean(struct gem_dev *dp, int slot)
1480f8919bdaSduboff {
1481f8919bdaSduboff 	struct sfe_desc		*tdp;
1482f8919bdaSduboff 
1483f8919bdaSduboff 	tdp = (void *)&dp->tx_ring[SFE_DESC_SIZE * slot];
1484f8919bdaSduboff 	tdp->d_cmdsts = 0;
1485f8919bdaSduboff }
1486f8919bdaSduboff 
1487f8919bdaSduboff static void
1488f8919bdaSduboff sfe_rx_desc_clean(struct gem_dev *dp, int slot)
1489f8919bdaSduboff {
1490f8919bdaSduboff 	struct sfe_desc		*rdp;
1491f8919bdaSduboff 
1492f8919bdaSduboff 	rdp = (void *)&dp->rx_ring[SFE_DESC_SIZE * slot];
1493f8919bdaSduboff 	rdp->d_cmdsts = LE_32(CMDSTS_OWN);
1494f8919bdaSduboff }
1495f8919bdaSduboff 
1496f8919bdaSduboff /*
1497f8919bdaSduboff  * Device depend interrupt handler
1498f8919bdaSduboff  */
1499f8919bdaSduboff static uint_t
1500f8919bdaSduboff sfe_interrupt(struct gem_dev *dp)
1501f8919bdaSduboff {
1502*23d366e3Sduboff 	uint_t		rx_ring_size = dp->gc.gc_rx_ring_size;
1503f8919bdaSduboff 	uint32_t	isr;
1504*23d366e3Sduboff 	uint32_t	isr_bogus;
1505f8919bdaSduboff 	uint_t		flags = 0;
1506f8919bdaSduboff 	boolean_t	need_to_reset = B_FALSE;
1507f8919bdaSduboff 	struct sfe_dev	*lp = dp->private;
1508f8919bdaSduboff 
1509f8919bdaSduboff 	/* read reason and clear interrupt */
1510f8919bdaSduboff 	isr = INL(dp, ISR);
1511f8919bdaSduboff 
1512*23d366e3Sduboff 	isr_bogus = lp->isr_pended;
1513*23d366e3Sduboff 	lp->isr_pended = 0;
1514*23d366e3Sduboff 
1515*23d366e3Sduboff 	if (((isr | isr_bogus) & lp->our_intr_bits) == 0) {
1516f8919bdaSduboff 		/* we are not the interrupt source */
1517f8919bdaSduboff 		return (DDI_INTR_UNCLAIMED);
1518f8919bdaSduboff 	}
1519f8919bdaSduboff 
1520f8919bdaSduboff 	DPRINTF(3, (CE_CONT,
1521f8919bdaSduboff 	    CONS "%s: time:%ld %s:called: isr:0x%b rx_active_head: %d",
1522f8919bdaSduboff 	    dp->name, ddi_get_lbolt(), __func__,
1523f8919bdaSduboff 	    isr, INTR_BITS, dp->rx_active_head));
1524f8919bdaSduboff 
1525f8919bdaSduboff 	if (!dp->mac_active) {
1526f8919bdaSduboff 		/* the device is going to stop */
1527f8919bdaSduboff 		lp->our_intr_bits = 0;
1528f8919bdaSduboff 		return (DDI_INTR_CLAIMED);
1529f8919bdaSduboff 	}
1530f8919bdaSduboff 
1531f8919bdaSduboff 	isr &= lp->our_intr_bits;
1532f8919bdaSduboff 
1533f8919bdaSduboff 	if (isr & (ISR_RXSOVR | ISR_RXORN | ISR_RXIDLE | ISR_RXERR |
1534f8919bdaSduboff 	    ISR_RXDESC | ISR_RXOK)) {
1535f8919bdaSduboff 		(void) gem_receive(dp);
1536f8919bdaSduboff 
1537f8919bdaSduboff 		if (isr & (ISR_RXSOVR | ISR_RXORN)) {
1538f8919bdaSduboff 			DPRINTF(0, (CE_CONT,
1539f8919bdaSduboff 			    CONS "%s: rx fifo overrun: isr %b",
1540f8919bdaSduboff 			    dp->name, isr, INTR_BITS));
1541f8919bdaSduboff 			/* no need restart rx */
1542f8919bdaSduboff 			dp->stats.overflow++;
1543f8919bdaSduboff 		}
1544f8919bdaSduboff 
1545f8919bdaSduboff 		if (isr & ISR_RXIDLE) {
1546f8919bdaSduboff 			DPRINTF(0, (CE_CONT,
1547f8919bdaSduboff 			    CONS "%s: rx buffer ran out: isr %b",
1548f8919bdaSduboff 			    dp->name, isr, INTR_BITS));
1549f8919bdaSduboff 
1550f8919bdaSduboff 			dp->stats.norcvbuf++;
1551f8919bdaSduboff 
1552f8919bdaSduboff 			/*
1553f8919bdaSduboff 			 * Make RXDP points the head of receive
1554f8919bdaSduboff 			 * buffer list.
1555f8919bdaSduboff 			 */
1556f8919bdaSduboff 			OUTL(dp, RXDP, dp->rx_ring_dma +
1557f8919bdaSduboff 			    SFE_DESC_SIZE *
1558*23d366e3Sduboff 			    SLOT(dp->rx_active_head, rx_ring_size));
1559f8919bdaSduboff 
1560f8919bdaSduboff 			/* Restart the receive engine */
1561f8919bdaSduboff 			OUTL(dp, CR, lp->cr | CR_RXE);
1562f8919bdaSduboff 		}
1563f8919bdaSduboff 	}
1564f8919bdaSduboff 
1565f8919bdaSduboff 	if (isr & (ISR_TXURN | ISR_TXERR | ISR_TXDESC |
1566f8919bdaSduboff 	    ISR_TXIDLE | ISR_TXOK)) {
1567f8919bdaSduboff 		/* need to reclaim tx buffers */
1568f8919bdaSduboff 		if (gem_tx_done(dp)) {
1569f8919bdaSduboff 			flags |= INTR_RESTART_TX;
1570f8919bdaSduboff 		}
1571f8919bdaSduboff 		/*
1572f8919bdaSduboff 		 * XXX - tx error statistics will be counted in
1573f8919bdaSduboff 		 * sfe_tx_desc_stat() and no need to restart tx on errors.
1574f8919bdaSduboff 		 */
1575f8919bdaSduboff 	}
1576f8919bdaSduboff 
1577f8919bdaSduboff 	if (isr & (ISR_DPERR | ISR_SSERR | ISR_RMABT | ISR_RTABT)) {
1578f8919bdaSduboff 		cmn_err(CE_WARN, "%s: ERROR interrupt: isr %b.",
1579f8919bdaSduboff 		    dp->name, isr, INTR_BITS);
1580f8919bdaSduboff 		need_to_reset = B_TRUE;
1581f8919bdaSduboff 	}
1582f8919bdaSduboff reset:
1583f8919bdaSduboff 	if (need_to_reset) {
1584f8919bdaSduboff 		(void) gem_restart_nic(dp, GEM_RESTART_KEEP_BUF);
1585f8919bdaSduboff 		flags |= INTR_RESTART_TX;
1586f8919bdaSduboff 	}
1587f8919bdaSduboff 
1588f8919bdaSduboff 	DPRINTF(5, (CE_CONT, CONS "%s: %s: return: isr: %b",
1589f8919bdaSduboff 	    dp->name, __func__, isr, INTR_BITS));
1590f8919bdaSduboff 
1591f8919bdaSduboff 	return (DDI_INTR_CLAIMED | flags);
1592f8919bdaSduboff }
1593f8919bdaSduboff 
1594f8919bdaSduboff /* ======================================================== */
1595f8919bdaSduboff /*
1596f8919bdaSduboff  * HW depend MII routine
1597f8919bdaSduboff  */
1598f8919bdaSduboff /* ======================================================== */
1599f8919bdaSduboff 
1600f8919bdaSduboff /*
1601f8919bdaSduboff  * MII routines for NS DP83815
1602f8919bdaSduboff  */
1603f8919bdaSduboff static void
1604f8919bdaSduboff sfe_mii_sync_dp83815(struct gem_dev *dp)
1605f8919bdaSduboff {
1606f8919bdaSduboff 	/* do nothing */
1607f8919bdaSduboff }
1608f8919bdaSduboff 
1609f8919bdaSduboff static uint16_t
1610f8919bdaSduboff sfe_mii_read_dp83815(struct gem_dev *dp, uint_t offset)
1611f8919bdaSduboff {
1612f8919bdaSduboff 	DPRINTF(4, (CE_CONT, CONS"%s: %s: offset 0x%x",
1613f8919bdaSduboff 	    dp->name, __func__, offset));
1614f8919bdaSduboff 	return ((uint16_t)INL(dp, MII_REGS_BASE + offset*4));
1615f8919bdaSduboff }
1616f8919bdaSduboff 
1617f8919bdaSduboff static void
1618f8919bdaSduboff sfe_mii_write_dp83815(struct gem_dev *dp, uint_t offset, uint16_t val)
1619f8919bdaSduboff {
1620f8919bdaSduboff 	DPRINTF(4, (CE_CONT, CONS"%s: %s: offset 0x%x 0x%x",
1621f8919bdaSduboff 	    dp->name, __func__, offset, val));
1622f8919bdaSduboff 	OUTL(dp, MII_REGS_BASE + offset*4, val);
1623f8919bdaSduboff }
1624f8919bdaSduboff 
1625f8919bdaSduboff static int
1626f8919bdaSduboff sfe_mii_config_dp83815(struct gem_dev *dp)
1627f8919bdaSduboff {
1628f8919bdaSduboff 	uint32_t	srr;
1629f8919bdaSduboff 
1630f8919bdaSduboff 	srr = INL(dp, SRR) & SRR_REV;
1631f8919bdaSduboff 
1632f8919bdaSduboff 	DPRINTF(0, (CE_CONT, CONS "%s: srr:0x%04x %04x %04x %04x %04x %04x",
1633f8919bdaSduboff 	    dp->name, srr,
1634f8919bdaSduboff 	    INW(dp, 0x00cc),	/* PGSEL */
1635f8919bdaSduboff 	    INW(dp, 0x00e4),	/* PMDCSR */
1636f8919bdaSduboff 	    INW(dp, 0x00fc),	/* TSTDAT */
1637f8919bdaSduboff 	    INW(dp, 0x00f4),	/* DSPCFG */
1638f8919bdaSduboff 	    INW(dp, 0x00f8)));	/* SDCFG */
1639f8919bdaSduboff 
1640*23d366e3Sduboff 	if (srr == SRR_REV_DP83815CVNG) {
1641f8919bdaSduboff 		/*
1642f8919bdaSduboff 		 * NS datasheet says that DP83815CVNG needs following
1643f8919bdaSduboff 		 * registers to be patched for optimizing its performance.
1644*23d366e3Sduboff 		 * A report said that CRC errors on RX disappeared
1645f8919bdaSduboff 		 * with the patch.
1646f8919bdaSduboff 		 */
1647f8919bdaSduboff 		OUTW(dp, 0x00cc, 0x0001);	/* PGSEL */
1648f8919bdaSduboff 		OUTW(dp, 0x00e4, 0x189c);	/* PMDCSR */
1649f8919bdaSduboff 		OUTW(dp, 0x00fc, 0x0000);	/* TSTDAT */
1650f8919bdaSduboff 		OUTW(dp, 0x00f4, 0x5040);	/* DSPCFG */
1651f8919bdaSduboff 		OUTW(dp, 0x00f8, 0x008c);	/* SDCFG */
1652*23d366e3Sduboff 		OUTW(dp, 0x00cc, 0x0000);	/* PGSEL */
1653f8919bdaSduboff 
1654f8919bdaSduboff 		DPRINTF(0, (CE_CONT,
1655f8919bdaSduboff 		    CONS "%s: PHY patched %04x %04x %04x %04x %04x",
1656f8919bdaSduboff 		    dp->name,
1657f8919bdaSduboff 		    INW(dp, 0x00cc),	/* PGSEL */
1658f8919bdaSduboff 		    INW(dp, 0x00e4),	/* PMDCSR */
1659f8919bdaSduboff 		    INW(dp, 0x00fc),	/* TSTDAT */
1660f8919bdaSduboff 		    INW(dp, 0x00f4),	/* DSPCFG */
1661f8919bdaSduboff 		    INW(dp, 0x00f8)));	/* SDCFG */
1662*23d366e3Sduboff 	} else if (((srr ^ SRR_REV_DP83815DVNG) & 0xff00) == 0 ||
1663*23d366e3Sduboff 	    ((srr ^ SRR_REV_DP83816AVNG) & 0xff00) == 0) {
1664*23d366e3Sduboff 		/*
1665*23d366e3Sduboff 		 * Additional packets for later chipset
1666*23d366e3Sduboff 		 */
1667*23d366e3Sduboff 		OUTW(dp, 0x00cc, 0x0001);	/* PGSEL */
1668*23d366e3Sduboff 		OUTW(dp, 0x00e4, 0x189c);	/* PMDCSR */
1669*23d366e3Sduboff 		OUTW(dp, 0x00cc, 0x0000);	/* PGSEL */
1670*23d366e3Sduboff 
1671*23d366e3Sduboff 		DPRINTF(0, (CE_CONT,
1672*23d366e3Sduboff 		    CONS "%s: PHY patched %04x %04x",
1673*23d366e3Sduboff 		    dp->name,
1674*23d366e3Sduboff 		    INW(dp, 0x00cc),	/* PGSEL */
1675*23d366e3Sduboff 		    INW(dp, 0x00e4)));	/* PMDCSR */
1676f8919bdaSduboff 	}
1677f8919bdaSduboff 
1678f8919bdaSduboff 	return (gem_mii_config_default(dp));
1679f8919bdaSduboff }
1680f8919bdaSduboff 
1681*23d366e3Sduboff static int
1682*23d366e3Sduboff sfe_mii_probe_dp83815(struct gem_dev *dp)
1683*23d366e3Sduboff {
1684*23d366e3Sduboff 	uint32_t	val;
1685*23d366e3Sduboff 
1686*23d366e3Sduboff 	/* try external phy first */
1687*23d366e3Sduboff 	DPRINTF(0, (CE_CONT, CONS "%s: %s: trying external phy",
1688*23d366e3Sduboff 	    dp->name, __func__));
1689*23d366e3Sduboff 	dp->mii_phy_addr = 0;
1690*23d366e3Sduboff 	dp->gc.gc_mii_sync = &sfe_mii_sync_sis900;
1691*23d366e3Sduboff 	dp->gc.gc_mii_read = &sfe_mii_read_sis900;
1692*23d366e3Sduboff 	dp->gc.gc_mii_write = &sfe_mii_write_sis900;
1693*23d366e3Sduboff 
1694*23d366e3Sduboff 	val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG);
1695*23d366e3Sduboff 	OUTL(dp, CFG, val | CFG_EXT_PHY | CFG_PHY_DIS);
1696*23d366e3Sduboff 
1697*23d366e3Sduboff 	if (gem_mii_probe_default(dp) == GEM_SUCCESS) {
1698*23d366e3Sduboff 		return (GEM_SUCCESS);
1699*23d366e3Sduboff 	}
1700*23d366e3Sduboff 
1701*23d366e3Sduboff 	/* switch to internal phy */
1702*23d366e3Sduboff 	DPRINTF(0, (CE_CONT, CONS "%s: %s: switching to internal phy",
1703*23d366e3Sduboff 	    dp->name, __func__));
1704*23d366e3Sduboff 	dp->mii_phy_addr = -1;
1705*23d366e3Sduboff 	dp->gc.gc_mii_sync = &sfe_mii_sync_dp83815;
1706*23d366e3Sduboff 	dp->gc.gc_mii_read = &sfe_mii_read_dp83815;
1707*23d366e3Sduboff 	dp->gc.gc_mii_write = &sfe_mii_write_dp83815;
1708*23d366e3Sduboff 
1709*23d366e3Sduboff 	val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG);
1710*23d366e3Sduboff 	OUTL(dp, CFG, val | CFG_PAUSE_ADV | CFG_PHY_RST);
1711*23d366e3Sduboff 	drv_usecwait(100);	/* keep to assert RST bit for a while */
1712*23d366e3Sduboff 	OUTL(dp, CFG, val | CFG_PAUSE_ADV);
1713*23d366e3Sduboff 
1714*23d366e3Sduboff 	/* wait for PHY reset */
1715*23d366e3Sduboff 	delay(drv_usectohz(10000));
1716*23d366e3Sduboff 
1717*23d366e3Sduboff 	return (gem_mii_probe_default(dp));
1718*23d366e3Sduboff }
1719*23d366e3Sduboff 
1720*23d366e3Sduboff static int
1721*23d366e3Sduboff sfe_mii_init_dp83815(struct gem_dev *dp)
1722*23d366e3Sduboff {
1723*23d366e3Sduboff 	uint32_t	val;
1724*23d366e3Sduboff 
1725*23d366e3Sduboff 	val = INL(dp, CFG) & (CFG_ANEG_SEL | CFG_PHY_CFG);
1726*23d366e3Sduboff 
1727*23d366e3Sduboff 	if (dp->mii_phy_addr == -1) {
1728*23d366e3Sduboff 		/* select internal phy */
1729*23d366e3Sduboff 		OUTL(dp, CFG, val | CFG_PAUSE_ADV);
1730*23d366e3Sduboff 	} else {
1731*23d366e3Sduboff 		/* select external phy */
1732*23d366e3Sduboff 		OUTL(dp, CFG, val | CFG_EXT_PHY | CFG_PHY_DIS);
1733*23d366e3Sduboff 	}
1734*23d366e3Sduboff 
1735*23d366e3Sduboff 	return (GEM_SUCCESS);
1736*23d366e3Sduboff }
1737f8919bdaSduboff 
1738f8919bdaSduboff /*
1739f8919bdaSduboff  * MII routines for SiS900
1740f8919bdaSduboff  */
1741*23d366e3Sduboff #define	MDIO_DELAY(dp)	{(void) INL(dp, MEAR); (void) INL(dp, MEAR); }
1742f8919bdaSduboff static void
1743f8919bdaSduboff sfe_mii_sync_sis900(struct gem_dev *dp)
1744f8919bdaSduboff {
1745f8919bdaSduboff 	int	i;
1746f8919bdaSduboff 
1747*23d366e3Sduboff 	/* send 32 ONE's to make MII line idle */
1748f8919bdaSduboff 	for (i = 0; i < 32; i++) {
1749f8919bdaSduboff 		OUTL(dp, MEAR, MEAR_MDDIR | MEAR_MDIO);
1750f8919bdaSduboff 		MDIO_DELAY(dp);
1751f8919bdaSduboff 		OUTL(dp, MEAR, MEAR_MDDIR | MEAR_MDIO | MEAR_MDC);
1752f8919bdaSduboff 		MDIO_DELAY(dp);
1753f8919bdaSduboff 	}
1754f8919bdaSduboff }
1755f8919bdaSduboff 
1756f8919bdaSduboff static int
1757f8919bdaSduboff sfe_mii_config_sis900(struct gem_dev *dp)
1758f8919bdaSduboff {
1759f8919bdaSduboff 	struct sfe_dev	*lp = dp->private;
1760f8919bdaSduboff 
1761f8919bdaSduboff 	/* Do chip depend setup */
1762f8919bdaSduboff 	if ((dp->mii_phy_id & PHY_MASK) == PHY_ICS1893) {
1763f8919bdaSduboff 		/* workaround for ICS1893 PHY */
1764f8919bdaSduboff 		gem_mii_write(dp, 0x0018, 0xD200);
1765f8919bdaSduboff 	}
1766f8919bdaSduboff 
1767f8919bdaSduboff 	if (lp->revid == SIS630E_900_REV) {
1768f8919bdaSduboff 		/*
1769f8919bdaSduboff 		 * SiS 630E has bugs on default values
1770f8919bdaSduboff 		 * of PHY registers
1771f8919bdaSduboff 		 */
1772f8919bdaSduboff 		gem_mii_write(dp, MII_AN_ADVERT, 0x05e1);
1773f8919bdaSduboff 		gem_mii_write(dp, MII_CONFIG1, 0x0022);
1774f8919bdaSduboff 		gem_mii_write(dp, MII_CONFIG2, 0xff00);
1775f8919bdaSduboff 		gem_mii_write(dp, MII_MASK,    0xffc0);
1776f8919bdaSduboff 	}
1777f8919bdaSduboff 	sfe_set_eq_sis630(dp);
1778f8919bdaSduboff 
1779f8919bdaSduboff 	return (gem_mii_config_default(dp));
1780f8919bdaSduboff }
1781f8919bdaSduboff 
1782f8919bdaSduboff static uint16_t
1783f8919bdaSduboff sfe_mii_read_sis900(struct gem_dev *dp, uint_t reg)
1784f8919bdaSduboff {
1785f8919bdaSduboff 	uint32_t	cmd;
1786f8919bdaSduboff 	uint16_t	ret;
1787f8919bdaSduboff 	int		i;
1788f8919bdaSduboff 	uint32_t	data;
1789f8919bdaSduboff 
1790f8919bdaSduboff 	cmd = MII_READ_CMD(dp->mii_phy_addr, reg);
1791f8919bdaSduboff 
1792f8919bdaSduboff 	for (i = 31; i >= 18; i--) {
1793f8919bdaSduboff 		data = ((cmd >> i) & 1) <<  MEAR_MDIO_SHIFT;
1794f8919bdaSduboff 		OUTL(dp, MEAR, data | MEAR_MDDIR);
1795f8919bdaSduboff 		MDIO_DELAY(dp);
1796f8919bdaSduboff 		OUTL(dp, MEAR, data | MEAR_MDDIR | MEAR_MDC);
1797f8919bdaSduboff 		MDIO_DELAY(dp);
1798f8919bdaSduboff 	}
1799f8919bdaSduboff 
1800f8919bdaSduboff 	/* turn around cycle */
1801*23d366e3Sduboff 	OUTL(dp, MEAR, 0);
1802f8919bdaSduboff 	MDIO_DELAY(dp);
1803f8919bdaSduboff 
1804f8919bdaSduboff 	/* get response from PHY */
1805f8919bdaSduboff 	OUTL(dp, MEAR, MEAR_MDC);
1806f8919bdaSduboff 	MDIO_DELAY(dp);
1807f8919bdaSduboff 
1808*23d366e3Sduboff 	OUTL(dp, MEAR, 0);
1809f8919bdaSduboff #if DEBUG_LEBEL > 0
1810*23d366e3Sduboff 	(void) INL(dp, MEAR);	/* delay */
1811f8919bdaSduboff 	if (INL(dp, MEAR) & MEAR_MDIO) {
1812f8919bdaSduboff 		cmn_err(CE_WARN, "%s: PHY@%d not responded",
1813f8919bdaSduboff 		    dp->name, dp->mii_phy_addr);
1814f8919bdaSduboff 	}
1815*23d366e3Sduboff #else
1816*23d366e3Sduboff 	MDIO_DELAY(dp);
1817f8919bdaSduboff #endif
1818f8919bdaSduboff 	/* terminate response cycle */
1819f8919bdaSduboff 	OUTL(dp, MEAR, MEAR_MDC);
1820*23d366e3Sduboff 	MDIO_DELAY(dp);
1821f8919bdaSduboff 
1822f8919bdaSduboff 	ret = 0;	/* to avoid lint errors */
1823f8919bdaSduboff 	for (i = 16; i > 0; i--) {
1824f8919bdaSduboff 		OUTL(dp, MEAR, 0);
1825*23d366e3Sduboff 		(void) INL(dp, MEAR);	/* delay */
1826f8919bdaSduboff 		ret = (ret << 1) | ((INL(dp, MEAR) >> MEAR_MDIO_SHIFT) & 1);
1827f8919bdaSduboff 		OUTL(dp, MEAR, MEAR_MDC);
1828f8919bdaSduboff 		MDIO_DELAY(dp);
1829f8919bdaSduboff 	}
1830f8919bdaSduboff 
1831*23d366e3Sduboff 	/* send two idle(Z) bits to terminate the read cycle */
1832*23d366e3Sduboff 	for (i = 0; i < 2; i++) {
1833*23d366e3Sduboff 		OUTL(dp, MEAR, 0);
1834*23d366e3Sduboff 		MDIO_DELAY(dp);
1835*23d366e3Sduboff 		OUTL(dp, MEAR, MEAR_MDC);
1836*23d366e3Sduboff 		MDIO_DELAY(dp);
1837*23d366e3Sduboff 	}
1838f8919bdaSduboff 
1839f8919bdaSduboff 	return (ret);
1840f8919bdaSduboff }
1841f8919bdaSduboff 
1842f8919bdaSduboff static void
1843f8919bdaSduboff sfe_mii_write_sis900(struct gem_dev *dp, uint_t reg, uint16_t val)
1844f8919bdaSduboff {
1845f8919bdaSduboff 	uint32_t	cmd;
1846f8919bdaSduboff 	int		i;
1847f8919bdaSduboff 	uint32_t	data;
1848f8919bdaSduboff 
1849f8919bdaSduboff 	cmd = MII_WRITE_CMD(dp->mii_phy_addr, reg, val);
1850f8919bdaSduboff 
1851f8919bdaSduboff 	for (i = 31; i >= 0; i--) {
1852f8919bdaSduboff 		data = ((cmd >> i) & 1) << MEAR_MDIO_SHIFT;
1853f8919bdaSduboff 		OUTL(dp, MEAR, data | MEAR_MDDIR);
1854f8919bdaSduboff 		MDIO_DELAY(dp);
1855f8919bdaSduboff 		OUTL(dp, MEAR, data | MEAR_MDDIR | MEAR_MDC);
1856f8919bdaSduboff 		MDIO_DELAY(dp);
1857f8919bdaSduboff 	}
1858f8919bdaSduboff 
1859*23d366e3Sduboff 	/* send two idle(Z) bits to terminate the write cycle. */
1860f8919bdaSduboff 	for (i = 0; i < 2; i++) {
1861*23d366e3Sduboff 		OUTL(dp, MEAR, 0);
1862f8919bdaSduboff 		MDIO_DELAY(dp);
1863*23d366e3Sduboff 		OUTL(dp, MEAR, MEAR_MDC);
1864f8919bdaSduboff 		MDIO_DELAY(dp);
1865f8919bdaSduboff 	}
1866f8919bdaSduboff }
1867f8919bdaSduboff #undef MDIO_DELAY
1868f8919bdaSduboff 
1869f8919bdaSduboff static void
1870f8919bdaSduboff sfe_set_eq_sis630(struct gem_dev *dp)
1871f8919bdaSduboff {
1872f8919bdaSduboff 	uint16_t	reg14h;
1873f8919bdaSduboff 	uint16_t	eq_value;
1874f8919bdaSduboff 	uint16_t	max_value;
1875f8919bdaSduboff 	uint16_t	min_value;
1876f8919bdaSduboff 	int		i;
1877f8919bdaSduboff 	uint8_t		rev;
1878f8919bdaSduboff 	struct sfe_dev	*lp = dp->private;
1879f8919bdaSduboff 
1880f8919bdaSduboff 	rev = lp->revid;
1881f8919bdaSduboff 
1882f8919bdaSduboff 	if (!(rev == SIS630E_900_REV || rev == SIS630EA1_900_REV ||
1883f8919bdaSduboff 	    rev == SIS630A_900_REV || rev == SIS630ET_900_REV)) {
1884f8919bdaSduboff 		/* it doesn't have a internal PHY */
1885f8919bdaSduboff 		return;
1886f8919bdaSduboff 	}
1887f8919bdaSduboff 
1888f8919bdaSduboff 	if (dp->mii_state == MII_STATE_LINKUP) {
1889f8919bdaSduboff 		reg14h = gem_mii_read(dp, MII_RESV);
1890f8919bdaSduboff 		gem_mii_write(dp, MII_RESV, (0x2200 | reg14h) & 0xBFFF);
1891f8919bdaSduboff 
1892f8919bdaSduboff 		eq_value = (0x00f8 & gem_mii_read(dp, MII_RESV)) >> 3;
1893f8919bdaSduboff 		max_value = min_value = eq_value;
1894f8919bdaSduboff 		for (i = 1; i < 10; i++) {
1895f8919bdaSduboff 			eq_value = (0x00f8 & gem_mii_read(dp, MII_RESV)) >> 3;
1896f8919bdaSduboff 			max_value = max(eq_value, max_value);
1897f8919bdaSduboff 			min_value = min(eq_value, min_value);
1898f8919bdaSduboff 		}
1899f8919bdaSduboff 
1900f8919bdaSduboff 		/* for 630E, rule to determine the equalizer value */
1901f8919bdaSduboff 		if (rev == SIS630E_900_REV || rev == SIS630EA1_900_REV ||
1902f8919bdaSduboff 		    rev == SIS630ET_900_REV) {
1903f8919bdaSduboff 			if (max_value < 5) {
1904f8919bdaSduboff 				eq_value = max_value;
1905f8919bdaSduboff 			} else if (5 <= max_value && max_value < 15) {
1906f8919bdaSduboff 				eq_value =
1907f8919bdaSduboff 				    max(max_value + 1,
1908f8919bdaSduboff 				    min_value + 2);
1909f8919bdaSduboff 			} else if (15 <= max_value) {
1910f8919bdaSduboff 				eq_value =
1911f8919bdaSduboff 				    max(max_value + 5,
1912f8919bdaSduboff 				    min_value + 6);
1913f8919bdaSduboff 			}
1914f8919bdaSduboff 		}
1915f8919bdaSduboff 		/* for 630B0&B1, rule to determine the equalizer value */
1916f8919bdaSduboff 		else
1917f8919bdaSduboff 		if (rev == SIS630A_900_REV &&
1918f8919bdaSduboff 		    (lp->bridge_revid == SIS630B0 ||
1919f8919bdaSduboff 		    lp->bridge_revid == SIS630B1)) {
1920f8919bdaSduboff 
1921f8919bdaSduboff 			if (max_value == 0) {
1922f8919bdaSduboff 				eq_value = 3;
1923f8919bdaSduboff 			} else {
1924f8919bdaSduboff 				eq_value = (max_value + min_value + 1)/2;
1925f8919bdaSduboff 			}
1926f8919bdaSduboff 		}
1927f8919bdaSduboff 		/* write equalizer value and setting */
1928f8919bdaSduboff 		reg14h = gem_mii_read(dp, MII_RESV) & ~0x02f8;
1929f8919bdaSduboff 		reg14h |= 0x6000 | (eq_value << 3);
1930f8919bdaSduboff 		gem_mii_write(dp, MII_RESV, reg14h);
1931f8919bdaSduboff 	} else {
1932f8919bdaSduboff 		reg14h = (gem_mii_read(dp, MII_RESV) & ~0x4000) | 0x2000;
1933f8919bdaSduboff 		if (rev == SIS630A_900_REV &&
1934f8919bdaSduboff 		    (lp->bridge_revid == SIS630B0 ||
1935f8919bdaSduboff 		    lp->bridge_revid == SIS630B1)) {
1936f8919bdaSduboff 
1937f8919bdaSduboff 			reg14h |= 0x0200;
1938f8919bdaSduboff 		}
1939f8919bdaSduboff 		gem_mii_write(dp, MII_RESV, reg14h);
1940f8919bdaSduboff 	}
1941f8919bdaSduboff }
1942f8919bdaSduboff 
1943f8919bdaSduboff /* ======================================================== */
1944f8919bdaSduboff /*
1945f8919bdaSduboff  * OS depend (device driver) routine
1946f8919bdaSduboff  */
1947f8919bdaSduboff /* ======================================================== */
1948f8919bdaSduboff static void
1949f8919bdaSduboff sfe_chipinfo_init_sis900(struct gem_dev *dp)
1950f8919bdaSduboff {
1951f8919bdaSduboff 	int		rev;
1952f8919bdaSduboff 	struct sfe_dev	*lp = (struct sfe_dev *)dp->private;
1953f8919bdaSduboff 
1954f8919bdaSduboff 	rev = lp->revid;
1955f8919bdaSduboff 
1956f8919bdaSduboff 	if (rev == SIS630E_900_REV /* 0x81 */) {
1957f8919bdaSduboff 		/* sis630E */
1958f8919bdaSduboff 		lp->get_mac_addr = &sfe_get_mac_addr_sis630e;
1959f8919bdaSduboff 	} else if (rev > 0x81 && rev <= 0x90) {
1960f8919bdaSduboff 		/* 630S, 630EA1, 630ET, 635A */
1961f8919bdaSduboff 		lp->get_mac_addr = &sfe_get_mac_addr_sis635;
1962f8919bdaSduboff 	} else if (rev == SIS962_900_REV /* 0x91 */) {
1963f8919bdaSduboff 		/* sis962 or later */
1964f8919bdaSduboff 		lp->get_mac_addr = &sfe_get_mac_addr_sis962;
1965f8919bdaSduboff 	} else {
1966f8919bdaSduboff 		/* sis900 */
1967f8919bdaSduboff 		lp->get_mac_addr = &sfe_get_mac_addr_sis900;
1968f8919bdaSduboff 	}
1969f8919bdaSduboff 
1970f8919bdaSduboff 	lp->bridge_revid = 0;
1971f8919bdaSduboff 
1972f8919bdaSduboff 	if (rev == SIS630E_900_REV || rev == SIS630EA1_900_REV ||
1973f8919bdaSduboff 	    rev == SIS630A_900_REV || rev ==  SIS630ET_900_REV) {
1974f8919bdaSduboff 		/*
1975f8919bdaSduboff 		 * read host bridge revision
1976f8919bdaSduboff 		 */
1977f8919bdaSduboff 		dev_info_t	*bridge;
1978f8919bdaSduboff 		ddi_acc_handle_t bridge_handle;
1979f8919bdaSduboff 
1980f8919bdaSduboff 		if ((bridge = sfe_search_pci_dev(0x1039, 0x630)) == NULL) {
1981f8919bdaSduboff 			cmn_err(CE_WARN,
1982f8919bdaSduboff 			    "%s: cannot find host bridge (pci1039,630)",
1983f8919bdaSduboff 			    dp->name);
1984f8919bdaSduboff 			return;
1985f8919bdaSduboff 		}
1986f8919bdaSduboff 
1987f8919bdaSduboff 		if (pci_config_setup(bridge, &bridge_handle) != DDI_SUCCESS) {
1988f8919bdaSduboff 			cmn_err(CE_WARN, "%s: pci_config_setup failed",
1989f8919bdaSduboff 			    dp->name);
1990f8919bdaSduboff 			return;
1991f8919bdaSduboff 		}
1992f8919bdaSduboff 
1993f8919bdaSduboff 		lp->bridge_revid =
1994f8919bdaSduboff 		    pci_config_get8(bridge_handle, PCI_CONF_REVID);
1995f8919bdaSduboff 		pci_config_teardown(&bridge_handle);
1996f8919bdaSduboff 	}
1997f8919bdaSduboff }
1998f8919bdaSduboff 
1999f8919bdaSduboff static int
2000f8919bdaSduboff sfe_attach_chip(struct gem_dev *dp)
2001f8919bdaSduboff {
2002f8919bdaSduboff 	struct sfe_dev		*lp = (struct sfe_dev *)dp->private;
2003f8919bdaSduboff 
2004f8919bdaSduboff 	DPRINTF(4, (CE_CONT, CONS "!%s: %s called", dp->name, __func__));
2005f8919bdaSduboff 
2006f8919bdaSduboff 	/* setup chip-depend get_mac_address function */
2007f8919bdaSduboff 	if (lp->chip->chip_type == CHIPTYPE_SIS900) {
2008f8919bdaSduboff 		sfe_chipinfo_init_sis900(dp);
2009f8919bdaSduboff 	} else {
2010f8919bdaSduboff 		lp->get_mac_addr = &sfe_get_mac_addr_dp83815;
2011f8919bdaSduboff 	}
2012f8919bdaSduboff 
2013f8919bdaSduboff 	/* read MAC address */
2014f8919bdaSduboff 	if (!(lp->get_mac_addr)(dp)) {
2015f8919bdaSduboff 		cmn_err(CE_WARN,
2016f8919bdaSduboff 		    "!%s: %s: failed to get factory mac address"
2017f8919bdaSduboff 		    " please specify a mac address in sfe.conf",
2018f8919bdaSduboff 		    dp->name, __func__);
2019f8919bdaSduboff 		return (GEM_FAILURE);
2020f8919bdaSduboff 	}
2021f8919bdaSduboff 
2022f8919bdaSduboff 	if (lp->chip->chip_type == CHIPTYPE_DP83815) {
2023f8919bdaSduboff 		dp->mii_phy_addr = -1;	/* no need to scan PHY */
2024f8919bdaSduboff 		dp->misc_flag |= GEM_VLAN_SOFT;
2025f8919bdaSduboff 		dp->txthr += 4; /* VTAG_SIZE */
2026f8919bdaSduboff 	}
2027f8919bdaSduboff 	dp->txthr = min(dp->txthr, TXFIFOSIZE - 2);
2028f8919bdaSduboff 
2029f8919bdaSduboff 	return (GEM_SUCCESS);
2030f8919bdaSduboff }
2031f8919bdaSduboff 
2032f8919bdaSduboff static int
2033f8919bdaSduboff sfeattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
2034f8919bdaSduboff {
2035f8919bdaSduboff 	int			unit;
2036f8919bdaSduboff 	const char		*drv_name;
2037f8919bdaSduboff 	int			i;
2038f8919bdaSduboff 	ddi_acc_handle_t	conf_handle;
2039f8919bdaSduboff 	uint16_t		vid;
2040f8919bdaSduboff 	uint16_t		did;
2041f8919bdaSduboff 	uint8_t			rev;
2042f8919bdaSduboff #ifdef DEBUG_LEVEL
2043f8919bdaSduboff 	uint32_t		iline;
2044f8919bdaSduboff 	uint8_t			latim;
2045f8919bdaSduboff #endif
2046f8919bdaSduboff 	struct chip_info	*p;
2047f8919bdaSduboff 	struct gem_dev		*dp;
2048f8919bdaSduboff 	struct sfe_dev		*lp;
2049f8919bdaSduboff 	caddr_t			base;
2050f8919bdaSduboff 	ddi_acc_handle_t	regs_ha;
2051f8919bdaSduboff 	struct gem_conf		*gcp;
2052f8919bdaSduboff 
2053f8919bdaSduboff 	unit = ddi_get_instance(dip);
2054f8919bdaSduboff 	drv_name = ddi_driver_name(dip);
2055f8919bdaSduboff 
2056f8919bdaSduboff 	DPRINTF(3, (CE_CONT, CONS "%s%d: sfeattach: called", drv_name, unit));
2057f8919bdaSduboff 
2058f8919bdaSduboff 	/*
2059f8919bdaSduboff 	 * Common codes after power-up
2060f8919bdaSduboff 	 */
2061f8919bdaSduboff 	if (pci_config_setup(dip, &conf_handle) != DDI_SUCCESS) {
2062f8919bdaSduboff 		cmn_err(CE_WARN, "%s%d: ddi_regs_map_setup failed",
2063f8919bdaSduboff 		    drv_name, unit);
2064f8919bdaSduboff 		goto err;
2065f8919bdaSduboff 	}
2066f8919bdaSduboff 
2067f8919bdaSduboff 	vid  = pci_config_get16(conf_handle, PCI_CONF_VENID);
2068f8919bdaSduboff 	did  = pci_config_get16(conf_handle, PCI_CONF_DEVID);
2069f8919bdaSduboff 	rev  = pci_config_get16(conf_handle, PCI_CONF_REVID);
2070f8919bdaSduboff #ifdef DEBUG_LEVEL
2071*23d366e3Sduboff 	iline = pci_config_get32(conf_handle, PCI_CONF_ILINE);
2072*23d366e3Sduboff 	latim = pci_config_get8(conf_handle, PCI_CONF_LATENCY_TIMER);
2073f8919bdaSduboff #endif
2074f8919bdaSduboff #ifdef DEBUG_BUILT_IN_SIS900
2075f8919bdaSduboff 	rev  = SIS630E_900_REV;
2076f8919bdaSduboff #endif
2077f8919bdaSduboff 	for (i = 0, p = sfe_chiptbl; i < CHIPTABLESIZE; i++, p++) {
2078f8919bdaSduboff 		if (p->venid == vid && p->devid == did) {
2079f8919bdaSduboff 			/* found */
2080f8919bdaSduboff 			goto chip_found;
2081f8919bdaSduboff 		}
2082f8919bdaSduboff 	}
2083f8919bdaSduboff 
2084f8919bdaSduboff 	/* Not found */
2085f8919bdaSduboff 	cmn_err(CE_WARN,
2086f8919bdaSduboff 	    "%s%d: sfe_attach: wrong PCI venid/devid (0x%x, 0x%x)",
2087f8919bdaSduboff 	    drv_name, unit, vid, did);
2088f8919bdaSduboff 	pci_config_teardown(&conf_handle);
2089f8919bdaSduboff 	goto err;
2090f8919bdaSduboff 
2091f8919bdaSduboff chip_found:
2092f8919bdaSduboff 	pci_config_put16(conf_handle, PCI_CONF_COMM,
2093f8919bdaSduboff 	    PCI_COMM_IO | PCI_COMM_MAE | PCI_COMM_ME |
2094f8919bdaSduboff 	    pci_config_get16(conf_handle, PCI_CONF_COMM));
2095f8919bdaSduboff 
2096f8919bdaSduboff 	/* ensure D0 mode */
2097f8919bdaSduboff 	(void) gem_pci_set_power_state(dip, conf_handle, PCI_PMCSR_D0);
2098f8919bdaSduboff 
2099f8919bdaSduboff 	pci_config_teardown(&conf_handle);
2100f8919bdaSduboff 
2101f8919bdaSduboff 	switch (cmd) {
2102f8919bdaSduboff 	case DDI_RESUME:
2103f8919bdaSduboff 		return (gem_resume(dip));
2104f8919bdaSduboff 
2105f8919bdaSduboff 	case DDI_ATTACH:
2106f8919bdaSduboff 
2107f8919bdaSduboff 		DPRINTF(0, (CE_CONT,
2108f8919bdaSduboff 		    CONS "%s%d: ilr 0x%08x, latency_timer:0x%02x",
2109f8919bdaSduboff 		    drv_name, unit, iline, latim));
2110f8919bdaSduboff 
2111f8919bdaSduboff 		/*
2112f8919bdaSduboff 		 * Map in the device registers.
2113f8919bdaSduboff 		 */
2114f8919bdaSduboff 		if (gem_pci_regs_map_setup(dip,
2115f8919bdaSduboff 		    (sfe_use_pcimemspace && p->chip_type == CHIPTYPE_DP83815)
2116f8919bdaSduboff 		    ? PCI_ADDR_MEM32 : PCI_ADDR_IO, PCI_ADDR_MASK,
2117f8919bdaSduboff 		    &sfe_dev_attr, &base, &regs_ha) != DDI_SUCCESS) {
2118f8919bdaSduboff 			cmn_err(CE_WARN,
2119f8919bdaSduboff 			    "%s%d: ddi_regs_map_setup failed",
2120f8919bdaSduboff 			    drv_name, unit);
2121f8919bdaSduboff 			goto err;
2122f8919bdaSduboff 		}
2123f8919bdaSduboff 
2124f8919bdaSduboff 		/*
2125f8919bdaSduboff 		 * construct gem configuration
2126f8919bdaSduboff 		 */
2127f8919bdaSduboff 		gcp = kmem_zalloc(sizeof (*gcp), KM_SLEEP);
2128f8919bdaSduboff 
2129f8919bdaSduboff 		/* name */
2130f8919bdaSduboff 		(void) sprintf(gcp->gc_name, "%s%d", drv_name, unit);
2131f8919bdaSduboff 
2132f8919bdaSduboff 		/* consistency on tx and rx */
2133f8919bdaSduboff 		gcp->gc_tx_buf_align = sizeof (uint8_t) - 1;
2134f8919bdaSduboff 		gcp->gc_tx_max_frags = MAXTXFRAGS;
2135f8919bdaSduboff 		gcp->gc_tx_max_descs_per_pkt = gcp->gc_tx_max_frags;
2136f8919bdaSduboff 		gcp->gc_tx_desc_unit_shift = 4;	/* 16 byte */
2137f8919bdaSduboff 		gcp->gc_tx_buf_size  = TX_BUF_SIZE;
2138f8919bdaSduboff 		gcp->gc_tx_buf_limit = gcp->gc_tx_buf_size;
2139f8919bdaSduboff 		gcp->gc_tx_ring_size = TX_RING_SIZE;
2140f8919bdaSduboff 		gcp->gc_tx_ring_limit = gcp->gc_tx_ring_size;
2141f8919bdaSduboff 		gcp->gc_tx_auto_pad  = B_TRUE;
2142f8919bdaSduboff 		gcp->gc_tx_copy_thresh = sfe_tx_copy_thresh;
2143f8919bdaSduboff 		gcp->gc_tx_desc_write_oo = B_TRUE;
2144f8919bdaSduboff 
2145f8919bdaSduboff 		gcp->gc_rx_buf_align = sizeof (uint8_t) - 1;
2146f8919bdaSduboff 		gcp->gc_rx_max_frags = MAXRXFRAGS;
2147f8919bdaSduboff 		gcp->gc_rx_desc_unit_shift = 4;
2148f8919bdaSduboff 		gcp->gc_rx_ring_size = RX_RING_SIZE;
2149f8919bdaSduboff 		gcp->gc_rx_buf_max   = RX_BUF_SIZE;
2150f8919bdaSduboff 		gcp->gc_rx_copy_thresh = sfe_rx_copy_thresh;
2151f8919bdaSduboff 
2152f8919bdaSduboff 		/* map attributes */
2153f8919bdaSduboff 		gcp->gc_dev_attr = sfe_dev_attr;
2154f8919bdaSduboff 		gcp->gc_buf_attr = sfe_buf_attr;
2155f8919bdaSduboff 		gcp->gc_desc_attr = sfe_buf_attr;
2156f8919bdaSduboff 
2157f8919bdaSduboff 		/* dma attributes */
2158f8919bdaSduboff 		gcp->gc_dma_attr_desc = sfe_dma_attr_desc;
2159f8919bdaSduboff 
2160f8919bdaSduboff 		gcp->gc_dma_attr_txbuf = sfe_dma_attr_buf;
2161f8919bdaSduboff 		gcp->gc_dma_attr_txbuf.dma_attr_align = gcp->gc_tx_buf_align+1;
2162f8919bdaSduboff 		gcp->gc_dma_attr_txbuf.dma_attr_sgllen = gcp->gc_tx_max_frags;
2163f8919bdaSduboff 
2164f8919bdaSduboff 		gcp->gc_dma_attr_rxbuf = sfe_dma_attr_buf;
2165f8919bdaSduboff 		gcp->gc_dma_attr_rxbuf.dma_attr_align = gcp->gc_rx_buf_align+1;
2166f8919bdaSduboff 		gcp->gc_dma_attr_rxbuf.dma_attr_sgllen = gcp->gc_rx_max_frags;
2167f8919bdaSduboff 
2168f8919bdaSduboff 		/* time out parameters */
2169f8919bdaSduboff 		gcp->gc_tx_timeout = 3*ONESEC;
2170f8919bdaSduboff 		gcp->gc_tx_timeout_interval = ONESEC;
2171*23d366e3Sduboff 		if (p->chip_type == CHIPTYPE_DP83815) {
2172*23d366e3Sduboff 			/* workaround for tx hang */
2173*23d366e3Sduboff 			gcp->gc_tx_timeout_interval = ONESEC/20; /* 50mS */
2174*23d366e3Sduboff 		}
2175f8919bdaSduboff 
2176f8919bdaSduboff 		/* MII timeout parameters */
2177f8919bdaSduboff 		gcp->gc_mii_link_watch_interval = ONESEC;
2178f8919bdaSduboff 		gcp->gc_mii_an_watch_interval   = ONESEC/5;
2179f8919bdaSduboff 		gcp->gc_mii_reset_timeout = MII_RESET_TIMEOUT;	/* 1 sec */
2180f8919bdaSduboff 		gcp->gc_mii_an_timeout = MII_AN_TIMEOUT;	/* 5 sec */
2181f8919bdaSduboff 		gcp->gc_mii_an_wait = 0;
2182f8919bdaSduboff 		gcp->gc_mii_linkdown_timeout = MII_LINKDOWN_TIMEOUT;
2183f8919bdaSduboff 
2184f8919bdaSduboff 		/* setting for general PHY */
2185f8919bdaSduboff 		gcp->gc_mii_an_delay = 0;
2186f8919bdaSduboff 		gcp->gc_mii_linkdown_action = MII_ACTION_RSA;
2187f8919bdaSduboff 		gcp->gc_mii_linkdown_timeout_action = MII_ACTION_RESET;
2188f8919bdaSduboff 		gcp->gc_mii_dont_reset = B_FALSE;
2189f8919bdaSduboff 
2190f8919bdaSduboff 
2191f8919bdaSduboff 		/* I/O methods */
2192f8919bdaSduboff 
2193f8919bdaSduboff 		/* mac operation */
2194f8919bdaSduboff 		gcp->gc_attach_chip = &sfe_attach_chip;
2195f8919bdaSduboff 		if (p->chip_type == CHIPTYPE_DP83815) {
2196f8919bdaSduboff 			gcp->gc_reset_chip = &sfe_reset_chip_dp83815;
2197f8919bdaSduboff 		} else {
2198f8919bdaSduboff 			gcp->gc_reset_chip = &sfe_reset_chip_sis900;
2199f8919bdaSduboff 		}
2200f8919bdaSduboff 		gcp->gc_init_chip  = &sfe_init_chip;
2201f8919bdaSduboff 		gcp->gc_start_chip = &sfe_start_chip;
2202f8919bdaSduboff 		gcp->gc_stop_chip  = &sfe_stop_chip;
2203f8919bdaSduboff #ifdef USE_MULTICAST_HASHTBL
2204f8919bdaSduboff 		gcp->gc_multicast_hash = &sfe_mcast_hash;
2205f8919bdaSduboff #endif
2206f8919bdaSduboff 		if (p->chip_type == CHIPTYPE_DP83815) {
2207f8919bdaSduboff 			gcp->gc_set_rx_filter = &sfe_set_rx_filter_dp83815;
2208f8919bdaSduboff 		} else {
2209f8919bdaSduboff 			gcp->gc_set_rx_filter = &sfe_set_rx_filter_sis900;
2210f8919bdaSduboff 		}
2211f8919bdaSduboff 		gcp->gc_set_media = &sfe_set_media;
2212f8919bdaSduboff 		gcp->gc_get_stats = &sfe_get_stats;
2213f8919bdaSduboff 		gcp->gc_interrupt = &sfe_interrupt;
2214f8919bdaSduboff 
2215f8919bdaSduboff 		/* descriptor operation */
2216f8919bdaSduboff 		gcp->gc_tx_desc_write = &sfe_tx_desc_write;
2217f8919bdaSduboff 		gcp->gc_tx_start = &sfe_tx_start;
2218f8919bdaSduboff 		gcp->gc_rx_desc_write = &sfe_rx_desc_write;
2219f8919bdaSduboff 		gcp->gc_rx_start = NULL;
2220f8919bdaSduboff 
2221f8919bdaSduboff 		gcp->gc_tx_desc_stat = &sfe_tx_desc_stat;
2222f8919bdaSduboff 		gcp->gc_rx_desc_stat = &sfe_rx_desc_stat;
2223f8919bdaSduboff 		gcp->gc_tx_desc_init = &sfe_tx_desc_init;
2224f8919bdaSduboff 		gcp->gc_rx_desc_init = &sfe_rx_desc_init;
2225f8919bdaSduboff 		gcp->gc_tx_desc_clean = &sfe_tx_desc_clean;
2226f8919bdaSduboff 		gcp->gc_rx_desc_clean = &sfe_rx_desc_clean;
2227f8919bdaSduboff 
2228f8919bdaSduboff 		/* mii operations */
2229f8919bdaSduboff 		if (p->chip_type == CHIPTYPE_DP83815) {
2230*23d366e3Sduboff 			gcp->gc_mii_probe = &sfe_mii_probe_dp83815;
2231*23d366e3Sduboff 			gcp->gc_mii_init = &sfe_mii_init_dp83815;
2232f8919bdaSduboff 			gcp->gc_mii_config = &sfe_mii_config_dp83815;
2233f8919bdaSduboff 			gcp->gc_mii_sync = &sfe_mii_sync_dp83815;
2234f8919bdaSduboff 			gcp->gc_mii_read = &sfe_mii_read_dp83815;
2235f8919bdaSduboff 			gcp->gc_mii_write = &sfe_mii_write_dp83815;
2236f8919bdaSduboff 			gcp->gc_mii_tune_phy = NULL;
2237f8919bdaSduboff 			gcp->gc_flow_control = FLOW_CONTROL_NONE;
2238f8919bdaSduboff 		} else {
2239f8919bdaSduboff 			gcp->gc_mii_probe = &gem_mii_probe_default;
2240f8919bdaSduboff 			gcp->gc_mii_init = NULL;
2241f8919bdaSduboff 			gcp->gc_mii_config = &sfe_mii_config_sis900;
2242f8919bdaSduboff 			gcp->gc_mii_sync = &sfe_mii_sync_sis900;
2243f8919bdaSduboff 			gcp->gc_mii_read = &sfe_mii_read_sis900;
2244f8919bdaSduboff 			gcp->gc_mii_write = &sfe_mii_write_sis900;
2245f8919bdaSduboff 			gcp->gc_mii_tune_phy = &sfe_set_eq_sis630;
2246f8919bdaSduboff 			gcp->gc_flow_control = FLOW_CONTROL_RX_PAUSE;
2247f8919bdaSduboff 		}
2248f8919bdaSduboff 
2249f8919bdaSduboff 		lp = kmem_zalloc(sizeof (*lp), KM_SLEEP);
2250f8919bdaSduboff 		lp->chip = p;
2251f8919bdaSduboff 		lp->revid = rev;
2252*23d366e3Sduboff 		lp->our_intr_bits = 0;
2253*23d366e3Sduboff 		lp->isr_pended = 0;
2254f8919bdaSduboff 
2255f8919bdaSduboff 		cmn_err(CE_CONT, CONS "%s%d: chip:%s rev:0x%02x",
2256f8919bdaSduboff 		    drv_name, unit, p->chip_name, rev);
2257f8919bdaSduboff 
2258f8919bdaSduboff 		dp = gem_do_attach(dip, 0, gcp, base, &regs_ha,
2259f8919bdaSduboff 		    lp, sizeof (*lp));
2260f8919bdaSduboff 		kmem_free(gcp, sizeof (*gcp));
2261f8919bdaSduboff 
2262f8919bdaSduboff 		if (dp == NULL) {
2263f8919bdaSduboff 			goto err_freelp;
2264f8919bdaSduboff 		}
2265f8919bdaSduboff 
2266f8919bdaSduboff 		return (DDI_SUCCESS);
2267f8919bdaSduboff 
2268f8919bdaSduboff err_freelp:
2269f8919bdaSduboff 		kmem_free(lp, sizeof (struct sfe_dev));
2270f8919bdaSduboff err:
2271f8919bdaSduboff 		return (DDI_FAILURE);
2272f8919bdaSduboff 	}
2273f8919bdaSduboff 	return (DDI_FAILURE);
2274f8919bdaSduboff }
2275f8919bdaSduboff 
2276f8919bdaSduboff static int
2277f8919bdaSduboff sfedetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
2278f8919bdaSduboff {
2279f8919bdaSduboff 	switch (cmd) {
2280f8919bdaSduboff 	case DDI_SUSPEND:
2281f8919bdaSduboff 		return (gem_suspend(dip));
2282f8919bdaSduboff 
2283f8919bdaSduboff 	case DDI_DETACH:
2284f8919bdaSduboff 		return (gem_do_detach(dip));
2285f8919bdaSduboff 	}
2286f8919bdaSduboff 	return (DDI_FAILURE);
2287f8919bdaSduboff }
2288f8919bdaSduboff 
2289f8919bdaSduboff /* ======================================================== */
2290f8919bdaSduboff /*
2291f8919bdaSduboff  * OS depend (loadable streams driver) routine
2292f8919bdaSduboff  */
2293f8919bdaSduboff /* ======================================================== */
2294f8919bdaSduboff DDI_DEFINE_STREAM_OPS(sfe_ops, nulldev, nulldev, sfeattach, sfedetach,
2295f8919bdaSduboff     nodev, NULL, D_MP, NULL);
2296f8919bdaSduboff 
2297f8919bdaSduboff static struct modldrv modldrv = {
2298f8919bdaSduboff 	&mod_driverops,	/* Type of module.  This one is a driver */
2299f8919bdaSduboff 	ident,
2300f8919bdaSduboff 	&sfe_ops,	/* driver ops */
2301f8919bdaSduboff };
2302f8919bdaSduboff 
2303f8919bdaSduboff static struct modlinkage modlinkage = {
2304f8919bdaSduboff 	MODREV_1, &modldrv, NULL
2305f8919bdaSduboff };
2306f8919bdaSduboff 
2307f8919bdaSduboff /* ======================================================== */
2308f8919bdaSduboff /*
2309f8919bdaSduboff  * Loadable module support
2310f8919bdaSduboff  */
2311f8919bdaSduboff /* ======================================================== */
2312f8919bdaSduboff int
2313f8919bdaSduboff _init(void)
2314f8919bdaSduboff {
2315f8919bdaSduboff 	int 	status;
2316f8919bdaSduboff 
2317f8919bdaSduboff 	DPRINTF(2, (CE_CONT, CONS "sfe: _init: called"));
2318f8919bdaSduboff 	gem_mod_init(&sfe_ops, "sfe");
2319f8919bdaSduboff 	status = mod_install(&modlinkage);
2320f8919bdaSduboff 	if (status != DDI_SUCCESS) {
2321f8919bdaSduboff 		gem_mod_fini(&sfe_ops);
2322f8919bdaSduboff 	}
2323f8919bdaSduboff 	return (status);
2324f8919bdaSduboff }
2325f8919bdaSduboff 
2326f8919bdaSduboff /*
2327f8919bdaSduboff  * _fini : done
2328f8919bdaSduboff  */
2329f8919bdaSduboff int
2330f8919bdaSduboff _fini(void)
2331f8919bdaSduboff {
2332f8919bdaSduboff 	int	status;
2333f8919bdaSduboff 
2334f8919bdaSduboff 	DPRINTF(2, (CE_CONT, CONS "sfe: _fini: called"));
2335f8919bdaSduboff 	status = mod_remove(&modlinkage);
2336f8919bdaSduboff 	if (status == DDI_SUCCESS) {
2337f8919bdaSduboff 		gem_mod_fini(&sfe_ops);
2338f8919bdaSduboff 	}
2339f8919bdaSduboff 	return (status);
2340f8919bdaSduboff }
2341f8919bdaSduboff 
2342f8919bdaSduboff int
2343f8919bdaSduboff _info(struct modinfo *modinfop)
2344f8919bdaSduboff {
2345f8919bdaSduboff 	return (mod_info(&modlinkage, modinfop));
2346f8919bdaSduboff }
2347