xref: /illumos-gate/usr/src/uts/common/io/rge/rge_chip.c (revision 75d94465dbafa487b716482dc36d5150a4ec9853)
1c7fd2ed0Sgs150176 /*
2c7fd2ed0Sgs150176  * CDDL HEADER START
3c7fd2ed0Sgs150176  *
4c7fd2ed0Sgs150176  * The contents of this file are subject to the terms of the
5ba2e4443Sseb  * Common Development and Distribution License (the "License").
6ba2e4443Sseb  * You may not use this file except in compliance with the License.
7c7fd2ed0Sgs150176  *
8c7fd2ed0Sgs150176  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9c7fd2ed0Sgs150176  * or http://www.opensolaris.org/os/licensing.
10c7fd2ed0Sgs150176  * See the License for the specific language governing permissions
11c7fd2ed0Sgs150176  * and limitations under the License.
12c7fd2ed0Sgs150176  *
13c7fd2ed0Sgs150176  * When distributing Covered Code, include this CDDL HEADER in each
14c7fd2ed0Sgs150176  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15c7fd2ed0Sgs150176  * If applicable, add the following below this CDDL HEADER, with the
16c7fd2ed0Sgs150176  * fields enclosed by brackets "[]" replaced with your own identifying
17c7fd2ed0Sgs150176  * information: Portions Copyright [yyyy] [name of copyright owner]
18c7fd2ed0Sgs150176  *
19c7fd2ed0Sgs150176  * CDDL HEADER END
20c7fd2ed0Sgs150176  */
21c7fd2ed0Sgs150176 /*
224bb4f326SLi-Zhen You  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23c7fd2ed0Sgs150176  * Use is subject to license terms.
24c7fd2ed0Sgs150176  */
25c7fd2ed0Sgs150176 
26c7fd2ed0Sgs150176 #include "rge.h"
27c7fd2ed0Sgs150176 
28c7fd2ed0Sgs150176 #define	REG32(rgep, reg)	((uint32_t *)(rgep->io_regs+(reg)))
29c7fd2ed0Sgs150176 #define	REG16(rgep, reg)	((uint16_t *)(rgep->io_regs+(reg)))
30c7fd2ed0Sgs150176 #define	REG8(rgep, reg)		((uint8_t *)(rgep->io_regs+(reg)))
31c7fd2ed0Sgs150176 #define	PIO_ADDR(rgep, offset)	((void *)(rgep->io_regs+(offset)))
32c7fd2ed0Sgs150176 
33c7fd2ed0Sgs150176 /*
34c7fd2ed0Sgs150176  * Patchable globals:
35c7fd2ed0Sgs150176  *
36c7fd2ed0Sgs150176  *	rge_autorecover
37c7fd2ed0Sgs150176  *		Enables/disables automatic recovery after fault detection
38c7fd2ed0Sgs150176  */
39c7fd2ed0Sgs150176 static uint32_t rge_autorecover = 1;
40c7fd2ed0Sgs150176 
41c7fd2ed0Sgs150176 /*
42c7fd2ed0Sgs150176  * globals:
43c7fd2ed0Sgs150176  */
44c7fd2ed0Sgs150176 #define	RGE_DBG		RGE_DBG_REGS	/* debug flag for this code	*/
459e1a9180SLi-Zhen You static uint32_t rge_watchdog_count	= 1 << 5;
467b114c4bSWinson Wang - Sun Microsystems - Beijing China static uint32_t rge_rx_watchdog_count	= 1 << 3;
47c7fd2ed0Sgs150176 
48c7fd2ed0Sgs150176 /*
49c7fd2ed0Sgs150176  * Operating register get/set access routines
50c7fd2ed0Sgs150176  */
51c7fd2ed0Sgs150176 
52c7fd2ed0Sgs150176 static uint32_t rge_reg_get32(rge_t *rgep, uintptr_t regno);
53c7fd2ed0Sgs150176 #pragma	inline(rge_reg_get32)
54c7fd2ed0Sgs150176 
55c7fd2ed0Sgs150176 static uint32_t
rge_reg_get32(rge_t * rgep,uintptr_t regno)56c7fd2ed0Sgs150176 rge_reg_get32(rge_t *rgep, uintptr_t regno)
57c7fd2ed0Sgs150176 {
58c7fd2ed0Sgs150176 	RGE_TRACE(("rge_reg_get32($%p, 0x%lx)",
59c7fd2ed0Sgs150176 	    (void *)rgep, regno));
60c7fd2ed0Sgs150176 
61c7fd2ed0Sgs150176 	return (ddi_get32(rgep->io_handle, REG32(rgep, regno)));
62c7fd2ed0Sgs150176 }
63c7fd2ed0Sgs150176 
64c7fd2ed0Sgs150176 static void rge_reg_put32(rge_t *rgep, uintptr_t regno, uint32_t data);
65c7fd2ed0Sgs150176 #pragma	inline(rge_reg_put32)
66c7fd2ed0Sgs150176 
67c7fd2ed0Sgs150176 static void
rge_reg_put32(rge_t * rgep,uintptr_t regno,uint32_t data)68c7fd2ed0Sgs150176 rge_reg_put32(rge_t *rgep, uintptr_t regno, uint32_t data)
69c7fd2ed0Sgs150176 {
70c7fd2ed0Sgs150176 	RGE_TRACE(("rge_reg_put32($%p, 0x%lx, 0x%x)",
71c7fd2ed0Sgs150176 	    (void *)rgep, regno, data));
72c7fd2ed0Sgs150176 
73c7fd2ed0Sgs150176 	ddi_put32(rgep->io_handle, REG32(rgep, regno), data);
74c7fd2ed0Sgs150176 }
75c7fd2ed0Sgs150176 
76c7fd2ed0Sgs150176 static void rge_reg_set32(rge_t *rgep, uintptr_t regno, uint32_t bits);
77c7fd2ed0Sgs150176 #pragma	inline(rge_reg_set32)
78c7fd2ed0Sgs150176 
79c7fd2ed0Sgs150176 static void
rge_reg_set32(rge_t * rgep,uintptr_t regno,uint32_t bits)80c7fd2ed0Sgs150176 rge_reg_set32(rge_t *rgep, uintptr_t regno, uint32_t bits)
81c7fd2ed0Sgs150176 {
82c7fd2ed0Sgs150176 	uint32_t regval;
83c7fd2ed0Sgs150176 
84c7fd2ed0Sgs150176 	RGE_TRACE(("rge_reg_set32($%p, 0x%lx, 0x%x)",
85c7fd2ed0Sgs150176 	    (void *)rgep, regno, bits));
86c7fd2ed0Sgs150176 
87c7fd2ed0Sgs150176 	regval = rge_reg_get32(rgep, regno);
88c7fd2ed0Sgs150176 	regval |= bits;
89c7fd2ed0Sgs150176 	rge_reg_put32(rgep, regno, regval);
90c7fd2ed0Sgs150176 }
91c7fd2ed0Sgs150176 
92c7fd2ed0Sgs150176 static void rge_reg_clr32(rge_t *rgep, uintptr_t regno, uint32_t bits);
93c7fd2ed0Sgs150176 #pragma	inline(rge_reg_clr32)
94c7fd2ed0Sgs150176 
95c7fd2ed0Sgs150176 static void
rge_reg_clr32(rge_t * rgep,uintptr_t regno,uint32_t bits)96c7fd2ed0Sgs150176 rge_reg_clr32(rge_t *rgep, uintptr_t regno, uint32_t bits)
97c7fd2ed0Sgs150176 {
98c7fd2ed0Sgs150176 	uint32_t regval;
99c7fd2ed0Sgs150176 
100c7fd2ed0Sgs150176 	RGE_TRACE(("rge_reg_clr32($%p, 0x%lx, 0x%x)",
101c7fd2ed0Sgs150176 	    (void *)rgep, regno, bits));
102c7fd2ed0Sgs150176 
103c7fd2ed0Sgs150176 	regval = rge_reg_get32(rgep, regno);
104c7fd2ed0Sgs150176 	regval &= ~bits;
105c7fd2ed0Sgs150176 	rge_reg_put32(rgep, regno, regval);
106c7fd2ed0Sgs150176 }
107c7fd2ed0Sgs150176 
108c7fd2ed0Sgs150176 static uint16_t rge_reg_get16(rge_t *rgep, uintptr_t regno);
109c7fd2ed0Sgs150176 #pragma	inline(rge_reg_get16)
110c7fd2ed0Sgs150176 
111c7fd2ed0Sgs150176 static uint16_t
rge_reg_get16(rge_t * rgep,uintptr_t regno)112c7fd2ed0Sgs150176 rge_reg_get16(rge_t *rgep, uintptr_t regno)
113c7fd2ed0Sgs150176 {
114c7fd2ed0Sgs150176 	RGE_TRACE(("rge_reg_get16($%p, 0x%lx)",
115c7fd2ed0Sgs150176 	    (void *)rgep, regno));
116c7fd2ed0Sgs150176 
117c7fd2ed0Sgs150176 	return (ddi_get16(rgep->io_handle, REG16(rgep, regno)));
118c7fd2ed0Sgs150176 }
119c7fd2ed0Sgs150176 
120c7fd2ed0Sgs150176 static void rge_reg_put16(rge_t *rgep, uintptr_t regno, uint16_t data);
121c7fd2ed0Sgs150176 #pragma	inline(rge_reg_put16)
122c7fd2ed0Sgs150176 
123c7fd2ed0Sgs150176 static void
rge_reg_put16(rge_t * rgep,uintptr_t regno,uint16_t data)124c7fd2ed0Sgs150176 rge_reg_put16(rge_t *rgep, uintptr_t regno, uint16_t data)
125c7fd2ed0Sgs150176 {
126c7fd2ed0Sgs150176 	RGE_TRACE(("rge_reg_put16($%p, 0x%lx, 0x%x)",
127c7fd2ed0Sgs150176 	    (void *)rgep, regno, data));
128c7fd2ed0Sgs150176 
129c7fd2ed0Sgs150176 	ddi_put16(rgep->io_handle, REG16(rgep, regno), data);
130c7fd2ed0Sgs150176 }
131c7fd2ed0Sgs150176 
132c7fd2ed0Sgs150176 static uint8_t rge_reg_get8(rge_t *rgep, uintptr_t regno);
133c7fd2ed0Sgs150176 #pragma	inline(rge_reg_get8)
134c7fd2ed0Sgs150176 
135c7fd2ed0Sgs150176 static uint8_t
rge_reg_get8(rge_t * rgep,uintptr_t regno)136c7fd2ed0Sgs150176 rge_reg_get8(rge_t *rgep, uintptr_t regno)
137c7fd2ed0Sgs150176 {
138c7fd2ed0Sgs150176 	RGE_TRACE(("rge_reg_get8($%p, 0x%lx)",
139c7fd2ed0Sgs150176 	    (void *)rgep, regno));
140c7fd2ed0Sgs150176 
141c7fd2ed0Sgs150176 	return (ddi_get8(rgep->io_handle, REG8(rgep, regno)));
142c7fd2ed0Sgs150176 }
143c7fd2ed0Sgs150176 
144c7fd2ed0Sgs150176 static void rge_reg_put8(rge_t *rgep, uintptr_t regno, uint8_t data);
145c7fd2ed0Sgs150176 #pragma	inline(rge_reg_put8)
146c7fd2ed0Sgs150176 
147c7fd2ed0Sgs150176 static void
rge_reg_put8(rge_t * rgep,uintptr_t regno,uint8_t data)148c7fd2ed0Sgs150176 rge_reg_put8(rge_t *rgep, uintptr_t regno, uint8_t data)
149c7fd2ed0Sgs150176 {
150c7fd2ed0Sgs150176 	RGE_TRACE(("rge_reg_put8($%p, 0x%lx, 0x%x)",
151c7fd2ed0Sgs150176 	    (void *)rgep, regno, data));
152c7fd2ed0Sgs150176 
153c7fd2ed0Sgs150176 	ddi_put8(rgep->io_handle, REG8(rgep, regno), data);
154c7fd2ed0Sgs150176 }
155c7fd2ed0Sgs150176 
156c7fd2ed0Sgs150176 static void rge_reg_set8(rge_t *rgep, uintptr_t regno, uint8_t bits);
157c7fd2ed0Sgs150176 #pragma	inline(rge_reg_set8)
158c7fd2ed0Sgs150176 
159c7fd2ed0Sgs150176 static void
rge_reg_set8(rge_t * rgep,uintptr_t regno,uint8_t bits)160c7fd2ed0Sgs150176 rge_reg_set8(rge_t *rgep, uintptr_t regno, uint8_t bits)
161c7fd2ed0Sgs150176 {
162c7fd2ed0Sgs150176 	uint8_t regval;
163c7fd2ed0Sgs150176 
164c7fd2ed0Sgs150176 	RGE_TRACE(("rge_reg_set8($%p, 0x%lx, 0x%x)",
165c7fd2ed0Sgs150176 	    (void *)rgep, regno, bits));
166c7fd2ed0Sgs150176 
167c7fd2ed0Sgs150176 	regval = rge_reg_get8(rgep, regno);
168c7fd2ed0Sgs150176 	regval |= bits;
169c7fd2ed0Sgs150176 	rge_reg_put8(rgep, regno, regval);
170c7fd2ed0Sgs150176 }
171c7fd2ed0Sgs150176 
172c7fd2ed0Sgs150176 static void rge_reg_clr8(rge_t *rgep, uintptr_t regno, uint8_t bits);
173c7fd2ed0Sgs150176 #pragma	inline(rge_reg_clr8)
174c7fd2ed0Sgs150176 
175c7fd2ed0Sgs150176 static void
rge_reg_clr8(rge_t * rgep,uintptr_t regno,uint8_t bits)176c7fd2ed0Sgs150176 rge_reg_clr8(rge_t *rgep, uintptr_t regno, uint8_t bits)
177c7fd2ed0Sgs150176 {
178c7fd2ed0Sgs150176 	uint8_t regval;
179c7fd2ed0Sgs150176 
180c7fd2ed0Sgs150176 	RGE_TRACE(("rge_reg_clr8($%p, 0x%lx, 0x%x)",
181c7fd2ed0Sgs150176 	    (void *)rgep, regno, bits));
182c7fd2ed0Sgs150176 
183c7fd2ed0Sgs150176 	regval = rge_reg_get8(rgep, regno);
184c7fd2ed0Sgs150176 	regval &= ~bits;
185c7fd2ed0Sgs150176 	rge_reg_put8(rgep, regno, regval);
186c7fd2ed0Sgs150176 }
187c7fd2ed0Sgs150176 
188c7fd2ed0Sgs150176 uint16_t rge_mii_get16(rge_t *rgep, uintptr_t mii);
189c7fd2ed0Sgs150176 #pragma	no_inline(rge_mii_get16)
190c7fd2ed0Sgs150176 
191c7fd2ed0Sgs150176 uint16_t
rge_mii_get16(rge_t * rgep,uintptr_t mii)192c7fd2ed0Sgs150176 rge_mii_get16(rge_t *rgep, uintptr_t mii)
193c7fd2ed0Sgs150176 {
194c7fd2ed0Sgs150176 	uint32_t regval;
195c7fd2ed0Sgs150176 	uint32_t val32;
196c7fd2ed0Sgs150176 	uint32_t i;
197c7fd2ed0Sgs150176 
198c7fd2ed0Sgs150176 	regval = (mii & PHY_REG_MASK) << PHY_REG_SHIFT;
199c7fd2ed0Sgs150176 	rge_reg_put32(rgep, PHY_ACCESS_REG, regval);
200c7fd2ed0Sgs150176 
201c7fd2ed0Sgs150176 	/*
202c7fd2ed0Sgs150176 	 * Waiting for PHY reading OK
203c7fd2ed0Sgs150176 	 */
204c7fd2ed0Sgs150176 	for (i = 0; i < PHY_RESET_LOOP; i++) {
20552643194Sgs150176 		drv_usecwait(1000);
206c7fd2ed0Sgs150176 		val32 = rge_reg_get32(rgep, PHY_ACCESS_REG);
207c7fd2ed0Sgs150176 		if (val32 & PHY_ACCESS_WR_FLAG)
208aa817493Sgs150176 			return ((uint16_t)(val32 & 0xffff));
209c7fd2ed0Sgs150176 	}
210c7fd2ed0Sgs150176 
211c7fd2ed0Sgs150176 	RGE_REPORT((rgep, "rge_mii_get16(0x%x) fail, val = %x", mii, val32));
212c7fd2ed0Sgs150176 	return ((uint16_t)~0u);
213c7fd2ed0Sgs150176 }
214c7fd2ed0Sgs150176 
215c7fd2ed0Sgs150176 void rge_mii_put16(rge_t *rgep, uintptr_t mii, uint16_t data);
216c7fd2ed0Sgs150176 #pragma	no_inline(rge_mii_put16)
217c7fd2ed0Sgs150176 
218c7fd2ed0Sgs150176 void
rge_mii_put16(rge_t * rgep,uintptr_t mii,uint16_t data)219c7fd2ed0Sgs150176 rge_mii_put16(rge_t *rgep, uintptr_t mii, uint16_t data)
220c7fd2ed0Sgs150176 {
221c7fd2ed0Sgs150176 	uint32_t regval;
222c7fd2ed0Sgs150176 	uint32_t val32;
223c7fd2ed0Sgs150176 	uint32_t i;
224c7fd2ed0Sgs150176 
225c7fd2ed0Sgs150176 	regval = (mii & PHY_REG_MASK) << PHY_REG_SHIFT;
226c7fd2ed0Sgs150176 	regval |= data & PHY_DATA_MASK;
227c7fd2ed0Sgs150176 	regval |= PHY_ACCESS_WR_FLAG;
228c7fd2ed0Sgs150176 	rge_reg_put32(rgep, PHY_ACCESS_REG, regval);
229c7fd2ed0Sgs150176 
230c7fd2ed0Sgs150176 	/*
231c7fd2ed0Sgs150176 	 * Waiting for PHY writing OK
232c7fd2ed0Sgs150176 	 */
233c7fd2ed0Sgs150176 	for (i = 0; i < PHY_RESET_LOOP; i++) {
23452643194Sgs150176 		drv_usecwait(1000);
235c7fd2ed0Sgs150176 		val32 = rge_reg_get32(rgep, PHY_ACCESS_REG);
236c7fd2ed0Sgs150176 		if (!(val32 & PHY_ACCESS_WR_FLAG))
237c7fd2ed0Sgs150176 			return;
238c7fd2ed0Sgs150176 	}
239c7fd2ed0Sgs150176 	RGE_REPORT((rgep, "rge_mii_put16(0x%lx, 0x%x) fail",
240c7fd2ed0Sgs150176 	    mii, data));
241c7fd2ed0Sgs150176 }
242c7fd2ed0Sgs150176 
243aa817493Sgs150176 void rge_ephy_put16(rge_t *rgep, uintptr_t emii, uint16_t data);
244aa817493Sgs150176 #pragma	no_inline(rge_ephy_put16)
245aa817493Sgs150176 
246aa817493Sgs150176 void
rge_ephy_put16(rge_t * rgep,uintptr_t emii,uint16_t data)247aa817493Sgs150176 rge_ephy_put16(rge_t *rgep, uintptr_t emii, uint16_t data)
248aa817493Sgs150176 {
249aa817493Sgs150176 	uint32_t regval;
250aa817493Sgs150176 	uint32_t val32;
251aa817493Sgs150176 	uint32_t i;
252aa817493Sgs150176 
253aa817493Sgs150176 	regval = (emii & EPHY_REG_MASK) << EPHY_REG_SHIFT;
254aa817493Sgs150176 	regval |= data & EPHY_DATA_MASK;
255aa817493Sgs150176 	regval |= EPHY_ACCESS_WR_FLAG;
256aa817493Sgs150176 	rge_reg_put32(rgep, EPHY_ACCESS_REG, regval);
257aa817493Sgs150176 
258aa817493Sgs150176 	/*
259aa817493Sgs150176 	 * Waiting for PHY writing OK
260aa817493Sgs150176 	 */
261aa817493Sgs150176 	for (i = 0; i < PHY_RESET_LOOP; i++) {
26252643194Sgs150176 		drv_usecwait(1000);
263aa817493Sgs150176 		val32 = rge_reg_get32(rgep, EPHY_ACCESS_REG);
264aa817493Sgs150176 		if (!(val32 & EPHY_ACCESS_WR_FLAG))
265aa817493Sgs150176 			return;
266aa817493Sgs150176 	}
267aa817493Sgs150176 	RGE_REPORT((rgep, "rge_ephy_put16(0x%lx, 0x%x) fail",
268aa817493Sgs150176 	    emii, data));
269aa817493Sgs150176 }
270aa817493Sgs150176 
271c7fd2ed0Sgs150176 /*
272c7fd2ed0Sgs150176  * Atomically shift a 32-bit word left, returning
273c7fd2ed0Sgs150176  * the value it had *before* the shift was applied
274c7fd2ed0Sgs150176  */
275c7fd2ed0Sgs150176 static uint32_t rge_atomic_shl32(uint32_t *sp, uint_t count);
276c7fd2ed0Sgs150176 #pragma	inline(rge_mii_put16)
277c7fd2ed0Sgs150176 
278c7fd2ed0Sgs150176 static uint32_t
rge_atomic_shl32(uint32_t * sp,uint_t count)279c7fd2ed0Sgs150176 rge_atomic_shl32(uint32_t *sp, uint_t count)
280c7fd2ed0Sgs150176 {
281c7fd2ed0Sgs150176 	uint32_t oldval;
282c7fd2ed0Sgs150176 	uint32_t newval;
283c7fd2ed0Sgs150176 
284c7fd2ed0Sgs150176 	/* ATOMICALLY */
285c7fd2ed0Sgs150176 	do {
286c7fd2ed0Sgs150176 		oldval = *sp;
287c7fd2ed0Sgs150176 		newval = oldval << count;
288*75d94465SJosef 'Jeff' Sipek 	} while (atomic_cas_32(sp, oldval, newval) != oldval);
289c7fd2ed0Sgs150176 
290c7fd2ed0Sgs150176 	return (oldval);
291c7fd2ed0Sgs150176 }
292c7fd2ed0Sgs150176 
293c7fd2ed0Sgs150176 /*
294c7fd2ed0Sgs150176  * PHY operation routines
295c7fd2ed0Sgs150176  */
296c7fd2ed0Sgs150176 #if	RGE_DEBUGGING
297c7fd2ed0Sgs150176 
29822eb7cb5Sgd78059 void
rge_phydump(rge_t * rgep)299c7fd2ed0Sgs150176 rge_phydump(rge_t *rgep)
300c7fd2ed0Sgs150176 {
301c7fd2ed0Sgs150176 	uint16_t regs[32];
302c7fd2ed0Sgs150176 	int i;
303c7fd2ed0Sgs150176 
304c7fd2ed0Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
305c7fd2ed0Sgs150176 
306c7fd2ed0Sgs150176 	for (i = 0; i < 32; ++i) {
307c7fd2ed0Sgs150176 		regs[i] = rge_mii_get16(rgep, i);
308c7fd2ed0Sgs150176 	}
309c7fd2ed0Sgs150176 
310c7fd2ed0Sgs150176 	for (i = 0; i < 32; i += 8)
311c7fd2ed0Sgs150176 		RGE_DEBUG(("rge_phydump: "
312c7fd2ed0Sgs150176 		    "0x%04x %04x %04x %04x %04x %04x %04x %04x",
313c7fd2ed0Sgs150176 		    regs[i+0], regs[i+1], regs[i+2], regs[i+3],
314c7fd2ed0Sgs150176 		    regs[i+4], regs[i+5], regs[i+6], regs[i+7]));
315c7fd2ed0Sgs150176 }
316c7fd2ed0Sgs150176 
317c7fd2ed0Sgs150176 #endif	/* RGE_DEBUGGING */
318c7fd2ed0Sgs150176 
319c7fd2ed0Sgs150176 static void
rge_phy_check(rge_t * rgep)320c7fd2ed0Sgs150176 rge_phy_check(rge_t *rgep)
321c7fd2ed0Sgs150176 {
322c7fd2ed0Sgs150176 	uint16_t gig_ctl;
323c7fd2ed0Sgs150176 
324c7fd2ed0Sgs150176 	if (rgep->param_link_up  == LINK_STATE_DOWN) {
325c7fd2ed0Sgs150176 		/*
326c7fd2ed0Sgs150176 		 * RTL8169S/8110S PHY has the "PCS bug".  Need reset PHY
327c7fd2ed0Sgs150176 		 * every 15 seconds whin link down & advertise is 1000.
328c7fd2ed0Sgs150176 		 */
329c7fd2ed0Sgs150176 		if (rgep->chipid.phy_ver == PHY_VER_S) {
330c7fd2ed0Sgs150176 			gig_ctl = rge_mii_get16(rgep, MII_1000BASE_T_CONTROL);
331c7fd2ed0Sgs150176 			if (gig_ctl & MII_1000BT_CTL_ADV_FDX) {
332c7fd2ed0Sgs150176 				rgep->link_down_count++;
333c7fd2ed0Sgs150176 				if (rgep->link_down_count > 15) {
334c7fd2ed0Sgs150176 					(void) rge_phy_reset(rgep);
335c7fd2ed0Sgs150176 					rgep->stats.phy_reset++;
336c7fd2ed0Sgs150176 					rgep->link_down_count = 0;
337c7fd2ed0Sgs150176 				}
338c7fd2ed0Sgs150176 			}
339c7fd2ed0Sgs150176 		}
340c7fd2ed0Sgs150176 	} else {
341c7fd2ed0Sgs150176 		rgep->link_down_count = 0;
342c7fd2ed0Sgs150176 	}
343c7fd2ed0Sgs150176 }
344c7fd2ed0Sgs150176 
345c7fd2ed0Sgs150176 /*
346c7fd2ed0Sgs150176  * Basic low-level function to reset the PHY.
347c7fd2ed0Sgs150176  * Doesn't incorporate any special-case workarounds.
348c7fd2ed0Sgs150176  *
349c7fd2ed0Sgs150176  * Returns TRUE on success, FALSE if the RESET bit doesn't clear
350c7fd2ed0Sgs150176  */
351c7fd2ed0Sgs150176 boolean_t
rge_phy_reset(rge_t * rgep)352c7fd2ed0Sgs150176 rge_phy_reset(rge_t *rgep)
353c7fd2ed0Sgs150176 {
354c7fd2ed0Sgs150176 	uint16_t control;
355c7fd2ed0Sgs150176 	uint_t count;
356c7fd2ed0Sgs150176 
357c7fd2ed0Sgs150176 	/*
358c7fd2ed0Sgs150176 	 * Set the PHY RESET bit, then wait up to 5 ms for it to self-clear
359c7fd2ed0Sgs150176 	 */
360c7fd2ed0Sgs150176 	control = rge_mii_get16(rgep, MII_CONTROL);
361c7fd2ed0Sgs150176 	rge_mii_put16(rgep, MII_CONTROL, control | MII_CONTROL_RESET);
36252643194Sgs150176 	for (count = 0; count < 5; count++) {
363c7fd2ed0Sgs150176 		drv_usecwait(100);
364c7fd2ed0Sgs150176 		control = rge_mii_get16(rgep, MII_CONTROL);
365c7fd2ed0Sgs150176 		if (BIC(control, MII_CONTROL_RESET))
366c7fd2ed0Sgs150176 			return (B_TRUE);
367c7fd2ed0Sgs150176 	}
368c7fd2ed0Sgs150176 
369c7fd2ed0Sgs150176 	RGE_REPORT((rgep, "rge_phy_reset: FAILED, control now 0x%x", control));
370c7fd2ed0Sgs150176 	return (B_FALSE);
371c7fd2ed0Sgs150176 }
372c7fd2ed0Sgs150176 
373c7fd2ed0Sgs150176 /*
374c7fd2ed0Sgs150176  * Synchronise the PHY's speed/duplex/autonegotiation capabilities
375c7fd2ed0Sgs150176  * and advertisements with the required settings as specified by the various
376c7fd2ed0Sgs150176  * param_* variables that can be poked via the NDD interface.
377c7fd2ed0Sgs150176  *
378c7fd2ed0Sgs150176  * We always reset the PHY and reprogram *all* the relevant registers,
379c7fd2ed0Sgs150176  * not just those changed.  This should cause the link to go down, and then
380c7fd2ed0Sgs150176  * back up again once the link is stable and autonegotiation (if enabled)
381c7fd2ed0Sgs150176  * is complete.  We should get a link state change interrupt somewhere along
382c7fd2ed0Sgs150176  * the way ...
383c7fd2ed0Sgs150176  *
384c7fd2ed0Sgs150176  * NOTE: <genlock> must already be held by the caller
385c7fd2ed0Sgs150176  */
386c7fd2ed0Sgs150176 void
rge_phy_update(rge_t * rgep)387c7fd2ed0Sgs150176 rge_phy_update(rge_t *rgep)
388c7fd2ed0Sgs150176 {
389c7fd2ed0Sgs150176 	boolean_t adv_autoneg;
390c7fd2ed0Sgs150176 	boolean_t adv_pause;
391c7fd2ed0Sgs150176 	boolean_t adv_asym_pause;
392c7fd2ed0Sgs150176 	boolean_t adv_1000fdx;
393c7fd2ed0Sgs150176 	boolean_t adv_1000hdx;
394c7fd2ed0Sgs150176 	boolean_t adv_100fdx;
395c7fd2ed0Sgs150176 	boolean_t adv_100hdx;
396c7fd2ed0Sgs150176 	boolean_t adv_10fdx;
397c7fd2ed0Sgs150176 	boolean_t adv_10hdx;
398c7fd2ed0Sgs150176 
399c7fd2ed0Sgs150176 	uint16_t control;
400c7fd2ed0Sgs150176 	uint16_t gigctrl;
401c7fd2ed0Sgs150176 	uint16_t anar;
402c7fd2ed0Sgs150176 
403c7fd2ed0Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
404c7fd2ed0Sgs150176 
405c7fd2ed0Sgs150176 	RGE_DEBUG(("rge_phy_update: autoneg %d "
406c7fd2ed0Sgs150176 	    "pause %d asym_pause %d "
407c7fd2ed0Sgs150176 	    "1000fdx %d 1000hdx %d "
408c7fd2ed0Sgs150176 	    "100fdx %d 100hdx %d "
409c7fd2ed0Sgs150176 	    "10fdx %d 10hdx %d ",
410c7fd2ed0Sgs150176 	    rgep->param_adv_autoneg,
411c7fd2ed0Sgs150176 	    rgep->param_adv_pause, rgep->param_adv_asym_pause,
412c7fd2ed0Sgs150176 	    rgep->param_adv_1000fdx, rgep->param_adv_1000hdx,
413c7fd2ed0Sgs150176 	    rgep->param_adv_100fdx, rgep->param_adv_100hdx,
414c7fd2ed0Sgs150176 	    rgep->param_adv_10fdx, rgep->param_adv_10hdx));
415c7fd2ed0Sgs150176 
416c7fd2ed0Sgs150176 	control = gigctrl = anar = 0;
417c7fd2ed0Sgs150176 
418c7fd2ed0Sgs150176 	/*
419c7fd2ed0Sgs150176 	 * PHY settings are normally based on the param_* variables,
420c7fd2ed0Sgs150176 	 * but if any loopback mode is in effect, that takes precedence.
421c7fd2ed0Sgs150176 	 *
422c7fd2ed0Sgs150176 	 * RGE supports MAC-internal loopback, PHY-internal loopback,
423c7fd2ed0Sgs150176 	 * and External loopback at a variety of speeds (with a special
424c7fd2ed0Sgs150176 	 * cable).  In all cases, autoneg is turned OFF, full-duplex
425c7fd2ed0Sgs150176 	 * is turned ON, and the speed/mastership is forced.
426c7fd2ed0Sgs150176 	 */
427c7fd2ed0Sgs150176 	switch (rgep->param_loop_mode) {
428c7fd2ed0Sgs150176 	case RGE_LOOP_NONE:
429c7fd2ed0Sgs150176 	default:
430c7fd2ed0Sgs150176 		adv_autoneg = rgep->param_adv_autoneg;
431c7fd2ed0Sgs150176 		adv_pause = rgep->param_adv_pause;
432c7fd2ed0Sgs150176 		adv_asym_pause = rgep->param_adv_asym_pause;
433c7fd2ed0Sgs150176 		adv_1000fdx = rgep->param_adv_1000fdx;
434c7fd2ed0Sgs150176 		adv_1000hdx = rgep->param_adv_1000hdx;
435c7fd2ed0Sgs150176 		adv_100fdx = rgep->param_adv_100fdx;
436c7fd2ed0Sgs150176 		adv_100hdx = rgep->param_adv_100hdx;
437c7fd2ed0Sgs150176 		adv_10fdx = rgep->param_adv_10fdx;
438c7fd2ed0Sgs150176 		adv_10hdx = rgep->param_adv_10hdx;
439c7fd2ed0Sgs150176 		break;
440c7fd2ed0Sgs150176 
441c7fd2ed0Sgs150176 	case RGE_LOOP_INTERNAL_PHY:
442c7fd2ed0Sgs150176 	case RGE_LOOP_INTERNAL_MAC:
443c7fd2ed0Sgs150176 		adv_autoneg = adv_pause = adv_asym_pause = B_FALSE;
444c7fd2ed0Sgs150176 		adv_1000fdx = adv_100fdx = adv_10fdx = B_FALSE;
445c7fd2ed0Sgs150176 		adv_1000hdx = adv_100hdx = adv_10hdx = B_FALSE;
446c7fd2ed0Sgs150176 		rgep->param_link_duplex = LINK_DUPLEX_FULL;
447c7fd2ed0Sgs150176 
448c7fd2ed0Sgs150176 		switch (rgep->param_loop_mode) {
449c7fd2ed0Sgs150176 		case RGE_LOOP_INTERNAL_PHY:
450dfc2d53eSmx205022 			if (rgep->chipid.mac_ver != MAC_VER_8101E) {
451c7fd2ed0Sgs150176 				rgep->param_link_speed = 1000;
452c7fd2ed0Sgs150176 				adv_1000fdx = B_TRUE;
453dfc2d53eSmx205022 			} else {
454dfc2d53eSmx205022 				rgep->param_link_speed = 100;
455dfc2d53eSmx205022 				adv_100fdx = B_TRUE;
456dfc2d53eSmx205022 			}
457c7fd2ed0Sgs150176 			control = MII_CONTROL_LOOPBACK;
458c7fd2ed0Sgs150176 			break;
459c7fd2ed0Sgs150176 
460c7fd2ed0Sgs150176 		case RGE_LOOP_INTERNAL_MAC:
461dfc2d53eSmx205022 			if (rgep->chipid.mac_ver != MAC_VER_8101E) {
462c7fd2ed0Sgs150176 				rgep->param_link_speed = 1000;
463c7fd2ed0Sgs150176 				adv_1000fdx = B_TRUE;
464dfc2d53eSmx205022 			} else {
465dfc2d53eSmx205022 				rgep->param_link_speed = 100;
466dfc2d53eSmx205022 				adv_100fdx = B_TRUE;
467c7fd2ed0Sgs150176 			break;
468c7fd2ed0Sgs150176 		}
469c7fd2ed0Sgs150176 	}
470c7fd2ed0Sgs150176 
471c7fd2ed0Sgs150176 	RGE_DEBUG(("rge_phy_update: autoneg %d "
472c7fd2ed0Sgs150176 	    "pause %d asym_pause %d "
473c7fd2ed0Sgs150176 	    "1000fdx %d 1000hdx %d "
474c7fd2ed0Sgs150176 	    "100fdx %d 100hdx %d "
475c7fd2ed0Sgs150176 	    "10fdx %d 10hdx %d ",
476c7fd2ed0Sgs150176 	    adv_autoneg,
477c7fd2ed0Sgs150176 	    adv_pause, adv_asym_pause,
478c7fd2ed0Sgs150176 	    adv_1000fdx, adv_1000hdx,
479c7fd2ed0Sgs150176 	    adv_100fdx, adv_100hdx,
480c7fd2ed0Sgs150176 	    adv_10fdx, adv_10hdx));
481c7fd2ed0Sgs150176 
482c7fd2ed0Sgs150176 	/*
483c7fd2ed0Sgs150176 	 * We should have at least one technology capability set;
484c7fd2ed0Sgs150176 	 * if not, we select a default of 1000Mb/s full-duplex
485c7fd2ed0Sgs150176 	 */
486c7fd2ed0Sgs150176 	if (!adv_1000fdx && !adv_100fdx && !adv_10fdx &&
487dfc2d53eSmx205022 	    !adv_1000hdx && !adv_100hdx && !adv_10hdx) {
488dfc2d53eSmx205022 		if (rgep->chipid.mac_ver != MAC_VER_8101E)
489c7fd2ed0Sgs150176 			adv_1000fdx = B_TRUE;
490dfc2d53eSmx205022 		} else {
491dfc2d53eSmx205022 			adv_1000fdx = B_FALSE;
492dfc2d53eSmx205022 			adv_100fdx = B_TRUE;
493dfc2d53eSmx205022 		}
494dfc2d53eSmx205022 	}
495c7fd2ed0Sgs150176 
496c7fd2ed0Sgs150176 	/*
497c7fd2ed0Sgs150176 	 * Now transform the adv_* variables into the proper settings
498c7fd2ed0Sgs150176 	 * of the PHY registers ...
499c7fd2ed0Sgs150176 	 *
500c7fd2ed0Sgs150176 	 * If autonegotiation is (now) enabled, we want to trigger
501c7fd2ed0Sgs150176 	 * a new autonegotiation cycle once the PHY has been
502c7fd2ed0Sgs150176 	 * programmed with the capabilities to be advertised.
503c7fd2ed0Sgs150176 	 *
504c7fd2ed0Sgs150176 	 * RTL8169/8110 doesn't support 1000Mb/s half-duplex.
505c7fd2ed0Sgs150176 	 */
506c7fd2ed0Sgs150176 	if (adv_autoneg)
507c7fd2ed0Sgs150176 		control |= MII_CONTROL_ANE|MII_CONTROL_RSAN;
508c7fd2ed0Sgs150176 
509c7fd2ed0Sgs150176 	if (adv_1000fdx)
510bdb9230aSGarrett D'Amore 		control |= MII_CONTROL_1GB|MII_CONTROL_FDUPLEX;
511c7fd2ed0Sgs150176 	else if (adv_1000hdx)
512bdb9230aSGarrett D'Amore 		control |= MII_CONTROL_1GB;
513c7fd2ed0Sgs150176 	else if (adv_100fdx)
514c7fd2ed0Sgs150176 		control |= MII_CONTROL_100MB|MII_CONTROL_FDUPLEX;
515c7fd2ed0Sgs150176 	else if (adv_100hdx)
516c7fd2ed0Sgs150176 		control |= MII_CONTROL_100MB;
517c7fd2ed0Sgs150176 	else if (adv_10fdx)
518c7fd2ed0Sgs150176 		control |= MII_CONTROL_FDUPLEX;
519c7fd2ed0Sgs150176 	else if (adv_10hdx)
520c7fd2ed0Sgs150176 		control |= 0;
521c7fd2ed0Sgs150176 	else
522c7fd2ed0Sgs150176 		{ _NOTE(EMPTY); }	/* Can't get here anyway ...	*/
523c7fd2ed0Sgs150176 
524c7fd2ed0Sgs150176 	if (adv_1000fdx) {
525c7fd2ed0Sgs150176 		gigctrl |= MII_1000BT_CTL_ADV_FDX;
526c7fd2ed0Sgs150176 		/*
527c7fd2ed0Sgs150176 		 * Chipset limitation: need set other capabilities to true
528c7fd2ed0Sgs150176 		 */
529aa817493Sgs150176 		if (rgep->chipid.is_pcie)
530aa817493Sgs150176 			adv_1000hdx = B_TRUE;
531c7fd2ed0Sgs150176 		adv_100fdx = B_TRUE;
532c7fd2ed0Sgs150176 		adv_100hdx  = B_TRUE;
533c7fd2ed0Sgs150176 		adv_10fdx = B_TRUE;
534c7fd2ed0Sgs150176 		adv_10hdx = B_TRUE;
535c7fd2ed0Sgs150176 	}
536c7fd2ed0Sgs150176 
537c7fd2ed0Sgs150176 	if (adv_1000hdx)
538c7fd2ed0Sgs150176 		gigctrl |= MII_1000BT_CTL_ADV_HDX;
539c7fd2ed0Sgs150176 
540c7fd2ed0Sgs150176 	if (adv_100fdx)
541c7fd2ed0Sgs150176 		anar |= MII_ABILITY_100BASE_TX_FD;
542c7fd2ed0Sgs150176 	if (adv_100hdx)
543c7fd2ed0Sgs150176 		anar |= MII_ABILITY_100BASE_TX;
544c7fd2ed0Sgs150176 	if (adv_10fdx)
545c7fd2ed0Sgs150176 		anar |= MII_ABILITY_10BASE_T_FD;
546c7fd2ed0Sgs150176 	if (adv_10hdx)
547c7fd2ed0Sgs150176 		anar |= MII_ABILITY_10BASE_T;
548c7fd2ed0Sgs150176 
549c7fd2ed0Sgs150176 	if (adv_pause)
550c7fd2ed0Sgs150176 		anar |= MII_ABILITY_PAUSE;
551c7fd2ed0Sgs150176 	if (adv_asym_pause)
552bdb9230aSGarrett D'Amore 		anar |= MII_ABILITY_ASMPAUSE;
553c7fd2ed0Sgs150176 
554c7fd2ed0Sgs150176 	/*
555c7fd2ed0Sgs150176 	 * Munge in any other fixed bits we require ...
556c7fd2ed0Sgs150176 	 */
557c7fd2ed0Sgs150176 	anar |= MII_AN_SELECTOR_8023;
558c7fd2ed0Sgs150176 
559c7fd2ed0Sgs150176 	/*
560c7fd2ed0Sgs150176 	 * Restart the PHY and write the new values.  Note the
561c7fd2ed0Sgs150176 	 * time, so that we can say whether subsequent link state
562c7fd2ed0Sgs150176 	 * changes can be attributed to our reprogramming the PHY
563c7fd2ed0Sgs150176 	 */
564c7fd2ed0Sgs150176 	rge_phy_init(rgep);
5657f58d67bSgs150176 	if (rgep->chipid.mac_ver == MAC_VER_8168B_B ||
5667f58d67bSgs150176 	    rgep->chipid.mac_ver == MAC_VER_8168B_C) {
5677f58d67bSgs150176 		/* power up PHY for RTL8168B chipset */
5687f58d67bSgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0000);
5697f58d67bSgs150176 		rge_mii_put16(rgep, PHY_0E_REG, 0x0000);
5707f58d67bSgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0000);
5717f58d67bSgs150176 	}
572c7fd2ed0Sgs150176 	rge_mii_put16(rgep, MII_AN_ADVERT, anar);
573c7fd2ed0Sgs150176 	rge_mii_put16(rgep, MII_1000BASE_T_CONTROL, gigctrl);
574aa817493Sgs150176 	rge_mii_put16(rgep, MII_CONTROL, control);
575c7fd2ed0Sgs150176 
576c7fd2ed0Sgs150176 	RGE_DEBUG(("rge_phy_update: anar <- 0x%x", anar));
577c7fd2ed0Sgs150176 	RGE_DEBUG(("rge_phy_update: control <- 0x%x", control));
578c7fd2ed0Sgs150176 	RGE_DEBUG(("rge_phy_update: gigctrl <- 0x%x", gigctrl));
579c7fd2ed0Sgs150176 }
580c7fd2ed0Sgs150176 
581c7fd2ed0Sgs150176 void rge_phy_init(rge_t *rgep);
582c7fd2ed0Sgs150176 #pragma	no_inline(rge_phy_init)
583c7fd2ed0Sgs150176 
584c7fd2ed0Sgs150176 void
rge_phy_init(rge_t * rgep)585c7fd2ed0Sgs150176 rge_phy_init(rge_t *rgep)
586c7fd2ed0Sgs150176 {
587c7fd2ed0Sgs150176 	rgep->phy_mii_addr = 1;
588c7fd2ed0Sgs150176 
589c7fd2ed0Sgs150176 	/*
590c7fd2ed0Sgs150176 	 * Below phy config steps are copied from the Programming Guide
591c7fd2ed0Sgs150176 	 * (there's no detail comments for these steps.)
592c7fd2ed0Sgs150176 	 */
593aa817493Sgs150176 	switch (rgep->chipid.mac_ver) {
594aa817493Sgs150176 	case MAC_VER_8169S_D:
595aa817493Sgs150176 	case MAC_VER_8169S_E :
596aa817493Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0001);
597c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_15_REG, 0x1000);
598c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_18_REG, 0x65c7);
599aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, 0x0000);
600c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_2, 0x00a1);
601c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_1, 0x0008);
602c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_BMSR_REG, 0x1020);
603c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_BMCR_REG, 0x1000);
604aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, 0x0800);
605aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, 0x0000);
606aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, 0x7000);
607c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_2, 0xff41);
608c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_1, 0xde60);
609c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_BMSR_REG, 0x0140);
610c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_BMCR_REG, 0x0077);
611aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, 0x7800);
612aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, 0x7000);
613aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, 0xa000);
614c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_2, 0xdf01);
615c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_1, 0xdf20);
616c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_BMSR_REG, 0xff95);
617c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_BMCR_REG, 0xfa00);
618aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, 0xa800);
619aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, 0xa000);
620aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, 0xb000);
621c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_2, 0xff41);
622c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_1, 0xde20);
623c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_BMSR_REG, 0x0140);
624c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_BMCR_REG, 0x00bb);
625aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, 0xb800);
626aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, 0xb000);
627aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, 0xf000);
628c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_2, 0xdf01);
629c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_1, 0xdf20);
630c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_BMSR_REG, 0xff95);
631c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_BMCR_REG, 0xbf00);
632aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, 0xf800);
633aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, 0xf000);
634aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, 0x0000);
635c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0000);
636c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_0B_REG, 0x0000);
637aa817493Sgs150176 		break;
638c7fd2ed0Sgs150176 
639aa817493Sgs150176 	case MAC_VER_8169SB:
640c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0001);
641aa817493Sgs150176 		rge_mii_put16(rgep, PHY_1B_REG, 0xD41E);
642aa817493Sgs150176 		rge_mii_put16(rgep, PHY_0E_REG, 0x7bff);
643c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_GBCR_REG, GBCR_DEFAULT);
644c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0002);
645c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_BMSR_REG, 0x90D0);
646c7fd2ed0Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0000);
647aa817493Sgs150176 		break;
648aa817493Sgs150176 
64952643194Sgs150176 	case MAC_VER_8169SC:
65052643194Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0001);
65152643194Sgs150176 		rge_mii_put16(rgep, PHY_ANER_REG, 0x0078);
65252643194Sgs150176 		rge_mii_put16(rgep, PHY_ANNPRR_REG, 0x05dc);
65352643194Sgs150176 		rge_mii_put16(rgep, PHY_GBCR_REG, 0x2672);
65452643194Sgs150176 		rge_mii_put16(rgep, PHY_GBSR_REG, 0x6a14);
65552643194Sgs150176 		rge_mii_put16(rgep, PHY_0B_REG, 0x7cb0);
65652643194Sgs150176 		rge_mii_put16(rgep, PHY_0C_REG, 0xdb80);
65752643194Sgs150176 		rge_mii_put16(rgep, PHY_1B_REG, 0xc414);
65852643194Sgs150176 		rge_mii_put16(rgep, PHY_1C_REG, 0xef03);
65952643194Sgs150176 		rge_mii_put16(rgep, PHY_1D_REG, 0x3dc8);
66052643194Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0003);
66152643194Sgs150176 		rge_mii_put16(rgep, PHY_13_REG, 0x0600);
66252643194Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0000);
66352643194Sgs150176 		break;
66452643194Sgs150176 
665aa817493Sgs150176 	case MAC_VER_8168:
666aa817493Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0001);
667aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANER_REG, 0x00aa);
668aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANNPTR_REG, 0x3173);
669aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANNPRR_REG, 0x08fc);
670aa817493Sgs150176 		rge_mii_put16(rgep, PHY_GBCR_REG, 0xe2d0);
671aa817493Sgs150176 		rge_mii_put16(rgep, PHY_0B_REG, 0x941a);
672aa817493Sgs150176 		rge_mii_put16(rgep, PHY_18_REG, 0x65fe);
673aa817493Sgs150176 		rge_mii_put16(rgep, PHY_1C_REG, 0x1e02);
674aa817493Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0002);
675aa817493Sgs150176 		rge_mii_put16(rgep, PHY_ANNPTR_REG, 0x103e);
676aa817493Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0000);
677aa817493Sgs150176 		break;
678aa817493Sgs150176 
679aa817493Sgs150176 	case MAC_VER_8168B_B:
680aa817493Sgs150176 	case MAC_VER_8168B_C:
681aa817493Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0001);
682aa817493Sgs150176 		rge_mii_put16(rgep, PHY_0B_REG, 0x94b0);
683aa817493Sgs150176 		rge_mii_put16(rgep, PHY_1B_REG, 0xc416);
684aa817493Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0003);
685aa817493Sgs150176 		rge_mii_put16(rgep, PHY_12_REG, 0x6096);
686aa817493Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0000);
687aa817493Sgs150176 		break;
688c7fd2ed0Sgs150176 	}
689c7fd2ed0Sgs150176 }
690c7fd2ed0Sgs150176 
691c7fd2ed0Sgs150176 void rge_chip_ident(rge_t *rgep);
692c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_ident)
693c7fd2ed0Sgs150176 
694c7fd2ed0Sgs150176 void
rge_chip_ident(rge_t * rgep)695c7fd2ed0Sgs150176 rge_chip_ident(rge_t *rgep)
696c7fd2ed0Sgs150176 {
697c7fd2ed0Sgs150176 	chip_id_t *chip = &rgep->chipid;
698c7fd2ed0Sgs150176 	uint32_t val32;
699c7fd2ed0Sgs150176 	uint16_t val16;
700c7fd2ed0Sgs150176 
701aa817493Sgs150176 	/*
702aa817493Sgs150176 	 * Read and record MAC version
703aa817493Sgs150176 	 */
704c7fd2ed0Sgs150176 	val32 = rge_reg_get32(rgep, TX_CONFIG_REG);
705c7fd2ed0Sgs150176 	val32 &= HW_VERSION_ID_0 | HW_VERSION_ID_1;
706c7fd2ed0Sgs150176 	chip->mac_ver = val32;
7073a84c50fSWinson Wang - Sun Microsystems - Beijing China 	chip->is_pcie = pci_lcap_locate(rgep->cfg_handle,
7083a84c50fSWinson Wang - Sun Microsystems - Beijing China 	    PCI_CAP_ID_PCI_E, &val16) == DDI_SUCCESS;
709aa817493Sgs150176 
710aa817493Sgs150176 	/*
7115ca61e50SLi-Zhen You 	 * Workaround for 8101E_C
7125ca61e50SLi-Zhen You 	 */
7130b758ccbSAlexander Eremin 	chip->enable_mac_first = !chip->is_pcie;
7145ca61e50SLi-Zhen You 	if (chip->mac_ver == MAC_VER_8101E_C) {
7155ca61e50SLi-Zhen You 		chip->is_pcie = B_FALSE;
7165ca61e50SLi-Zhen You 	}
7175ca61e50SLi-Zhen You 
7185ca61e50SLi-Zhen You 	/*
719aa817493Sgs150176 	 * Read and record PHY version
720aa817493Sgs150176 	 */
721c7fd2ed0Sgs150176 	val16 = rge_mii_get16(rgep, PHY_ID_REG_2);
722c7fd2ed0Sgs150176 	val16 &= PHY_VER_MASK;
723c7fd2ed0Sgs150176 	chip->phy_ver = val16;
724c7fd2ed0Sgs150176 
725aa817493Sgs150176 	/* set pci latency timer */
726aa817493Sgs150176 	if (chip->mac_ver == MAC_VER_8169 ||
72752643194Sgs150176 	    chip->mac_ver == MAC_VER_8169S_D ||
7287b114c4bSWinson Wang - Sun Microsystems - Beijing China 	    chip->mac_ver == MAC_VER_8169S_E ||
72952643194Sgs150176 	    chip->mac_ver == MAC_VER_8169SC)
730aa817493Sgs150176 		pci_config_put8(rgep->cfg_handle, PCI_CONF_LATENCY_TIMER, 0x40);
731aa817493Sgs150176 
73252643194Sgs150176 	if (chip->mac_ver == MAC_VER_8169SC) {
73352643194Sgs150176 		val16 = rge_reg_get16(rgep, RT_CONFIG_1_REG);
73452643194Sgs150176 		val16 &= 0x0300;
73552643194Sgs150176 		if (val16 == 0x1)	/* 66Mhz PCI */
7367b114c4bSWinson Wang - Sun Microsystems - Beijing China 			rge_reg_put32(rgep, 0x7c, 0x000700ff);
73752643194Sgs150176 		else if (val16 == 0x0) /* 33Mhz PCI */
7387b114c4bSWinson Wang - Sun Microsystems - Beijing China 			rge_reg_put32(rgep, 0x7c, 0x0007ff00);
73952643194Sgs150176 	}
74052643194Sgs150176 
741aa817493Sgs150176 	/*
742aa817493Sgs150176 	 * PCIE chipset require the Rx buffer start address must be
743aa817493Sgs150176 	 * 8-byte alignment and the Rx buffer size must be multiple of 8.
744aa817493Sgs150176 	 * We'll just use bcopy in receive procedure for the PCIE chipset.
745aa817493Sgs150176 	 */
746aa817493Sgs150176 	if (chip->is_pcie) {
747aa817493Sgs150176 		rgep->chip_flags |= CHIP_FLAG_FORCE_BCOPY;
748aa817493Sgs150176 		if (rgep->default_mtu > ETHERMTU) {
749aa817493Sgs150176 			rge_notice(rgep, "Jumbo packets not supported "
750aa817493Sgs150176 			    "for this PCIE chipset");
751aa817493Sgs150176 			rgep->default_mtu = ETHERMTU;
752aa817493Sgs150176 		}
753aa817493Sgs150176 	}
754aa817493Sgs150176 	if (rgep->chip_flags & CHIP_FLAG_FORCE_BCOPY)
755aa817493Sgs150176 		rgep->head_room = 0;
756aa817493Sgs150176 	else
757aa817493Sgs150176 		rgep->head_room = RGE_HEADROOM;
758aa817493Sgs150176 
759aa817493Sgs150176 	/*
760aa817493Sgs150176 	 * Initialize other variables.
761aa817493Sgs150176 	 */
762aa817493Sgs150176 	if (rgep->default_mtu < ETHERMTU || rgep->default_mtu > RGE_JUMBO_MTU)
763aa817493Sgs150176 		rgep->default_mtu = ETHERMTU;
764aa817493Sgs150176 	if (rgep->default_mtu > ETHERMTU) {
765c7fd2ed0Sgs150176 		rgep->rxbuf_size = RGE_BUFF_SIZE_JUMBO;
766c7fd2ed0Sgs150176 		rgep->txbuf_size = RGE_BUFF_SIZE_JUMBO;
767c7fd2ed0Sgs150176 		rgep->ethmax_size = RGE_JUMBO_SIZE;
768c7fd2ed0Sgs150176 	} else {
769c7fd2ed0Sgs150176 		rgep->rxbuf_size = RGE_BUFF_SIZE_STD;
770c7fd2ed0Sgs150176 		rgep->txbuf_size = RGE_BUFF_SIZE_STD;
771c7fd2ed0Sgs150176 		rgep->ethmax_size = ETHERMAX;
772c7fd2ed0Sgs150176 	}
773c7fd2ed0Sgs150176 	chip->rxconfig = RX_CONFIG_DEFAULT;
774c7fd2ed0Sgs150176 	chip->txconfig = TX_CONFIG_DEFAULT;
775c7fd2ed0Sgs150176 
7763a84c50fSWinson Wang - Sun Microsystems - Beijing China 	/* interval to update statistics for polling mode */
7773a84c50fSWinson Wang - Sun Microsystems - Beijing China 	rgep->tick_delta = drv_usectohz(1000*1000/CLK_TICK);
7783a84c50fSWinson Wang - Sun Microsystems - Beijing China 
7793a84c50fSWinson Wang - Sun Microsystems - Beijing China 	/* ensure we are not in polling mode */
7803a84c50fSWinson Wang - Sun Microsystems - Beijing China 	rgep->curr_tick = ddi_get_lbolt() - 2*rgep->tick_delta;
781c7fd2ed0Sgs150176 	RGE_TRACE(("%s: MAC version = %x, PHY version = %x",
782c7fd2ed0Sgs150176 	    rgep->ifname, chip->mac_ver, chip->phy_ver));
783c7fd2ed0Sgs150176 }
784c7fd2ed0Sgs150176 
785c7fd2ed0Sgs150176 /*
786c7fd2ed0Sgs150176  * Perform first-stage chip (re-)initialisation, using only config-space
787c7fd2ed0Sgs150176  * accesses:
788c7fd2ed0Sgs150176  *
789c7fd2ed0Sgs150176  * + Read the vendor/device/revision/subsystem/cache-line-size registers,
790c7fd2ed0Sgs150176  *   returning the data in the structure pointed to by <idp>.
791c7fd2ed0Sgs150176  * + Enable Memory Space accesses.
792c7fd2ed0Sgs150176  * + Enable Bus Mastering according.
793c7fd2ed0Sgs150176  */
794c7fd2ed0Sgs150176 void rge_chip_cfg_init(rge_t *rgep, chip_id_t *cidp);
795c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_cfg_init)
796c7fd2ed0Sgs150176 
797c7fd2ed0Sgs150176 void
rge_chip_cfg_init(rge_t * rgep,chip_id_t * cidp)798c7fd2ed0Sgs150176 rge_chip_cfg_init(rge_t *rgep, chip_id_t *cidp)
799c7fd2ed0Sgs150176 {
800c7fd2ed0Sgs150176 	ddi_acc_handle_t handle;
801c7fd2ed0Sgs150176 	uint16_t commd;
802c7fd2ed0Sgs150176 
803c7fd2ed0Sgs150176 	handle = rgep->cfg_handle;
804c7fd2ed0Sgs150176 
805c7fd2ed0Sgs150176 	/*
806c7fd2ed0Sgs150176 	 * Save PCI cache line size and subsystem vendor ID
807c7fd2ed0Sgs150176 	 */
808c7fd2ed0Sgs150176 	cidp->command = pci_config_get16(handle, PCI_CONF_COMM);
809c7fd2ed0Sgs150176 	cidp->vendor = pci_config_get16(handle, PCI_CONF_VENID);
810c7fd2ed0Sgs150176 	cidp->device = pci_config_get16(handle, PCI_CONF_DEVID);
811c7fd2ed0Sgs150176 	cidp->subven = pci_config_get16(handle, PCI_CONF_SUBVENID);
812c7fd2ed0Sgs150176 	cidp->subdev = pci_config_get16(handle, PCI_CONF_SUBSYSID);
813c7fd2ed0Sgs150176 	cidp->revision = pci_config_get8(handle, PCI_CONF_REVID);
814c7fd2ed0Sgs150176 	cidp->clsize = pci_config_get8(handle, PCI_CONF_CACHE_LINESZ);
815c7fd2ed0Sgs150176 	cidp->latency = pci_config_get8(handle, PCI_CONF_LATENCY_TIMER);
816c7fd2ed0Sgs150176 
817c7fd2ed0Sgs150176 	/*
818c7fd2ed0Sgs150176 	 * Turn on Master Enable (DMA) and IO Enable bits.
819c7fd2ed0Sgs150176 	 * Enable PCI Memory Space accesses
820c7fd2ed0Sgs150176 	 */
821c7fd2ed0Sgs150176 	commd = cidp->command;
822c7fd2ed0Sgs150176 	commd |= PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_IO;
823c7fd2ed0Sgs150176 	pci_config_put16(handle, PCI_CONF_COMM, commd);
824c7fd2ed0Sgs150176 
825c7fd2ed0Sgs150176 	RGE_DEBUG(("rge_chip_cfg_init: vendor 0x%x device 0x%x revision 0x%x",
826c7fd2ed0Sgs150176 	    cidp->vendor, cidp->device, cidp->revision));
827c7fd2ed0Sgs150176 	RGE_DEBUG(("rge_chip_cfg_init: subven 0x%x subdev 0x%x",
828c7fd2ed0Sgs150176 	    cidp->subven, cidp->subdev));
829c7fd2ed0Sgs150176 	RGE_DEBUG(("rge_chip_cfg_init: clsize %d latency %d command 0x%x",
830c7fd2ed0Sgs150176 	    cidp->clsize, cidp->latency, cidp->command));
831c7fd2ed0Sgs150176 }
832c7fd2ed0Sgs150176 
833c7fd2ed0Sgs150176 int rge_chip_reset(rge_t *rgep);
834c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_reset)
835c7fd2ed0Sgs150176 
836c7fd2ed0Sgs150176 int
rge_chip_reset(rge_t * rgep)837c7fd2ed0Sgs150176 rge_chip_reset(rge_t *rgep)
838c7fd2ed0Sgs150176 {
839c7fd2ed0Sgs150176 	int i;
840c7fd2ed0Sgs150176 	uint8_t val8;
841c7fd2ed0Sgs150176 
842c7fd2ed0Sgs150176 	/*
843c7fd2ed0Sgs150176 	 * Chip should be in STOP state
844c7fd2ed0Sgs150176 	 */
845c7fd2ed0Sgs150176 	rge_reg_clr8(rgep, RT_COMMAND_REG,
846c7fd2ed0Sgs150176 	    RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
847c7fd2ed0Sgs150176 
848c7fd2ed0Sgs150176 	/*
849c7fd2ed0Sgs150176 	 * Disable interrupt
850c7fd2ed0Sgs150176 	 */
851c7fd2ed0Sgs150176 	rgep->int_mask = INT_MASK_NONE;
852aa817493Sgs150176 	rge_reg_put16(rgep, INT_MASK_REG, rgep->int_mask);
853c7fd2ed0Sgs150176 
854c7fd2ed0Sgs150176 	/*
855c7fd2ed0Sgs150176 	 * Clear pended interrupt
856c7fd2ed0Sgs150176 	 */
857c7fd2ed0Sgs150176 	rge_reg_put16(rgep, INT_STATUS_REG, INT_MASK_ALL);
858c7fd2ed0Sgs150176 
859c7fd2ed0Sgs150176 	/*
860c7fd2ed0Sgs150176 	 * Reset chip
861c7fd2ed0Sgs150176 	 */
862c7fd2ed0Sgs150176 	rge_reg_set8(rgep, RT_COMMAND_REG, RT_COMMAND_RESET);
863c7fd2ed0Sgs150176 
864c7fd2ed0Sgs150176 	/*
865c7fd2ed0Sgs150176 	 * Wait for reset success
866c7fd2ed0Sgs150176 	 */
867c7fd2ed0Sgs150176 	for (i = 0; i < CHIP_RESET_LOOP; i++) {
868c7fd2ed0Sgs150176 		drv_usecwait(10);
869c7fd2ed0Sgs150176 		val8 = rge_reg_get8(rgep, RT_COMMAND_REG);
870c7fd2ed0Sgs150176 		if (!(val8 & RT_COMMAND_RESET)) {
871c7fd2ed0Sgs150176 			rgep->rge_chip_state = RGE_CHIP_RESET;
872c7fd2ed0Sgs150176 			return (0);
873c7fd2ed0Sgs150176 		}
874c7fd2ed0Sgs150176 	}
875c7fd2ed0Sgs150176 	RGE_REPORT((rgep, "rge_chip_reset fail."));
876c7fd2ed0Sgs150176 	return (-1);
877c7fd2ed0Sgs150176 }
878c7fd2ed0Sgs150176 
879c7fd2ed0Sgs150176 void rge_chip_init(rge_t *rgep);
880c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_init)
881c7fd2ed0Sgs150176 
882c7fd2ed0Sgs150176 void
rge_chip_init(rge_t * rgep)883c7fd2ed0Sgs150176 rge_chip_init(rge_t *rgep)
884c7fd2ed0Sgs150176 {
885c7fd2ed0Sgs150176 	uint32_t val32;
886aa817493Sgs150176 	uint32_t val16;
887aa817493Sgs150176 	uint32_t *hashp;
888aa817493Sgs150176 	chip_id_t *chip = &rgep->chipid;
889aa817493Sgs150176 
890aa817493Sgs150176 	/*
891aa817493Sgs150176 	 * Increase the threshold voltage of RX sensitivity
892aa817493Sgs150176 	 */
8933a84c50fSWinson Wang - Sun Microsystems - Beijing China 	if (chip->mac_ver == MAC_VER_8168B_B ||
8943a84c50fSWinson Wang - Sun Microsystems - Beijing China 	    chip->mac_ver == MAC_VER_8168B_C ||
8955ca61e50SLi-Zhen You 	    chip->mac_ver == MAC_VER_8101E) {
896aa817493Sgs150176 		rge_ephy_put16(rgep, 0x01, 0x1bd3);
8973a84c50fSWinson Wang - Sun Microsystems - Beijing China 	}
898aa817493Sgs150176 
8993a84c50fSWinson Wang - Sun Microsystems - Beijing China 	if (chip->mac_ver == MAC_VER_8168 ||
9003a84c50fSWinson Wang - Sun Microsystems - Beijing China 	    chip->mac_ver == MAC_VER_8168B_B) {
901aa817493Sgs150176 		val16 = rge_reg_get8(rgep, PHY_STATUS_REG);
902aa817493Sgs150176 		val16 = 0x12<<8 | val16;
903aa817493Sgs150176 		rge_reg_put16(rgep, PHY_STATUS_REG, val16);
904aa817493Sgs150176 		rge_reg_put32(rgep, RT_CSI_DATA_REG, 0x00021c01);
905aa817493Sgs150176 		rge_reg_put32(rgep, RT_CSI_ACCESS_REG, 0x8000f088);
906aa817493Sgs150176 		rge_reg_put32(rgep, RT_CSI_DATA_REG, 0x00004000);
907aa817493Sgs150176 		rge_reg_put32(rgep, RT_CSI_ACCESS_REG, 0x8000f0b0);
908aa817493Sgs150176 		rge_reg_put32(rgep, RT_CSI_ACCESS_REG, 0x0000f068);
909aa817493Sgs150176 		val32 = rge_reg_get32(rgep, RT_CSI_DATA_REG);
910aa817493Sgs150176 		val32 |= 0x7000;
911aa817493Sgs150176 		val32 &= 0xffff5fff;
912aa817493Sgs150176 		rge_reg_put32(rgep, RT_CSI_DATA_REG, val32);
913aa817493Sgs150176 		rge_reg_put32(rgep, RT_CSI_ACCESS_REG, 0x8000f068);
914aa817493Sgs150176 	}
915c7fd2ed0Sgs150176 
916c7fd2ed0Sgs150176 	/*
917c7fd2ed0Sgs150176 	 * Config MII register
918c7fd2ed0Sgs150176 	 */
919c7fd2ed0Sgs150176 	rgep->param_link_up = LINK_STATE_DOWN;
920c7fd2ed0Sgs150176 	rge_phy_update(rgep);
921c7fd2ed0Sgs150176 
922c7fd2ed0Sgs150176 	/*
923c7fd2ed0Sgs150176 	 * Enable Rx checksum offload.
924c7fd2ed0Sgs150176 	 *  Then for vlan support, we must enable receive vlan de-tagging.
925c7fd2ed0Sgs150176 	 *  Otherwise, there'll be checksum error.
926c7fd2ed0Sgs150176 	 */
927aa817493Sgs150176 	val16 = rge_reg_get16(rgep, CPLUS_COMMAND_REG);
928aa817493Sgs150176 	val16 |= RX_CKSM_OFFLOAD | RX_VLAN_DETAG;
929aa817493Sgs150176 	if (chip->mac_ver == MAC_VER_8169S_D) {
930aa817493Sgs150176 		val16 |= CPLUS_BIT14 | MUL_PCI_RW_ENABLE;
931c7fd2ed0Sgs150176 		rge_reg_put8(rgep, RESV_82_REG, 0x01);
932c7fd2ed0Sgs150176 	}
9337b114c4bSWinson Wang - Sun Microsystems - Beijing China 	if (chip->mac_ver == MAC_VER_8169S_E ||
9347b114c4bSWinson Wang - Sun Microsystems - Beijing China 	    chip->mac_ver == MAC_VER_8169SC) {
9357b114c4bSWinson Wang - Sun Microsystems - Beijing China 		val16 |= MUL_PCI_RW_ENABLE;
9367b114c4bSWinson Wang - Sun Microsystems - Beijing China 	}
937aa817493Sgs150176 	rge_reg_put16(rgep, CPLUS_COMMAND_REG, val16 & (~0x03));
938c7fd2ed0Sgs150176 
939c7fd2ed0Sgs150176 	/*
940c7fd2ed0Sgs150176 	 * Start transmit/receive before set tx/rx configuration register
941c7fd2ed0Sgs150176 	 */
9420b758ccbSAlexander Eremin 	if (chip->enable_mac_first)
943c7fd2ed0Sgs150176 		rge_reg_set8(rgep, RT_COMMAND_REG,
944c7fd2ed0Sgs150176 		    RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
945c7fd2ed0Sgs150176 
946c7fd2ed0Sgs150176 	/*
947c7fd2ed0Sgs150176 	 * Set dump tally counter register
948c7fd2ed0Sgs150176 	 */
949c7fd2ed0Sgs150176 	val32 = rgep->dma_area_stats.cookie.dmac_laddress >> 32;
950c7fd2ed0Sgs150176 	rge_reg_put32(rgep, DUMP_COUNTER_REG_1, val32);
951c7fd2ed0Sgs150176 	val32 = rge_reg_get32(rgep, DUMP_COUNTER_REG_0);
952c7fd2ed0Sgs150176 	val32 &= DUMP_COUNTER_REG_RESV;
953c7fd2ed0Sgs150176 	val32 |= rgep->dma_area_stats.cookie.dmac_laddress;
954c7fd2ed0Sgs150176 	rge_reg_put32(rgep, DUMP_COUNTER_REG_0, val32);
955c7fd2ed0Sgs150176 
956c7fd2ed0Sgs150176 	/*
957c7fd2ed0Sgs150176 	 * Change to config register write enable mode
958c7fd2ed0Sgs150176 	 */
959c7fd2ed0Sgs150176 	rge_reg_set8(rgep, RT_93c46_COMMOND_REG, RT_93c46_MODE_CONFIG);
960c7fd2ed0Sgs150176 
961c7fd2ed0Sgs150176 	/*
962c7fd2ed0Sgs150176 	 * Set Tx/Rx maximum packet size
963c7fd2ed0Sgs150176 	 */
964aa817493Sgs150176 	if (rgep->default_mtu > ETHERMTU) {
965c7fd2ed0Sgs150176 		rge_reg_put8(rgep, TX_MAX_PKTSIZE_REG, TX_PKTSIZE_JUMBO);
966c7fd2ed0Sgs150176 		rge_reg_put16(rgep, RX_MAX_PKTSIZE_REG, RX_PKTSIZE_JUMBO);
967dfc2d53eSmx205022 	} else if (rgep->chipid.mac_ver != MAC_VER_8101E) {
968c7fd2ed0Sgs150176 		rge_reg_put8(rgep, TX_MAX_PKTSIZE_REG, TX_PKTSIZE_STD);
969c7fd2ed0Sgs150176 		rge_reg_put16(rgep, RX_MAX_PKTSIZE_REG, RX_PKTSIZE_STD);
970dfc2d53eSmx205022 	} else {
971dfc2d53eSmx205022 		rge_reg_put8(rgep, TX_MAX_PKTSIZE_REG, TX_PKTSIZE_STD_8101E);
972dfc2d53eSmx205022 		rge_reg_put16(rgep, RX_MAX_PKTSIZE_REG, RX_PKTSIZE_STD_8101E);
973c7fd2ed0Sgs150176 	}
974c7fd2ed0Sgs150176 
975c7fd2ed0Sgs150176 	/*
976c7fd2ed0Sgs150176 	 * Set receive configuration register
977c7fd2ed0Sgs150176 	 */
978c7fd2ed0Sgs150176 	val32 = rge_reg_get32(rgep, RX_CONFIG_REG);
979c7fd2ed0Sgs150176 	val32 &= RX_CONFIG_REG_RESV;
980c7fd2ed0Sgs150176 	if (rgep->promisc)
981c7fd2ed0Sgs150176 		val32 |= RX_ACCEPT_ALL_PKT;
982aa817493Sgs150176 	rge_reg_put32(rgep, RX_CONFIG_REG, val32 | chip->rxconfig);
983c7fd2ed0Sgs150176 
984c7fd2ed0Sgs150176 	/*
985c7fd2ed0Sgs150176 	 * Set transmit configuration register
986c7fd2ed0Sgs150176 	 */
987c7fd2ed0Sgs150176 	val32 = rge_reg_get32(rgep, TX_CONFIG_REG);
988c7fd2ed0Sgs150176 	val32 &= TX_CONFIG_REG_RESV;
989aa817493Sgs150176 	rge_reg_put32(rgep, TX_CONFIG_REG, val32 | chip->txconfig);
990c7fd2ed0Sgs150176 
991c7fd2ed0Sgs150176 	/*
992c7fd2ed0Sgs150176 	 * Set Tx/Rx descriptor register
993c7fd2ed0Sgs150176 	 */
994c7fd2ed0Sgs150176 	val32 = rgep->tx_desc.cookie.dmac_laddress;
995c7fd2ed0Sgs150176 	rge_reg_put32(rgep, NORMAL_TX_RING_ADDR_LO_REG, val32);
996c7fd2ed0Sgs150176 	val32 = rgep->tx_desc.cookie.dmac_laddress >> 32;
997c7fd2ed0Sgs150176 	rge_reg_put32(rgep, NORMAL_TX_RING_ADDR_HI_REG, val32);
998c7fd2ed0Sgs150176 	rge_reg_put32(rgep, HIGH_TX_RING_ADDR_LO_REG, 0);
999c7fd2ed0Sgs150176 	rge_reg_put32(rgep, HIGH_TX_RING_ADDR_HI_REG, 0);
1000c7fd2ed0Sgs150176 	val32 = rgep->rx_desc.cookie.dmac_laddress;
1001c7fd2ed0Sgs150176 	rge_reg_put32(rgep, RX_RING_ADDR_LO_REG, val32);
1002c7fd2ed0Sgs150176 	val32 = rgep->rx_desc.cookie.dmac_laddress >> 32;
1003c7fd2ed0Sgs150176 	rge_reg_put32(rgep, RX_RING_ADDR_HI_REG, val32);
1004c7fd2ed0Sgs150176 
1005c7fd2ed0Sgs150176 	/*
1006c7fd2ed0Sgs150176 	 * Suggested setting from Realtek
1007c7fd2ed0Sgs150176 	 */
1008dfc2d53eSmx205022 	if (rgep->chipid.mac_ver != MAC_VER_8101E)
1009c7fd2ed0Sgs150176 		rge_reg_put16(rgep, RESV_E2_REG, 0x282a);
1010dfc2d53eSmx205022 	else
1011dfc2d53eSmx205022 		rge_reg_put16(rgep, RESV_E2_REG, 0x0000);
1012c7fd2ed0Sgs150176 
1013c7fd2ed0Sgs150176 	/*
1014c7fd2ed0Sgs150176 	 * Set multicast register
1015c7fd2ed0Sgs150176 	 */
1016aa817493Sgs150176 	hashp = (uint32_t *)rgep->mcast_hash;
10175927ab2bSKHF04453@nifty.ne.jp 	if (rgep->promisc) {
10185927ab2bSKHF04453@nifty.ne.jp 		rge_reg_put32(rgep, MULTICAST_0_REG, ~0U);
10195927ab2bSKHF04453@nifty.ne.jp 		rge_reg_put32(rgep, MULTICAST_4_REG, ~0U);
10205927ab2bSKHF04453@nifty.ne.jp 	} else {
10215927ab2bSKHF04453@nifty.ne.jp 		rge_reg_put32(rgep, MULTICAST_0_REG, RGE_BSWAP_32(hashp[0]));
10225927ab2bSKHF04453@nifty.ne.jp 		rge_reg_put32(rgep, MULTICAST_4_REG, RGE_BSWAP_32(hashp[1]));
10235927ab2bSKHF04453@nifty.ne.jp 	}
1024c7fd2ed0Sgs150176 
1025c7fd2ed0Sgs150176 	/*
1026c7fd2ed0Sgs150176 	 * Msic register setting:
1027c7fd2ed0Sgs150176 	 *   -- Missed packet counter: clear it
1028c7fd2ed0Sgs150176 	 *   -- TimerInt Register
1029c7fd2ed0Sgs150176 	 *   -- Timer count register
1030c7fd2ed0Sgs150176 	 */
1031c7fd2ed0Sgs150176 	rge_reg_put32(rgep, RX_PKT_MISS_COUNT_REG, 0);
1032c7fd2ed0Sgs150176 	rge_reg_put32(rgep, TIMER_INT_REG, TIMER_INT_NONE);
1033c7fd2ed0Sgs150176 	rge_reg_put32(rgep, TIMER_COUNT_REG, 0);
103452643194Sgs150176 
103552643194Sgs150176 	/*
1036368a5ef8SMiles Xu, Sun Microsystems 	 * disable the Unicast Wakeup Frame capability
1037368a5ef8SMiles Xu, Sun Microsystems 	 */
1038368a5ef8SMiles Xu, Sun Microsystems 	rge_reg_clr8(rgep, RT_CONFIG_5_REG, RT_UNI_WAKE_FRAME);
1039368a5ef8SMiles Xu, Sun Microsystems 
1040368a5ef8SMiles Xu, Sun Microsystems 	/*
104152643194Sgs150176 	 * Return to normal network/host communication mode
104252643194Sgs150176 	 */
104352643194Sgs150176 	rge_reg_clr8(rgep, RT_93c46_COMMOND_REG, RT_93c46_MODE_CONFIG);
104452643194Sgs150176 	drv_usecwait(20);
1045c7fd2ed0Sgs150176 }
1046c7fd2ed0Sgs150176 
1047c7fd2ed0Sgs150176 /*
1048c7fd2ed0Sgs150176  * rge_chip_start() -- start the chip transmitting and/or receiving,
1049c7fd2ed0Sgs150176  * including enabling interrupts
1050c7fd2ed0Sgs150176  */
1051c7fd2ed0Sgs150176 void rge_chip_start(rge_t *rgep);
1052c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_start)
1053c7fd2ed0Sgs150176 
1054c7fd2ed0Sgs150176 void
rge_chip_start(rge_t * rgep)1055c7fd2ed0Sgs150176 rge_chip_start(rge_t *rgep)
1056c7fd2ed0Sgs150176 {
1057c7fd2ed0Sgs150176 	/*
1058c7fd2ed0Sgs150176 	 * Clear statistics
1059c7fd2ed0Sgs150176 	 */
1060c7fd2ed0Sgs150176 	bzero(&rgep->stats, sizeof (rge_stats_t));
1061c7fd2ed0Sgs150176 	DMA_ZERO(rgep->dma_area_stats);
1062c7fd2ed0Sgs150176 
1063c7fd2ed0Sgs150176 	/*
1064c7fd2ed0Sgs150176 	 * Start transmit/receive
1065c7fd2ed0Sgs150176 	 */
1066c7fd2ed0Sgs150176 	rge_reg_set8(rgep, RT_COMMAND_REG,
1067c7fd2ed0Sgs150176 	    RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
1068c7fd2ed0Sgs150176 
1069c7fd2ed0Sgs150176 	/*
1070c7fd2ed0Sgs150176 	 * Enable interrupt
1071c7fd2ed0Sgs150176 	 */
1072c7fd2ed0Sgs150176 	rgep->int_mask = RGE_INT_MASK;
10733a84c50fSWinson Wang - Sun Microsystems - Beijing China 	if (rgep->chipid.is_pcie) {
10743a84c50fSWinson Wang - Sun Microsystems - Beijing China 		rgep->int_mask |= NO_TXDESC_INT;
10753a84c50fSWinson Wang - Sun Microsystems - Beijing China 	}
10767b114c4bSWinson Wang - Sun Microsystems - Beijing China 	rgep->rx_fifo_ovf = 0;
10777b114c4bSWinson Wang - Sun Microsystems - Beijing China 	rgep->int_mask |= RX_FIFO_OVERFLOW_INT;
1078aa817493Sgs150176 	rge_reg_put16(rgep, INT_MASK_REG, rgep->int_mask);
1079c7fd2ed0Sgs150176 
1080c7fd2ed0Sgs150176 	/*
1081c7fd2ed0Sgs150176 	 * All done!
1082c7fd2ed0Sgs150176 	 */
1083c7fd2ed0Sgs150176 	rgep->rge_chip_state = RGE_CHIP_RUNNING;
1084c7fd2ed0Sgs150176 }
1085c7fd2ed0Sgs150176 
1086c7fd2ed0Sgs150176 /*
1087c7fd2ed0Sgs150176  * rge_chip_stop() -- stop board receiving
108819397407SSherry Moore  *
108919397407SSherry Moore  * Since this function is also invoked by rge_quiesce(), it
109019397407SSherry Moore  * must not block; also, no tracing or logging takes place
109119397407SSherry Moore  * when invoked by rge_quiesce().
1092c7fd2ed0Sgs150176  */
1093c7fd2ed0Sgs150176 void rge_chip_stop(rge_t *rgep, boolean_t fault);
1094c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_stop)
1095c7fd2ed0Sgs150176 
1096c7fd2ed0Sgs150176 void
rge_chip_stop(rge_t * rgep,boolean_t fault)1097c7fd2ed0Sgs150176 rge_chip_stop(rge_t *rgep, boolean_t fault)
1098c7fd2ed0Sgs150176 {
1099c7fd2ed0Sgs150176 	/*
1100c7fd2ed0Sgs150176 	 * Disable interrupt
1101c7fd2ed0Sgs150176 	 */
1102c7fd2ed0Sgs150176 	rgep->int_mask = INT_MASK_NONE;
1103aa817493Sgs150176 	rge_reg_put16(rgep, INT_MASK_REG, rgep->int_mask);
1104c7fd2ed0Sgs150176 
1105c7fd2ed0Sgs150176 	/*
1106c7fd2ed0Sgs150176 	 * Clear pended interrupt
1107c7fd2ed0Sgs150176 	 */
1108343c2616Smx205022 	if (!rgep->suspended) {
1109c7fd2ed0Sgs150176 		rge_reg_put16(rgep, INT_STATUS_REG, INT_MASK_ALL);
1110343c2616Smx205022 	}
1111c7fd2ed0Sgs150176 
1112c7fd2ed0Sgs150176 	/*
1113c7fd2ed0Sgs150176 	 * Stop the board and disable transmit/receive
1114c7fd2ed0Sgs150176 	 */
1115c7fd2ed0Sgs150176 	rge_reg_clr8(rgep, RT_COMMAND_REG,
1116c7fd2ed0Sgs150176 	    RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
1117c7fd2ed0Sgs150176 
1118c7fd2ed0Sgs150176 	if (fault)
1119c7fd2ed0Sgs150176 		rgep->rge_chip_state = RGE_CHIP_FAULT;
1120c7fd2ed0Sgs150176 	else
1121c7fd2ed0Sgs150176 		rgep->rge_chip_state = RGE_CHIP_STOPPED;
1122c7fd2ed0Sgs150176 }
1123c7fd2ed0Sgs150176 
1124c7fd2ed0Sgs150176 /*
1125c7fd2ed0Sgs150176  * rge_get_mac_addr() -- get the MAC address on NIC
1126c7fd2ed0Sgs150176  */
1127c7fd2ed0Sgs150176 static void rge_get_mac_addr(rge_t *rgep);
1128c7fd2ed0Sgs150176 #pragma	inline(rge_get_mac_addr)
1129c7fd2ed0Sgs150176 
1130c7fd2ed0Sgs150176 static void
rge_get_mac_addr(rge_t * rgep)1131c7fd2ed0Sgs150176 rge_get_mac_addr(rge_t *rgep)
1132c7fd2ed0Sgs150176 {
1133c7fd2ed0Sgs150176 	uint8_t *macaddr = rgep->netaddr;
1134c7fd2ed0Sgs150176 	uint32_t val32;
1135c7fd2ed0Sgs150176 
1136c7fd2ed0Sgs150176 	/*
1137c7fd2ed0Sgs150176 	 * Read first 4-byte of mac address
1138c7fd2ed0Sgs150176 	 */
1139c7fd2ed0Sgs150176 	val32 = rge_reg_get32(rgep, ID_0_REG);
1140c7fd2ed0Sgs150176 	macaddr[0] = val32 & 0xff;
1141c7fd2ed0Sgs150176 	val32 = val32 >> 8;
1142c7fd2ed0Sgs150176 	macaddr[1] = val32 & 0xff;
1143c7fd2ed0Sgs150176 	val32 = val32 >> 8;
1144c7fd2ed0Sgs150176 	macaddr[2] = val32 & 0xff;
1145c7fd2ed0Sgs150176 	val32 = val32 >> 8;
1146c7fd2ed0Sgs150176 	macaddr[3] = val32 & 0xff;
1147c7fd2ed0Sgs150176 
1148c7fd2ed0Sgs150176 	/*
1149c7fd2ed0Sgs150176 	 * Read last 2-byte of mac address
1150c7fd2ed0Sgs150176 	 */
1151c7fd2ed0Sgs150176 	val32 = rge_reg_get32(rgep, ID_4_REG);
1152c7fd2ed0Sgs150176 	macaddr[4] = val32 & 0xff;
1153c7fd2ed0Sgs150176 	val32 = val32 >> 8;
1154c7fd2ed0Sgs150176 	macaddr[5] = val32 & 0xff;
1155c7fd2ed0Sgs150176 }
1156c7fd2ed0Sgs150176 
1157c7fd2ed0Sgs150176 static void rge_set_mac_addr(rge_t *rgep);
1158c7fd2ed0Sgs150176 #pragma	inline(rge_set_mac_addr)
1159c7fd2ed0Sgs150176 
1160c7fd2ed0Sgs150176 static void
rge_set_mac_addr(rge_t * rgep)1161c7fd2ed0Sgs150176 rge_set_mac_addr(rge_t *rgep)
1162c7fd2ed0Sgs150176 {
1163c7fd2ed0Sgs150176 	uint8_t *p = rgep->netaddr;
1164c7fd2ed0Sgs150176 	uint32_t val32;
1165c7fd2ed0Sgs150176 
1166c7fd2ed0Sgs150176 	/*
1167c7fd2ed0Sgs150176 	 * Change to config register write enable mode
1168c7fd2ed0Sgs150176 	 */
1169c7fd2ed0Sgs150176 	rge_reg_set8(rgep, RT_93c46_COMMOND_REG, RT_93c46_MODE_CONFIG);
1170c7fd2ed0Sgs150176 
1171c7fd2ed0Sgs150176 	/*
1172c7fd2ed0Sgs150176 	 * Get first 4 bytes of mac address
1173c7fd2ed0Sgs150176 	 */
1174c7fd2ed0Sgs150176 	val32 = p[3];
1175c7fd2ed0Sgs150176 	val32 = val32 << 8;
1176c7fd2ed0Sgs150176 	val32 |= p[2];
1177c7fd2ed0Sgs150176 	val32 = val32 << 8;
1178c7fd2ed0Sgs150176 	val32 |= p[1];
1179c7fd2ed0Sgs150176 	val32 = val32 << 8;
1180c7fd2ed0Sgs150176 	val32 |= p[0];
1181c7fd2ed0Sgs150176 
1182c7fd2ed0Sgs150176 	/*
1183c7fd2ed0Sgs150176 	 * Set first 4 bytes of mac address
1184c7fd2ed0Sgs150176 	 */
1185c7fd2ed0Sgs150176 	rge_reg_put32(rgep, ID_0_REG, val32);
1186c7fd2ed0Sgs150176 
1187c7fd2ed0Sgs150176 	/*
1188c7fd2ed0Sgs150176 	 * Get last 2 bytes of mac address
1189c7fd2ed0Sgs150176 	 */
1190c7fd2ed0Sgs150176 	val32 = p[5];
1191c7fd2ed0Sgs150176 	val32 = val32 << 8;
1192c7fd2ed0Sgs150176 	val32 |= p[4];
1193c7fd2ed0Sgs150176 
1194c7fd2ed0Sgs150176 	/*
1195c7fd2ed0Sgs150176 	 * Set last 2 bytes of mac address
1196c7fd2ed0Sgs150176 	 */
1197c7fd2ed0Sgs150176 	val32 |= rge_reg_get32(rgep, ID_4_REG) & ~0xffff;
1198c7fd2ed0Sgs150176 	rge_reg_put32(rgep, ID_4_REG, val32);
1199c7fd2ed0Sgs150176 
1200c7fd2ed0Sgs150176 	/*
1201c7fd2ed0Sgs150176 	 * Return to normal network/host communication mode
1202c7fd2ed0Sgs150176 	 */
1203c7fd2ed0Sgs150176 	rge_reg_clr8(rgep, RT_93c46_COMMOND_REG, RT_93c46_MODE_CONFIG);
1204c7fd2ed0Sgs150176 }
1205c7fd2ed0Sgs150176 
1206c7fd2ed0Sgs150176 static void rge_set_multi_addr(rge_t *rgep);
1207c7fd2ed0Sgs150176 #pragma	inline(rge_set_multi_addr)
1208c7fd2ed0Sgs150176 
1209c7fd2ed0Sgs150176 static void
rge_set_multi_addr(rge_t * rgep)1210c7fd2ed0Sgs150176 rge_set_multi_addr(rge_t *rgep)
1211c7fd2ed0Sgs150176 {
1212c7fd2ed0Sgs150176 	uint32_t *hashp;
1213c7fd2ed0Sgs150176 
1214aa817493Sgs150176 	hashp = (uint32_t *)rgep->mcast_hash;
121552643194Sgs150176 
121652643194Sgs150176 	/*
121752643194Sgs150176 	 * Change to config register write enable mode
121852643194Sgs150176 	 */
1219368a5ef8SMiles Xu, Sun Microsystems 	if (rgep->chipid.mac_ver == MAC_VER_8169SC) {
122052643194Sgs150176 		rge_reg_set8(rgep, RT_93c46_COMMOND_REG, RT_93c46_MODE_CONFIG);
1221368a5ef8SMiles Xu, Sun Microsystems 	}
12225927ab2bSKHF04453@nifty.ne.jp 	if (rgep->promisc) {
12235927ab2bSKHF04453@nifty.ne.jp 		rge_reg_put32(rgep, MULTICAST_0_REG, ~0U);
12245927ab2bSKHF04453@nifty.ne.jp 		rge_reg_put32(rgep, MULTICAST_4_REG, ~0U);
12255927ab2bSKHF04453@nifty.ne.jp 	} else {
1226aa817493Sgs150176 		rge_reg_put32(rgep, MULTICAST_0_REG, RGE_BSWAP_32(hashp[0]));
1227aa817493Sgs150176 		rge_reg_put32(rgep, MULTICAST_4_REG, RGE_BSWAP_32(hashp[1]));
12285927ab2bSKHF04453@nifty.ne.jp 	}
122952643194Sgs150176 
123052643194Sgs150176 	/*
123152643194Sgs150176 	 * Return to normal network/host communication mode
123252643194Sgs150176 	 */
1233368a5ef8SMiles Xu, Sun Microsystems 	if (rgep->chipid.mac_ver == MAC_VER_8169SC) {
123452643194Sgs150176 		rge_reg_clr8(rgep, RT_93c46_COMMOND_REG, RT_93c46_MODE_CONFIG);
1235c7fd2ed0Sgs150176 	}
1236368a5ef8SMiles Xu, Sun Microsystems }
1237c7fd2ed0Sgs150176 
1238c7fd2ed0Sgs150176 static void rge_set_promisc(rge_t *rgep);
1239c7fd2ed0Sgs150176 #pragma	inline(rge_set_promisc)
1240c7fd2ed0Sgs150176 
1241c7fd2ed0Sgs150176 static void
rge_set_promisc(rge_t * rgep)1242c7fd2ed0Sgs150176 rge_set_promisc(rge_t *rgep)
1243c7fd2ed0Sgs150176 {
1244c7fd2ed0Sgs150176 	if (rgep->promisc)
1245c7fd2ed0Sgs150176 		rge_reg_set32(rgep, RX_CONFIG_REG, RX_ACCEPT_ALL_PKT);
1246c7fd2ed0Sgs150176 	else
1247c7fd2ed0Sgs150176 		rge_reg_clr32(rgep, RX_CONFIG_REG, RX_ACCEPT_ALL_PKT);
1248c7fd2ed0Sgs150176 }
1249c7fd2ed0Sgs150176 
1250c7fd2ed0Sgs150176 /*
1251c7fd2ed0Sgs150176  * rge_chip_sync() -- program the chip with the unicast MAC address,
1252c7fd2ed0Sgs150176  * the multicast hash table, the required level of promiscuity, and
1253c7fd2ed0Sgs150176  * the current loopback mode ...
1254c7fd2ed0Sgs150176  */
1255c7fd2ed0Sgs150176 void rge_chip_sync(rge_t *rgep, enum rge_sync_op todo);
1256c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_sync)
1257c7fd2ed0Sgs150176 
1258c7fd2ed0Sgs150176 void
rge_chip_sync(rge_t * rgep,enum rge_sync_op todo)1259c7fd2ed0Sgs150176 rge_chip_sync(rge_t *rgep, enum rge_sync_op todo)
1260c7fd2ed0Sgs150176 {
1261c7fd2ed0Sgs150176 	switch (todo) {
1262c7fd2ed0Sgs150176 	case RGE_GET_MAC:
1263c7fd2ed0Sgs150176 		rge_get_mac_addr(rgep);
1264c7fd2ed0Sgs150176 		break;
1265c7fd2ed0Sgs150176 	case RGE_SET_MAC:
1266c7fd2ed0Sgs150176 		/* Reprogram the unicast MAC address(es) ... */
1267c7fd2ed0Sgs150176 		rge_set_mac_addr(rgep);
1268c7fd2ed0Sgs150176 		break;
1269c7fd2ed0Sgs150176 	case RGE_SET_MUL:
1270c7fd2ed0Sgs150176 		/* Reprogram the hashed multicast address table ... */
1271c7fd2ed0Sgs150176 		rge_set_multi_addr(rgep);
1272c7fd2ed0Sgs150176 		break;
1273c7fd2ed0Sgs150176 	case RGE_SET_PROMISC:
1274c7fd2ed0Sgs150176 		/* Set or clear the PROMISCUOUS mode bit */
12755927ab2bSKHF04453@nifty.ne.jp 		rge_set_multi_addr(rgep);
1276c7fd2ed0Sgs150176 		rge_set_promisc(rgep);
1277c7fd2ed0Sgs150176 		break;
1278c7fd2ed0Sgs150176 	default:
1279c7fd2ed0Sgs150176 		break;
1280c7fd2ed0Sgs150176 	}
1281c7fd2ed0Sgs150176 }
1282c7fd2ed0Sgs150176 
1283da14cebeSEric Cheng void rge_chip_blank(void *arg, time_t ticks, uint_t count, int flag);
1284c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_blank)
1285c7fd2ed0Sgs150176 
1286da14cebeSEric Cheng /* ARGSUSED */
1287c7fd2ed0Sgs150176 void
rge_chip_blank(void * arg,time_t ticks,uint_t count,int flag)1288da14cebeSEric Cheng rge_chip_blank(void *arg, time_t ticks, uint_t count, int flag)
1289c7fd2ed0Sgs150176 {
1290c7fd2ed0Sgs150176 	_NOTE(ARGUNUSED(arg, ticks, count));
1291c7fd2ed0Sgs150176 }
1292c7fd2ed0Sgs150176 
1293c7fd2ed0Sgs150176 void rge_tx_trigger(rge_t *rgep);
1294c7fd2ed0Sgs150176 #pragma	no_inline(rge_tx_trigger)
1295c7fd2ed0Sgs150176 
1296c7fd2ed0Sgs150176 void
rge_tx_trigger(rge_t * rgep)1297c7fd2ed0Sgs150176 rge_tx_trigger(rge_t *rgep)
1298c7fd2ed0Sgs150176 {
12993a84c50fSWinson Wang - Sun Microsystems - Beijing China 	rge_reg_put8(rgep, TX_RINGS_POLL_REG, NORMAL_TX_RING_POLL);
1300c7fd2ed0Sgs150176 }
1301c7fd2ed0Sgs150176 
1302c7fd2ed0Sgs150176 void rge_hw_stats_dump(rge_t *rgep);
1303c7fd2ed0Sgs150176 #pragma	no_inline(rge_tx_trigger)
1304c7fd2ed0Sgs150176 
1305c7fd2ed0Sgs150176 void
rge_hw_stats_dump(rge_t * rgep)1306c7fd2ed0Sgs150176 rge_hw_stats_dump(rge_t *rgep)
1307c7fd2ed0Sgs150176 {
1308c7fd2ed0Sgs150176 	int i = 0;
13094bb4f326SLi-Zhen You 	uint32_t regval = 0;
1310c7fd2ed0Sgs150176 
13114bb4f326SLi-Zhen You 	if (rgep->rge_mac_state == RGE_MAC_STOPPED)
13124bb4f326SLi-Zhen You 		return;
13134bb4f326SLi-Zhen You 
13144bb4f326SLi-Zhen You 	regval = rge_reg_get32(rgep, DUMP_COUNTER_REG_0);
13154bb4f326SLi-Zhen You 	while (regval & DUMP_START) {
1316c7fd2ed0Sgs150176 		drv_usecwait(100);
1317c7fd2ed0Sgs150176 		if (++i > STATS_DUMP_LOOP) {
1318c7fd2ed0Sgs150176 			RGE_DEBUG(("rge h/w statistics dump fail!"));
1319c7fd2ed0Sgs150176 			rgep->rge_chip_state = RGE_CHIP_ERROR;
1320c7fd2ed0Sgs150176 			return;
1321c7fd2ed0Sgs150176 		}
13224bb4f326SLi-Zhen You 		regval = rge_reg_get32(rgep, DUMP_COUNTER_REG_0);
1323c7fd2ed0Sgs150176 	}
1324c7fd2ed0Sgs150176 	DMA_SYNC(rgep->dma_area_stats, DDI_DMA_SYNC_FORKERNEL);
1325c7fd2ed0Sgs150176 
1326c7fd2ed0Sgs150176 	/*
1327c7fd2ed0Sgs150176 	 * Start H/W statistics dump for RTL8169 chip
1328c7fd2ed0Sgs150176 	 */
1329c7fd2ed0Sgs150176 	rge_reg_set32(rgep, DUMP_COUNTER_REG_0, DUMP_START);
1330c7fd2ed0Sgs150176 }
1331c7fd2ed0Sgs150176 
1332c7fd2ed0Sgs150176 /*
1333c7fd2ed0Sgs150176  * ========== Hardware interrupt handler ==========
1334c7fd2ed0Sgs150176  */
1335c7fd2ed0Sgs150176 
1336c7fd2ed0Sgs150176 #undef	RGE_DBG
1337c7fd2ed0Sgs150176 #define	RGE_DBG		RGE_DBG_INT	/* debug flag for this code	*/
1338c7fd2ed0Sgs150176 
1339c7fd2ed0Sgs150176 static void rge_wake_factotum(rge_t *rgep);
1340c7fd2ed0Sgs150176 #pragma	inline(rge_wake_factotum)
1341c7fd2ed0Sgs150176 
1342c7fd2ed0Sgs150176 static void
rge_wake_factotum(rge_t * rgep)1343c7fd2ed0Sgs150176 rge_wake_factotum(rge_t *rgep)
1344c7fd2ed0Sgs150176 {
1345c7fd2ed0Sgs150176 	if (rgep->factotum_flag == 0) {
1346c7fd2ed0Sgs150176 		rgep->factotum_flag = 1;
1347aa817493Sgs150176 		(void) ddi_intr_trigger_softint(rgep->factotum_hdl, NULL);
1348c7fd2ed0Sgs150176 	}
1349c7fd2ed0Sgs150176 }
1350c7fd2ed0Sgs150176 
1351c7fd2ed0Sgs150176 /*
1352c7fd2ed0Sgs150176  *	rge_intr() -- handle chip interrupts
1353c7fd2ed0Sgs150176  */
1354aa817493Sgs150176 uint_t rge_intr(caddr_t arg1, caddr_t arg2);
1355c7fd2ed0Sgs150176 #pragma	no_inline(rge_intr)
1356c7fd2ed0Sgs150176 
1357c7fd2ed0Sgs150176 uint_t
rge_intr(caddr_t arg1,caddr_t arg2)1358aa817493Sgs150176 rge_intr(caddr_t arg1, caddr_t arg2)
1359c7fd2ed0Sgs150176 {
1360aa817493Sgs150176 	rge_t *rgep = (rge_t *)arg1;
1361c7fd2ed0Sgs150176 	uint16_t int_status;
13623a84c50fSWinson Wang - Sun Microsystems - Beijing China 	clock_t	now;
13633a84c50fSWinson Wang - Sun Microsystems - Beijing China 	uint32_t tx_pkts;
13643a84c50fSWinson Wang - Sun Microsystems - Beijing China 	uint32_t rx_pkts;
13653a84c50fSWinson Wang - Sun Microsystems - Beijing China 	uint32_t poll_rate;
13663a84c50fSWinson Wang - Sun Microsystems - Beijing China 	uint32_t opt_pkts;
13673a84c50fSWinson Wang - Sun Microsystems - Beijing China 	uint32_t opt_intrs;
13683a84c50fSWinson Wang - Sun Microsystems - Beijing China 	boolean_t update_int_mask = B_FALSE;
13693a84c50fSWinson Wang - Sun Microsystems - Beijing China 	uint32_t itimer;
1370c7fd2ed0Sgs150176 
1371aa817493Sgs150176 	_NOTE(ARGUNUSED(arg2))
1372c7fd2ed0Sgs150176 
1373aa817493Sgs150176 	mutex_enter(rgep->genlock);
1374343c2616Smx205022 
1375343c2616Smx205022 	if (rgep->suspended) {
1376343c2616Smx205022 		mutex_exit(rgep->genlock);
1377343c2616Smx205022 		return (DDI_INTR_UNCLAIMED);
1378343c2616Smx205022 	}
1379343c2616Smx205022 
1380c7fd2ed0Sgs150176 	/*
1381c7fd2ed0Sgs150176 	 * Was this interrupt caused by our device...
1382c7fd2ed0Sgs150176 	 */
1383c7fd2ed0Sgs150176 	int_status = rge_reg_get16(rgep, INT_STATUS_REG);
1384c7fd2ed0Sgs150176 	if (!(int_status & rgep->int_mask)) {
1385c7fd2ed0Sgs150176 		mutex_exit(rgep->genlock);
1386c7fd2ed0Sgs150176 		return (DDI_INTR_UNCLAIMED);
1387c7fd2ed0Sgs150176 				/* indicate it wasn't our interrupt */
1388c7fd2ed0Sgs150176 	}
1389c7fd2ed0Sgs150176 	rgep->stats.intr++;
1390c7fd2ed0Sgs150176 
1391c7fd2ed0Sgs150176 	/*
1392c7fd2ed0Sgs150176 	 * Clear interrupt
1393aa817493Sgs150176 	 *	For PCIE chipset, we need disable interrupt first.
1394c7fd2ed0Sgs150176 	 */
13953a84c50fSWinson Wang - Sun Microsystems - Beijing China 	if (rgep->chipid.is_pcie) {
1396aa817493Sgs150176 		rge_reg_put16(rgep, INT_MASK_REG, INT_MASK_NONE);
13973a84c50fSWinson Wang - Sun Microsystems - Beijing China 		update_int_mask = B_TRUE;
13983a84c50fSWinson Wang - Sun Microsystems - Beijing China 	}
1399c7fd2ed0Sgs150176 	rge_reg_put16(rgep, INT_STATUS_REG, int_status);
1400c7fd2ed0Sgs150176 
1401c7fd2ed0Sgs150176 	/*
14023a84c50fSWinson Wang - Sun Microsystems - Beijing China 	 * Calculate optimal polling interval
14033a84c50fSWinson Wang - Sun Microsystems - Beijing China 	 */
14043a84c50fSWinson Wang - Sun Microsystems - Beijing China 	now = ddi_get_lbolt();
14053a84c50fSWinson Wang - Sun Microsystems - Beijing China 	if (now - rgep->curr_tick >= rgep->tick_delta &&
14063a84c50fSWinson Wang - Sun Microsystems - Beijing China 	    (rgep->param_link_speed == RGE_SPEED_1000M ||
14073a84c50fSWinson Wang - Sun Microsystems - Beijing China 	    rgep->param_link_speed == RGE_SPEED_100M)) {
14083a84c50fSWinson Wang - Sun Microsystems - Beijing China 		/* number of rx and tx packets in the last tick */
14093a84c50fSWinson Wang - Sun Microsystems - Beijing China 		tx_pkts = rgep->stats.opackets - rgep->last_opackets;
14103a84c50fSWinson Wang - Sun Microsystems - Beijing China 		rx_pkts = rgep->stats.rpackets - rgep->last_rpackets;
14113a84c50fSWinson Wang - Sun Microsystems - Beijing China 
14123a84c50fSWinson Wang - Sun Microsystems - Beijing China 		rgep->last_opackets = rgep->stats.opackets;
14133a84c50fSWinson Wang - Sun Microsystems - Beijing China 		rgep->last_rpackets = rgep->stats.rpackets;
14143a84c50fSWinson Wang - Sun Microsystems - Beijing China 
14153a84c50fSWinson Wang - Sun Microsystems - Beijing China 		/* restore interrupt mask */
14163a84c50fSWinson Wang - Sun Microsystems - Beijing China 		rgep->int_mask |= TX_OK_INT | RX_OK_INT;
14173a84c50fSWinson Wang - Sun Microsystems - Beijing China 		if (rgep->chipid.is_pcie) {
14183a84c50fSWinson Wang - Sun Microsystems - Beijing China 			rgep->int_mask |= NO_TXDESC_INT;
14193a84c50fSWinson Wang - Sun Microsystems - Beijing China 		}
14203a84c50fSWinson Wang - Sun Microsystems - Beijing China 
14213a84c50fSWinson Wang - Sun Microsystems - Beijing China 		/* optimal number of packets in a tick */
14223a84c50fSWinson Wang - Sun Microsystems - Beijing China 		if (rgep->param_link_speed == RGE_SPEED_1000M) {
14233a84c50fSWinson Wang - Sun Microsystems - Beijing China 			opt_pkts = (1000*1000*1000/8)/ETHERMTU/CLK_TICK;
14243a84c50fSWinson Wang - Sun Microsystems - Beijing China 		} else {
14253a84c50fSWinson Wang - Sun Microsystems - Beijing China 			opt_pkts = (100*1000*1000/8)/ETHERMTU/CLK_TICK;
14263a84c50fSWinson Wang - Sun Microsystems - Beijing China 		}
14273a84c50fSWinson Wang - Sun Microsystems - Beijing China 
14283a84c50fSWinson Wang - Sun Microsystems - Beijing China 		/*
14293a84c50fSWinson Wang - Sun Microsystems - Beijing China 		 * calculate polling interval based on rx and tx packets
14303a84c50fSWinson Wang - Sun Microsystems - Beijing China 		 * in the last tick
14313a84c50fSWinson Wang - Sun Microsystems - Beijing China 		 */
14323a84c50fSWinson Wang - Sun Microsystems - Beijing China 		poll_rate = 0;
14333a84c50fSWinson Wang - Sun Microsystems - Beijing China 		if (now - rgep->curr_tick < 2*rgep->tick_delta) {
14343a84c50fSWinson Wang - Sun Microsystems - Beijing China 			opt_intrs = opt_pkts/TX_COALESC;
14353a84c50fSWinson Wang - Sun Microsystems - Beijing China 			if (tx_pkts > opt_intrs) {
14363a84c50fSWinson Wang - Sun Microsystems - Beijing China 				poll_rate = max(tx_pkts/TX_COALESC, opt_intrs);
14373a84c50fSWinson Wang - Sun Microsystems - Beijing China 				rgep->int_mask &= ~(TX_OK_INT | NO_TXDESC_INT);
14383a84c50fSWinson Wang - Sun Microsystems - Beijing China 			}
14393a84c50fSWinson Wang - Sun Microsystems - Beijing China 
14403a84c50fSWinson Wang - Sun Microsystems - Beijing China 			opt_intrs = opt_pkts/RX_COALESC;
14413a84c50fSWinson Wang - Sun Microsystems - Beijing China 			if (rx_pkts > opt_intrs) {
14423a84c50fSWinson Wang - Sun Microsystems - Beijing China 				opt_intrs = max(rx_pkts/RX_COALESC, opt_intrs);
14433a84c50fSWinson Wang - Sun Microsystems - Beijing China 				poll_rate = max(opt_intrs, poll_rate);
14443a84c50fSWinson Wang - Sun Microsystems - Beijing China 				rgep->int_mask &= ~RX_OK_INT;
14453a84c50fSWinson Wang - Sun Microsystems - Beijing China 			}
14463a84c50fSWinson Wang - Sun Microsystems - Beijing China 			/* ensure poll_rate reasonable */
14473a84c50fSWinson Wang - Sun Microsystems - Beijing China 			poll_rate = min(poll_rate, opt_pkts*4);
14483a84c50fSWinson Wang - Sun Microsystems - Beijing China 		}
14493a84c50fSWinson Wang - Sun Microsystems - Beijing China 
14503a84c50fSWinson Wang - Sun Microsystems - Beijing China 		if (poll_rate) {
14513a84c50fSWinson Wang - Sun Microsystems - Beijing China 			/* move to polling mode */
14523a84c50fSWinson Wang - Sun Microsystems - Beijing China 			if (rgep->chipid.is_pcie) {
14533a84c50fSWinson Wang - Sun Microsystems - Beijing China 				itimer = (TIMER_CLK_PCIE/CLK_TICK)/poll_rate;
14543a84c50fSWinson Wang - Sun Microsystems - Beijing China 			} else {
14553a84c50fSWinson Wang - Sun Microsystems - Beijing China 				itimer = (TIMER_CLK_PCI/CLK_TICK)/poll_rate;
14563a84c50fSWinson Wang - Sun Microsystems - Beijing China 			}
14573a84c50fSWinson Wang - Sun Microsystems - Beijing China 		} else {
14583a84c50fSWinson Wang - Sun Microsystems - Beijing China 			/* move to normal mode */
14593a84c50fSWinson Wang - Sun Microsystems - Beijing China 			itimer = 0;
14603a84c50fSWinson Wang - Sun Microsystems - Beijing China 		}
14613a84c50fSWinson Wang - Sun Microsystems - Beijing China 		RGE_DEBUG(("%s: poll: itimer:%d int_mask:0x%x",
14623a84c50fSWinson Wang - Sun Microsystems - Beijing China 		    __func__, itimer, rgep->int_mask));
14633a84c50fSWinson Wang - Sun Microsystems - Beijing China 		rge_reg_put32(rgep, TIMER_INT_REG, itimer);
14643a84c50fSWinson Wang - Sun Microsystems - Beijing China 
14653a84c50fSWinson Wang - Sun Microsystems - Beijing China 		/* update timestamp for statistics */
14663a84c50fSWinson Wang - Sun Microsystems - Beijing China 		rgep->curr_tick = now;
14673a84c50fSWinson Wang - Sun Microsystems - Beijing China 
14683a84c50fSWinson Wang - Sun Microsystems - Beijing China 		/* reset timer */
14693a84c50fSWinson Wang - Sun Microsystems - Beijing China 		int_status |= TIME_OUT_INT;
14703a84c50fSWinson Wang - Sun Microsystems - Beijing China 
14713a84c50fSWinson Wang - Sun Microsystems - Beijing China 		update_int_mask = B_TRUE;
14723a84c50fSWinson Wang - Sun Microsystems - Beijing China 	}
14733a84c50fSWinson Wang - Sun Microsystems - Beijing China 
14743a84c50fSWinson Wang - Sun Microsystems - Beijing China 	if (int_status & TIME_OUT_INT) {
14753a84c50fSWinson Wang - Sun Microsystems - Beijing China 		rge_reg_put32(rgep, TIMER_COUNT_REG, 0);
14763a84c50fSWinson Wang - Sun Microsystems - Beijing China 	}
14773a84c50fSWinson Wang - Sun Microsystems - Beijing China 
14783a84c50fSWinson Wang - Sun Microsystems - Beijing China 	/* flush post writes */
14793a84c50fSWinson Wang - Sun Microsystems - Beijing China 	(void) rge_reg_get16(rgep, INT_STATUS_REG);
14803a84c50fSWinson Wang - Sun Microsystems - Beijing China 
14813a84c50fSWinson Wang - Sun Microsystems - Beijing China 	/*
1482c7fd2ed0Sgs150176 	 * Cable link change interrupt
1483c7fd2ed0Sgs150176 	 */
1484c7fd2ed0Sgs150176 	if (int_status & LINK_CHANGE_INT) {
1485c7fd2ed0Sgs150176 		rge_chip_cyclic(rgep);
1486c7fd2ed0Sgs150176 	}
1487aa817493Sgs150176 
14887b114c4bSWinson Wang - Sun Microsystems - Beijing China 	if (int_status & RX_FIFO_OVERFLOW_INT) {
14897b114c4bSWinson Wang - Sun Microsystems - Beijing China 		/* start rx watchdog timeout detection */
14907b114c4bSWinson Wang - Sun Microsystems - Beijing China 		rgep->rx_fifo_ovf = 1;
14917b114c4bSWinson Wang - Sun Microsystems - Beijing China 		if (rgep->int_mask & RX_FIFO_OVERFLOW_INT) {
14927b114c4bSWinson Wang - Sun Microsystems - Beijing China 			rgep->int_mask &= ~RX_FIFO_OVERFLOW_INT;
14937b114c4bSWinson Wang - Sun Microsystems - Beijing China 			update_int_mask = B_TRUE;
14947b114c4bSWinson Wang - Sun Microsystems - Beijing China 		}
14957b114c4bSWinson Wang - Sun Microsystems - Beijing China 	} else if (int_status & RGE_RX_INT) {
14967b114c4bSWinson Wang - Sun Microsystems - Beijing China 		/* stop rx watchdog timeout detection */
14977b114c4bSWinson Wang - Sun Microsystems - Beijing China 		rgep->rx_fifo_ovf = 0;
14987b114c4bSWinson Wang - Sun Microsystems - Beijing China 		if ((rgep->int_mask & RX_FIFO_OVERFLOW_INT) == 0) {
14997b114c4bSWinson Wang - Sun Microsystems - Beijing China 			rgep->int_mask |= RX_FIFO_OVERFLOW_INT;
15007b114c4bSWinson Wang - Sun Microsystems - Beijing China 			update_int_mask = B_TRUE;
15017b114c4bSWinson Wang - Sun Microsystems - Beijing China 		}
15027b114c4bSWinson Wang - Sun Microsystems - Beijing China 	}
15037b114c4bSWinson Wang - Sun Microsystems - Beijing China 
1504c7fd2ed0Sgs150176 	mutex_exit(rgep->genlock);
1505c7fd2ed0Sgs150176 
1506c7fd2ed0Sgs150176 	/*
1507c7fd2ed0Sgs150176 	 * Receive interrupt
1508c7fd2ed0Sgs150176 	 */
1509aa817493Sgs150176 	if (int_status & RGE_RX_INT)
1510c7fd2ed0Sgs150176 		rge_receive(rgep);
1511c7fd2ed0Sgs150176 
1512aa817493Sgs150176 	/*
15133a84c50fSWinson Wang - Sun Microsystems - Beijing China 	 * Transmit interrupt
1514aa817493Sgs150176 	 */
15153a84c50fSWinson Wang - Sun Microsystems - Beijing China 	if (int_status & TX_ERR_INT) {
15163a84c50fSWinson Wang - Sun Microsystems - Beijing China 		RGE_REPORT((rgep, "tx error happened, resetting the chip "));
15173a84c50fSWinson Wang - Sun Microsystems - Beijing China 		mutex_enter(rgep->genlock);
15183a84c50fSWinson Wang - Sun Microsystems - Beijing China 		rgep->rge_chip_state = RGE_CHIP_ERROR;
15193a84c50fSWinson Wang - Sun Microsystems - Beijing China 		mutex_exit(rgep->genlock);
15203a84c50fSWinson Wang - Sun Microsystems - Beijing China 	} else if ((rgep->chipid.is_pcie && (int_status & NO_TXDESC_INT)) ||
15213a84c50fSWinson Wang - Sun Microsystems - Beijing China 	    ((int_status & TX_OK_INT) && rgep->tx_free < RGE_SEND_SLOTS/8)) {
15223a84c50fSWinson Wang - Sun Microsystems - Beijing China 		(void) ddi_intr_trigger_softint(rgep->resched_hdl, NULL);
15233a84c50fSWinson Wang - Sun Microsystems - Beijing China 	}
15243a84c50fSWinson Wang - Sun Microsystems - Beijing China 
15253a84c50fSWinson Wang - Sun Microsystems - Beijing China 	/*
15269e1a9180SLi-Zhen You 	 * System error interrupt
15279e1a9180SLi-Zhen You 	 */
15289e1a9180SLi-Zhen You 	if (int_status & SYS_ERR_INT) {
15299e1a9180SLi-Zhen You 		RGE_REPORT((rgep, "sys error happened, resetting the chip "));
15309e1a9180SLi-Zhen You 		mutex_enter(rgep->genlock);
15319e1a9180SLi-Zhen You 		rgep->rge_chip_state = RGE_CHIP_ERROR;
15329e1a9180SLi-Zhen You 		mutex_exit(rgep->genlock);
15339e1a9180SLi-Zhen You 	}
15349e1a9180SLi-Zhen You 
15359e1a9180SLi-Zhen You 	/*
15363a84c50fSWinson Wang - Sun Microsystems - Beijing China 	 * Re-enable interrupt for PCIE chipset or install new int_mask
15373a84c50fSWinson Wang - Sun Microsystems - Beijing China 	 */
15383a84c50fSWinson Wang - Sun Microsystems - Beijing China 	if (update_int_mask)
1539aa817493Sgs150176 		rge_reg_put16(rgep, INT_MASK_REG, rgep->int_mask);
1540aa817493Sgs150176 
1541c7fd2ed0Sgs150176 	return (DDI_INTR_CLAIMED);	/* indicate it was our interrupt */
1542c7fd2ed0Sgs150176 }
1543c7fd2ed0Sgs150176 
1544c7fd2ed0Sgs150176 /*
1545c7fd2ed0Sgs150176  * ========== Factotum, implemented as a softint handler ==========
1546c7fd2ed0Sgs150176  */
1547c7fd2ed0Sgs150176 
1548c7fd2ed0Sgs150176 #undef	RGE_DBG
1549c7fd2ed0Sgs150176 #define	RGE_DBG		RGE_DBG_FACT	/* debug flag for this code	*/
1550c7fd2ed0Sgs150176 
1551c7fd2ed0Sgs150176 static boolean_t rge_factotum_link_check(rge_t *rgep);
1552c7fd2ed0Sgs150176 #pragma	no_inline(rge_factotum_link_check)
1553c7fd2ed0Sgs150176 
1554c7fd2ed0Sgs150176 static boolean_t
rge_factotum_link_check(rge_t * rgep)1555c7fd2ed0Sgs150176 rge_factotum_link_check(rge_t *rgep)
1556c7fd2ed0Sgs150176 {
1557c7fd2ed0Sgs150176 	uint8_t media_status;
1558c7fd2ed0Sgs150176 	int32_t link;
1559c7fd2ed0Sgs150176 
1560c7fd2ed0Sgs150176 	media_status = rge_reg_get8(rgep, PHY_STATUS_REG);
1561c7fd2ed0Sgs150176 	link = (media_status & PHY_STATUS_LINK_UP) ?
1562c7fd2ed0Sgs150176 	    LINK_STATE_UP : LINK_STATE_DOWN;
1563c7fd2ed0Sgs150176 	if (rgep->param_link_up != link) {
1564c7fd2ed0Sgs150176 		/*
15650d2a8e5eSgd78059 		 * Link change.
1566c7fd2ed0Sgs150176 		 */
1567c7fd2ed0Sgs150176 		rgep->param_link_up = link;
1568c7fd2ed0Sgs150176 
1569c7fd2ed0Sgs150176 		if (link == LINK_STATE_UP) {
1570c7fd2ed0Sgs150176 			if (media_status & PHY_STATUS_1000MF) {
1571c7fd2ed0Sgs150176 				rgep->param_link_speed = RGE_SPEED_1000M;
1572c7fd2ed0Sgs150176 				rgep->param_link_duplex = LINK_DUPLEX_FULL;
1573c7fd2ed0Sgs150176 			} else {
1574c7fd2ed0Sgs150176 				rgep->param_link_speed =
1575c7fd2ed0Sgs150176 				    (media_status & PHY_STATUS_100M) ?
1576c7fd2ed0Sgs150176 				    RGE_SPEED_100M : RGE_SPEED_10M;
1577c7fd2ed0Sgs150176 				rgep->param_link_duplex =
1578c7fd2ed0Sgs150176 				    (media_status & PHY_STATUS_DUPLEX_FULL) ?
1579c7fd2ed0Sgs150176 				    LINK_DUPLEX_FULL : LINK_DUPLEX_HALF;
1580c7fd2ed0Sgs150176 			}
1581c7fd2ed0Sgs150176 		}
1582c7fd2ed0Sgs150176 		return (B_TRUE);
1583c7fd2ed0Sgs150176 	}
1584c7fd2ed0Sgs150176 	return (B_FALSE);
1585c7fd2ed0Sgs150176 }
1586c7fd2ed0Sgs150176 
1587c7fd2ed0Sgs150176 /*
1588c7fd2ed0Sgs150176  * Factotum routine to check for Tx stall, using the 'watchdog' counter
1589c7fd2ed0Sgs150176  */
1590c7fd2ed0Sgs150176 static boolean_t rge_factotum_stall_check(rge_t *rgep);
1591c7fd2ed0Sgs150176 #pragma	no_inline(rge_factotum_stall_check)
1592c7fd2ed0Sgs150176 
1593c7fd2ed0Sgs150176 static boolean_t
rge_factotum_stall_check(rge_t * rgep)1594c7fd2ed0Sgs150176 rge_factotum_stall_check(rge_t *rgep)
1595c7fd2ed0Sgs150176 {
1596c7fd2ed0Sgs150176 	uint32_t dogval;
1597c7fd2ed0Sgs150176 
1598c7fd2ed0Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
1599c7fd2ed0Sgs150176 
1600c7fd2ed0Sgs150176 	/*
16017b114c4bSWinson Wang - Sun Microsystems - Beijing China 	 * Specific check for RX stall ...
16027b114c4bSWinson Wang - Sun Microsystems - Beijing China 	 */
16037b114c4bSWinson Wang - Sun Microsystems - Beijing China 	rgep->rx_fifo_ovf <<= 1;
16047b114c4bSWinson Wang - Sun Microsystems - Beijing China 	if (rgep->rx_fifo_ovf > rge_rx_watchdog_count) {
16057b114c4bSWinson Wang - Sun Microsystems - Beijing China 		RGE_REPORT((rgep, "rx_hang detected"));
16067b114c4bSWinson Wang - Sun Microsystems - Beijing China 		return (B_TRUE);
16077b114c4bSWinson Wang - Sun Microsystems - Beijing China 	}
16087b114c4bSWinson Wang - Sun Microsystems - Beijing China 
16097b114c4bSWinson Wang - Sun Microsystems - Beijing China 	/*
1610c7fd2ed0Sgs150176 	 * Specific check for Tx stall ...
1611c7fd2ed0Sgs150176 	 *
1612c7fd2ed0Sgs150176 	 * The 'watchdog' counter is incremented whenever a packet
1613c7fd2ed0Sgs150176 	 * is queued, reset to 1 when some (but not all) buffers
1614c7fd2ed0Sgs150176 	 * are reclaimed, reset to 0 (disabled) when all buffers
1615c7fd2ed0Sgs150176 	 * are reclaimed, and shifted left here.  If it exceeds the
1616c7fd2ed0Sgs150176 	 * threshold value, the chip is assumed to have stalled and
1617c7fd2ed0Sgs150176 	 * is put into the ERROR state.  The factotum will then reset
1618c7fd2ed0Sgs150176 	 * it on the next pass.
1619c7fd2ed0Sgs150176 	 *
1620c7fd2ed0Sgs150176 	 * All of which should ensure that we don't get into a state
1621c7fd2ed0Sgs150176 	 * where packets are left pending indefinitely!
1622c7fd2ed0Sgs150176 	 */
1623aa817493Sgs150176 	if (rgep->resched_needed)
1624aa817493Sgs150176 		(void) ddi_intr_trigger_softint(rgep->resched_hdl, NULL);
1625c7fd2ed0Sgs150176 	dogval = rge_atomic_shl32(&rgep->watchdog, 1);
1626c7fd2ed0Sgs150176 	if (dogval < rge_watchdog_count)
1627c7fd2ed0Sgs150176 		return (B_FALSE);
1628c7fd2ed0Sgs150176 
1629c7fd2ed0Sgs150176 	RGE_REPORT((rgep, "Tx stall detected, watchdog code 0x%x", dogval));
1630c7fd2ed0Sgs150176 	return (B_TRUE);
1631c7fd2ed0Sgs150176 
1632c7fd2ed0Sgs150176 }
1633c7fd2ed0Sgs150176 
1634c7fd2ed0Sgs150176 /*
1635c7fd2ed0Sgs150176  * The factotum is woken up when there's something to do that we'd rather
1636c7fd2ed0Sgs150176  * not do from inside a hardware interrupt handler or high-level cyclic.
1637c7fd2ed0Sgs150176  * Its two main tasks are:
1638c7fd2ed0Sgs150176  *	reset & restart the chip after an error
1639c7fd2ed0Sgs150176  *	check the link status whenever necessary
1640c7fd2ed0Sgs150176  */
1641aa817493Sgs150176 uint_t rge_chip_factotum(caddr_t arg1, caddr_t arg2);
1642c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_factotum)
1643c7fd2ed0Sgs150176 
1644c7fd2ed0Sgs150176 uint_t
rge_chip_factotum(caddr_t arg1,caddr_t arg2)1645aa817493Sgs150176 rge_chip_factotum(caddr_t arg1, caddr_t arg2)
1646c7fd2ed0Sgs150176 {
1647c7fd2ed0Sgs150176 	rge_t *rgep;
1648c7fd2ed0Sgs150176 	uint_t result;
1649c7fd2ed0Sgs150176 	boolean_t error;
1650c7fd2ed0Sgs150176 	boolean_t linkchg;
1651c7fd2ed0Sgs150176 
1652aa817493Sgs150176 	rgep = (rge_t *)arg1;
1653aa817493Sgs150176 	_NOTE(ARGUNUSED(arg2))
1654c7fd2ed0Sgs150176 
1655c7fd2ed0Sgs150176 	if (rgep->factotum_flag == 0)
1656c7fd2ed0Sgs150176 		return (DDI_INTR_UNCLAIMED);
1657c7fd2ed0Sgs150176 
1658c7fd2ed0Sgs150176 	rgep->factotum_flag = 0;
1659c7fd2ed0Sgs150176 	result = DDI_INTR_CLAIMED;
1660c7fd2ed0Sgs150176 	error = B_FALSE;
1661c7fd2ed0Sgs150176 	linkchg = B_FALSE;
1662c7fd2ed0Sgs150176 
1663c7fd2ed0Sgs150176 	mutex_enter(rgep->genlock);
1664c7fd2ed0Sgs150176 	switch (rgep->rge_chip_state) {
1665c7fd2ed0Sgs150176 	default:
1666c7fd2ed0Sgs150176 		break;
1667c7fd2ed0Sgs150176 
1668c7fd2ed0Sgs150176 	case RGE_CHIP_RUNNING:
1669c7fd2ed0Sgs150176 		linkchg = rge_factotum_link_check(rgep);
1670c7fd2ed0Sgs150176 		error = rge_factotum_stall_check(rgep);
1671c7fd2ed0Sgs150176 		break;
1672c7fd2ed0Sgs150176 
1673c7fd2ed0Sgs150176 	case RGE_CHIP_ERROR:
1674c7fd2ed0Sgs150176 		error = B_TRUE;
1675c7fd2ed0Sgs150176 		break;
1676c7fd2ed0Sgs150176 
1677c7fd2ed0Sgs150176 	case RGE_CHIP_FAULT:
1678c7fd2ed0Sgs150176 		/*
1679c7fd2ed0Sgs150176 		 * Fault detected, time to reset ...
1680c7fd2ed0Sgs150176 		 */
1681c7fd2ed0Sgs150176 		if (rge_autorecover) {
1682c7fd2ed0Sgs150176 			RGE_REPORT((rgep, "automatic recovery activated"));
1683c7fd2ed0Sgs150176 			rge_restart(rgep);
1684c7fd2ed0Sgs150176 		}
1685c7fd2ed0Sgs150176 		break;
1686c7fd2ed0Sgs150176 	}
1687c7fd2ed0Sgs150176 
1688c7fd2ed0Sgs150176 	/*
1689c7fd2ed0Sgs150176 	 * If an error is detected, stop the chip now, marking it as
1690c7fd2ed0Sgs150176 	 * faulty, so that it will be reset next time through ...
1691c7fd2ed0Sgs150176 	 */
1692c7fd2ed0Sgs150176 	if (error)
1693c7fd2ed0Sgs150176 		rge_chip_stop(rgep, B_TRUE);
1694c7fd2ed0Sgs150176 	mutex_exit(rgep->genlock);
1695c7fd2ed0Sgs150176 
1696c7fd2ed0Sgs150176 	/*
1697c7fd2ed0Sgs150176 	 * If the link state changed, tell the world about it.
1698c7fd2ed0Sgs150176 	 * Note: can't do this while still holding the mutex.
1699c7fd2ed0Sgs150176 	 */
1700c7fd2ed0Sgs150176 	if (linkchg)
1701ba2e4443Sseb 		mac_link_update(rgep->mh, rgep->param_link_up);
1702c7fd2ed0Sgs150176 
1703c7fd2ed0Sgs150176 	return (result);
1704c7fd2ed0Sgs150176 }
1705c7fd2ed0Sgs150176 
1706c7fd2ed0Sgs150176 /*
1707c7fd2ed0Sgs150176  * High-level cyclic handler
1708c7fd2ed0Sgs150176  *
1709c7fd2ed0Sgs150176  * This routine schedules a (low-level) softint callback to the
1710c7fd2ed0Sgs150176  * factotum, and prods the chip to update the status block (which
1711c7fd2ed0Sgs150176  * will cause a hardware interrupt when complete).
1712c7fd2ed0Sgs150176  */
1713c7fd2ed0Sgs150176 void rge_chip_cyclic(void *arg);
1714c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_cyclic)
1715c7fd2ed0Sgs150176 
1716c7fd2ed0Sgs150176 void
rge_chip_cyclic(void * arg)1717c7fd2ed0Sgs150176 rge_chip_cyclic(void *arg)
1718c7fd2ed0Sgs150176 {
1719c7fd2ed0Sgs150176 	rge_t *rgep;
1720c7fd2ed0Sgs150176 
1721c7fd2ed0Sgs150176 	rgep = arg;
1722c7fd2ed0Sgs150176 
1723c7fd2ed0Sgs150176 	switch (rgep->rge_chip_state) {
1724c7fd2ed0Sgs150176 	default:
1725c7fd2ed0Sgs150176 		return;
1726c7fd2ed0Sgs150176 
1727c7fd2ed0Sgs150176 	case RGE_CHIP_RUNNING:
1728c7fd2ed0Sgs150176 		rge_phy_check(rgep);
17299e1a9180SLi-Zhen You 		if (rgep->tx_free < RGE_SEND_SLOTS)
17309e1a9180SLi-Zhen You 			rge_send_recycle(rgep);
1731c7fd2ed0Sgs150176 		break;
1732c7fd2ed0Sgs150176 
1733c7fd2ed0Sgs150176 	case RGE_CHIP_FAULT:
1734c7fd2ed0Sgs150176 	case RGE_CHIP_ERROR:
1735c7fd2ed0Sgs150176 		break;
1736c7fd2ed0Sgs150176 	}
1737c7fd2ed0Sgs150176 
1738c7fd2ed0Sgs150176 	rge_wake_factotum(rgep);
1739c7fd2ed0Sgs150176 }
1740c7fd2ed0Sgs150176 
1741c7fd2ed0Sgs150176 
1742c7fd2ed0Sgs150176 /*
1743c7fd2ed0Sgs150176  * ========== Ioctl subfunctions ==========
1744c7fd2ed0Sgs150176  */
1745c7fd2ed0Sgs150176 
1746c7fd2ed0Sgs150176 #undef	RGE_DBG
1747c7fd2ed0Sgs150176 #define	RGE_DBG		RGE_DBG_PPIO	/* debug flag for this code	*/
1748c7fd2ed0Sgs150176 
1749c7fd2ed0Sgs150176 #if	RGE_DEBUGGING || RGE_DO_PPIO
1750c7fd2ed0Sgs150176 
1751c7fd2ed0Sgs150176 static void rge_chip_peek_cfg(rge_t *rgep, rge_peekpoke_t *ppd);
1752c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_peek_cfg)
1753c7fd2ed0Sgs150176 
1754c7fd2ed0Sgs150176 static void
rge_chip_peek_cfg(rge_t * rgep,rge_peekpoke_t * ppd)1755c7fd2ed0Sgs150176 rge_chip_peek_cfg(rge_t *rgep, rge_peekpoke_t *ppd)
1756c7fd2ed0Sgs150176 {
1757c7fd2ed0Sgs150176 	uint64_t regval;
1758c7fd2ed0Sgs150176 	uint64_t regno;
1759c7fd2ed0Sgs150176 
1760c7fd2ed0Sgs150176 	RGE_TRACE(("rge_chip_peek_cfg($%p, $%p)",
1761c7fd2ed0Sgs150176 	    (void *)rgep, (void *)ppd));
1762c7fd2ed0Sgs150176 
1763c7fd2ed0Sgs150176 	regno = ppd->pp_acc_offset;
1764c7fd2ed0Sgs150176 
1765c7fd2ed0Sgs150176 	switch (ppd->pp_acc_size) {
1766c7fd2ed0Sgs150176 	case 1:
1767c7fd2ed0Sgs150176 		regval = pci_config_get8(rgep->cfg_handle, regno);
1768c7fd2ed0Sgs150176 		break;
1769c7fd2ed0Sgs150176 
1770c7fd2ed0Sgs150176 	case 2:
1771c7fd2ed0Sgs150176 		regval = pci_config_get16(rgep->cfg_handle, regno);
1772c7fd2ed0Sgs150176 		break;
1773c7fd2ed0Sgs150176 
1774c7fd2ed0Sgs150176 	case 4:
1775c7fd2ed0Sgs150176 		regval = pci_config_get32(rgep->cfg_handle, regno);
1776c7fd2ed0Sgs150176 		break;
1777c7fd2ed0Sgs150176 
1778c7fd2ed0Sgs150176 	case 8:
1779c7fd2ed0Sgs150176 		regval = pci_config_get64(rgep->cfg_handle, regno);
1780c7fd2ed0Sgs150176 		break;
1781c7fd2ed0Sgs150176 	}
1782c7fd2ed0Sgs150176 
1783c7fd2ed0Sgs150176 	ppd->pp_acc_data = regval;
1784c7fd2ed0Sgs150176 }
1785c7fd2ed0Sgs150176 
1786c7fd2ed0Sgs150176 static void rge_chip_poke_cfg(rge_t *rgep, rge_peekpoke_t *ppd);
1787c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_poke_cfg)
1788c7fd2ed0Sgs150176 
1789c7fd2ed0Sgs150176 static void
rge_chip_poke_cfg(rge_t * rgep,rge_peekpoke_t * ppd)1790c7fd2ed0Sgs150176 rge_chip_poke_cfg(rge_t *rgep, rge_peekpoke_t *ppd)
1791c7fd2ed0Sgs150176 {
1792c7fd2ed0Sgs150176 	uint64_t regval;
1793c7fd2ed0Sgs150176 	uint64_t regno;
1794c7fd2ed0Sgs150176 
1795c7fd2ed0Sgs150176 	RGE_TRACE(("rge_chip_poke_cfg($%p, $%p)",
1796c7fd2ed0Sgs150176 	    (void *)rgep, (void *)ppd));
1797c7fd2ed0Sgs150176 
1798c7fd2ed0Sgs150176 	regno = ppd->pp_acc_offset;
1799c7fd2ed0Sgs150176 	regval = ppd->pp_acc_data;
1800c7fd2ed0Sgs150176 
1801c7fd2ed0Sgs150176 	switch (ppd->pp_acc_size) {
1802c7fd2ed0Sgs150176 	case 1:
1803c7fd2ed0Sgs150176 		pci_config_put8(rgep->cfg_handle, regno, regval);
1804c7fd2ed0Sgs150176 		break;
1805c7fd2ed0Sgs150176 
1806c7fd2ed0Sgs150176 	case 2:
1807c7fd2ed0Sgs150176 		pci_config_put16(rgep->cfg_handle, regno, regval);
1808c7fd2ed0Sgs150176 		break;
1809c7fd2ed0Sgs150176 
1810c7fd2ed0Sgs150176 	case 4:
1811c7fd2ed0Sgs150176 		pci_config_put32(rgep->cfg_handle, regno, regval);
1812c7fd2ed0Sgs150176 		break;
1813c7fd2ed0Sgs150176 
1814c7fd2ed0Sgs150176 	case 8:
1815c7fd2ed0Sgs150176 		pci_config_put64(rgep->cfg_handle, regno, regval);
1816c7fd2ed0Sgs150176 		break;
1817c7fd2ed0Sgs150176 	}
1818c7fd2ed0Sgs150176 }
1819c7fd2ed0Sgs150176 
1820c7fd2ed0Sgs150176 static void rge_chip_peek_reg(rge_t *rgep, rge_peekpoke_t *ppd);
1821c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_peek_reg)
1822c7fd2ed0Sgs150176 
1823c7fd2ed0Sgs150176 static void
rge_chip_peek_reg(rge_t * rgep,rge_peekpoke_t * ppd)1824c7fd2ed0Sgs150176 rge_chip_peek_reg(rge_t *rgep, rge_peekpoke_t *ppd)
1825c7fd2ed0Sgs150176 {
1826c7fd2ed0Sgs150176 	uint64_t regval;
1827c7fd2ed0Sgs150176 	void *regaddr;
1828c7fd2ed0Sgs150176 
1829c7fd2ed0Sgs150176 	RGE_TRACE(("rge_chip_peek_reg($%p, $%p)",
1830c7fd2ed0Sgs150176 	    (void *)rgep, (void *)ppd));
1831c7fd2ed0Sgs150176 
1832c7fd2ed0Sgs150176 	regaddr = PIO_ADDR(rgep, ppd->pp_acc_offset);
1833c7fd2ed0Sgs150176 
1834c7fd2ed0Sgs150176 	switch (ppd->pp_acc_size) {
1835c7fd2ed0Sgs150176 	case 1:
1836c7fd2ed0Sgs150176 		regval = ddi_get8(rgep->io_handle, regaddr);
1837c7fd2ed0Sgs150176 		break;
1838c7fd2ed0Sgs150176 
1839c7fd2ed0Sgs150176 	case 2:
1840c7fd2ed0Sgs150176 		regval = ddi_get16(rgep->io_handle, regaddr);
1841c7fd2ed0Sgs150176 		break;
1842c7fd2ed0Sgs150176 
1843c7fd2ed0Sgs150176 	case 4:
1844c7fd2ed0Sgs150176 		regval = ddi_get32(rgep->io_handle, regaddr);
1845c7fd2ed0Sgs150176 		break;
1846c7fd2ed0Sgs150176 
1847c7fd2ed0Sgs150176 	case 8:
1848c7fd2ed0Sgs150176 		regval = ddi_get64(rgep->io_handle, regaddr);
1849c7fd2ed0Sgs150176 		break;
1850c7fd2ed0Sgs150176 	}
1851c7fd2ed0Sgs150176 
1852c7fd2ed0Sgs150176 	ppd->pp_acc_data = regval;
1853c7fd2ed0Sgs150176 }
1854c7fd2ed0Sgs150176 
1855c7fd2ed0Sgs150176 static void rge_chip_poke_reg(rge_t *rgep, rge_peekpoke_t *ppd);
1856c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_peek_reg)
1857c7fd2ed0Sgs150176 
1858c7fd2ed0Sgs150176 static void
rge_chip_poke_reg(rge_t * rgep,rge_peekpoke_t * ppd)1859c7fd2ed0Sgs150176 rge_chip_poke_reg(rge_t *rgep, rge_peekpoke_t *ppd)
1860c7fd2ed0Sgs150176 {
1861c7fd2ed0Sgs150176 	uint64_t regval;
1862c7fd2ed0Sgs150176 	void *regaddr;
1863c7fd2ed0Sgs150176 
1864c7fd2ed0Sgs150176 	RGE_TRACE(("rge_chip_poke_reg($%p, $%p)",
1865c7fd2ed0Sgs150176 	    (void *)rgep, (void *)ppd));
1866c7fd2ed0Sgs150176 
1867c7fd2ed0Sgs150176 	regaddr = PIO_ADDR(rgep, ppd->pp_acc_offset);
1868c7fd2ed0Sgs150176 	regval = ppd->pp_acc_data;
1869c7fd2ed0Sgs150176 
1870c7fd2ed0Sgs150176 	switch (ppd->pp_acc_size) {
1871c7fd2ed0Sgs150176 	case 1:
1872c7fd2ed0Sgs150176 		ddi_put8(rgep->io_handle, regaddr, regval);
1873c7fd2ed0Sgs150176 		break;
1874c7fd2ed0Sgs150176 
1875c7fd2ed0Sgs150176 	case 2:
1876c7fd2ed0Sgs150176 		ddi_put16(rgep->io_handle, regaddr, regval);
1877c7fd2ed0Sgs150176 		break;
1878c7fd2ed0Sgs150176 
1879c7fd2ed0Sgs150176 	case 4:
1880c7fd2ed0Sgs150176 		ddi_put32(rgep->io_handle, regaddr, regval);
1881c7fd2ed0Sgs150176 		break;
1882c7fd2ed0Sgs150176 
1883c7fd2ed0Sgs150176 	case 8:
1884c7fd2ed0Sgs150176 		ddi_put64(rgep->io_handle, regaddr, regval);
1885c7fd2ed0Sgs150176 		break;
1886c7fd2ed0Sgs150176 	}
1887c7fd2ed0Sgs150176 }
1888c7fd2ed0Sgs150176 
1889c7fd2ed0Sgs150176 static void rge_chip_peek_mii(rge_t *rgep, rge_peekpoke_t *ppd);
1890c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_peek_mii)
1891c7fd2ed0Sgs150176 
1892c7fd2ed0Sgs150176 static void
rge_chip_peek_mii(rge_t * rgep,rge_peekpoke_t * ppd)1893c7fd2ed0Sgs150176 rge_chip_peek_mii(rge_t *rgep, rge_peekpoke_t *ppd)
1894c7fd2ed0Sgs150176 {
1895c7fd2ed0Sgs150176 	RGE_TRACE(("rge_chip_peek_mii($%p, $%p)",
1896c7fd2ed0Sgs150176 	    (void *)rgep, (void *)ppd));
1897c7fd2ed0Sgs150176 
1898c7fd2ed0Sgs150176 	ppd->pp_acc_data = rge_mii_get16(rgep, ppd->pp_acc_offset/2);
1899c7fd2ed0Sgs150176 }
1900c7fd2ed0Sgs150176 
1901c7fd2ed0Sgs150176 static void rge_chip_poke_mii(rge_t *rgep, rge_peekpoke_t *ppd);
1902c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_poke_mii)
1903c7fd2ed0Sgs150176 
1904c7fd2ed0Sgs150176 static void
rge_chip_poke_mii(rge_t * rgep,rge_peekpoke_t * ppd)1905c7fd2ed0Sgs150176 rge_chip_poke_mii(rge_t *rgep, rge_peekpoke_t *ppd)
1906c7fd2ed0Sgs150176 {
1907c7fd2ed0Sgs150176 	RGE_TRACE(("rge_chip_poke_mii($%p, $%p)",
1908c7fd2ed0Sgs150176 	    (void *)rgep, (void *)ppd));
1909c7fd2ed0Sgs150176 
1910c7fd2ed0Sgs150176 	rge_mii_put16(rgep, ppd->pp_acc_offset/2, ppd->pp_acc_data);
1911c7fd2ed0Sgs150176 }
1912c7fd2ed0Sgs150176 
1913c7fd2ed0Sgs150176 static void rge_chip_peek_mem(rge_t *rgep, rge_peekpoke_t *ppd);
1914c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_peek_mem)
1915c7fd2ed0Sgs150176 
1916c7fd2ed0Sgs150176 static void
rge_chip_peek_mem(rge_t * rgep,rge_peekpoke_t * ppd)1917c7fd2ed0Sgs150176 rge_chip_peek_mem(rge_t *rgep, rge_peekpoke_t *ppd)
1918c7fd2ed0Sgs150176 {
1919c7fd2ed0Sgs150176 	uint64_t regval;
1920c7fd2ed0Sgs150176 	void *vaddr;
1921c7fd2ed0Sgs150176 
1922c7fd2ed0Sgs150176 	RGE_TRACE(("rge_chip_peek_rge($%p, $%p)",
1923c7fd2ed0Sgs150176 	    (void *)rgep, (void *)ppd));
1924c7fd2ed0Sgs150176 
1925c7fd2ed0Sgs150176 	vaddr = (void *)(uintptr_t)ppd->pp_acc_offset;
1926c7fd2ed0Sgs150176 
1927c7fd2ed0Sgs150176 	switch (ppd->pp_acc_size) {
1928c7fd2ed0Sgs150176 	case 1:
1929c7fd2ed0Sgs150176 		regval = *(uint8_t *)vaddr;
1930c7fd2ed0Sgs150176 		break;
1931c7fd2ed0Sgs150176 
1932c7fd2ed0Sgs150176 	case 2:
1933c7fd2ed0Sgs150176 		regval = *(uint16_t *)vaddr;
1934c7fd2ed0Sgs150176 		break;
1935c7fd2ed0Sgs150176 
1936c7fd2ed0Sgs150176 	case 4:
1937c7fd2ed0Sgs150176 		regval = *(uint32_t *)vaddr;
1938c7fd2ed0Sgs150176 		break;
1939c7fd2ed0Sgs150176 
1940c7fd2ed0Sgs150176 	case 8:
1941c7fd2ed0Sgs150176 		regval = *(uint64_t *)vaddr;
1942c7fd2ed0Sgs150176 		break;
1943c7fd2ed0Sgs150176 	}
1944c7fd2ed0Sgs150176 
1945c7fd2ed0Sgs150176 	RGE_DEBUG(("rge_chip_peek_mem($%p, $%p) peeked 0x%llx from $%p",
1946c7fd2ed0Sgs150176 	    (void *)rgep, (void *)ppd, regval, vaddr));
1947c7fd2ed0Sgs150176 
1948c7fd2ed0Sgs150176 	ppd->pp_acc_data = regval;
1949c7fd2ed0Sgs150176 }
1950c7fd2ed0Sgs150176 
1951c7fd2ed0Sgs150176 static void rge_chip_poke_mem(rge_t *rgep, rge_peekpoke_t *ppd);
1952c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_poke_mem)
1953c7fd2ed0Sgs150176 
1954c7fd2ed0Sgs150176 static void
rge_chip_poke_mem(rge_t * rgep,rge_peekpoke_t * ppd)1955c7fd2ed0Sgs150176 rge_chip_poke_mem(rge_t *rgep, rge_peekpoke_t *ppd)
1956c7fd2ed0Sgs150176 {
1957c7fd2ed0Sgs150176 	uint64_t regval;
1958c7fd2ed0Sgs150176 	void *vaddr;
1959c7fd2ed0Sgs150176 
1960c7fd2ed0Sgs150176 	RGE_TRACE(("rge_chip_poke_mem($%p, $%p)",
1961c7fd2ed0Sgs150176 	    (void *)rgep, (void *)ppd));
1962c7fd2ed0Sgs150176 
1963c7fd2ed0Sgs150176 	vaddr = (void *)(uintptr_t)ppd->pp_acc_offset;
1964c7fd2ed0Sgs150176 	regval = ppd->pp_acc_data;
1965c7fd2ed0Sgs150176 
1966c7fd2ed0Sgs150176 	RGE_DEBUG(("rge_chip_poke_mem($%p, $%p) poking 0x%llx at $%p",
1967c7fd2ed0Sgs150176 	    (void *)rgep, (void *)ppd, regval, vaddr));
1968c7fd2ed0Sgs150176 
1969c7fd2ed0Sgs150176 	switch (ppd->pp_acc_size) {
1970c7fd2ed0Sgs150176 	case 1:
1971c7fd2ed0Sgs150176 		*(uint8_t *)vaddr = (uint8_t)regval;
1972c7fd2ed0Sgs150176 		break;
1973c7fd2ed0Sgs150176 
1974c7fd2ed0Sgs150176 	case 2:
1975c7fd2ed0Sgs150176 		*(uint16_t *)vaddr = (uint16_t)regval;
1976c7fd2ed0Sgs150176 		break;
1977c7fd2ed0Sgs150176 
1978c7fd2ed0Sgs150176 	case 4:
1979c7fd2ed0Sgs150176 		*(uint32_t *)vaddr = (uint32_t)regval;
1980c7fd2ed0Sgs150176 		break;
1981c7fd2ed0Sgs150176 
1982c7fd2ed0Sgs150176 	case 8:
1983c7fd2ed0Sgs150176 		*(uint64_t *)vaddr = (uint64_t)regval;
1984c7fd2ed0Sgs150176 		break;
1985c7fd2ed0Sgs150176 	}
1986c7fd2ed0Sgs150176 }
1987c7fd2ed0Sgs150176 
1988c7fd2ed0Sgs150176 static enum ioc_reply rge_pp_ioctl(rge_t *rgep, int cmd, mblk_t *mp,
1989c7fd2ed0Sgs150176 					struct iocblk *iocp);
1990c7fd2ed0Sgs150176 #pragma	no_inline(rge_pp_ioctl)
1991c7fd2ed0Sgs150176 
1992c7fd2ed0Sgs150176 static enum ioc_reply
rge_pp_ioctl(rge_t * rgep,int cmd,mblk_t * mp,struct iocblk * iocp)1993c7fd2ed0Sgs150176 rge_pp_ioctl(rge_t *rgep, int cmd, mblk_t *mp, struct iocblk *iocp)
1994c7fd2ed0Sgs150176 {
1995c7fd2ed0Sgs150176 	void (*ppfn)(rge_t *rgep, rge_peekpoke_t *ppd);
1996c7fd2ed0Sgs150176 	rge_peekpoke_t *ppd;
1997c7fd2ed0Sgs150176 	dma_area_t *areap;
1998c7fd2ed0Sgs150176 	uint64_t sizemask;
1999c7fd2ed0Sgs150176 	uint64_t mem_va;
2000c7fd2ed0Sgs150176 	uint64_t maxoff;
2001c7fd2ed0Sgs150176 	boolean_t peek;
2002c7fd2ed0Sgs150176 
2003c7fd2ed0Sgs150176 	switch (cmd) {
2004c7fd2ed0Sgs150176 	default:
2005c7fd2ed0Sgs150176 		/* NOTREACHED */
2006c7fd2ed0Sgs150176 		rge_error(rgep, "rge_pp_ioctl: invalid cmd 0x%x", cmd);
2007c7fd2ed0Sgs150176 		return (IOC_INVAL);
2008c7fd2ed0Sgs150176 
2009c7fd2ed0Sgs150176 	case RGE_PEEK:
2010c7fd2ed0Sgs150176 		peek = B_TRUE;
2011c7fd2ed0Sgs150176 		break;
2012c7fd2ed0Sgs150176 
2013c7fd2ed0Sgs150176 	case RGE_POKE:
2014c7fd2ed0Sgs150176 		peek = B_FALSE;
2015c7fd2ed0Sgs150176 		break;
2016c7fd2ed0Sgs150176 	}
2017c7fd2ed0Sgs150176 
2018c7fd2ed0Sgs150176 	/*
2019c7fd2ed0Sgs150176 	 * Validate format of ioctl
2020c7fd2ed0Sgs150176 	 */
2021c7fd2ed0Sgs150176 	if (iocp->ioc_count != sizeof (rge_peekpoke_t))
2022c7fd2ed0Sgs150176 		return (IOC_INVAL);
2023c7fd2ed0Sgs150176 	if (mp->b_cont == NULL)
2024c7fd2ed0Sgs150176 		return (IOC_INVAL);
2025c7fd2ed0Sgs150176 	ppd = (rge_peekpoke_t *)mp->b_cont->b_rptr;
2026c7fd2ed0Sgs150176 
2027c7fd2ed0Sgs150176 	/*
2028c7fd2ed0Sgs150176 	 * Validate request parameters
2029c7fd2ed0Sgs150176 	 */
2030c7fd2ed0Sgs150176 	switch (ppd->pp_acc_space) {
2031c7fd2ed0Sgs150176 	default:
2032c7fd2ed0Sgs150176 		return (IOC_INVAL);
2033c7fd2ed0Sgs150176 
2034c7fd2ed0Sgs150176 	case RGE_PP_SPACE_CFG:
2035c7fd2ed0Sgs150176 		/*
2036c7fd2ed0Sgs150176 		 * Config space
2037c7fd2ed0Sgs150176 		 */
2038c7fd2ed0Sgs150176 		sizemask = 8|4|2|1;
2039c7fd2ed0Sgs150176 		mem_va = 0;
2040c7fd2ed0Sgs150176 		maxoff = PCI_CONF_HDR_SIZE;
2041c7fd2ed0Sgs150176 		ppfn = peek ? rge_chip_peek_cfg : rge_chip_poke_cfg;
2042c7fd2ed0Sgs150176 		break;
2043c7fd2ed0Sgs150176 
2044c7fd2ed0Sgs150176 	case RGE_PP_SPACE_REG:
2045c7fd2ed0Sgs150176 		/*
2046c7fd2ed0Sgs150176 		 * Memory-mapped I/O space
2047c7fd2ed0Sgs150176 		 */
2048c7fd2ed0Sgs150176 		sizemask = 8|4|2|1;
2049c7fd2ed0Sgs150176 		mem_va = 0;
2050c7fd2ed0Sgs150176 		maxoff = RGE_REGISTER_MAX;
2051c7fd2ed0Sgs150176 		ppfn = peek ? rge_chip_peek_reg : rge_chip_poke_reg;
2052c7fd2ed0Sgs150176 		break;
2053c7fd2ed0Sgs150176 
2054c7fd2ed0Sgs150176 	case RGE_PP_SPACE_MII:
2055c7fd2ed0Sgs150176 		/*
2056c7fd2ed0Sgs150176 		 * PHY's MII registers
2057c7fd2ed0Sgs150176 		 * NB: all PHY registers are two bytes, but the
2058c7fd2ed0Sgs150176 		 * addresses increment in ones (word addressing).
2059c7fd2ed0Sgs150176 		 * So we scale the address here, then undo the
2060c7fd2ed0Sgs150176 		 * transformation inside the peek/poke functions.
2061c7fd2ed0Sgs150176 		 */
2062c7fd2ed0Sgs150176 		ppd->pp_acc_offset *= 2;
2063c7fd2ed0Sgs150176 		sizemask = 2;
2064c7fd2ed0Sgs150176 		mem_va = 0;
2065c7fd2ed0Sgs150176 		maxoff = (MII_MAXREG+1)*2;
2066c7fd2ed0Sgs150176 		ppfn = peek ? rge_chip_peek_mii : rge_chip_poke_mii;
2067c7fd2ed0Sgs150176 		break;
2068c7fd2ed0Sgs150176 
2069c7fd2ed0Sgs150176 	case RGE_PP_SPACE_RGE:
2070c7fd2ed0Sgs150176 		/*
2071c7fd2ed0Sgs150176 		 * RGE data structure!
2072c7fd2ed0Sgs150176 		 */
2073c7fd2ed0Sgs150176 		sizemask = 8|4|2|1;
2074c7fd2ed0Sgs150176 		mem_va = (uintptr_t)rgep;
2075c7fd2ed0Sgs150176 		maxoff = sizeof (*rgep);
2076c7fd2ed0Sgs150176 		ppfn = peek ? rge_chip_peek_mem : rge_chip_poke_mem;
2077c7fd2ed0Sgs150176 		break;
2078c7fd2ed0Sgs150176 
2079c7fd2ed0Sgs150176 	case RGE_PP_SPACE_STATISTICS:
2080c7fd2ed0Sgs150176 	case RGE_PP_SPACE_TXDESC:
2081c7fd2ed0Sgs150176 	case RGE_PP_SPACE_TXBUFF:
2082c7fd2ed0Sgs150176 	case RGE_PP_SPACE_RXDESC:
2083c7fd2ed0Sgs150176 	case RGE_PP_SPACE_RXBUFF:
2084c7fd2ed0Sgs150176 		/*
2085c7fd2ed0Sgs150176 		 * Various DMA_AREAs
2086c7fd2ed0Sgs150176 		 */
2087c7fd2ed0Sgs150176 		switch (ppd->pp_acc_space) {
2088c7fd2ed0Sgs150176 		case RGE_PP_SPACE_TXDESC:
2089c7fd2ed0Sgs150176 			areap = &rgep->dma_area_txdesc;
2090c7fd2ed0Sgs150176 			break;
2091c7fd2ed0Sgs150176 		case RGE_PP_SPACE_RXDESC:
2092c7fd2ed0Sgs150176 			areap = &rgep->dma_area_rxdesc;
2093c7fd2ed0Sgs150176 			break;
2094c7fd2ed0Sgs150176 		case RGE_PP_SPACE_STATISTICS:
2095c7fd2ed0Sgs150176 			areap = &rgep->dma_area_stats;
2096c7fd2ed0Sgs150176 			break;
2097c7fd2ed0Sgs150176 		}
2098c7fd2ed0Sgs150176 
2099c7fd2ed0Sgs150176 		sizemask = 8|4|2|1;
2100c7fd2ed0Sgs150176 		mem_va = (uintptr_t)areap->mem_va;
2101c7fd2ed0Sgs150176 		maxoff = areap->alength;
2102c7fd2ed0Sgs150176 		ppfn = peek ? rge_chip_peek_mem : rge_chip_poke_mem;
2103c7fd2ed0Sgs150176 		break;
2104c7fd2ed0Sgs150176 	}
2105c7fd2ed0Sgs150176 
2106c7fd2ed0Sgs150176 	switch (ppd->pp_acc_size) {
2107c7fd2ed0Sgs150176 	default:
2108c7fd2ed0Sgs150176 		return (IOC_INVAL);
2109c7fd2ed0Sgs150176 
2110c7fd2ed0Sgs150176 	case 8:
2111c7fd2ed0Sgs150176 	case 4:
2112c7fd2ed0Sgs150176 	case 2:
2113c7fd2ed0Sgs150176 	case 1:
2114c7fd2ed0Sgs150176 		if ((ppd->pp_acc_size & sizemask) == 0)
2115c7fd2ed0Sgs150176 			return (IOC_INVAL);
2116c7fd2ed0Sgs150176 		break;
2117c7fd2ed0Sgs150176 	}
2118c7fd2ed0Sgs150176 
2119c7fd2ed0Sgs150176 	if ((ppd->pp_acc_offset % ppd->pp_acc_size) != 0)
2120c7fd2ed0Sgs150176 		return (IOC_INVAL);
2121c7fd2ed0Sgs150176 
2122c7fd2ed0Sgs150176 	if (ppd->pp_acc_offset >= maxoff)
2123c7fd2ed0Sgs150176 		return (IOC_INVAL);
2124c7fd2ed0Sgs150176 
2125c7fd2ed0Sgs150176 	if (ppd->pp_acc_offset+ppd->pp_acc_size > maxoff)
2126c7fd2ed0Sgs150176 		return (IOC_INVAL);
2127c7fd2ed0Sgs150176 
2128c7fd2ed0Sgs150176 	/*
2129c7fd2ed0Sgs150176 	 * All OK - go do it!
2130c7fd2ed0Sgs150176 	 */
2131c7fd2ed0Sgs150176 	ppd->pp_acc_offset += mem_va;
2132c7fd2ed0Sgs150176 	(*ppfn)(rgep, ppd);
2133c7fd2ed0Sgs150176 	return (peek ? IOC_REPLY : IOC_ACK);
2134c7fd2ed0Sgs150176 }
2135c7fd2ed0Sgs150176 
2136c7fd2ed0Sgs150176 static enum ioc_reply rge_diag_ioctl(rge_t *rgep, int cmd, mblk_t *mp,
2137c7fd2ed0Sgs150176 					struct iocblk *iocp);
2138c7fd2ed0Sgs150176 #pragma	no_inline(rge_diag_ioctl)
2139c7fd2ed0Sgs150176 
2140c7fd2ed0Sgs150176 static enum ioc_reply
rge_diag_ioctl(rge_t * rgep,int cmd,mblk_t * mp,struct iocblk * iocp)2141c7fd2ed0Sgs150176 rge_diag_ioctl(rge_t *rgep, int cmd, mblk_t *mp, struct iocblk *iocp)
2142c7fd2ed0Sgs150176 {
2143c7fd2ed0Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
2144c7fd2ed0Sgs150176 
2145c7fd2ed0Sgs150176 	switch (cmd) {
2146c7fd2ed0Sgs150176 	default:
2147c7fd2ed0Sgs150176 		/* NOTREACHED */
2148c7fd2ed0Sgs150176 		rge_error(rgep, "rge_diag_ioctl: invalid cmd 0x%x", cmd);
2149c7fd2ed0Sgs150176 		return (IOC_INVAL);
2150c7fd2ed0Sgs150176 
2151c7fd2ed0Sgs150176 	case RGE_DIAG:
2152c7fd2ed0Sgs150176 		/*
2153c7fd2ed0Sgs150176 		 * Currently a no-op
2154c7fd2ed0Sgs150176 		 */
2155c7fd2ed0Sgs150176 		return (IOC_ACK);
2156c7fd2ed0Sgs150176 
2157c7fd2ed0Sgs150176 	case RGE_PEEK:
2158c7fd2ed0Sgs150176 	case RGE_POKE:
2159c7fd2ed0Sgs150176 		return (rge_pp_ioctl(rgep, cmd, mp, iocp));
2160c7fd2ed0Sgs150176 
2161c7fd2ed0Sgs150176 	case RGE_PHY_RESET:
2162c7fd2ed0Sgs150176 		return (IOC_RESTART_ACK);
2163c7fd2ed0Sgs150176 
2164c7fd2ed0Sgs150176 	case RGE_SOFT_RESET:
2165c7fd2ed0Sgs150176 	case RGE_HARD_RESET:
2166c7fd2ed0Sgs150176 		/*
2167c7fd2ed0Sgs150176 		 * Reset and reinitialise the 570x hardware
2168c7fd2ed0Sgs150176 		 */
2169c7fd2ed0Sgs150176 		rge_restart(rgep);
2170c7fd2ed0Sgs150176 		return (IOC_ACK);
2171c7fd2ed0Sgs150176 	}
2172c7fd2ed0Sgs150176 
2173c7fd2ed0Sgs150176 	/* NOTREACHED */
2174c7fd2ed0Sgs150176 }
2175c7fd2ed0Sgs150176 
2176c7fd2ed0Sgs150176 #endif	/* RGE_DEBUGGING || RGE_DO_PPIO */
2177c7fd2ed0Sgs150176 
2178c7fd2ed0Sgs150176 static enum ioc_reply rge_mii_ioctl(rge_t *rgep, int cmd, mblk_t *mp,
2179c7fd2ed0Sgs150176 				    struct iocblk *iocp);
2180c7fd2ed0Sgs150176 #pragma	no_inline(rge_mii_ioctl)
2181c7fd2ed0Sgs150176 
2182c7fd2ed0Sgs150176 static enum ioc_reply
rge_mii_ioctl(rge_t * rgep,int cmd,mblk_t * mp,struct iocblk * iocp)2183c7fd2ed0Sgs150176 rge_mii_ioctl(rge_t *rgep, int cmd, mblk_t *mp, struct iocblk *iocp)
2184c7fd2ed0Sgs150176 {
2185c7fd2ed0Sgs150176 	struct rge_mii_rw *miirwp;
2186c7fd2ed0Sgs150176 
2187c7fd2ed0Sgs150176 	/*
2188c7fd2ed0Sgs150176 	 * Validate format of ioctl
2189c7fd2ed0Sgs150176 	 */
2190c7fd2ed0Sgs150176 	if (iocp->ioc_count != sizeof (struct rge_mii_rw))
2191c7fd2ed0Sgs150176 		return (IOC_INVAL);
2192c7fd2ed0Sgs150176 	if (mp->b_cont == NULL)
2193c7fd2ed0Sgs150176 		return (IOC_INVAL);
2194c7fd2ed0Sgs150176 	miirwp = (struct rge_mii_rw *)mp->b_cont->b_rptr;
2195c7fd2ed0Sgs150176 
2196c7fd2ed0Sgs150176 	/*
2197c7fd2ed0Sgs150176 	 * Validate request parameters ...
2198c7fd2ed0Sgs150176 	 */
2199c7fd2ed0Sgs150176 	if (miirwp->mii_reg > MII_MAXREG)
2200c7fd2ed0Sgs150176 		return (IOC_INVAL);
2201c7fd2ed0Sgs150176 
2202c7fd2ed0Sgs150176 	switch (cmd) {
2203c7fd2ed0Sgs150176 	default:
2204c7fd2ed0Sgs150176 		/* NOTREACHED */
2205c7fd2ed0Sgs150176 		rge_error(rgep, "rge_mii_ioctl: invalid cmd 0x%x", cmd);
2206c7fd2ed0Sgs150176 		return (IOC_INVAL);
2207c7fd2ed0Sgs150176 
2208c7fd2ed0Sgs150176 	case RGE_MII_READ:
2209c7fd2ed0Sgs150176 		miirwp->mii_data = rge_mii_get16(rgep, miirwp->mii_reg);
2210c7fd2ed0Sgs150176 		return (IOC_REPLY);
2211c7fd2ed0Sgs150176 
2212c7fd2ed0Sgs150176 	case RGE_MII_WRITE:
2213c7fd2ed0Sgs150176 		rge_mii_put16(rgep, miirwp->mii_reg, miirwp->mii_data);
2214c7fd2ed0Sgs150176 		return (IOC_ACK);
2215c7fd2ed0Sgs150176 	}
2216c7fd2ed0Sgs150176 
2217c7fd2ed0Sgs150176 	/* NOTREACHED */
2218c7fd2ed0Sgs150176 }
2219c7fd2ed0Sgs150176 
2220c7fd2ed0Sgs150176 enum ioc_reply rge_chip_ioctl(rge_t *rgep, queue_t *wq, mblk_t *mp,
2221c7fd2ed0Sgs150176 				struct iocblk *iocp);
2222c7fd2ed0Sgs150176 #pragma	no_inline(rge_chip_ioctl)
2223c7fd2ed0Sgs150176 
2224c7fd2ed0Sgs150176 enum ioc_reply
rge_chip_ioctl(rge_t * rgep,queue_t * wq,mblk_t * mp,struct iocblk * iocp)2225c7fd2ed0Sgs150176 rge_chip_ioctl(rge_t *rgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp)
2226c7fd2ed0Sgs150176 {
2227c7fd2ed0Sgs150176 	int cmd;
2228c7fd2ed0Sgs150176 
2229c7fd2ed0Sgs150176 	RGE_TRACE(("rge_chip_ioctl($%p, $%p, $%p, $%p)",
2230c7fd2ed0Sgs150176 	    (void *)rgep, (void *)wq, (void *)mp, (void *)iocp));
2231c7fd2ed0Sgs150176 
2232c7fd2ed0Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
2233c7fd2ed0Sgs150176 
2234c7fd2ed0Sgs150176 	cmd = iocp->ioc_cmd;
2235c7fd2ed0Sgs150176 	switch (cmd) {
2236c7fd2ed0Sgs150176 	default:
2237c7fd2ed0Sgs150176 		/* NOTREACHED */
2238c7fd2ed0Sgs150176 		rge_error(rgep, "rge_chip_ioctl: invalid cmd 0x%x", cmd);
2239c7fd2ed0Sgs150176 		return (IOC_INVAL);
2240c7fd2ed0Sgs150176 
2241c7fd2ed0Sgs150176 	case RGE_DIAG:
2242c7fd2ed0Sgs150176 	case RGE_PEEK:
2243c7fd2ed0Sgs150176 	case RGE_POKE:
2244c7fd2ed0Sgs150176 	case RGE_PHY_RESET:
2245c7fd2ed0Sgs150176 	case RGE_SOFT_RESET:
2246c7fd2ed0Sgs150176 	case RGE_HARD_RESET:
2247c7fd2ed0Sgs150176 #if	RGE_DEBUGGING || RGE_DO_PPIO
2248c7fd2ed0Sgs150176 		return (rge_diag_ioctl(rgep, cmd, mp, iocp));
2249c7fd2ed0Sgs150176 #else
2250c7fd2ed0Sgs150176 		return (IOC_INVAL);
2251c7fd2ed0Sgs150176 #endif	/* RGE_DEBUGGING || RGE_DO_PPIO */
2252c7fd2ed0Sgs150176 
2253c7fd2ed0Sgs150176 	case RGE_MII_READ:
2254c7fd2ed0Sgs150176 	case RGE_MII_WRITE:
2255c7fd2ed0Sgs150176 		return (rge_mii_ioctl(rgep, cmd, mp, iocp));
2256c7fd2ed0Sgs150176 
2257c7fd2ed0Sgs150176 	}
2258c7fd2ed0Sgs150176 
2259c7fd2ed0Sgs150176 	/* NOTREACHED */
2260c7fd2ed0Sgs150176 }
2261