xref: /onnv-gate/usr/src/uts/common/io/rge/rge_chip.c (revision 2311:2d86e52dcdf0)
1744Sgs150176 /*
2744Sgs150176  * CDDL HEADER START
3744Sgs150176  *
4744Sgs150176  * The contents of this file are subject to the terms of the
5*2311Sseb  * Common Development and Distribution License (the "License").
6*2311Sseb  * You may not use this file except in compliance with the License.
7744Sgs150176  *
8744Sgs150176  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9744Sgs150176  * or http://www.opensolaris.org/os/licensing.
10744Sgs150176  * See the License for the specific language governing permissions
11744Sgs150176  * and limitations under the License.
12744Sgs150176  *
13744Sgs150176  * When distributing Covered Code, include this CDDL HEADER in each
14744Sgs150176  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15744Sgs150176  * If applicable, add the following below this CDDL HEADER, with the
16744Sgs150176  * fields enclosed by brackets "[]" replaced with your own identifying
17744Sgs150176  * information: Portions Copyright [yyyy] [name of copyright owner]
18744Sgs150176  *
19744Sgs150176  * CDDL HEADER END
20744Sgs150176  */
21744Sgs150176 /*
22*2311Sseb  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23744Sgs150176  * Use is subject to license terms.
24744Sgs150176  */
25744Sgs150176 
26744Sgs150176 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27744Sgs150176 
28744Sgs150176 #include "rge.h"
29744Sgs150176 
30744Sgs150176 #define	REG32(rgep, reg)	((uint32_t *)(rgep->io_regs+(reg)))
31744Sgs150176 #define	REG16(rgep, reg)	((uint16_t *)(rgep->io_regs+(reg)))
32744Sgs150176 #define	REG8(rgep, reg)		((uint8_t *)(rgep->io_regs+(reg)))
33744Sgs150176 #define	PIO_ADDR(rgep, offset)	((void *)(rgep->io_regs+(offset)))
34744Sgs150176 
35744Sgs150176 /*
36744Sgs150176  * Patchable globals:
37744Sgs150176  *
38744Sgs150176  *	rge_autorecover
39744Sgs150176  *		Enables/disables automatic recovery after fault detection
40744Sgs150176  */
41744Sgs150176 static uint32_t rge_autorecover = 1;
42744Sgs150176 
43744Sgs150176 /*
44744Sgs150176  * globals:
45744Sgs150176  */
46744Sgs150176 #define	RGE_DBG		RGE_DBG_REGS	/* debug flag for this code	*/
47744Sgs150176 static uint32_t rge_watchdog_count	= 1 << 16;
48744Sgs150176 
49744Sgs150176 /*
50744Sgs150176  * Operating register get/set access routines
51744Sgs150176  */
52744Sgs150176 #if	RGE_DEBUGGING
53744Sgs150176 
54744Sgs150176 static void rge_pci_check(rge_t *rgep);
55744Sgs150176 #pragma	no_inline(rge_pci_check)
56744Sgs150176 
57744Sgs150176 static void
58744Sgs150176 rge_pci_check(rge_t *rgep)
59744Sgs150176 {
60744Sgs150176 	uint16_t pcistatus;
61744Sgs150176 
62744Sgs150176 	pcistatus = pci_config_get16(rgep->cfg_handle, PCI_CONF_STAT);
63744Sgs150176 	if ((pcistatus & (PCI_STAT_R_MAST_AB | PCI_STAT_R_TARG_AB)) != 0)
64744Sgs150176 		RGE_DEBUG(("rge_pci_check($%p): PCI status 0x%x",
65744Sgs150176 			(void *)rgep, pcistatus));
66744Sgs150176 }
67744Sgs150176 
68744Sgs150176 #endif	/* RGE_DEBUGGING */
69744Sgs150176 
70744Sgs150176 static uint32_t rge_reg_get32(rge_t *rgep, uintptr_t regno);
71744Sgs150176 #pragma	inline(rge_reg_get32)
72744Sgs150176 
73744Sgs150176 static uint32_t
74744Sgs150176 rge_reg_get32(rge_t *rgep, uintptr_t regno)
75744Sgs150176 {
76744Sgs150176 	RGE_TRACE(("rge_reg_get32($%p, 0x%lx)",
77744Sgs150176 		(void *)rgep, regno));
78744Sgs150176 
79744Sgs150176 	return (ddi_get32(rgep->io_handle, REG32(rgep, regno)));
80744Sgs150176 }
81744Sgs150176 
82744Sgs150176 static void rge_reg_put32(rge_t *rgep, uintptr_t regno, uint32_t data);
83744Sgs150176 #pragma	inline(rge_reg_put32)
84744Sgs150176 
85744Sgs150176 static void
86744Sgs150176 rge_reg_put32(rge_t *rgep, uintptr_t regno, uint32_t data)
87744Sgs150176 {
88744Sgs150176 	RGE_TRACE(("rge_reg_put32($%p, 0x%lx, 0x%x)",
89744Sgs150176 		(void *)rgep, regno, data));
90744Sgs150176 
91744Sgs150176 	ddi_put32(rgep->io_handle, REG32(rgep, regno), data);
92744Sgs150176 	RGE_PCICHK(rgep);
93744Sgs150176 }
94744Sgs150176 
95744Sgs150176 static void rge_reg_set32(rge_t *rgep, uintptr_t regno, uint32_t bits);
96744Sgs150176 #pragma	inline(rge_reg_set32)
97744Sgs150176 
98744Sgs150176 static void
99744Sgs150176 rge_reg_set32(rge_t *rgep, uintptr_t regno, uint32_t bits)
100744Sgs150176 {
101744Sgs150176 	uint32_t regval;
102744Sgs150176 
103744Sgs150176 	RGE_TRACE(("rge_reg_set32($%p, 0x%lx, 0x%x)",
104744Sgs150176 		(void *)rgep, regno, bits));
105744Sgs150176 
106744Sgs150176 	regval = rge_reg_get32(rgep, regno);
107744Sgs150176 	regval |= bits;
108744Sgs150176 	rge_reg_put32(rgep, regno, regval);
109744Sgs150176 }
110744Sgs150176 
111744Sgs150176 static void rge_reg_clr32(rge_t *rgep, uintptr_t regno, uint32_t bits);
112744Sgs150176 #pragma	inline(rge_reg_clr32)
113744Sgs150176 
114744Sgs150176 static void
115744Sgs150176 rge_reg_clr32(rge_t *rgep, uintptr_t regno, uint32_t bits)
116744Sgs150176 {
117744Sgs150176 	uint32_t regval;
118744Sgs150176 
119744Sgs150176 	RGE_TRACE(("rge_reg_clr32($%p, 0x%lx, 0x%x)",
120744Sgs150176 		(void *)rgep, regno, bits));
121744Sgs150176 
122744Sgs150176 	regval = rge_reg_get32(rgep, regno);
123744Sgs150176 	regval &= ~bits;
124744Sgs150176 	rge_reg_put32(rgep, regno, regval);
125744Sgs150176 }
126744Sgs150176 
127744Sgs150176 static uint16_t rge_reg_get16(rge_t *rgep, uintptr_t regno);
128744Sgs150176 #pragma	inline(rge_reg_get16)
129744Sgs150176 
130744Sgs150176 static uint16_t
131744Sgs150176 rge_reg_get16(rge_t *rgep, uintptr_t regno)
132744Sgs150176 {
133744Sgs150176 	RGE_TRACE(("rge_reg_get16($%p, 0x%lx)",
134744Sgs150176 		(void *)rgep, regno));
135744Sgs150176 
136744Sgs150176 	return (ddi_get16(rgep->io_handle, REG16(rgep, regno)));
137744Sgs150176 }
138744Sgs150176 
139744Sgs150176 static void rge_reg_put16(rge_t *rgep, uintptr_t regno, uint16_t data);
140744Sgs150176 #pragma	inline(rge_reg_put16)
141744Sgs150176 
142744Sgs150176 static void
143744Sgs150176 rge_reg_put16(rge_t *rgep, uintptr_t regno, uint16_t data)
144744Sgs150176 {
145744Sgs150176 	RGE_TRACE(("rge_reg_put16($%p, 0x%lx, 0x%x)",
146744Sgs150176 		(void *)rgep, regno, data));
147744Sgs150176 
148744Sgs150176 	ddi_put16(rgep->io_handle, REG16(rgep, regno), data);
149744Sgs150176 	RGE_PCICHK(rgep);
150744Sgs150176 }
151744Sgs150176 
152744Sgs150176 static void rge_reg_set16(rge_t *rgep, uintptr_t regno, uint16_t bits);
153744Sgs150176 #pragma	inline(rge_reg_set16)
154744Sgs150176 
155744Sgs150176 static void
156744Sgs150176 rge_reg_set16(rge_t *rgep, uintptr_t regno, uint16_t bits)
157744Sgs150176 {
158744Sgs150176 	uint16_t regval;
159744Sgs150176 
160744Sgs150176 	RGE_TRACE(("rge_reg_set16($%p, 0x%lx, 0x%x)",
161744Sgs150176 		(void *)rgep, regno, bits));
162744Sgs150176 
163744Sgs150176 	regval = rge_reg_get16(rgep, regno);
164744Sgs150176 	regval |= bits;
165744Sgs150176 	rge_reg_put16(rgep, regno, regval);
166744Sgs150176 }
167744Sgs150176 
168744Sgs150176 static void rge_reg_clr16(rge_t *rgep, uintptr_t regno, uint16_t bits);
169744Sgs150176 #pragma	inline(rge_reg_clr16)
170744Sgs150176 
171744Sgs150176 static void
172744Sgs150176 rge_reg_clr16(rge_t *rgep, uintptr_t regno, uint16_t bits)
173744Sgs150176 {
174744Sgs150176 	uint16_t regval;
175744Sgs150176 
176744Sgs150176 	RGE_TRACE(("rge_reg_clr16($%p, 0x%lx, 0x%x)",
177744Sgs150176 		(void *)rgep, regno, bits));
178744Sgs150176 
179744Sgs150176 	regval = rge_reg_get16(rgep, regno);
180744Sgs150176 	regval &= ~bits;
181744Sgs150176 	rge_reg_put16(rgep, regno, regval);
182744Sgs150176 }
183744Sgs150176 
184744Sgs150176 static uint8_t rge_reg_get8(rge_t *rgep, uintptr_t regno);
185744Sgs150176 #pragma	inline(rge_reg_get8)
186744Sgs150176 
187744Sgs150176 static uint8_t
188744Sgs150176 rge_reg_get8(rge_t *rgep, uintptr_t regno)
189744Sgs150176 {
190744Sgs150176 	RGE_TRACE(("rge_reg_get8($%p, 0x%lx)",
191744Sgs150176 		(void *)rgep, regno));
192744Sgs150176 
193744Sgs150176 	return (ddi_get8(rgep->io_handle, REG8(rgep, regno)));
194744Sgs150176 }
195744Sgs150176 
196744Sgs150176 static void rge_reg_put8(rge_t *rgep, uintptr_t regno, uint8_t data);
197744Sgs150176 #pragma	inline(rge_reg_put8)
198744Sgs150176 
199744Sgs150176 static void
200744Sgs150176 rge_reg_put8(rge_t *rgep, uintptr_t regno, uint8_t data)
201744Sgs150176 {
202744Sgs150176 	RGE_TRACE(("rge_reg_put8($%p, 0x%lx, 0x%x)",
203744Sgs150176 		(void *)rgep, regno, data));
204744Sgs150176 
205744Sgs150176 	ddi_put8(rgep->io_handle, REG8(rgep, regno), data);
206744Sgs150176 	RGE_PCICHK(rgep);
207744Sgs150176 }
208744Sgs150176 
209744Sgs150176 static void rge_reg_set8(rge_t *rgep, uintptr_t regno, uint8_t bits);
210744Sgs150176 #pragma	inline(rge_reg_set8)
211744Sgs150176 
212744Sgs150176 static void
213744Sgs150176 rge_reg_set8(rge_t *rgep, uintptr_t regno, uint8_t bits)
214744Sgs150176 {
215744Sgs150176 	uint8_t regval;
216744Sgs150176 
217744Sgs150176 	RGE_TRACE(("rge_reg_set8($%p, 0x%lx, 0x%x)",
218744Sgs150176 		(void *)rgep, regno, bits));
219744Sgs150176 
220744Sgs150176 	regval = rge_reg_get8(rgep, regno);
221744Sgs150176 	regval |= bits;
222744Sgs150176 	rge_reg_put8(rgep, regno, regval);
223744Sgs150176 }
224744Sgs150176 
225744Sgs150176 static void rge_reg_clr8(rge_t *rgep, uintptr_t regno, uint8_t bits);
226744Sgs150176 #pragma	inline(rge_reg_clr8)
227744Sgs150176 
228744Sgs150176 static void
229744Sgs150176 rge_reg_clr8(rge_t *rgep, uintptr_t regno, uint8_t bits)
230744Sgs150176 {
231744Sgs150176 	uint8_t regval;
232744Sgs150176 
233744Sgs150176 	RGE_TRACE(("rge_reg_clr8($%p, 0x%lx, 0x%x)",
234744Sgs150176 		(void *)rgep, regno, bits));
235744Sgs150176 
236744Sgs150176 	regval = rge_reg_get8(rgep, regno);
237744Sgs150176 	regval &= ~bits;
238744Sgs150176 	rge_reg_put8(rgep, regno, regval);
239744Sgs150176 }
240744Sgs150176 
241744Sgs150176 uint16_t rge_mii_get16(rge_t *rgep, uintptr_t mii);
242744Sgs150176 #pragma	no_inline(rge_mii_get16)
243744Sgs150176 
244744Sgs150176 uint16_t
245744Sgs150176 rge_mii_get16(rge_t *rgep, uintptr_t mii)
246744Sgs150176 {
247744Sgs150176 	uint32_t regval;
248744Sgs150176 	uint32_t val32;
249744Sgs150176 	uint32_t i;
250744Sgs150176 
251744Sgs150176 	regval = (mii & PHY_REG_MASK) << PHY_REG_SHIFT;
252744Sgs150176 	rge_reg_put32(rgep, PHY_ACCESS_REG, regval);
253744Sgs150176 
254744Sgs150176 	/*
255744Sgs150176 	 * Waiting for PHY reading OK
256744Sgs150176 	 */
257744Sgs150176 	for (i = 0; i < PHY_RESET_LOOP; i++) {
258744Sgs150176 		drv_usecwait(100);
259744Sgs150176 		val32 = rge_reg_get32(rgep, PHY_ACCESS_REG);
260744Sgs150176 		if (val32 & PHY_ACCESS_WR_FLAG)
261744Sgs150176 			return (val32 & 0xffff);
262744Sgs150176 	}
263744Sgs150176 
264744Sgs150176 	RGE_REPORT((rgep, "rge_mii_get16(0x%x) fail, val = %x", mii, val32));
265744Sgs150176 	return ((uint16_t)~0u);
266744Sgs150176 }
267744Sgs150176 
268744Sgs150176 void rge_mii_put16(rge_t *rgep, uintptr_t mii, uint16_t data);
269744Sgs150176 #pragma	no_inline(rge_mii_put16)
270744Sgs150176 
271744Sgs150176 void
272744Sgs150176 rge_mii_put16(rge_t *rgep, uintptr_t mii, uint16_t data)
273744Sgs150176 {
274744Sgs150176 	uint32_t regval;
275744Sgs150176 	uint32_t val32;
276744Sgs150176 	uint32_t i;
277744Sgs150176 
278744Sgs150176 	regval = (mii & PHY_REG_MASK) << PHY_REG_SHIFT;
279744Sgs150176 	regval |= data & PHY_DATA_MASK;
280744Sgs150176 	regval |= PHY_ACCESS_WR_FLAG;
281744Sgs150176 	rge_reg_put32(rgep, PHY_ACCESS_REG, regval);
282744Sgs150176 
283744Sgs150176 	/*
284744Sgs150176 	 * Waiting for PHY writing OK
285744Sgs150176 	 */
286744Sgs150176 	for (i = 0; i < PHY_RESET_LOOP; i++) {
287744Sgs150176 		drv_usecwait(100);
288744Sgs150176 		val32 = rge_reg_get32(rgep, PHY_ACCESS_REG);
289744Sgs150176 		if (!(val32 & PHY_ACCESS_WR_FLAG))
290744Sgs150176 			return;
291744Sgs150176 	}
292744Sgs150176 	RGE_REPORT((rgep, "rge_mii_put16(0x%lx, 0x%x) fail",
293744Sgs150176 	    mii, data));
294744Sgs150176 }
295744Sgs150176 
296744Sgs150176 /*
297744Sgs150176  * Atomically shift a 32-bit word left, returning
298744Sgs150176  * the value it had *before* the shift was applied
299744Sgs150176  */
300744Sgs150176 static uint32_t rge_atomic_shl32(uint32_t *sp, uint_t count);
301744Sgs150176 #pragma	inline(rge_mii_put16)
302744Sgs150176 
303744Sgs150176 static uint32_t
304744Sgs150176 rge_atomic_shl32(uint32_t *sp, uint_t count)
305744Sgs150176 {
306744Sgs150176 	uint32_t oldval;
307744Sgs150176 	uint32_t newval;
308744Sgs150176 
309744Sgs150176 	/* ATOMICALLY */
310744Sgs150176 	do {
311744Sgs150176 		oldval = *sp;
312744Sgs150176 		newval = oldval << count;
313744Sgs150176 	} while (cas32(sp, oldval, newval) != oldval);
314744Sgs150176 
315744Sgs150176 	return (oldval);
316744Sgs150176 }
317744Sgs150176 
318744Sgs150176 /*
319744Sgs150176  * PHY operation routines
320744Sgs150176  */
321744Sgs150176 #if	RGE_DEBUGGING
322744Sgs150176 
323744Sgs150176 static void
324744Sgs150176 rge_phydump(rge_t *rgep)
325744Sgs150176 {
326744Sgs150176 	uint16_t regs[32];
327744Sgs150176 	int i;
328744Sgs150176 
329744Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
330744Sgs150176 
331744Sgs150176 	for (i = 0; i < 32; ++i) {
332744Sgs150176 		regs[i] = rge_mii_get16(rgep, i);
333744Sgs150176 	}
334744Sgs150176 
335744Sgs150176 	for (i = 0; i < 32; i += 8)
336744Sgs150176 		RGE_DEBUG(("rge_phydump: "
337744Sgs150176 				"0x%04x %04x %04x %04x %04x %04x %04x %04x",
338744Sgs150176 			regs[i+0], regs[i+1], regs[i+2], regs[i+3],
339744Sgs150176 			regs[i+4], regs[i+5], regs[i+6], regs[i+7]));
340744Sgs150176 }
341744Sgs150176 
342744Sgs150176 #endif	/* RGE_DEBUGGING */
343744Sgs150176 
344744Sgs150176 /*
345744Sgs150176  * Basic low-level function to probe for a PHY
346744Sgs150176  *
347744Sgs150176  * Returns TRUE if the PHY responds with valid data, FALSE otherwise
348744Sgs150176  */
349744Sgs150176 static boolean_t
350744Sgs150176 rge_phy_probe(rge_t *rgep)
351744Sgs150176 {
352744Sgs150176 	uint16_t phy_status;
353744Sgs150176 
354744Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
355744Sgs150176 
356744Sgs150176 	/*
357744Sgs150176 	 * Read the MII_STATUS register twice, in
358744Sgs150176 	 * order to clear any sticky bits (but they should
359744Sgs150176 	 * have been cleared by the RESET, I think).
360744Sgs150176 	 */
361744Sgs150176 	phy_status = rge_mii_get16(rgep, MII_STATUS);
362744Sgs150176 	phy_status = rge_mii_get16(rgep, MII_STATUS);
363744Sgs150176 	RGE_DEBUG(("rge_phy_probe: status 0x%x", phy_status));
364744Sgs150176 
365744Sgs150176 	/*
366744Sgs150176 	 * Now check the value read; it should have at least one bit set
367744Sgs150176 	 * (for the device capabilities) and at least one clear (one of
368744Sgs150176 	 * the error bits). So if we see all 0s or all 1s, there's a
369744Sgs150176 	 * problem.  In particular, rge_mii_get16() returns all 1s if
370744Sgs150176 	 * communications fails ...
371744Sgs150176 	 */
372744Sgs150176 	switch (phy_status) {
373744Sgs150176 	case 0x0000:
374744Sgs150176 	case 0xffff:
375744Sgs150176 		return (B_FALSE);
376744Sgs150176 
377744Sgs150176 	default :
378744Sgs150176 		return (B_TRUE);
379744Sgs150176 	}
380744Sgs150176 }
381744Sgs150176 
382744Sgs150176 static void
383744Sgs150176 rge_phy_check(rge_t *rgep)
384744Sgs150176 {
385744Sgs150176 	uint16_t gig_ctl;
386744Sgs150176 
387744Sgs150176 	if (rgep->param_link_up  == LINK_STATE_DOWN) {
388744Sgs150176 		/*
389744Sgs150176 		 * RTL8169S/8110S PHY has the "PCS bug".  Need reset PHY
390744Sgs150176 		 * every 15 seconds whin link down & advertise is 1000.
391744Sgs150176 		 */
392744Sgs150176 		if (rgep->chipid.phy_ver == PHY_VER_S) {
393744Sgs150176 			gig_ctl = rge_mii_get16(rgep, MII_1000BASE_T_CONTROL);
394744Sgs150176 			if (gig_ctl & MII_1000BT_CTL_ADV_FDX) {
395744Sgs150176 				rgep->link_down_count++;
396744Sgs150176 				if (rgep->link_down_count > 15) {
397744Sgs150176 					(void) rge_phy_reset(rgep);
398744Sgs150176 					rgep->stats.phy_reset++;
399744Sgs150176 					rgep->link_down_count = 0;
400744Sgs150176 				}
401744Sgs150176 			}
402744Sgs150176 		}
403744Sgs150176 	} else {
404744Sgs150176 		rgep->link_down_count = 0;
405744Sgs150176 	}
406744Sgs150176 }
407744Sgs150176 
408744Sgs150176 /*
409744Sgs150176  * Basic low-level function to reset the PHY.
410744Sgs150176  * Doesn't incorporate any special-case workarounds.
411744Sgs150176  *
412744Sgs150176  * Returns TRUE on success, FALSE if the RESET bit doesn't clear
413744Sgs150176  */
414744Sgs150176 boolean_t
415744Sgs150176 rge_phy_reset(rge_t *rgep)
416744Sgs150176 {
417744Sgs150176 	uint16_t control;
418744Sgs150176 	uint_t count;
419744Sgs150176 
420744Sgs150176 	/*
421744Sgs150176 	 * Set the PHY RESET bit, then wait up to 5 ms for it to self-clear
422744Sgs150176 	 */
423744Sgs150176 	control = rge_mii_get16(rgep, MII_CONTROL);
424744Sgs150176 	rge_mii_put16(rgep, MII_CONTROL, control | MII_CONTROL_RESET);
425744Sgs150176 	for (count = 0; ++count < 1000; ) {
426744Sgs150176 		drv_usecwait(100);
427744Sgs150176 		control = rge_mii_get16(rgep, MII_CONTROL);
428744Sgs150176 		if (BIC(control, MII_CONTROL_RESET))
429744Sgs150176 			return (B_TRUE);
430744Sgs150176 	}
431744Sgs150176 
432744Sgs150176 	RGE_REPORT((rgep, "rge_phy_reset: FAILED, control now 0x%x", control));
433744Sgs150176 	return (B_FALSE);
434744Sgs150176 }
435744Sgs150176 
436744Sgs150176 /*
437744Sgs150176  * Synchronise the PHY's speed/duplex/autonegotiation capabilities
438744Sgs150176  * and advertisements with the required settings as specified by the various
439744Sgs150176  * param_* variables that can be poked via the NDD interface.
440744Sgs150176  *
441744Sgs150176  * We always reset the PHY and reprogram *all* the relevant registers,
442744Sgs150176  * not just those changed.  This should cause the link to go down, and then
443744Sgs150176  * back up again once the link is stable and autonegotiation (if enabled)
444744Sgs150176  * is complete.  We should get a link state change interrupt somewhere along
445744Sgs150176  * the way ...
446744Sgs150176  *
447744Sgs150176  * NOTE: <genlock> must already be held by the caller
448744Sgs150176  */
449744Sgs150176 void
450744Sgs150176 rge_phy_update(rge_t *rgep)
451744Sgs150176 {
452744Sgs150176 	boolean_t adv_autoneg;
453744Sgs150176 	boolean_t adv_pause;
454744Sgs150176 	boolean_t adv_asym_pause;
455744Sgs150176 	boolean_t adv_1000fdx;
456744Sgs150176 	boolean_t adv_1000hdx;
457744Sgs150176 	boolean_t adv_100fdx;
458744Sgs150176 	boolean_t adv_100hdx;
459744Sgs150176 	boolean_t adv_10fdx;
460744Sgs150176 	boolean_t adv_10hdx;
461744Sgs150176 
462744Sgs150176 	uint16_t control;
463744Sgs150176 	uint16_t gigctrl;
464744Sgs150176 	uint16_t anar;
465744Sgs150176 
466744Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
467744Sgs150176 
468744Sgs150176 	RGE_DEBUG(("rge_phy_update: autoneg %d "
469744Sgs150176 			"pause %d asym_pause %d "
470744Sgs150176 			"1000fdx %d 1000hdx %d "
471744Sgs150176 			"100fdx %d 100hdx %d "
472744Sgs150176 			"10fdx %d 10hdx %d ",
473744Sgs150176 		rgep->param_adv_autoneg,
474744Sgs150176 		rgep->param_adv_pause, rgep->param_adv_asym_pause,
475744Sgs150176 		rgep->param_adv_1000fdx, rgep->param_adv_1000hdx,
476744Sgs150176 		rgep->param_adv_100fdx, rgep->param_adv_100hdx,
477744Sgs150176 		rgep->param_adv_10fdx, rgep->param_adv_10hdx));
478744Sgs150176 
479744Sgs150176 	control = gigctrl = anar = 0;
480744Sgs150176 
481744Sgs150176 	/*
482744Sgs150176 	 * PHY settings are normally based on the param_* variables,
483744Sgs150176 	 * but if any loopback mode is in effect, that takes precedence.
484744Sgs150176 	 *
485744Sgs150176 	 * RGE supports MAC-internal loopback, PHY-internal loopback,
486744Sgs150176 	 * and External loopback at a variety of speeds (with a special
487744Sgs150176 	 * cable).  In all cases, autoneg is turned OFF, full-duplex
488744Sgs150176 	 * is turned ON, and the speed/mastership is forced.
489744Sgs150176 	 */
490744Sgs150176 	switch (rgep->param_loop_mode) {
491744Sgs150176 	case RGE_LOOP_NONE:
492744Sgs150176 	default:
493744Sgs150176 		adv_autoneg = rgep->param_adv_autoneg;
494744Sgs150176 		adv_pause = rgep->param_adv_pause;
495744Sgs150176 		adv_asym_pause = rgep->param_adv_asym_pause;
496744Sgs150176 		adv_1000fdx = rgep->param_adv_1000fdx;
497744Sgs150176 		adv_1000hdx = rgep->param_adv_1000hdx;
498744Sgs150176 		adv_100fdx = rgep->param_adv_100fdx;
499744Sgs150176 		adv_100hdx = rgep->param_adv_100hdx;
500744Sgs150176 		adv_10fdx = rgep->param_adv_10fdx;
501744Sgs150176 		adv_10hdx = rgep->param_adv_10hdx;
502744Sgs150176 		break;
503744Sgs150176 
504744Sgs150176 	case RGE_LOOP_INTERNAL_PHY:
505744Sgs150176 	case RGE_LOOP_INTERNAL_MAC:
506744Sgs150176 		adv_autoneg = adv_pause = adv_asym_pause = B_FALSE;
507744Sgs150176 		adv_1000fdx = adv_100fdx = adv_10fdx = B_FALSE;
508744Sgs150176 		adv_1000hdx = adv_100hdx = adv_10hdx = B_FALSE;
509744Sgs150176 		rgep->param_link_duplex = LINK_DUPLEX_FULL;
510744Sgs150176 
511744Sgs150176 		switch (rgep->param_loop_mode) {
512744Sgs150176 		case RGE_LOOP_INTERNAL_PHY:
513744Sgs150176 			rgep->param_link_speed = 1000;
514744Sgs150176 			adv_1000fdx = B_TRUE;
515744Sgs150176 			control = MII_CONTROL_LOOPBACK;
516744Sgs150176 			break;
517744Sgs150176 
518744Sgs150176 		case RGE_LOOP_INTERNAL_MAC:
519744Sgs150176 			rgep->param_link_speed = 1000;
520744Sgs150176 			adv_1000fdx = B_TRUE;
521744Sgs150176 			break;
522744Sgs150176 		}
523744Sgs150176 	}
524744Sgs150176 
525744Sgs150176 	RGE_DEBUG(("rge_phy_update: autoneg %d "
526744Sgs150176 			"pause %d asym_pause %d "
527744Sgs150176 			"1000fdx %d 1000hdx %d "
528744Sgs150176 			"100fdx %d 100hdx %d "
529744Sgs150176 			"10fdx %d 10hdx %d ",
530744Sgs150176 		adv_autoneg,
531744Sgs150176 		adv_pause, adv_asym_pause,
532744Sgs150176 		adv_1000fdx, adv_1000hdx,
533744Sgs150176 		adv_100fdx, adv_100hdx,
534744Sgs150176 		adv_10fdx, adv_10hdx));
535744Sgs150176 
536744Sgs150176 	/*
537744Sgs150176 	 * We should have at least one technology capability set;
538744Sgs150176 	 * if not, we select a default of 1000Mb/s full-duplex
539744Sgs150176 	 */
540744Sgs150176 	if (!adv_1000fdx && !adv_100fdx && !adv_10fdx &&
541744Sgs150176 	    !adv_1000hdx && !adv_100hdx && !adv_10hdx)
542744Sgs150176 		adv_1000fdx = B_TRUE;
543744Sgs150176 
544744Sgs150176 	/*
545744Sgs150176 	 * Now transform the adv_* variables into the proper settings
546744Sgs150176 	 * of the PHY registers ...
547744Sgs150176 	 *
548744Sgs150176 	 * If autonegotiation is (now) enabled, we want to trigger
549744Sgs150176 	 * a new autonegotiation cycle once the PHY has been
550744Sgs150176 	 * programmed with the capabilities to be advertised.
551744Sgs150176 	 *
552744Sgs150176 	 * RTL8169/8110 doesn't support 1000Mb/s half-duplex.
553744Sgs150176 	 */
554744Sgs150176 	if (adv_autoneg)
555744Sgs150176 		control |= MII_CONTROL_ANE|MII_CONTROL_RSAN;
556744Sgs150176 
557744Sgs150176 	if (adv_1000fdx)
558744Sgs150176 		control |= MII_CONTROL_1000MB|MII_CONTROL_FDUPLEX;
559744Sgs150176 	else if (adv_1000hdx)
560744Sgs150176 		control |= MII_CONTROL_1000MB;
561744Sgs150176 	else if (adv_100fdx)
562744Sgs150176 		control |= MII_CONTROL_100MB|MII_CONTROL_FDUPLEX;
563744Sgs150176 	else if (adv_100hdx)
564744Sgs150176 		control |= MII_CONTROL_100MB;
565744Sgs150176 	else if (adv_10fdx)
566744Sgs150176 		control |= MII_CONTROL_FDUPLEX;
567744Sgs150176 	else if (adv_10hdx)
568744Sgs150176 		control |= 0;
569744Sgs150176 	else
570744Sgs150176 		{ _NOTE(EMPTY); }	/* Can't get here anyway ...	*/
571744Sgs150176 
572744Sgs150176 	if (adv_1000fdx) {
573744Sgs150176 		gigctrl |= MII_1000BT_CTL_ADV_FDX;
574744Sgs150176 		/*
575744Sgs150176 		 * Chipset limitation: need set other capabilities to true
576744Sgs150176 		 */
577744Sgs150176 		adv_100fdx = B_TRUE;
578744Sgs150176 		adv_100hdx  = B_TRUE;
579744Sgs150176 		adv_10fdx = B_TRUE;
580744Sgs150176 		adv_10hdx = B_TRUE;
581744Sgs150176 	}
582744Sgs150176 
583744Sgs150176 	if (adv_1000hdx)
584744Sgs150176 		gigctrl |= MII_1000BT_CTL_ADV_HDX;
585744Sgs150176 
586744Sgs150176 	if (adv_100fdx)
587744Sgs150176 		anar |= MII_ABILITY_100BASE_TX_FD;
588744Sgs150176 	if (adv_100hdx)
589744Sgs150176 		anar |= MII_ABILITY_100BASE_TX;
590744Sgs150176 	if (adv_10fdx)
591744Sgs150176 		anar |= MII_ABILITY_10BASE_T_FD;
592744Sgs150176 	if (adv_10hdx)
593744Sgs150176 		anar |= MII_ABILITY_10BASE_T;
594744Sgs150176 
595744Sgs150176 	if (adv_pause)
596744Sgs150176 		anar |= MII_ABILITY_PAUSE;
597744Sgs150176 	if (adv_asym_pause)
598744Sgs150176 		anar |= MII_ABILITY_ASYM_PAUSE;
599744Sgs150176 
600744Sgs150176 	/*
601744Sgs150176 	 * Munge in any other fixed bits we require ...
602744Sgs150176 	 */
603744Sgs150176 	anar |= MII_AN_SELECTOR_8023;
604744Sgs150176 
605744Sgs150176 	/*
606744Sgs150176 	 * Restart the PHY and write the new values.  Note the
607744Sgs150176 	 * time, so that we can say whether subsequent link state
608744Sgs150176 	 * changes can be attributed to our reprogramming the PHY
609744Sgs150176 	 */
610744Sgs150176 	rgep->phys_write_time = gethrtime();
611744Sgs150176 	rge_phy_init(rgep);
612744Sgs150176 	rge_mii_put16(rgep, MII_AN_ADVERT, anar);
613744Sgs150176 	rge_mii_put16(rgep, MII_CONTROL, control);
614744Sgs150176 	rge_mii_put16(rgep, MII_1000BASE_T_CONTROL, gigctrl);
615744Sgs150176 
616744Sgs150176 	RGE_DEBUG(("rge_phy_update: anar <- 0x%x", anar));
617744Sgs150176 	RGE_DEBUG(("rge_phy_update: control <- 0x%x", control));
618744Sgs150176 	RGE_DEBUG(("rge_phy_update: gigctrl <- 0x%x", gigctrl));
619744Sgs150176 }
620744Sgs150176 
621744Sgs150176 void rge_phy_init(rge_t *rgep);
622744Sgs150176 #pragma	no_inline(rge_phy_init)
623744Sgs150176 
624744Sgs150176 void
625744Sgs150176 rge_phy_init(rge_t *rgep)
626744Sgs150176 {
627744Sgs150176 	uint16_t val16;
628744Sgs150176 
629744Sgs150176 	rgep->phy_mii_addr = 1;
630744Sgs150176 
631744Sgs150176 	/*
632744Sgs150176 	 * Below phy config steps are copied from the Programming Guide
633744Sgs150176 	 * (there's no detail comments for these steps.)
634744Sgs150176 	 */
635744Sgs150176 	if ((rgep->chipid.mac_ver == MAC_VER_SD ||
636744Sgs150176 	    rgep->chipid.mac_ver == MAC_VER_SE) &&
637744Sgs150176 	    (rgep->chipid.phy_ver == PHY_VER_S)) {
638744Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 1);
639744Sgs150176 		rge_mii_put16(rgep, PHY_15_REG, 0x1000);
640744Sgs150176 		rge_mii_put16(rgep, PHY_18_REG, 0x65c7);
641744Sgs150176 		val16 = rge_mii_get16(rgep, PHY_ANAR_REG);
642744Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, val16 & (~ANAR_ASY_PAUSE));
643744Sgs150176 		val16 = rge_mii_get16(rgep, PHY_ANAR_REG);
644744Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, val16 & 0x0fff);
645744Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_2, 0x00a1);
646744Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_1, 0x0008);
647744Sgs150176 		rge_mii_put16(rgep, PHY_BMSR_REG, 0x1020);
648744Sgs150176 		rge_mii_put16(rgep, PHY_BMCR_REG, 0x1000);
649744Sgs150176 		val16 = rge_mii_get16(rgep, PHY_ANAR_REG);
650744Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, val16 | ANAR_ASY_PAUSE);
651744Sgs150176 		val16 = rge_mii_get16(rgep, PHY_ANAR_REG);
652744Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, val16 & (~ANAR_ASY_PAUSE));
653744Sgs150176 		val16 = rge_mii_get16(rgep, PHY_ANAR_REG);
654744Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, (val16 & 0x0fff) | 0x7000);
655744Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_2, 0xff41);
656744Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_1, 0xde60);
657744Sgs150176 		rge_mii_put16(rgep, PHY_BMSR_REG, 0x0140);
658744Sgs150176 		rge_mii_put16(rgep, PHY_BMCR_REG, 0x0077);
659744Sgs150176 		val16 = rge_mii_get16(rgep, PHY_ANAR_REG);
660744Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, val16 | ANAR_ASY_PAUSE);
661744Sgs150176 		val16 = rge_mii_get16(rgep, PHY_ANAR_REG);
662744Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, val16 & (~ANAR_ASY_PAUSE));
663744Sgs150176 		val16 = rge_mii_get16(rgep, PHY_ANAR_REG);
664744Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, (val16 & 0x0fff) | 0xa000);
665744Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_2, 0xdf01);
666744Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_1, 0xdf20);
667744Sgs150176 		rge_mii_put16(rgep, PHY_BMSR_REG, 0xff95);
668744Sgs150176 		rge_mii_put16(rgep, PHY_BMCR_REG, 0xfa00);
669744Sgs150176 		val16 = rge_mii_get16(rgep, PHY_ANAR_REG);
670744Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, val16 | ANAR_ASY_PAUSE);
671744Sgs150176 		val16 = rge_mii_get16(rgep, PHY_ANAR_REG);
672744Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, val16 & (~ANAR_ASY_PAUSE));
673744Sgs150176 		val16 = rge_mii_get16(rgep, PHY_ANAR_REG);
674744Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, (val16 & 0x0fff) | 0xb000);
675744Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_2, 0xff41);
676744Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_1, 0xde20);
677744Sgs150176 		rge_mii_put16(rgep, PHY_BMSR_REG, 0x0140);
678744Sgs150176 		rge_mii_put16(rgep, PHY_BMCR_REG, 0x00bb);
679744Sgs150176 		val16 = rge_mii_get16(rgep, PHY_ANAR_REG);
680744Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, val16 | ANAR_ASY_PAUSE);
681744Sgs150176 		val16 = rge_mii_get16(rgep, PHY_ANAR_REG);
682744Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, val16 & (~ANAR_ASY_PAUSE));
683744Sgs150176 		val16 = rge_mii_get16(rgep, PHY_ANAR_REG);
684744Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, (val16 & 0x0fff) | 0xf000);
685744Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_2, 0xdf01);
686744Sgs150176 		rge_mii_put16(rgep, PHY_ID_REG_1, 0xdf20);
687744Sgs150176 		rge_mii_put16(rgep, PHY_BMSR_REG, 0xff95);
688744Sgs150176 		rge_mii_put16(rgep, PHY_BMCR_REG, 0xbf00);
689744Sgs150176 		val16 = rge_mii_get16(rgep, PHY_ANAR_REG);
690744Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, val16 | ANAR_ASY_PAUSE);
691744Sgs150176 		val16 = rge_mii_get16(rgep, PHY_ANAR_REG);
692744Sgs150176 		rge_mii_put16(rgep, PHY_ANAR_REG, val16 & (~ANAR_ASY_PAUSE));
693744Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0000);
694744Sgs150176 		rge_mii_put16(rgep, PHY_0B_REG, 0x0000);
695744Sgs150176 	}
696744Sgs150176 
697744Sgs150176 	if (rgep->chipid.mac_ver == MAC_VER_SB) {
698744Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0001);
699744Sgs150176 		rge_mii_put16(rgep, PHY_1B_REG, 0x841e);
700744Sgs150176 		rge_mii_put16(rgep, PHY_0E_REG, 0x7bfb);
701744Sgs150176 		rge_mii_put16(rgep, PHY_GBCR_REG, GBCR_DEFAULT);
702744Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0002);
703744Sgs150176 		rge_mii_put16(rgep, PHY_BMSR_REG, 0x90D0);
704744Sgs150176 		rge_mii_put16(rgep, PHY_1F_REG, 0x0000);
705744Sgs150176 	}
706744Sgs150176 }
707744Sgs150176 
708744Sgs150176 void rge_chip_ident(rge_t *rgep);
709744Sgs150176 #pragma	no_inline(rge_chip_ident)
710744Sgs150176 
711744Sgs150176 void
712744Sgs150176 rge_chip_ident(rge_t *rgep)
713744Sgs150176 {
714744Sgs150176 	chip_id_t *chip = &rgep->chipid;
715744Sgs150176 	uint32_t val32;
716744Sgs150176 	uint16_t val16;
717744Sgs150176 
718744Sgs150176 	val32 = rge_reg_get32(rgep, TX_CONFIG_REG);
719744Sgs150176 	val32 &= HW_VERSION_ID_0 | HW_VERSION_ID_1;
720744Sgs150176 	chip->mac_ver = val32;
721744Sgs150176 
722744Sgs150176 	val16 = rge_mii_get16(rgep, PHY_ID_REG_2);
723744Sgs150176 	val16 &= PHY_VER_MASK;
724744Sgs150176 	chip->phy_ver = val16;
725744Sgs150176 
726744Sgs150176 	if (rgep->param_default_mtu > ETHERMTU) {
727744Sgs150176 		rgep->rxbuf_size = RGE_BUFF_SIZE_JUMBO;
728744Sgs150176 		rgep->txbuf_size = RGE_BUFF_SIZE_JUMBO;
729744Sgs150176 		rgep->ethmax_size = RGE_JUMBO_SIZE;
730744Sgs150176 	} else {
731744Sgs150176 		rgep->rxbuf_size = RGE_BUFF_SIZE_STD;
732744Sgs150176 		rgep->txbuf_size = RGE_BUFF_SIZE_STD;
733744Sgs150176 		rgep->ethmax_size = ETHERMAX;
734744Sgs150176 	}
735744Sgs150176 
736744Sgs150176 	chip->rxconfig = RX_CONFIG_DEFAULT;
737744Sgs150176 	chip->txconfig = TX_CONFIG_DEFAULT;
738744Sgs150176 
739744Sgs150176 	RGE_TRACE(("%s: MAC version = %x, PHY version = %x",
740744Sgs150176 	    rgep->ifname, chip->mac_ver, chip->phy_ver));
741744Sgs150176 
742744Sgs150176 	/* set pci latency timer */
743744Sgs150176 	if (chip->mac_ver == MAC_VER_NS || chip->mac_ver == MAC_VER_SD)
744744Sgs150176 		pci_config_put8(rgep->cfg_handle, PCI_CONF_LATENCY_TIMER, 0x40);
745744Sgs150176 }
746744Sgs150176 
747744Sgs150176 /*
748744Sgs150176  * Perform first-stage chip (re-)initialisation, using only config-space
749744Sgs150176  * accesses:
750744Sgs150176  *
751744Sgs150176  * + Read the vendor/device/revision/subsystem/cache-line-size registers,
752744Sgs150176  *   returning the data in the structure pointed to by <idp>.
753744Sgs150176  * + Enable Memory Space accesses.
754744Sgs150176  * + Enable Bus Mastering according.
755744Sgs150176  */
756744Sgs150176 void rge_chip_cfg_init(rge_t *rgep, chip_id_t *cidp);
757744Sgs150176 #pragma	no_inline(rge_chip_cfg_init)
758744Sgs150176 
759744Sgs150176 void
760744Sgs150176 rge_chip_cfg_init(rge_t *rgep, chip_id_t *cidp)
761744Sgs150176 {
762744Sgs150176 	ddi_acc_handle_t handle;
763744Sgs150176 	uint16_t commd;
764744Sgs150176 
765744Sgs150176 	handle = rgep->cfg_handle;
766744Sgs150176 
767744Sgs150176 	/*
768744Sgs150176 	 * Save PCI cache line size and subsystem vendor ID
769744Sgs150176 	 */
770744Sgs150176 	cidp->command = pci_config_get16(handle, PCI_CONF_COMM);
771744Sgs150176 	cidp->vendor = pci_config_get16(handle, PCI_CONF_VENID);
772744Sgs150176 	cidp->device = pci_config_get16(handle, PCI_CONF_DEVID);
773744Sgs150176 	cidp->subven = pci_config_get16(handle, PCI_CONF_SUBVENID);
774744Sgs150176 	cidp->subdev = pci_config_get16(handle, PCI_CONF_SUBSYSID);
775744Sgs150176 	cidp->revision = pci_config_get8(handle, PCI_CONF_REVID);
776744Sgs150176 	cidp->clsize = pci_config_get8(handle, PCI_CONF_CACHE_LINESZ);
777744Sgs150176 	cidp->latency = pci_config_get8(handle, PCI_CONF_LATENCY_TIMER);
778744Sgs150176 
779744Sgs150176 	/*
780744Sgs150176 	 * Turn on Master Enable (DMA) and IO Enable bits.
781744Sgs150176 	 * Enable PCI Memory Space accesses
782744Sgs150176 	 */
783744Sgs150176 	commd = cidp->command;
784744Sgs150176 	commd |= PCI_COMM_ME | PCI_COMM_MAE | PCI_COMM_IO;
785744Sgs150176 	pci_config_put16(handle, PCI_CONF_COMM, commd);
786744Sgs150176 
787744Sgs150176 	RGE_DEBUG(("rge_chip_cfg_init: vendor 0x%x device 0x%x revision 0x%x",
788744Sgs150176 		cidp->vendor, cidp->device, cidp->revision));
789744Sgs150176 	RGE_DEBUG(("rge_chip_cfg_init: subven 0x%x subdev 0x%x",
790744Sgs150176 		cidp->subven, cidp->subdev));
791744Sgs150176 	RGE_DEBUG(("rge_chip_cfg_init: clsize %d latency %d command 0x%x",
792744Sgs150176 		cidp->clsize, cidp->latency, cidp->command));
793744Sgs150176 }
794744Sgs150176 
795744Sgs150176 int rge_chip_reset(rge_t *rgep);
796744Sgs150176 #pragma	no_inline(rge_chip_reset)
797744Sgs150176 
798744Sgs150176 int
799744Sgs150176 rge_chip_reset(rge_t *rgep)
800744Sgs150176 {
801744Sgs150176 	int i;
802744Sgs150176 	uint8_t val8;
803744Sgs150176 
804744Sgs150176 	/*
805744Sgs150176 	 * Chip should be in STOP state
806744Sgs150176 	 */
807744Sgs150176 	rge_reg_clr8(rgep, RT_COMMAND_REG,
808744Sgs150176 	    RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
809744Sgs150176 
810744Sgs150176 	/*
811744Sgs150176 	 * Disable interrupt
812744Sgs150176 	 */
813744Sgs150176 	rge_reg_clr16(rgep, INT_MASK_REG, INT_MASK_ALL);
814744Sgs150176 	rgep->int_mask = INT_MASK_NONE;
815744Sgs150176 
816744Sgs150176 	/*
817744Sgs150176 	 * Clear pended interrupt
818744Sgs150176 	 */
819744Sgs150176 	rge_reg_put16(rgep, INT_STATUS_REG, INT_MASK_ALL);
820744Sgs150176 
821744Sgs150176 	/*
822744Sgs150176 	 * Reset chip
823744Sgs150176 	 */
824744Sgs150176 	rge_reg_set8(rgep, RT_COMMAND_REG, RT_COMMAND_RESET);
825744Sgs150176 
826744Sgs150176 	/*
827744Sgs150176 	 * Wait for reset success
828744Sgs150176 	 */
829744Sgs150176 	for (i = 0; i < CHIP_RESET_LOOP; i++) {
830744Sgs150176 		drv_usecwait(10);
831744Sgs150176 		val8 = rge_reg_get8(rgep, RT_COMMAND_REG);
832744Sgs150176 		if (!(val8 & RT_COMMAND_RESET)) {
833744Sgs150176 			rgep->rge_chip_state = RGE_CHIP_RESET;
834744Sgs150176 			return (0);
835744Sgs150176 		}
836744Sgs150176 	}
837744Sgs150176 	RGE_REPORT((rgep, "rge_chip_reset fail."));
838744Sgs150176 	return (-1);
839744Sgs150176 }
840744Sgs150176 
841744Sgs150176 void rge_chip_init(rge_t *rgep);
842744Sgs150176 #pragma	no_inline(rge_chip_init)
843744Sgs150176 
844744Sgs150176 void
845744Sgs150176 rge_chip_init(rge_t *rgep)
846744Sgs150176 {
847744Sgs150176 	uint32_t val32;
848744Sgs150176 
849744Sgs150176 	/*
850744Sgs150176 	 * Config MII register
851744Sgs150176 	 */
852744Sgs150176 	rgep->param_link_up = LINK_STATE_DOWN;
853744Sgs150176 	rge_phy_update(rgep);
854744Sgs150176 
855744Sgs150176 	/*
856744Sgs150176 	 * Enable Rx checksum offload.
857744Sgs150176 	 *  Then for vlan support, we must enable receive vlan de-tagging.
858744Sgs150176 	 *  Otherwise, there'll be checksum error.
859744Sgs150176 	 */
860744Sgs150176 	rge_reg_set16(rgep, CPLUS_COMMAND_REG, RX_CKSM_OFFLOAD | RX_VLAN_DETAG);
861744Sgs150176 
862744Sgs150176 	/*
863744Sgs150176 	 * Suggested setting from Realtek
864744Sgs150176 	 */
865744Sgs150176 	if (rgep->chipid.mac_ver == MAC_VER_SD) {
866744Sgs150176 		rge_reg_set16(rgep, CPLUS_COMMAND_REG,
867744Sgs150176 		    CPLUS_BIT14 | MUL_PCI_RW_ENABLE);
868744Sgs150176 		rge_reg_put8(rgep, RESV_82_REG, 0x01);
869744Sgs150176 	}
870744Sgs150176 	rge_reg_clr16(rgep, CPLUS_COMMAND_REG, 0x03);
871744Sgs150176 
872744Sgs150176 	/*
873744Sgs150176 	 * Start transmit/receive before set tx/rx configuration register
874744Sgs150176 	 */
875744Sgs150176 	rge_reg_set8(rgep, RT_COMMAND_REG,
876744Sgs150176 	    RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
877744Sgs150176 
878744Sgs150176 	/*
879744Sgs150176 	 * Set dump tally counter register
880744Sgs150176 	 */
881744Sgs150176 	val32 = rgep->dma_area_stats.cookie.dmac_laddress >> 32;
882744Sgs150176 	rge_reg_put32(rgep, DUMP_COUNTER_REG_1, val32);
883744Sgs150176 	val32 = rge_reg_get32(rgep, DUMP_COUNTER_REG_0);
884744Sgs150176 	val32 &= DUMP_COUNTER_REG_RESV;
885744Sgs150176 	val32 |= rgep->dma_area_stats.cookie.dmac_laddress;
886744Sgs150176 	rge_reg_put32(rgep, DUMP_COUNTER_REG_0, val32);
887744Sgs150176 
888744Sgs150176 	/*
889744Sgs150176 	 * Change to config register write enable mode
890744Sgs150176 	 */
891744Sgs150176 	rge_reg_set8(rgep, RT_93c46_COMMOND_REG, RT_93c46_MODE_CONFIG);
892744Sgs150176 
893744Sgs150176 	/*
894744Sgs150176 	 * Set Tx/Rx maximum packet size
895744Sgs150176 	 */
896744Sgs150176 	if (rgep->param_default_mtu > ETHERMTU) {
897744Sgs150176 		rge_reg_put8(rgep, TX_MAX_PKTSIZE_REG, TX_PKTSIZE_JUMBO);
898744Sgs150176 		rge_reg_put16(rgep, RX_MAX_PKTSIZE_REG, RX_PKTSIZE_JUMBO);
899744Sgs150176 	} else {
900744Sgs150176 		rge_reg_put8(rgep, TX_MAX_PKTSIZE_REG, TX_PKTSIZE_STD);
901744Sgs150176 		rge_reg_put16(rgep, RX_MAX_PKTSIZE_REG, RX_PKTSIZE_STD);
902744Sgs150176 	}
903744Sgs150176 
904744Sgs150176 	/*
905744Sgs150176 	 * Set receive configuration register
906744Sgs150176 	 */
907744Sgs150176 	val32 = rge_reg_get32(rgep, RX_CONFIG_REG);
908744Sgs150176 	val32 &= RX_CONFIG_REG_RESV;
909744Sgs150176 	if (rgep->promisc)
910744Sgs150176 		val32 |= RX_ACCEPT_ALL_PKT;
911744Sgs150176 	rge_reg_put32(rgep, RX_CONFIG_REG, val32 | rgep->chipid.rxconfig);
912744Sgs150176 
913744Sgs150176 	/*
914744Sgs150176 	 * Set transmit configuration register
915744Sgs150176 	 */
916744Sgs150176 	val32 = rge_reg_get32(rgep, TX_CONFIG_REG);
917744Sgs150176 	val32 &= TX_CONFIG_REG_RESV;
918744Sgs150176 	rge_reg_put32(rgep, TX_CONFIG_REG, val32 | rgep->chipid.txconfig);
919744Sgs150176 
920744Sgs150176 	/*
921744Sgs150176 	 * Initialize PHY registers
922744Sgs150176 	 */
923744Sgs150176 	rge_phy_init(rgep);
924744Sgs150176 
925744Sgs150176 	/*
926744Sgs150176 	 * Set Tx/Rx descriptor register
927744Sgs150176 	 */
928744Sgs150176 	val32 = rgep->tx_desc.cookie.dmac_laddress;
929744Sgs150176 	rge_reg_put32(rgep, NORMAL_TX_RING_ADDR_LO_REG, val32);
930744Sgs150176 	val32 = rgep->tx_desc.cookie.dmac_laddress >> 32;
931744Sgs150176 	rge_reg_put32(rgep, NORMAL_TX_RING_ADDR_HI_REG, val32);
932744Sgs150176 	rge_reg_put32(rgep, HIGH_TX_RING_ADDR_LO_REG, 0);
933744Sgs150176 	rge_reg_put32(rgep, HIGH_TX_RING_ADDR_HI_REG, 0);
934744Sgs150176 	val32 = rgep->rx_desc.cookie.dmac_laddress;
935744Sgs150176 	rge_reg_put32(rgep, RX_RING_ADDR_LO_REG, val32);
936744Sgs150176 	val32 = rgep->rx_desc.cookie.dmac_laddress >> 32;
937744Sgs150176 	rge_reg_put32(rgep, RX_RING_ADDR_HI_REG, val32);
938744Sgs150176 
939744Sgs150176 	/*
940744Sgs150176 	 * Suggested setting from Realtek
941744Sgs150176 	 */
942744Sgs150176 	rge_reg_put16(rgep, RESV_E2_REG, 0x282a);
943744Sgs150176 
944744Sgs150176 	/*
945744Sgs150176 	 * Return to normal network/host communication mode
946744Sgs150176 	 */
947744Sgs150176 	rge_reg_clr8(rgep, RT_93c46_COMMOND_REG, RT_93c46_MODE_CONFIG);
948744Sgs150176 	drv_usecwait(20);
949744Sgs150176 
950744Sgs150176 	/*
951744Sgs150176 	 * Set multicast register
952744Sgs150176 	 */
953744Sgs150176 	rge_reg_put32(rgep, MULTICAST_0_REG, rgep->mcast_hash[0]);
954744Sgs150176 	rge_reg_put32(rgep, MULTICAST_4_REG, rgep->mcast_hash[1]);
955744Sgs150176 
956744Sgs150176 	/*
957744Sgs150176 	 * Mask and clear all Interrupt
958744Sgs150176 	 */
959744Sgs150176 	rge_reg_put16(rgep, INT_MASK_REG, INT_MASK_NONE);
960744Sgs150176 	rge_reg_put16(rgep, INT_STATUS_REG, INT_MASK_ALL);
961744Sgs150176 
962744Sgs150176 	/*
963744Sgs150176 	 * Msic register setting:
964744Sgs150176 	 *   -- Missed packet counter: clear it
965744Sgs150176 	 *   -- TimerInt Register
966744Sgs150176 	 *   -- Timer count register
967744Sgs150176 	 */
968744Sgs150176 	rge_reg_put32(rgep, RX_PKT_MISS_COUNT_REG, 0);
969744Sgs150176 	rge_reg_put32(rgep, TIMER_INT_REG, TIMER_INT_NONE);
970744Sgs150176 	rge_reg_put32(rgep, TIMER_COUNT_REG, 0);
971744Sgs150176 }
972744Sgs150176 
973744Sgs150176 /*
974744Sgs150176  * rge_chip_start() -- start the chip transmitting and/or receiving,
975744Sgs150176  * including enabling interrupts
976744Sgs150176  */
977744Sgs150176 void rge_chip_start(rge_t *rgep);
978744Sgs150176 #pragma	no_inline(rge_chip_start)
979744Sgs150176 
980744Sgs150176 void
981744Sgs150176 rge_chip_start(rge_t *rgep)
982744Sgs150176 {
983744Sgs150176 	/*
984744Sgs150176 	 * Clear statistics
985744Sgs150176 	 */
986744Sgs150176 	bzero(&rgep->stats, sizeof (rge_stats_t));
987744Sgs150176 	DMA_ZERO(rgep->dma_area_stats);
988744Sgs150176 
989744Sgs150176 	/*
990744Sgs150176 	 * Start transmit/receive
991744Sgs150176 	 */
992744Sgs150176 	rge_reg_set8(rgep, RT_COMMAND_REG,
993744Sgs150176 	    RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
994744Sgs150176 
995744Sgs150176 	/*
996744Sgs150176 	 * Enable interrupt
997744Sgs150176 	 */
998744Sgs150176 	rge_reg_set16(rgep, INT_MASK_REG, RGE_INT_MASK);
999744Sgs150176 	rgep->int_mask = RGE_INT_MASK;
1000744Sgs150176 
1001744Sgs150176 	/*
1002744Sgs150176 	 * All done!
1003744Sgs150176 	 */
1004744Sgs150176 	rgep->rge_chip_state = RGE_CHIP_RUNNING;
1005744Sgs150176 }
1006744Sgs150176 
1007744Sgs150176 /*
1008744Sgs150176  * rge_chip_stop() -- stop board receiving
1009744Sgs150176  */
1010744Sgs150176 void rge_chip_stop(rge_t *rgep, boolean_t fault);
1011744Sgs150176 #pragma	no_inline(rge_chip_stop)
1012744Sgs150176 
1013744Sgs150176 void
1014744Sgs150176 rge_chip_stop(rge_t *rgep, boolean_t fault)
1015744Sgs150176 {
1016744Sgs150176 	/*
1017744Sgs150176 	 * Disable interrupt
1018744Sgs150176 	 */
1019744Sgs150176 	rge_reg_put16(rgep, INT_MASK_REG, INT_MASK_NONE);
1020744Sgs150176 	rgep->int_mask = INT_MASK_NONE;
1021744Sgs150176 
1022744Sgs150176 	/*
1023744Sgs150176 	 * Clear pended interrupt
1024744Sgs150176 	 */
1025744Sgs150176 	rge_reg_put16(rgep, INT_STATUS_REG, INT_MASK_ALL);
1026744Sgs150176 
1027744Sgs150176 	/*
1028744Sgs150176 	 * Stop the board and disable transmit/receive
1029744Sgs150176 	 */
1030744Sgs150176 	rge_reg_clr8(rgep, RT_COMMAND_REG,
1031744Sgs150176 	    RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
1032744Sgs150176 
1033744Sgs150176 	if (fault)
1034744Sgs150176 		rgep->rge_chip_state = RGE_CHIP_FAULT;
1035744Sgs150176 	else
1036744Sgs150176 		rgep->rge_chip_state = RGE_CHIP_STOPPED;
1037744Sgs150176 }
1038744Sgs150176 
1039744Sgs150176 /*
1040744Sgs150176  * rge_get_mac_addr() -- get the MAC address on NIC
1041744Sgs150176  */
1042744Sgs150176 static void rge_get_mac_addr(rge_t *rgep);
1043744Sgs150176 #pragma	inline(rge_get_mac_addr)
1044744Sgs150176 
1045744Sgs150176 static void
1046744Sgs150176 rge_get_mac_addr(rge_t *rgep)
1047744Sgs150176 {
1048744Sgs150176 	uint8_t *macaddr = rgep->netaddr;
1049744Sgs150176 	uint32_t val32;
1050744Sgs150176 
1051744Sgs150176 	/*
1052744Sgs150176 	 * Read first 4-byte of mac address
1053744Sgs150176 	 */
1054744Sgs150176 	val32 = rge_reg_get32(rgep, ID_0_REG);
1055744Sgs150176 	macaddr[0] = val32 & 0xff;
1056744Sgs150176 	val32 = val32 >> 8;
1057744Sgs150176 	macaddr[1] = val32 & 0xff;
1058744Sgs150176 	val32 = val32 >> 8;
1059744Sgs150176 	macaddr[2] = val32 & 0xff;
1060744Sgs150176 	val32 = val32 >> 8;
1061744Sgs150176 	macaddr[3] = val32 & 0xff;
1062744Sgs150176 
1063744Sgs150176 	/*
1064744Sgs150176 	 * Read last 2-byte of mac address
1065744Sgs150176 	 */
1066744Sgs150176 	val32 = rge_reg_get32(rgep, ID_4_REG);
1067744Sgs150176 	macaddr[4] = val32 & 0xff;
1068744Sgs150176 	val32 = val32 >> 8;
1069744Sgs150176 	macaddr[5] = val32 & 0xff;
1070744Sgs150176 }
1071744Sgs150176 
1072744Sgs150176 static void rge_set_mac_addr(rge_t *rgep);
1073744Sgs150176 #pragma	inline(rge_set_mac_addr)
1074744Sgs150176 
1075744Sgs150176 static void
1076744Sgs150176 rge_set_mac_addr(rge_t *rgep)
1077744Sgs150176 {
1078744Sgs150176 	uint8_t *p = rgep->netaddr;
1079744Sgs150176 	uint32_t val32;
1080744Sgs150176 
1081744Sgs150176 	/*
1082744Sgs150176 	 * Change to config register write enable mode
1083744Sgs150176 	 */
1084744Sgs150176 	rge_reg_set8(rgep, RT_93c46_COMMOND_REG, RT_93c46_MODE_CONFIG);
1085744Sgs150176 
1086744Sgs150176 	/*
1087744Sgs150176 	 * Get first 4 bytes of mac address
1088744Sgs150176 	 */
1089744Sgs150176 	val32 = p[3];
1090744Sgs150176 	val32 = val32 << 8;
1091744Sgs150176 	val32 |= p[2];
1092744Sgs150176 	val32 = val32 << 8;
1093744Sgs150176 	val32 |= p[1];
1094744Sgs150176 	val32 = val32 << 8;
1095744Sgs150176 	val32 |= p[0];
1096744Sgs150176 
1097744Sgs150176 	/*
1098744Sgs150176 	 * Set first 4 bytes of mac address
1099744Sgs150176 	 */
1100744Sgs150176 	rge_reg_put32(rgep, ID_0_REG, val32);
1101744Sgs150176 
1102744Sgs150176 	/*
1103744Sgs150176 	 * Get last 2 bytes of mac address
1104744Sgs150176 	 */
1105744Sgs150176 	val32 = p[5];
1106744Sgs150176 	val32 = val32 << 8;
1107744Sgs150176 	val32 |= p[4];
1108744Sgs150176 
1109744Sgs150176 	/*
1110744Sgs150176 	 * Set last 2 bytes of mac address
1111744Sgs150176 	 */
1112744Sgs150176 	val32 |= rge_reg_get32(rgep, ID_4_REG) & ~0xffff;
1113744Sgs150176 	rge_reg_put32(rgep, ID_4_REG, val32);
1114744Sgs150176 
1115744Sgs150176 	/*
1116744Sgs150176 	 * Return to normal network/host communication mode
1117744Sgs150176 	 */
1118744Sgs150176 	rge_reg_clr8(rgep, RT_93c46_COMMOND_REG, RT_93c46_MODE_CONFIG);
1119744Sgs150176 }
1120744Sgs150176 
1121744Sgs150176 static void rge_set_multi_addr(rge_t *rgep);
1122744Sgs150176 #pragma	inline(rge_set_multi_addr)
1123744Sgs150176 
1124744Sgs150176 static void
1125744Sgs150176 rge_set_multi_addr(rge_t *rgep)
1126744Sgs150176 {
1127744Sgs150176 	uint32_t *hashp;
1128744Sgs150176 
1129744Sgs150176 	hashp = rgep->mcast_hash;
1130744Sgs150176 	rge_reg_put32(rgep, MULTICAST_0_REG, hashp[0]);
1131744Sgs150176 	rge_reg_put32(rgep, MULTICAST_4_REG, hashp[1]);
1132744Sgs150176 	rge_reg_set8(rgep, RT_COMMAND_REG,
1133744Sgs150176 	    RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
1134744Sgs150176 }
1135744Sgs150176 
1136744Sgs150176 static void rge_set_promisc(rge_t *rgep);
1137744Sgs150176 #pragma	inline(rge_set_promisc)
1138744Sgs150176 
1139744Sgs150176 static void
1140744Sgs150176 rge_set_promisc(rge_t *rgep)
1141744Sgs150176 {
1142744Sgs150176 	if (rgep->promisc)
1143744Sgs150176 		rge_reg_set32(rgep, RX_CONFIG_REG, RX_ACCEPT_ALL_PKT);
1144744Sgs150176 	else
1145744Sgs150176 		rge_reg_clr32(rgep, RX_CONFIG_REG, RX_ACCEPT_ALL_PKT);
1146744Sgs150176 
1147744Sgs150176 	rge_reg_set8(rgep, RT_COMMAND_REG,
1148744Sgs150176 	    RT_COMMAND_RX_ENABLE | RT_COMMAND_TX_ENABLE);
1149744Sgs150176 }
1150744Sgs150176 
1151744Sgs150176 /*
1152744Sgs150176  * rge_chip_sync() -- program the chip with the unicast MAC address,
1153744Sgs150176  * the multicast hash table, the required level of promiscuity, and
1154744Sgs150176  * the current loopback mode ...
1155744Sgs150176  */
1156744Sgs150176 void rge_chip_sync(rge_t *rgep, enum rge_sync_op todo);
1157744Sgs150176 #pragma	no_inline(rge_chip_sync)
1158744Sgs150176 
1159744Sgs150176 void
1160744Sgs150176 rge_chip_sync(rge_t *rgep, enum rge_sync_op todo)
1161744Sgs150176 {
1162744Sgs150176 	switch (todo) {
1163744Sgs150176 	case RGE_GET_MAC:
1164744Sgs150176 		rge_get_mac_addr(rgep);
1165744Sgs150176 		break;
1166744Sgs150176 	case RGE_SET_MAC:
1167744Sgs150176 		/* Reprogram the unicast MAC address(es) ... */
1168744Sgs150176 		rge_set_mac_addr(rgep);
1169744Sgs150176 		break;
1170744Sgs150176 	case RGE_SET_MUL:
1171744Sgs150176 		/* Reprogram the hashed multicast address table ... */
1172744Sgs150176 		rge_set_multi_addr(rgep);
1173744Sgs150176 		break;
1174744Sgs150176 	case RGE_SET_PROMISC:
1175744Sgs150176 		/* Set or clear the PROMISCUOUS mode bit */
1176744Sgs150176 		rge_set_promisc(rgep);
1177744Sgs150176 		break;
1178744Sgs150176 	default:
1179744Sgs150176 		break;
1180744Sgs150176 	}
1181744Sgs150176 }
1182744Sgs150176 
1183744Sgs150176 void rge_chip_blank(void *arg, time_t ticks, uint_t count);
1184744Sgs150176 #pragma	no_inline(rge_chip_blank)
1185744Sgs150176 
1186744Sgs150176 void
1187744Sgs150176 rge_chip_blank(void *arg, time_t ticks, uint_t count)
1188744Sgs150176 {
1189744Sgs150176 	_NOTE(ARGUNUSED(arg, ticks, count));
1190744Sgs150176 }
1191744Sgs150176 
1192744Sgs150176 void rge_tx_trigger(rge_t *rgep);
1193744Sgs150176 #pragma	no_inline(rge_tx_trigger)
1194744Sgs150176 
1195744Sgs150176 void
1196744Sgs150176 rge_tx_trigger(rge_t *rgep)
1197744Sgs150176 {
1198744Sgs150176 	rge_reg_set8(rgep, TX_RINGS_POLL_REG, NORMAL_TX_RING_POLL);
1199744Sgs150176 }
1200744Sgs150176 
1201744Sgs150176 void rge_hw_stats_dump(rge_t *rgep);
1202744Sgs150176 #pragma	no_inline(rge_tx_trigger)
1203744Sgs150176 
1204744Sgs150176 void
1205744Sgs150176 rge_hw_stats_dump(rge_t *rgep)
1206744Sgs150176 {
1207744Sgs150176 	int i = 0;
1208744Sgs150176 
1209744Sgs150176 	while (rge_reg_get32(rgep, DUMP_COUNTER_REG_0) & DUMP_START) {
1210744Sgs150176 		drv_usecwait(100);
1211744Sgs150176 		if (++i > STATS_DUMP_LOOP) {
1212744Sgs150176 			RGE_DEBUG(("rge h/w statistics dump fail!"));
1213744Sgs150176 			rgep->rge_chip_state = RGE_CHIP_ERROR;
1214744Sgs150176 			return;
1215744Sgs150176 		}
1216744Sgs150176 	}
1217744Sgs150176 	DMA_SYNC(rgep->dma_area_stats, DDI_DMA_SYNC_FORKERNEL);
1218744Sgs150176 
1219744Sgs150176 	/*
1220744Sgs150176 	 * Start H/W statistics dump for RTL8169 chip
1221744Sgs150176 	 */
1222744Sgs150176 	rge_reg_set32(rgep, DUMP_COUNTER_REG_0, DUMP_START);
1223744Sgs150176 }
1224744Sgs150176 
1225744Sgs150176 /*
1226744Sgs150176  * ========== Hardware interrupt handler ==========
1227744Sgs150176  */
1228744Sgs150176 
1229744Sgs150176 #undef	RGE_DBG
1230744Sgs150176 #define	RGE_DBG		RGE_DBG_INT	/* debug flag for this code	*/
1231744Sgs150176 
1232744Sgs150176 static void rge_wake_factotum(rge_t *rgep);
1233744Sgs150176 #pragma	inline(rge_wake_factotum)
1234744Sgs150176 
1235744Sgs150176 static void
1236744Sgs150176 rge_wake_factotum(rge_t *rgep)
1237744Sgs150176 {
1238744Sgs150176 	if (rgep->factotum_flag == 0) {
1239744Sgs150176 		rgep->factotum_flag = 1;
1240744Sgs150176 		ddi_trigger_softintr(rgep->factotum_id);
1241744Sgs150176 	}
1242744Sgs150176 }
1243744Sgs150176 
1244744Sgs150176 /*
1245744Sgs150176  *	rge_intr() -- handle chip interrupts
1246744Sgs150176  */
1247744Sgs150176 uint_t rge_intr(caddr_t arg);
1248744Sgs150176 #pragma	no_inline(rge_intr)
1249744Sgs150176 
1250744Sgs150176 uint_t
1251744Sgs150176 rge_intr(caddr_t arg)
1252744Sgs150176 {
1253744Sgs150176 	rge_t *rgep = (rge_t *)arg;
1254744Sgs150176 	uint16_t int_status;
1255744Sgs150176 
1256744Sgs150176 	mutex_enter(rgep->genlock);
1257744Sgs150176 
1258744Sgs150176 	/*
1259744Sgs150176 	 * Was this interrupt caused by our device...
1260744Sgs150176 	 */
1261744Sgs150176 	int_status = rge_reg_get16(rgep, INT_STATUS_REG);
1262744Sgs150176 	if (!(int_status & rgep->int_mask)) {
1263744Sgs150176 		mutex_exit(rgep->genlock);
1264744Sgs150176 		return (DDI_INTR_UNCLAIMED);
1265744Sgs150176 				/* indicate it wasn't our interrupt */
1266744Sgs150176 	}
1267744Sgs150176 
1268744Sgs150176 	rgep->stats.intr++;
1269744Sgs150176 
1270744Sgs150176 	/*
1271744Sgs150176 	 * Clear interrupt
1272744Sgs150176 	 */
1273744Sgs150176 	rge_reg_put16(rgep, INT_STATUS_REG, int_status);
1274744Sgs150176 
1275744Sgs150176 	/*
1276744Sgs150176 	 * Cable link change interrupt
1277744Sgs150176 	 */
1278744Sgs150176 	if (int_status & LINK_CHANGE_INT) {
1279744Sgs150176 		rge_chip_cyclic(rgep);
1280744Sgs150176 	}
1281744Sgs150176 	mutex_exit(rgep->genlock);
1282744Sgs150176 
1283744Sgs150176 	/*
1284744Sgs150176 	 * Receive interrupt
1285744Sgs150176 	 */
1286744Sgs150176 	if (int_status & RGE_RX_OVERFLOW_INT)
1287744Sgs150176 		rgep->stats.overflow++;
1288744Sgs150176 	if (rgep->rge_chip_state == RGE_CHIP_RUNNING)
1289744Sgs150176 		rge_receive(rgep);
1290744Sgs150176 
1291744Sgs150176 	return (DDI_INTR_CLAIMED);	/* indicate it was our interrupt */
1292744Sgs150176 }
1293744Sgs150176 
1294744Sgs150176 /*
1295744Sgs150176  * ========== Factotum, implemented as a softint handler ==========
1296744Sgs150176  */
1297744Sgs150176 
1298744Sgs150176 #undef	RGE_DBG
1299744Sgs150176 #define	RGE_DBG		RGE_DBG_FACT	/* debug flag for this code	*/
1300744Sgs150176 
1301744Sgs150176 static boolean_t rge_factotum_link_check(rge_t *rgep);
1302744Sgs150176 #pragma	no_inline(rge_factotum_link_check)
1303744Sgs150176 
1304744Sgs150176 static boolean_t
1305744Sgs150176 rge_factotum_link_check(rge_t *rgep)
1306744Sgs150176 {
1307744Sgs150176 	uint8_t media_status;
1308744Sgs150176 	int32_t link;
1309744Sgs150176 	void (*logfn)(rge_t *rgep, const char *fmt, ...);
1310744Sgs150176 	const char *msg;
1311744Sgs150176 	hrtime_t deltat;
1312744Sgs150176 
1313744Sgs150176 	media_status = rge_reg_get8(rgep, PHY_STATUS_REG);
1314744Sgs150176 	link = (media_status & PHY_STATUS_LINK_UP) ?
1315744Sgs150176 	    LINK_STATE_UP : LINK_STATE_DOWN;
1316744Sgs150176 	if (rgep->param_link_up != link) {
1317744Sgs150176 		/*
1318744Sgs150176 		 * Link change. We have to decide whether to write a message
1319744Sgs150176 		 * on the console or only in the log.  If the PHY has
1320744Sgs150176 		 * been reprogrammed (at user request) "recently", then
1321744Sgs150176 		 * the message only goes in the log.  Otherwise it's an
1322744Sgs150176 		 * "unexpected" event, and it goes on the console as well.
1323744Sgs150176 		 */
1324744Sgs150176 		rgep->param_link_up = link;
1325744Sgs150176 		rgep->phys_event_time = gethrtime();
1326744Sgs150176 		deltat = rgep->phys_event_time - rgep->phys_write_time;
1327744Sgs150176 		if (deltat > RGE_LINK_SETTLE_TIME)
1328744Sgs150176 			msg = "";
1329744Sgs150176 		else if (link == LINK_STATE_UP)
1330744Sgs150176 			msg = rgep->link_up_msg;
1331744Sgs150176 		else
1332744Sgs150176 			msg = rgep->link_down_msg;
1333744Sgs150176 		logfn = (msg == NULL || *msg == '\0') ? rge_notice : rge_log;
1334744Sgs150176 
1335744Sgs150176 		if (link == LINK_STATE_UP) {
1336744Sgs150176 			if (media_status & PHY_STATUS_1000MF) {
1337744Sgs150176 				rgep->param_link_speed = RGE_SPEED_1000M;
1338744Sgs150176 				rgep->param_link_duplex = LINK_DUPLEX_FULL;
1339744Sgs150176 			} else {
1340744Sgs150176 				rgep->param_link_speed =
1341744Sgs150176 				    (media_status & PHY_STATUS_100M) ?
1342744Sgs150176 				    RGE_SPEED_100M : RGE_SPEED_10M;
1343744Sgs150176 				rgep->param_link_duplex =
1344744Sgs150176 				    (media_status & PHY_STATUS_DUPLEX_FULL) ?
1345744Sgs150176 				    LINK_DUPLEX_FULL : LINK_DUPLEX_HALF;
1346744Sgs150176 			}
1347744Sgs150176 			logfn(rgep,
1348744Sgs150176 			    "link up %sbps %s_Duplex%s",
1349744Sgs150176 			    (rgep->param_link_speed == RGE_SPEED_10M) ?
1350744Sgs150176 			    "10M" : (rgep->param_link_speed == RGE_SPEED_100M ?
1351744Sgs150176 			    "100M" : "1000M"),
1352744Sgs150176 			    (rgep->param_link_duplex == LINK_DUPLEX_FULL) ?
1353744Sgs150176 			    "Full" : "Half",
1354744Sgs150176 			    msg);
1355744Sgs150176 		} else {
1356744Sgs150176 			logfn(rgep, "link down%s", msg);
1357744Sgs150176 		}
1358744Sgs150176 		return (B_TRUE);
1359744Sgs150176 	}
1360744Sgs150176 	return (B_FALSE);
1361744Sgs150176 }
1362744Sgs150176 
1363744Sgs150176 /*
1364744Sgs150176  * Factotum routine to check for Tx stall, using the 'watchdog' counter
1365744Sgs150176  */
1366744Sgs150176 static boolean_t rge_factotum_stall_check(rge_t *rgep);
1367744Sgs150176 #pragma	no_inline(rge_factotum_stall_check)
1368744Sgs150176 
1369744Sgs150176 static boolean_t
1370744Sgs150176 rge_factotum_stall_check(rge_t *rgep)
1371744Sgs150176 {
1372744Sgs150176 	uint32_t dogval;
1373744Sgs150176 
1374744Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
1375744Sgs150176 
1376744Sgs150176 	/*
1377744Sgs150176 	 * Specific check for Tx stall ...
1378744Sgs150176 	 *
1379744Sgs150176 	 * The 'watchdog' counter is incremented whenever a packet
1380744Sgs150176 	 * is queued, reset to 1 when some (but not all) buffers
1381744Sgs150176 	 * are reclaimed, reset to 0 (disabled) when all buffers
1382744Sgs150176 	 * are reclaimed, and shifted left here.  If it exceeds the
1383744Sgs150176 	 * threshold value, the chip is assumed to have stalled and
1384744Sgs150176 	 * is put into the ERROR state.  The factotum will then reset
1385744Sgs150176 	 * it on the next pass.
1386744Sgs150176 	 *
1387744Sgs150176 	 * All of which should ensure that we don't get into a state
1388744Sgs150176 	 * where packets are left pending indefinitely!
1389744Sgs150176 	 */
1390744Sgs150176 	dogval = rge_atomic_shl32(&rgep->watchdog, 1);
1391744Sgs150176 	if (dogval < rge_watchdog_count)
1392744Sgs150176 		return (B_FALSE);
1393744Sgs150176 
1394744Sgs150176 	RGE_REPORT((rgep, "Tx stall detected, watchdog code 0x%x", dogval));
1395744Sgs150176 	return (B_TRUE);
1396744Sgs150176 
1397744Sgs150176 }
1398744Sgs150176 
1399744Sgs150176 /*
1400744Sgs150176  * The factotum is woken up when there's something to do that we'd rather
1401744Sgs150176  * not do from inside a hardware interrupt handler or high-level cyclic.
1402744Sgs150176  * Its two main tasks are:
1403744Sgs150176  *	reset & restart the chip after an error
1404744Sgs150176  *	check the link status whenever necessary
1405744Sgs150176  */
1406744Sgs150176 uint_t rge_chip_factotum(caddr_t arg);
1407744Sgs150176 #pragma	no_inline(rge_chip_factotum)
1408744Sgs150176 
1409744Sgs150176 uint_t
1410744Sgs150176 rge_chip_factotum(caddr_t arg)
1411744Sgs150176 {
1412744Sgs150176 	rge_t *rgep;
1413744Sgs150176 	uint_t result;
1414744Sgs150176 	boolean_t error;
1415744Sgs150176 	boolean_t linkchg;
1416744Sgs150176 
1417744Sgs150176 	rgep = (rge_t *)arg;
1418744Sgs150176 
1419744Sgs150176 	if (rgep->factotum_flag == 0)
1420744Sgs150176 		return (DDI_INTR_UNCLAIMED);
1421744Sgs150176 
1422744Sgs150176 	rgep->factotum_flag = 0;
1423744Sgs150176 	result = DDI_INTR_CLAIMED;
1424744Sgs150176 	error = B_FALSE;
1425744Sgs150176 	linkchg = B_FALSE;
1426744Sgs150176 
1427744Sgs150176 	mutex_enter(rgep->genlock);
1428744Sgs150176 	switch (rgep->rge_chip_state) {
1429744Sgs150176 	default:
1430744Sgs150176 		break;
1431744Sgs150176 
1432744Sgs150176 	case RGE_CHIP_RUNNING:
1433744Sgs150176 		linkchg = rge_factotum_link_check(rgep);
1434744Sgs150176 		error = rge_factotum_stall_check(rgep);
1435744Sgs150176 		break;
1436744Sgs150176 
1437744Sgs150176 	case RGE_CHIP_ERROR:
1438744Sgs150176 		error = B_TRUE;
1439744Sgs150176 		break;
1440744Sgs150176 
1441744Sgs150176 	case RGE_CHIP_FAULT:
1442744Sgs150176 		/*
1443744Sgs150176 		 * Fault detected, time to reset ...
1444744Sgs150176 		 */
1445744Sgs150176 		if (rge_autorecover) {
1446744Sgs150176 			RGE_REPORT((rgep, "automatic recovery activated"));
1447744Sgs150176 			rge_restart(rgep);
1448744Sgs150176 		}
1449744Sgs150176 		break;
1450744Sgs150176 	}
1451744Sgs150176 
1452744Sgs150176 	/*
1453744Sgs150176 	 * If an error is detected, stop the chip now, marking it as
1454744Sgs150176 	 * faulty, so that it will be reset next time through ...
1455744Sgs150176 	 */
1456744Sgs150176 	if (error)
1457744Sgs150176 		rge_chip_stop(rgep, B_TRUE);
1458744Sgs150176 	mutex_exit(rgep->genlock);
1459744Sgs150176 
1460744Sgs150176 	/*
1461744Sgs150176 	 * If the link state changed, tell the world about it.
1462744Sgs150176 	 * Note: can't do this while still holding the mutex.
1463744Sgs150176 	 */
1464744Sgs150176 	if (linkchg)
1465*2311Sseb 		mac_link_update(rgep->mh, rgep->param_link_up);
1466744Sgs150176 
1467744Sgs150176 	return (result);
1468744Sgs150176 }
1469744Sgs150176 
1470744Sgs150176 /*
1471744Sgs150176  * High-level cyclic handler
1472744Sgs150176  *
1473744Sgs150176  * This routine schedules a (low-level) softint callback to the
1474744Sgs150176  * factotum, and prods the chip to update the status block (which
1475744Sgs150176  * will cause a hardware interrupt when complete).
1476744Sgs150176  */
1477744Sgs150176 void rge_chip_cyclic(void *arg);
1478744Sgs150176 #pragma	no_inline(rge_chip_cyclic)
1479744Sgs150176 
1480744Sgs150176 void
1481744Sgs150176 rge_chip_cyclic(void *arg)
1482744Sgs150176 {
1483744Sgs150176 	rge_t *rgep;
1484744Sgs150176 
1485744Sgs150176 	rgep = arg;
1486744Sgs150176 
1487744Sgs150176 	switch (rgep->rge_chip_state) {
1488744Sgs150176 	default:
1489744Sgs150176 		return;
1490744Sgs150176 
1491744Sgs150176 	case RGE_CHIP_RUNNING:
1492744Sgs150176 		rge_phy_check(rgep);
1493744Sgs150176 		break;
1494744Sgs150176 
1495744Sgs150176 	case RGE_CHIP_FAULT:
1496744Sgs150176 	case RGE_CHIP_ERROR:
1497744Sgs150176 		break;
1498744Sgs150176 	}
1499744Sgs150176 
1500744Sgs150176 	rge_wake_factotum(rgep);
1501744Sgs150176 }
1502744Sgs150176 
1503744Sgs150176 
1504744Sgs150176 /*
1505744Sgs150176  * ========== Ioctl subfunctions ==========
1506744Sgs150176  */
1507744Sgs150176 
1508744Sgs150176 #undef	RGE_DBG
1509744Sgs150176 #define	RGE_DBG		RGE_DBG_PPIO	/* debug flag for this code	*/
1510744Sgs150176 
1511744Sgs150176 #if	RGE_DEBUGGING || RGE_DO_PPIO
1512744Sgs150176 
1513744Sgs150176 static void rge_chip_peek_cfg(rge_t *rgep, rge_peekpoke_t *ppd);
1514744Sgs150176 #pragma	no_inline(rge_chip_peek_cfg)
1515744Sgs150176 
1516744Sgs150176 static void
1517744Sgs150176 rge_chip_peek_cfg(rge_t *rgep, rge_peekpoke_t *ppd)
1518744Sgs150176 {
1519744Sgs150176 	uint64_t regval;
1520744Sgs150176 	uint64_t regno;
1521744Sgs150176 
1522744Sgs150176 	RGE_TRACE(("rge_chip_peek_cfg($%p, $%p)",
1523744Sgs150176 		(void *)rgep, (void *)ppd));
1524744Sgs150176 
1525744Sgs150176 	regno = ppd->pp_acc_offset;
1526744Sgs150176 
1527744Sgs150176 	switch (ppd->pp_acc_size) {
1528744Sgs150176 	case 1:
1529744Sgs150176 		regval = pci_config_get8(rgep->cfg_handle, regno);
1530744Sgs150176 		break;
1531744Sgs150176 
1532744Sgs150176 	case 2:
1533744Sgs150176 		regval = pci_config_get16(rgep->cfg_handle, regno);
1534744Sgs150176 		break;
1535744Sgs150176 
1536744Sgs150176 	case 4:
1537744Sgs150176 		regval = pci_config_get32(rgep->cfg_handle, regno);
1538744Sgs150176 		break;
1539744Sgs150176 
1540744Sgs150176 	case 8:
1541744Sgs150176 		regval = pci_config_get64(rgep->cfg_handle, regno);
1542744Sgs150176 		break;
1543744Sgs150176 	}
1544744Sgs150176 
1545744Sgs150176 	ppd->pp_acc_data = regval;
1546744Sgs150176 }
1547744Sgs150176 
1548744Sgs150176 static void rge_chip_poke_cfg(rge_t *rgep, rge_peekpoke_t *ppd);
1549744Sgs150176 #pragma	no_inline(rge_chip_poke_cfg)
1550744Sgs150176 
1551744Sgs150176 static void
1552744Sgs150176 rge_chip_poke_cfg(rge_t *rgep, rge_peekpoke_t *ppd)
1553744Sgs150176 {
1554744Sgs150176 	uint64_t regval;
1555744Sgs150176 	uint64_t regno;
1556744Sgs150176 
1557744Sgs150176 	RGE_TRACE(("rge_chip_poke_cfg($%p, $%p)",
1558744Sgs150176 		(void *)rgep, (void *)ppd));
1559744Sgs150176 
1560744Sgs150176 	regno = ppd->pp_acc_offset;
1561744Sgs150176 	regval = ppd->pp_acc_data;
1562744Sgs150176 
1563744Sgs150176 	switch (ppd->pp_acc_size) {
1564744Sgs150176 	case 1:
1565744Sgs150176 		pci_config_put8(rgep->cfg_handle, regno, regval);
1566744Sgs150176 		break;
1567744Sgs150176 
1568744Sgs150176 	case 2:
1569744Sgs150176 		pci_config_put16(rgep->cfg_handle, regno, regval);
1570744Sgs150176 		break;
1571744Sgs150176 
1572744Sgs150176 	case 4:
1573744Sgs150176 		pci_config_put32(rgep->cfg_handle, regno, regval);
1574744Sgs150176 		break;
1575744Sgs150176 
1576744Sgs150176 	case 8:
1577744Sgs150176 		pci_config_put64(rgep->cfg_handle, regno, regval);
1578744Sgs150176 		break;
1579744Sgs150176 	}
1580744Sgs150176 }
1581744Sgs150176 
1582744Sgs150176 static void rge_chip_peek_reg(rge_t *rgep, rge_peekpoke_t *ppd);
1583744Sgs150176 #pragma	no_inline(rge_chip_peek_reg)
1584744Sgs150176 
1585744Sgs150176 static void
1586744Sgs150176 rge_chip_peek_reg(rge_t *rgep, rge_peekpoke_t *ppd)
1587744Sgs150176 {
1588744Sgs150176 	uint64_t regval;
1589744Sgs150176 	void *regaddr;
1590744Sgs150176 
1591744Sgs150176 	RGE_TRACE(("rge_chip_peek_reg($%p, $%p)",
1592744Sgs150176 		(void *)rgep, (void *)ppd));
1593744Sgs150176 
1594744Sgs150176 	regaddr = PIO_ADDR(rgep, ppd->pp_acc_offset);
1595744Sgs150176 
1596744Sgs150176 	switch (ppd->pp_acc_size) {
1597744Sgs150176 	case 1:
1598744Sgs150176 		regval = ddi_get8(rgep->io_handle, regaddr);
1599744Sgs150176 		break;
1600744Sgs150176 
1601744Sgs150176 	case 2:
1602744Sgs150176 		regval = ddi_get16(rgep->io_handle, regaddr);
1603744Sgs150176 		break;
1604744Sgs150176 
1605744Sgs150176 	case 4:
1606744Sgs150176 		regval = ddi_get32(rgep->io_handle, regaddr);
1607744Sgs150176 		break;
1608744Sgs150176 
1609744Sgs150176 	case 8:
1610744Sgs150176 		regval = ddi_get64(rgep->io_handle, regaddr);
1611744Sgs150176 		break;
1612744Sgs150176 	}
1613744Sgs150176 
1614744Sgs150176 	ppd->pp_acc_data = regval;
1615744Sgs150176 }
1616744Sgs150176 
1617744Sgs150176 static void rge_chip_poke_reg(rge_t *rgep, rge_peekpoke_t *ppd);
1618744Sgs150176 #pragma	no_inline(rge_chip_peek_reg)
1619744Sgs150176 
1620744Sgs150176 static void
1621744Sgs150176 rge_chip_poke_reg(rge_t *rgep, rge_peekpoke_t *ppd)
1622744Sgs150176 {
1623744Sgs150176 	uint64_t regval;
1624744Sgs150176 	void *regaddr;
1625744Sgs150176 
1626744Sgs150176 	RGE_TRACE(("rge_chip_poke_reg($%p, $%p)",
1627744Sgs150176 		(void *)rgep, (void *)ppd));
1628744Sgs150176 
1629744Sgs150176 	regaddr = PIO_ADDR(rgep, ppd->pp_acc_offset);
1630744Sgs150176 	regval = ppd->pp_acc_data;
1631744Sgs150176 
1632744Sgs150176 	switch (ppd->pp_acc_size) {
1633744Sgs150176 	case 1:
1634744Sgs150176 		ddi_put8(rgep->io_handle, regaddr, regval);
1635744Sgs150176 		break;
1636744Sgs150176 
1637744Sgs150176 	case 2:
1638744Sgs150176 		ddi_put16(rgep->io_handle, regaddr, regval);
1639744Sgs150176 		break;
1640744Sgs150176 
1641744Sgs150176 	case 4:
1642744Sgs150176 		ddi_put32(rgep->io_handle, regaddr, regval);
1643744Sgs150176 		break;
1644744Sgs150176 
1645744Sgs150176 	case 8:
1646744Sgs150176 		ddi_put64(rgep->io_handle, regaddr, regval);
1647744Sgs150176 		break;
1648744Sgs150176 	}
1649744Sgs150176 	RGE_PCICHK(rgep);
1650744Sgs150176 }
1651744Sgs150176 
1652744Sgs150176 static void rge_chip_peek_mii(rge_t *rgep, rge_peekpoke_t *ppd);
1653744Sgs150176 #pragma	no_inline(rge_chip_peek_mii)
1654744Sgs150176 
1655744Sgs150176 static void
1656744Sgs150176 rge_chip_peek_mii(rge_t *rgep, rge_peekpoke_t *ppd)
1657744Sgs150176 {
1658744Sgs150176 	RGE_TRACE(("rge_chip_peek_mii($%p, $%p)",
1659744Sgs150176 		(void *)rgep, (void *)ppd));
1660744Sgs150176 
1661744Sgs150176 	ppd->pp_acc_data = rge_mii_get16(rgep, ppd->pp_acc_offset/2);
1662744Sgs150176 }
1663744Sgs150176 
1664744Sgs150176 static void rge_chip_poke_mii(rge_t *rgep, rge_peekpoke_t *ppd);
1665744Sgs150176 #pragma	no_inline(rge_chip_poke_mii)
1666744Sgs150176 
1667744Sgs150176 static void
1668744Sgs150176 rge_chip_poke_mii(rge_t *rgep, rge_peekpoke_t *ppd)
1669744Sgs150176 {
1670744Sgs150176 	RGE_TRACE(("rge_chip_poke_mii($%p, $%p)",
1671744Sgs150176 		(void *)rgep, (void *)ppd));
1672744Sgs150176 
1673744Sgs150176 	rge_mii_put16(rgep, ppd->pp_acc_offset/2, ppd->pp_acc_data);
1674744Sgs150176 }
1675744Sgs150176 
1676744Sgs150176 static void rge_chip_peek_mem(rge_t *rgep, rge_peekpoke_t *ppd);
1677744Sgs150176 #pragma	no_inline(rge_chip_peek_mem)
1678744Sgs150176 
1679744Sgs150176 static void
1680744Sgs150176 rge_chip_peek_mem(rge_t *rgep, rge_peekpoke_t *ppd)
1681744Sgs150176 {
1682744Sgs150176 	uint64_t regval;
1683744Sgs150176 	void *vaddr;
1684744Sgs150176 
1685744Sgs150176 	RGE_TRACE(("rge_chip_peek_rge($%p, $%p)",
1686744Sgs150176 		(void *)rgep, (void *)ppd));
1687744Sgs150176 
1688744Sgs150176 	vaddr = (void *)(uintptr_t)ppd->pp_acc_offset;
1689744Sgs150176 
1690744Sgs150176 	switch (ppd->pp_acc_size) {
1691744Sgs150176 	case 1:
1692744Sgs150176 		regval = *(uint8_t *)vaddr;
1693744Sgs150176 		break;
1694744Sgs150176 
1695744Sgs150176 	case 2:
1696744Sgs150176 		regval = *(uint16_t *)vaddr;
1697744Sgs150176 		break;
1698744Sgs150176 
1699744Sgs150176 	case 4:
1700744Sgs150176 		regval = *(uint32_t *)vaddr;
1701744Sgs150176 		break;
1702744Sgs150176 
1703744Sgs150176 	case 8:
1704744Sgs150176 		regval = *(uint64_t *)vaddr;
1705744Sgs150176 		break;
1706744Sgs150176 	}
1707744Sgs150176 
1708744Sgs150176 	RGE_DEBUG(("rge_chip_peek_mem($%p, $%p) peeked 0x%llx from $%p",
1709744Sgs150176 		(void *)rgep, (void *)ppd, regval, vaddr));
1710744Sgs150176 
1711744Sgs150176 	ppd->pp_acc_data = regval;
1712744Sgs150176 }
1713744Sgs150176 
1714744Sgs150176 static void rge_chip_poke_mem(rge_t *rgep, rge_peekpoke_t *ppd);
1715744Sgs150176 #pragma	no_inline(rge_chip_poke_mem)
1716744Sgs150176 
1717744Sgs150176 static void
1718744Sgs150176 rge_chip_poke_mem(rge_t *rgep, rge_peekpoke_t *ppd)
1719744Sgs150176 {
1720744Sgs150176 	uint64_t regval;
1721744Sgs150176 	void *vaddr;
1722744Sgs150176 
1723744Sgs150176 	RGE_TRACE(("rge_chip_poke_mem($%p, $%p)",
1724744Sgs150176 		(void *)rgep, (void *)ppd));
1725744Sgs150176 
1726744Sgs150176 	vaddr = (void *)(uintptr_t)ppd->pp_acc_offset;
1727744Sgs150176 	regval = ppd->pp_acc_data;
1728744Sgs150176 
1729744Sgs150176 	RGE_DEBUG(("rge_chip_poke_mem($%p, $%p) poking 0x%llx at $%p",
1730744Sgs150176 		(void *)rgep, (void *)ppd, regval, vaddr));
1731744Sgs150176 
1732744Sgs150176 	switch (ppd->pp_acc_size) {
1733744Sgs150176 	case 1:
1734744Sgs150176 		*(uint8_t *)vaddr = (uint8_t)regval;
1735744Sgs150176 		break;
1736744Sgs150176 
1737744Sgs150176 	case 2:
1738744Sgs150176 		*(uint16_t *)vaddr = (uint16_t)regval;
1739744Sgs150176 		break;
1740744Sgs150176 
1741744Sgs150176 	case 4:
1742744Sgs150176 		*(uint32_t *)vaddr = (uint32_t)regval;
1743744Sgs150176 		break;
1744744Sgs150176 
1745744Sgs150176 	case 8:
1746744Sgs150176 		*(uint64_t *)vaddr = (uint64_t)regval;
1747744Sgs150176 		break;
1748744Sgs150176 	}
1749744Sgs150176 }
1750744Sgs150176 
1751744Sgs150176 static enum ioc_reply rge_pp_ioctl(rge_t *rgep, int cmd, mblk_t *mp,
1752744Sgs150176 					struct iocblk *iocp);
1753744Sgs150176 #pragma	no_inline(rge_pp_ioctl)
1754744Sgs150176 
1755744Sgs150176 static enum ioc_reply
1756744Sgs150176 rge_pp_ioctl(rge_t *rgep, int cmd, mblk_t *mp, struct iocblk *iocp)
1757744Sgs150176 {
1758744Sgs150176 	void (*ppfn)(rge_t *rgep, rge_peekpoke_t *ppd);
1759744Sgs150176 	rge_peekpoke_t *ppd;
1760744Sgs150176 	dma_area_t *areap;
1761744Sgs150176 	uint64_t sizemask;
1762744Sgs150176 	uint64_t mem_va;
1763744Sgs150176 	uint64_t maxoff;
1764744Sgs150176 	boolean_t peek;
1765744Sgs150176 
1766744Sgs150176 	switch (cmd) {
1767744Sgs150176 	default:
1768744Sgs150176 		/* NOTREACHED */
1769744Sgs150176 		rge_error(rgep, "rge_pp_ioctl: invalid cmd 0x%x", cmd);
1770744Sgs150176 		return (IOC_INVAL);
1771744Sgs150176 
1772744Sgs150176 	case RGE_PEEK:
1773744Sgs150176 		peek = B_TRUE;
1774744Sgs150176 		break;
1775744Sgs150176 
1776744Sgs150176 	case RGE_POKE:
1777744Sgs150176 		peek = B_FALSE;
1778744Sgs150176 		break;
1779744Sgs150176 	}
1780744Sgs150176 
1781744Sgs150176 	/*
1782744Sgs150176 	 * Validate format of ioctl
1783744Sgs150176 	 */
1784744Sgs150176 	if (iocp->ioc_count != sizeof (rge_peekpoke_t))
1785744Sgs150176 		return (IOC_INVAL);
1786744Sgs150176 	if (mp->b_cont == NULL)
1787744Sgs150176 		return (IOC_INVAL);
1788744Sgs150176 	ppd = (rge_peekpoke_t *)mp->b_cont->b_rptr;
1789744Sgs150176 
1790744Sgs150176 	/*
1791744Sgs150176 	 * Validate request parameters
1792744Sgs150176 	 */
1793744Sgs150176 	switch (ppd->pp_acc_space) {
1794744Sgs150176 	default:
1795744Sgs150176 		return (IOC_INVAL);
1796744Sgs150176 
1797744Sgs150176 	case RGE_PP_SPACE_CFG:
1798744Sgs150176 		/*
1799744Sgs150176 		 * Config space
1800744Sgs150176 		 */
1801744Sgs150176 		sizemask = 8|4|2|1;
1802744Sgs150176 		mem_va = 0;
1803744Sgs150176 		maxoff = PCI_CONF_HDR_SIZE;
1804744Sgs150176 		ppfn = peek ? rge_chip_peek_cfg : rge_chip_poke_cfg;
1805744Sgs150176 		break;
1806744Sgs150176 
1807744Sgs150176 	case RGE_PP_SPACE_REG:
1808744Sgs150176 		/*
1809744Sgs150176 		 * Memory-mapped I/O space
1810744Sgs150176 		 */
1811744Sgs150176 		sizemask = 8|4|2|1;
1812744Sgs150176 		mem_va = 0;
1813744Sgs150176 		maxoff = RGE_REGISTER_MAX;
1814744Sgs150176 		ppfn = peek ? rge_chip_peek_reg : rge_chip_poke_reg;
1815744Sgs150176 		break;
1816744Sgs150176 
1817744Sgs150176 	case RGE_PP_SPACE_MII:
1818744Sgs150176 		/*
1819744Sgs150176 		 * PHY's MII registers
1820744Sgs150176 		 * NB: all PHY registers are two bytes, but the
1821744Sgs150176 		 * addresses increment in ones (word addressing).
1822744Sgs150176 		 * So we scale the address here, then undo the
1823744Sgs150176 		 * transformation inside the peek/poke functions.
1824744Sgs150176 		 */
1825744Sgs150176 		ppd->pp_acc_offset *= 2;
1826744Sgs150176 		sizemask = 2;
1827744Sgs150176 		mem_va = 0;
1828744Sgs150176 		maxoff = (MII_MAXREG+1)*2;
1829744Sgs150176 		ppfn = peek ? rge_chip_peek_mii : rge_chip_poke_mii;
1830744Sgs150176 		break;
1831744Sgs150176 
1832744Sgs150176 	case RGE_PP_SPACE_RGE:
1833744Sgs150176 		/*
1834744Sgs150176 		 * RGE data structure!
1835744Sgs150176 		 */
1836744Sgs150176 		sizemask = 8|4|2|1;
1837744Sgs150176 		mem_va = (uintptr_t)rgep;
1838744Sgs150176 		maxoff = sizeof (*rgep);
1839744Sgs150176 		ppfn = peek ? rge_chip_peek_mem : rge_chip_poke_mem;
1840744Sgs150176 		break;
1841744Sgs150176 
1842744Sgs150176 	case RGE_PP_SPACE_STATISTICS:
1843744Sgs150176 	case RGE_PP_SPACE_TXDESC:
1844744Sgs150176 	case RGE_PP_SPACE_TXBUFF:
1845744Sgs150176 	case RGE_PP_SPACE_RXDESC:
1846744Sgs150176 	case RGE_PP_SPACE_RXBUFF:
1847744Sgs150176 		/*
1848744Sgs150176 		 * Various DMA_AREAs
1849744Sgs150176 		 */
1850744Sgs150176 		switch (ppd->pp_acc_space) {
1851744Sgs150176 		case RGE_PP_SPACE_TXDESC:
1852744Sgs150176 			areap = &rgep->dma_area_txdesc;
1853744Sgs150176 			break;
1854744Sgs150176 		case RGE_PP_SPACE_TXBUFF:
1855744Sgs150176 			areap = &rgep->dma_area_txbuf[0];
1856744Sgs150176 			break;
1857744Sgs150176 		case RGE_PP_SPACE_RXDESC:
1858744Sgs150176 			areap = &rgep->dma_area_rxdesc;
1859744Sgs150176 			break;
1860744Sgs150176 		case RGE_PP_SPACE_RXBUFF:
1861744Sgs150176 			areap = &rgep->dma_area_rxbuf[0];
1862744Sgs150176 			break;
1863744Sgs150176 		case RGE_PP_SPACE_STATISTICS:
1864744Sgs150176 			areap = &rgep->dma_area_stats;
1865744Sgs150176 			break;
1866744Sgs150176 		}
1867744Sgs150176 
1868744Sgs150176 		sizemask = 8|4|2|1;
1869744Sgs150176 		mem_va = (uintptr_t)areap->mem_va;
1870744Sgs150176 		maxoff = areap->alength;
1871744Sgs150176 		ppfn = peek ? rge_chip_peek_mem : rge_chip_poke_mem;
1872744Sgs150176 		break;
1873744Sgs150176 	}
1874744Sgs150176 
1875744Sgs150176 	switch (ppd->pp_acc_size) {
1876744Sgs150176 	default:
1877744Sgs150176 		return (IOC_INVAL);
1878744Sgs150176 
1879744Sgs150176 	case 8:
1880744Sgs150176 	case 4:
1881744Sgs150176 	case 2:
1882744Sgs150176 	case 1:
1883744Sgs150176 		if ((ppd->pp_acc_size & sizemask) == 0)
1884744Sgs150176 			return (IOC_INVAL);
1885744Sgs150176 		break;
1886744Sgs150176 	}
1887744Sgs150176 
1888744Sgs150176 	if ((ppd->pp_acc_offset % ppd->pp_acc_size) != 0)
1889744Sgs150176 		return (IOC_INVAL);
1890744Sgs150176 
1891744Sgs150176 	if (ppd->pp_acc_offset >= maxoff)
1892744Sgs150176 		return (IOC_INVAL);
1893744Sgs150176 
1894744Sgs150176 	if (ppd->pp_acc_offset+ppd->pp_acc_size > maxoff)
1895744Sgs150176 		return (IOC_INVAL);
1896744Sgs150176 
1897744Sgs150176 	/*
1898744Sgs150176 	 * All OK - go do it!
1899744Sgs150176 	 */
1900744Sgs150176 	ppd->pp_acc_offset += mem_va;
1901744Sgs150176 	(*ppfn)(rgep, ppd);
1902744Sgs150176 	return (peek ? IOC_REPLY : IOC_ACK);
1903744Sgs150176 }
1904744Sgs150176 
1905744Sgs150176 static enum ioc_reply rge_diag_ioctl(rge_t *rgep, int cmd, mblk_t *mp,
1906744Sgs150176 					struct iocblk *iocp);
1907744Sgs150176 #pragma	no_inline(rge_diag_ioctl)
1908744Sgs150176 
1909744Sgs150176 static enum ioc_reply
1910744Sgs150176 rge_diag_ioctl(rge_t *rgep, int cmd, mblk_t *mp, struct iocblk *iocp)
1911744Sgs150176 {
1912744Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
1913744Sgs150176 
1914744Sgs150176 	switch (cmd) {
1915744Sgs150176 	default:
1916744Sgs150176 		/* NOTREACHED */
1917744Sgs150176 		rge_error(rgep, "rge_diag_ioctl: invalid cmd 0x%x", cmd);
1918744Sgs150176 		return (IOC_INVAL);
1919744Sgs150176 
1920744Sgs150176 	case RGE_DIAG:
1921744Sgs150176 		/*
1922744Sgs150176 		 * Currently a no-op
1923744Sgs150176 		 */
1924744Sgs150176 		return (IOC_ACK);
1925744Sgs150176 
1926744Sgs150176 	case RGE_PEEK:
1927744Sgs150176 	case RGE_POKE:
1928744Sgs150176 		return (rge_pp_ioctl(rgep, cmd, mp, iocp));
1929744Sgs150176 
1930744Sgs150176 	case RGE_PHY_RESET:
1931744Sgs150176 		return (IOC_RESTART_ACK);
1932744Sgs150176 
1933744Sgs150176 	case RGE_SOFT_RESET:
1934744Sgs150176 	case RGE_HARD_RESET:
1935744Sgs150176 		/*
1936744Sgs150176 		 * Reset and reinitialise the 570x hardware
1937744Sgs150176 		 */
1938744Sgs150176 		rge_restart(rgep);
1939744Sgs150176 		return (IOC_ACK);
1940744Sgs150176 	}
1941744Sgs150176 
1942744Sgs150176 	/* NOTREACHED */
1943744Sgs150176 }
1944744Sgs150176 
1945744Sgs150176 #endif	/* RGE_DEBUGGING || RGE_DO_PPIO */
1946744Sgs150176 
1947744Sgs150176 static enum ioc_reply rge_mii_ioctl(rge_t *rgep, int cmd, mblk_t *mp,
1948744Sgs150176 				    struct iocblk *iocp);
1949744Sgs150176 #pragma	no_inline(rge_mii_ioctl)
1950744Sgs150176 
1951744Sgs150176 static enum ioc_reply
1952744Sgs150176 rge_mii_ioctl(rge_t *rgep, int cmd, mblk_t *mp, struct iocblk *iocp)
1953744Sgs150176 {
1954744Sgs150176 	struct rge_mii_rw *miirwp;
1955744Sgs150176 
1956744Sgs150176 	/*
1957744Sgs150176 	 * Validate format of ioctl
1958744Sgs150176 	 */
1959744Sgs150176 	if (iocp->ioc_count != sizeof (struct rge_mii_rw))
1960744Sgs150176 		return (IOC_INVAL);
1961744Sgs150176 	if (mp->b_cont == NULL)
1962744Sgs150176 		return (IOC_INVAL);
1963744Sgs150176 	miirwp = (struct rge_mii_rw *)mp->b_cont->b_rptr;
1964744Sgs150176 
1965744Sgs150176 	/*
1966744Sgs150176 	 * Validate request parameters ...
1967744Sgs150176 	 */
1968744Sgs150176 	if (miirwp->mii_reg > MII_MAXREG)
1969744Sgs150176 		return (IOC_INVAL);
1970744Sgs150176 
1971744Sgs150176 	switch (cmd) {
1972744Sgs150176 	default:
1973744Sgs150176 		/* NOTREACHED */
1974744Sgs150176 		rge_error(rgep, "rge_mii_ioctl: invalid cmd 0x%x", cmd);
1975744Sgs150176 		return (IOC_INVAL);
1976744Sgs150176 
1977744Sgs150176 	case RGE_MII_READ:
1978744Sgs150176 		miirwp->mii_data = rge_mii_get16(rgep, miirwp->mii_reg);
1979744Sgs150176 		return (IOC_REPLY);
1980744Sgs150176 
1981744Sgs150176 	case RGE_MII_WRITE:
1982744Sgs150176 		rge_mii_put16(rgep, miirwp->mii_reg, miirwp->mii_data);
1983744Sgs150176 		return (IOC_ACK);
1984744Sgs150176 	}
1985744Sgs150176 
1986744Sgs150176 	/* NOTREACHED */
1987744Sgs150176 }
1988744Sgs150176 
1989744Sgs150176 enum ioc_reply rge_chip_ioctl(rge_t *rgep, queue_t *wq, mblk_t *mp,
1990744Sgs150176 				struct iocblk *iocp);
1991744Sgs150176 #pragma	no_inline(rge_chip_ioctl)
1992744Sgs150176 
1993744Sgs150176 enum ioc_reply
1994744Sgs150176 rge_chip_ioctl(rge_t *rgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp)
1995744Sgs150176 {
1996744Sgs150176 	int cmd;
1997744Sgs150176 
1998744Sgs150176 	RGE_TRACE(("rge_chip_ioctl($%p, $%p, $%p, $%p)",
1999744Sgs150176 		(void *)rgep, (void *)wq, (void *)mp, (void *)iocp));
2000744Sgs150176 
2001744Sgs150176 	ASSERT(mutex_owned(rgep->genlock));
2002744Sgs150176 
2003744Sgs150176 	cmd = iocp->ioc_cmd;
2004744Sgs150176 	switch (cmd) {
2005744Sgs150176 	default:
2006744Sgs150176 		/* NOTREACHED */
2007744Sgs150176 		rge_error(rgep, "rge_chip_ioctl: invalid cmd 0x%x", cmd);
2008744Sgs150176 		return (IOC_INVAL);
2009744Sgs150176 
2010744Sgs150176 	case RGE_DIAG:
2011744Sgs150176 	case RGE_PEEK:
2012744Sgs150176 	case RGE_POKE:
2013744Sgs150176 	case RGE_PHY_RESET:
2014744Sgs150176 	case RGE_SOFT_RESET:
2015744Sgs150176 	case RGE_HARD_RESET:
2016744Sgs150176 #if	RGE_DEBUGGING || RGE_DO_PPIO
2017744Sgs150176 		return (rge_diag_ioctl(rgep, cmd, mp, iocp));
2018744Sgs150176 #else
2019744Sgs150176 		return (IOC_INVAL);
2020744Sgs150176 #endif	/* RGE_DEBUGGING || RGE_DO_PPIO */
2021744Sgs150176 
2022744Sgs150176 	case RGE_MII_READ:
2023744Sgs150176 	case RGE_MII_WRITE:
2024744Sgs150176 		return (rge_mii_ioctl(rgep, cmd, mp, iocp));
2025744Sgs150176 
2026744Sgs150176 	}
2027744Sgs150176 
2028744Sgs150176 	/* NOTREACHED */
2029744Sgs150176 }
2030