xref: /titanic_50/usr/src/uts/sun/io/eri/eri.c (revision 0dc2366f7b9f9f36e10909b1e95edbf2a261c2ac)
1297a64e7Sgd78059 /*
2297a64e7Sgd78059  * CDDL HEADER START
3297a64e7Sgd78059  *
4297a64e7Sgd78059  * The contents of this file are subject to the terms of the
5297a64e7Sgd78059  * Common Development and Distribution License (the "License").
6297a64e7Sgd78059  * You may not use this file except in compliance with the License.
7297a64e7Sgd78059  *
8297a64e7Sgd78059  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9297a64e7Sgd78059  * or http://www.opensolaris.org/os/licensing.
10297a64e7Sgd78059  * See the License for the specific language governing permissions
11297a64e7Sgd78059  * and limitations under the License.
12297a64e7Sgd78059  *
13297a64e7Sgd78059  * When distributing Covered Code, include this CDDL HEADER in each
14297a64e7Sgd78059  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15297a64e7Sgd78059  * If applicable, add the following below this CDDL HEADER, with the
16297a64e7Sgd78059  * fields enclosed by brackets "[]" replaced with your own identifying
17297a64e7Sgd78059  * information: Portions Copyright [yyyy] [name of copyright owner]
18297a64e7Sgd78059  *
19297a64e7Sgd78059  * CDDL HEADER END
20297a64e7Sgd78059  */
21297a64e7Sgd78059 /*
22*0dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
23297a64e7Sgd78059  * Use is subject to license terms.
24297a64e7Sgd78059  */
25297a64e7Sgd78059 
26297a64e7Sgd78059 /*
27297a64e7Sgd78059  * SunOS MT STREAMS ERI(PCI) 10/100 Mb Ethernet Device Driver
28297a64e7Sgd78059  */
29297a64e7Sgd78059 
30297a64e7Sgd78059 #include	<sys/types.h>
31297a64e7Sgd78059 #include	<sys/debug.h>
32297a64e7Sgd78059 #include	<sys/stropts.h>
33297a64e7Sgd78059 #include	<sys/stream.h>
34297a64e7Sgd78059 #include	<sys/strsubr.h>
35297a64e7Sgd78059 #include	<sys/kmem.h>
36297a64e7Sgd78059 #include	<sys/crc32.h>
37297a64e7Sgd78059 #include	<sys/ddi.h>
38297a64e7Sgd78059 #include	<sys/sunddi.h>
39297a64e7Sgd78059 #include	<sys/strsun.h>
40297a64e7Sgd78059 #include	<sys/stat.h>
41297a64e7Sgd78059 #include	<sys/cpu.h>
42297a64e7Sgd78059 #include	<sys/kstat.h>
43297a64e7Sgd78059 #include	<inet/common.h>
44297a64e7Sgd78059 #include	<sys/pattr.h>
45297a64e7Sgd78059 #include	<inet/mi.h>
46297a64e7Sgd78059 #include	<inet/nd.h>
47297a64e7Sgd78059 #include	<sys/ethernet.h>
48297a64e7Sgd78059 #include	<sys/vlan.h>
49297a64e7Sgd78059 #include	<sys/policy.h>
50da14cebeSEric Cheng #include	<sys/mac_provider.h>
51297a64e7Sgd78059 #include	<sys/mac_ether.h>
52297a64e7Sgd78059 #include	<sys/dlpi.h>
53297a64e7Sgd78059 
54297a64e7Sgd78059 #include	<sys/pci.h>
55297a64e7Sgd78059 
56297a64e7Sgd78059 #include	"eri_phy.h"
57297a64e7Sgd78059 #include	"eri_mac.h"
58297a64e7Sgd78059 #include	"eri.h"
59297a64e7Sgd78059 #include	"eri_common.h"
60297a64e7Sgd78059 
61297a64e7Sgd78059 #include	"eri_msg.h"
62297a64e7Sgd78059 
63297a64e7Sgd78059 /*
64297a64e7Sgd78059  *  **** Function Prototypes *****
65297a64e7Sgd78059  */
66297a64e7Sgd78059 /*
67297a64e7Sgd78059  * Entry points (man9e)
68297a64e7Sgd78059  */
69297a64e7Sgd78059 static	int	eri_attach(dev_info_t *, ddi_attach_cmd_t);
70297a64e7Sgd78059 static	int	eri_detach(dev_info_t *, ddi_detach_cmd_t);
71297a64e7Sgd78059 static	uint_t	eri_intr(caddr_t);
72297a64e7Sgd78059 
73297a64e7Sgd78059 /*
74297a64e7Sgd78059  * I/O (Input/Output) Functions
75297a64e7Sgd78059  */
76297a64e7Sgd78059 static	boolean_t	eri_send_msg(struct eri *, mblk_t *);
77297a64e7Sgd78059 static  mblk_t		*eri_read_dma(struct eri *, volatile struct rmd *,
78297a64e7Sgd78059 			    volatile int, uint64_t flags);
79297a64e7Sgd78059 
80297a64e7Sgd78059 /*
81297a64e7Sgd78059  * Initialization Functions
82297a64e7Sgd78059  */
83297a64e7Sgd78059 static  boolean_t	eri_init(struct eri *);
84297a64e7Sgd78059 static	int	eri_allocthings(struct eri *);
85297a64e7Sgd78059 static  int	eri_init_xfer_params(struct eri *);
86297a64e7Sgd78059 static  void	eri_statinit(struct eri *);
87297a64e7Sgd78059 static	int	eri_burstsize(struct eri *);
88297a64e7Sgd78059 
89297a64e7Sgd78059 static	void	eri_setup_mac_address(struct eri *, dev_info_t *);
90297a64e7Sgd78059 
91297a64e7Sgd78059 static	uint32_t eri_init_rx_channel(struct eri *);
92297a64e7Sgd78059 static	void	eri_init_rx(struct eri *);
93297a64e7Sgd78059 static	void	eri_init_txmac(struct eri *);
94297a64e7Sgd78059 
95297a64e7Sgd78059 /*
96297a64e7Sgd78059  * Un-init Functions
97297a64e7Sgd78059  */
98297a64e7Sgd78059 static	uint32_t eri_txmac_disable(struct eri *);
99297a64e7Sgd78059 static	uint32_t eri_rxmac_disable(struct eri *);
100297a64e7Sgd78059 static	int	eri_stop(struct eri *);
101297a64e7Sgd78059 static	void	eri_uninit(struct eri *erip);
102297a64e7Sgd78059 static	int	eri_freebufs(struct eri *);
103297a64e7Sgd78059 static	boolean_t	eri_reclaim(struct eri *, uint32_t);
104297a64e7Sgd78059 
105297a64e7Sgd78059 /*
106297a64e7Sgd78059  * Transceiver (xcvr) Functions
107297a64e7Sgd78059  */
108297a64e7Sgd78059 static	int	eri_new_xcvr(struct eri *); /* Initializes & detects xcvrs */
109297a64e7Sgd78059 static	int	eri_reset_xcvr(struct eri *);
110297a64e7Sgd78059 
111297a64e7Sgd78059 #ifdef	ERI_10_10_FORCE_SPEED_WORKAROUND
112297a64e7Sgd78059 static	void	eri_xcvr_force_mode(struct eri *, uint32_t *);
113297a64e7Sgd78059 #endif
114297a64e7Sgd78059 
115297a64e7Sgd78059 static	void	eri_mif_poll(struct eri *, soft_mif_enable_t);
116297a64e7Sgd78059 static	void	eri_check_link(struct eri *);
117297a64e7Sgd78059 static	uint32_t eri_check_link_noind(struct eri *);
118297a64e7Sgd78059 static	link_state_t eri_mif_check(struct eri *, uint16_t, uint16_t);
119297a64e7Sgd78059 static	void    eri_mii_write(struct eri *, uint8_t, uint16_t);
120297a64e7Sgd78059 static	uint32_t eri_mii_read(struct eri *, uint8_t, uint16_t *);
121297a64e7Sgd78059 
122297a64e7Sgd78059 /*
123297a64e7Sgd78059  * Reset Functions
124297a64e7Sgd78059  */
125297a64e7Sgd78059 static	uint32_t eri_etx_reset(struct eri *);
126297a64e7Sgd78059 static	uint32_t eri_erx_reset(struct eri *);
127297a64e7Sgd78059 
128297a64e7Sgd78059 /*
129297a64e7Sgd78059  * Error Functions
130297a64e7Sgd78059  */
131297a64e7Sgd78059 static	void eri_fatal_err(struct eri *, uint32_t);
132297a64e7Sgd78059 static	void eri_nonfatal_err(struct eri *, uint32_t);
133297a64e7Sgd78059 
134297a64e7Sgd78059 #ifdef	ERI_TX_HUNG
135297a64e7Sgd78059 static	int eri_check_txhung(struct eri *);
136297a64e7Sgd78059 #endif
137297a64e7Sgd78059 
138297a64e7Sgd78059 /*
139297a64e7Sgd78059  * Hardening Functions
140297a64e7Sgd78059  */
141297a64e7Sgd78059 static void eri_fault_msg(struct eri *, uint_t, msg_t, const char *, ...);
142297a64e7Sgd78059 
143297a64e7Sgd78059 /*
144297a64e7Sgd78059  * Misc Functions
145297a64e7Sgd78059  */
146297a64e7Sgd78059 static void	eri_savecntrs(struct eri *);
147297a64e7Sgd78059 
148297a64e7Sgd78059 static	void	eri_stop_timer(struct eri *erip);
149297a64e7Sgd78059 static	void	eri_start_timer(struct eri *erip, fptrv_t func, clock_t msec);
150297a64e7Sgd78059 
151297a64e7Sgd78059 static	void eri_bb_force_idle(struct eri *);
152297a64e7Sgd78059 
153297a64e7Sgd78059 /*
154297a64e7Sgd78059  * Utility Functions
155297a64e7Sgd78059  */
156297a64e7Sgd78059 static	mblk_t *eri_allocb(size_t size);
157297a64e7Sgd78059 static	mblk_t *eri_allocb_sp(size_t size);
158297a64e7Sgd78059 static	int	eri_param_get(queue_t *q, mblk_t *mp, caddr_t cp);
159297a64e7Sgd78059 static	int	eri_param_set(queue_t *, mblk_t *, char *, caddr_t);
160297a64e7Sgd78059 
161297a64e7Sgd78059 /*
162297a64e7Sgd78059  * Functions to support ndd
163297a64e7Sgd78059  */
164297a64e7Sgd78059 static	void	eri_nd_free(caddr_t *nd_pparam);
165297a64e7Sgd78059 
166297a64e7Sgd78059 static	boolean_t	eri_nd_load(caddr_t *nd_pparam, char *name,
167297a64e7Sgd78059 				pfi_t get_pfi, pfi_t set_pfi, caddr_t data);
168297a64e7Sgd78059 
169297a64e7Sgd78059 static	int	eri_nd_getset(queue_t *q, caddr_t nd_param, MBLKP mp);
170297a64e7Sgd78059 static	void	eri_param_cleanup(struct eri *);
171297a64e7Sgd78059 static	int	eri_param_register(struct eri *, param_t *, int);
172297a64e7Sgd78059 static	void	eri_process_ndd_ioctl(struct eri *, queue_t *, mblk_t *, int);
173297a64e7Sgd78059 static	int	eri_mk_mblk_tail_space(mblk_t *, mblk_t **, size_t);
174297a64e7Sgd78059 
175297a64e7Sgd78059 
176297a64e7Sgd78059 static	void eri_loopback(struct eri *, queue_t *, mblk_t *);
177297a64e7Sgd78059 
178297a64e7Sgd78059 static uint32_t	eri_ladrf_bit(const uint8_t *);
179297a64e7Sgd78059 
180297a64e7Sgd78059 
181297a64e7Sgd78059 /*
182297a64e7Sgd78059  * Nemo (GLDv3) Functions.
183297a64e7Sgd78059  */
184297a64e7Sgd78059 static	int		eri_m_stat(void *, uint_t, uint64_t *);
185297a64e7Sgd78059 static	int		eri_m_start(void *);
186297a64e7Sgd78059 static	void		eri_m_stop(void *);
187297a64e7Sgd78059 static	int		eri_m_promisc(void *, boolean_t);
188297a64e7Sgd78059 static	int		eri_m_multicst(void *, boolean_t, const uint8_t *);
189297a64e7Sgd78059 static	int		eri_m_unicst(void *, const uint8_t *);
190297a64e7Sgd78059 static	void		eri_m_ioctl(void *, queue_t *, mblk_t *);
191297a64e7Sgd78059 static	boolean_t	eri_m_getcapab(void *, mac_capab_t, void *);
192297a64e7Sgd78059 static	mblk_t		*eri_m_tx(void *, mblk_t *);
193297a64e7Sgd78059 
194297a64e7Sgd78059 static mac_callbacks_t eri_m_callbacks = {
195297a64e7Sgd78059 	MC_IOCTL | MC_GETCAPAB,
196297a64e7Sgd78059 	eri_m_stat,
197297a64e7Sgd78059 	eri_m_start,
198297a64e7Sgd78059 	eri_m_stop,
199297a64e7Sgd78059 	eri_m_promisc,
200297a64e7Sgd78059 	eri_m_multicst,
201297a64e7Sgd78059 	eri_m_unicst,
202297a64e7Sgd78059 	eri_m_tx,
203*0dc2366fSVenugopal Iyer 	NULL,
204297a64e7Sgd78059 	eri_m_ioctl,
205297a64e7Sgd78059 	eri_m_getcapab
206297a64e7Sgd78059 };
207297a64e7Sgd78059 
208297a64e7Sgd78059 /*
209297a64e7Sgd78059  * Define PHY Vendors: Matches to IEEE
210297a64e7Sgd78059  * Organizationally Unique Identifier (OUI)
211297a64e7Sgd78059  */
212297a64e7Sgd78059 /*
213297a64e7Sgd78059  * The first two are supported as Internal XCVRs
214297a64e7Sgd78059  */
215297a64e7Sgd78059 #define	PHY_VENDOR_LUCENT	0x601d
216297a64e7Sgd78059 
217297a64e7Sgd78059 #define	PHY_LINK_NONE		0	/* Not attempted yet or retry */
218297a64e7Sgd78059 #define	PHY_LINK_DOWN		1	/* Not being used	*/
219297a64e7Sgd78059 #define	PHY_LINK_UP		2	/* Not being used	*/
220297a64e7Sgd78059 
221297a64e7Sgd78059 #define	AUTO_SPEED		0
222297a64e7Sgd78059 #define	FORCE_SPEED		1
223297a64e7Sgd78059 
224297a64e7Sgd78059 /*
225297a64e7Sgd78059  * MIB II broadcast/multicast packets
226297a64e7Sgd78059  */
227297a64e7Sgd78059 
228297a64e7Sgd78059 #define	IS_BROADCAST(pkt) (bcmp(pkt, &etherbroadcastaddr, ETHERADDRL) == 0)
229297a64e7Sgd78059 #define	IS_MULTICAST(pkt) ((pkt[0] & 01) == 1)
230297a64e7Sgd78059 
231297a64e7Sgd78059 #define	BUMP_InNUcast(erip, pkt) \
232297a64e7Sgd78059 		if (IS_BROADCAST(pkt)) { \
233297a64e7Sgd78059 			HSTAT(erip, brdcstrcv); \
234297a64e7Sgd78059 		} else if (IS_MULTICAST(pkt)) { \
235297a64e7Sgd78059 			HSTAT(erip, multircv); \
236297a64e7Sgd78059 		}
237297a64e7Sgd78059 
238297a64e7Sgd78059 #define	BUMP_OutNUcast(erip, pkt) \
239297a64e7Sgd78059 		if (IS_BROADCAST(pkt)) { \
240297a64e7Sgd78059 			HSTAT(erip, brdcstxmt); \
241297a64e7Sgd78059 		} else if (IS_MULTICAST(pkt)) { \
242297a64e7Sgd78059 			HSTAT(erip, multixmt); \
243297a64e7Sgd78059 		}
244297a64e7Sgd78059 
245297a64e7Sgd78059 #define	NEXTTMDP(tbasep, tmdlimp, tmdp)	(((tmdp) + 1) == tmdlimp	\
246297a64e7Sgd78059 	? tbasep : ((tmdp) + 1))
247297a64e7Sgd78059 
248297a64e7Sgd78059 #define	ETHERHEADER_SIZE (sizeof (struct ether_header))
249297a64e7Sgd78059 
250297a64e7Sgd78059 #ifdef	ERI_RCV_CKSUM
251297a64e7Sgd78059 #define	ERI_PROCESS_READ(erip, bp, sum)				\
252297a64e7Sgd78059 {								\
253297a64e7Sgd78059 	t_uscalar_t	type;					\
254297a64e7Sgd78059 	uint_t	start_offset, end_offset;			\
255297a64e7Sgd78059 								\
256297a64e7Sgd78059 	*(bp->b_wptr) = 0;	/* pad byte */			\
257297a64e7Sgd78059 								\
258297a64e7Sgd78059 	/*							\
259297a64e7Sgd78059 	 * update MIB II statistics				\
260297a64e7Sgd78059 	 */							\
261297a64e7Sgd78059 	HSTAT(erip, ipackets64);				\
262297a64e7Sgd78059 	HSTATN(erip, rbytes64, len);				\
263297a64e7Sgd78059 	BUMP_InNUcast(erip, bp->b_rptr);			\
264297a64e7Sgd78059 	type = get_ether_type(bp->b_rptr);			\
265297a64e7Sgd78059 	if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6) {	\
266297a64e7Sgd78059 		start_offset = 0;				\
26722eb7cb5Sgd78059 		end_offset = MBLKL(bp) - ETHERHEADER_SIZE;	\
268*0dc2366fSVenugopal Iyer 		mac_hcksum_set(bp,				\
269297a64e7Sgd78059 			start_offset, 0, end_offset, sum, 	\
270*0dc2366fSVenugopal Iyer 			HCK_PARTIALCKSUM);			\
271297a64e7Sgd78059 	} else {						\
272297a64e7Sgd78059 		/*						\
273297a64e7Sgd78059 		 * Strip the PADS for 802.3			\
274297a64e7Sgd78059 		 */						\
275297a64e7Sgd78059 		if (type <= ETHERMTU)				\
276297a64e7Sgd78059 			bp->b_wptr = bp->b_rptr +		\
277297a64e7Sgd78059 				ETHERHEADER_SIZE + type;	\
278297a64e7Sgd78059 	}							\
279297a64e7Sgd78059 }
280297a64e7Sgd78059 #else
281297a64e7Sgd78059 
282297a64e7Sgd78059 #define	ERI_PROCESS_READ(erip, bp)				\
283297a64e7Sgd78059 {								\
284297a64e7Sgd78059 	t_uscalar_t	type;					\
285297a64e7Sgd78059 	type = get_ether_type(bp->b_rptr);			\
286297a64e7Sgd78059 								\
287297a64e7Sgd78059 	/*							\
288297a64e7Sgd78059 	 * update MIB II statistics				\
289297a64e7Sgd78059 	 */							\
290297a64e7Sgd78059 	HSTAT(erip, ipackets64);				\
291297a64e7Sgd78059 	HSTATN(erip, rbytes64, len);				\
292297a64e7Sgd78059 	BUMP_InNUcast(erip, bp->b_rptr);			\
293297a64e7Sgd78059 	/*							\
294297a64e7Sgd78059 	 * Strip the PADS for 802.3				\
295297a64e7Sgd78059 	 */							\
296297a64e7Sgd78059 	if (type <= ETHERMTU)					\
297297a64e7Sgd78059 		bp->b_wptr = bp->b_rptr + ETHERHEADER_SIZE + 	\
298297a64e7Sgd78059 			type;					\
299297a64e7Sgd78059 }
300297a64e7Sgd78059 #endif  /* ERI_RCV_CKSUM */
301297a64e7Sgd78059 
302297a64e7Sgd78059 /*
303297a64e7Sgd78059  * TX Interrupt Rate
304297a64e7Sgd78059  */
305297a64e7Sgd78059 static	int	tx_interrupt_rate = 16;
306297a64e7Sgd78059 
307297a64e7Sgd78059 /*
308297a64e7Sgd78059  * Ethernet broadcast address definition.
309297a64e7Sgd78059  */
310297a64e7Sgd78059 static uint8_t	etherbroadcastaddr[] = {
311297a64e7Sgd78059 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
312297a64e7Sgd78059 };
313297a64e7Sgd78059 
314297a64e7Sgd78059 /*
315297a64e7Sgd78059  * The following variables are used for configuring various features
316297a64e7Sgd78059  */
317297a64e7Sgd78059 #define	ERI_DESC_HANDLE_ALLOC	0x0001
318297a64e7Sgd78059 #define	ERI_DESC_MEM_ALLOC	0x0002
319297a64e7Sgd78059 #define	ERI_DESC_MEM_MAP	0x0004
320297a64e7Sgd78059 #define	ERI_RCV_HANDLE_ALLOC	0x0020
321297a64e7Sgd78059 #define	ERI_RCV_HANDLE_BIND	0x0040
322297a64e7Sgd78059 #define	ERI_XMIT_DVMA_ALLOC	0x0100
323297a64e7Sgd78059 #define	ERI_RCV_DVMA_ALLOC	0x0200
324297a64e7Sgd78059 #define	ERI_XBUFS_HANDLE_ALLOC  0x0400
325297a64e7Sgd78059 #define	ERI_XBUFS_KMEM_ALLOC    0x0800
326297a64e7Sgd78059 #define	ERI_XBUFS_KMEM_DMABIND  0x1000
327297a64e7Sgd78059 
328297a64e7Sgd78059 
329297a64e7Sgd78059 #define	ERI_DONT_STRIP_CRC
330297a64e7Sgd78059 /*
331297a64e7Sgd78059  * Translate a kernel virtual address to i/o address.
332297a64e7Sgd78059  */
333297a64e7Sgd78059 #define	ERI_IOPBIOADDR(erip, a) \
334297a64e7Sgd78059 	((erip)->iopbiobase + ((uintptr_t)a - (erip)->iopbkbase))
335297a64e7Sgd78059 
336297a64e7Sgd78059 /*
337297a64e7Sgd78059  * ERI Configuration Register Value
338297a64e7Sgd78059  * Used to configure parameters that define DMA burst
339297a64e7Sgd78059  * and internal arbitration behavior.
340297a64e7Sgd78059  * for equal TX and RX bursts, set the following in global
341297a64e7Sgd78059  * configuration register.
342297a64e7Sgd78059  * static	int	global_config = 0x42;
343297a64e7Sgd78059  */
344297a64e7Sgd78059 
345297a64e7Sgd78059 /*
346297a64e7Sgd78059  * ERI ERX Interrupt Blanking Time
347297a64e7Sgd78059  * Each count is about 16 us (2048 clocks) for 66 MHz PCI.
348297a64e7Sgd78059  */
349297a64e7Sgd78059 static	int	intr_blank_time = 6;	/* for about 96 us */
350297a64e7Sgd78059 static	int	intr_blank_packets = 8;	/*  */
351297a64e7Sgd78059 
352297a64e7Sgd78059 /*
353297a64e7Sgd78059  * ERX PAUSE Threshold Register value
354297a64e7Sgd78059  * The following value is for an OFF Threshold of about 15.5 Kbytes
355297a64e7Sgd78059  * and an ON Threshold of 4K bytes.
356297a64e7Sgd78059  */
357297a64e7Sgd78059 static	int rx_pause_threshold = 0xf8 | (0x40 << 12);
358297a64e7Sgd78059 static	int eri_reinit_fatal = 0;
359297a64e7Sgd78059 #ifdef	DEBUG
360297a64e7Sgd78059 static	int noteri = 0;
361297a64e7Sgd78059 #endif
362297a64e7Sgd78059 
363297a64e7Sgd78059 #ifdef	ERI_TX_HUNG
364297a64e7Sgd78059 static	int eri_reinit_txhung = 0;
365297a64e7Sgd78059 #endif
366297a64e7Sgd78059 
367297a64e7Sgd78059 #ifdef ERI_HDX_BUG_WORKAROUND
368297a64e7Sgd78059 /*
369297a64e7Sgd78059  * By default enable padding in hdx mode to 97 bytes.
370297a64e7Sgd78059  * To disabled, in /etc/system:
371297a64e7Sgd78059  * set eri:eri_hdx_pad_enable=0
372297a64e7Sgd78059  */
373297a64e7Sgd78059 static	uchar_t eri_hdx_pad_enable = 1;
374297a64e7Sgd78059 #endif
375297a64e7Sgd78059 
376297a64e7Sgd78059 /*
377297a64e7Sgd78059  * Default values to initialize the cache line size and latency timer
378297a64e7Sgd78059  * registers in the PCI configuration space.
379297a64e7Sgd78059  * ERI_G_CACHE_LINE_SIZE_16 is defined as 16 since RIO expects in units
380297a64e7Sgd78059  * of 4 bytes.
381297a64e7Sgd78059  */
382297a64e7Sgd78059 #ifdef ERI_PM_WORKAROUND_PCI
383297a64e7Sgd78059 static int eri_pci_cache_line = ERI_G_CACHE_LINE_SIZE_32; /* 128 bytes */
384297a64e7Sgd78059 static int eri_pci_latency_timer = 0xff;		/* 255 PCI cycles */
385297a64e7Sgd78059 #else
386297a64e7Sgd78059 static int eri_pci_cache_line = ERI_G_CACHE_LINE_SIZE_16; /* 64 bytes */
387297a64e7Sgd78059 static int eri_pci_latency_timer = 0x40;		/* 64 PCI cycles */
388297a64e7Sgd78059 #endif
389297a64e7Sgd78059 #define	ERI_CACHE_LINE_SIZE	(eri_pci_cache_line << ERI_G_CACHE_BIT)
390297a64e7Sgd78059 
391297a64e7Sgd78059 /*
392297a64e7Sgd78059  * Claim the device is ultra-capable of burst in the beginning.  Use
393297a64e7Sgd78059  * the value returned by ddi_dma_burstsizes() to actually set the ERI
394297a64e7Sgd78059  * global configuration register later.
395297a64e7Sgd78059  *
396297a64e7Sgd78059  * PCI_ERI supports Infinite burst or 64-byte-multiple bursts.
397297a64e7Sgd78059  */
398297a64e7Sgd78059 #define	ERI_LIMADDRLO	((uint64_t)0x00000000)
399297a64e7Sgd78059 #define	ERI_LIMADDRHI	((uint64_t)0xffffffff)
400297a64e7Sgd78059 
401297a64e7Sgd78059 static ddi_dma_attr_t dma_attr = {
402297a64e7Sgd78059 	DMA_ATTR_V0,		/* version number. */
403297a64e7Sgd78059 	(uint64_t)ERI_LIMADDRLO, /* low address */
404297a64e7Sgd78059 	(uint64_t)ERI_LIMADDRHI, /* high address */
405297a64e7Sgd78059 	(uint64_t)0x00ffffff,	/* address counter max */
406297a64e7Sgd78059 	(uint64_t)1,		/* alignment */
407297a64e7Sgd78059 	(uint_t)0xe000e0,	/* dlim_burstsizes for 32 4 bit xfers */
408297a64e7Sgd78059 	(uint32_t)0x1,		/* minimum transfer size */
409297a64e7Sgd78059 	(uint64_t)0x7fffffff,	/* maximum transfer size */
410297a64e7Sgd78059 	(uint64_t)0x00ffffff,	/* maximum segment size */
411297a64e7Sgd78059 	1,			/* scatter/gather list length */
412297a64e7Sgd78059 	(uint32_t)1,		/* granularity */
413297a64e7Sgd78059 	(uint_t)0		/* attribute flags */
414297a64e7Sgd78059 };
415297a64e7Sgd78059 
416297a64e7Sgd78059 static ddi_dma_attr_t desc_dma_attr = {
417297a64e7Sgd78059 	DMA_ATTR_V0,		/* version number. */
418297a64e7Sgd78059 	(uint64_t)ERI_LIMADDRLO, /* low address */
419297a64e7Sgd78059 	(uint64_t)ERI_LIMADDRHI, /* high address */
420297a64e7Sgd78059 	(uint64_t)0x00ffffff,	/* address counter max */
421297a64e7Sgd78059 	(uint64_t)8,		/* alignment */
422297a64e7Sgd78059 	(uint_t)0xe000e0,	/* dlim_burstsizes for 32 4 bit xfers */
423297a64e7Sgd78059 	(uint32_t)0x1,		/* minimum transfer size */
424297a64e7Sgd78059 	(uint64_t)0x7fffffff,	/* maximum transfer size */
425297a64e7Sgd78059 	(uint64_t)0x00ffffff,	/* maximum segment size */
426297a64e7Sgd78059 	1,			/* scatter/gather list length */
427297a64e7Sgd78059 	16,			/* granularity */
428297a64e7Sgd78059 	0			/* attribute flags */
429297a64e7Sgd78059 };
430297a64e7Sgd78059 
431bd78278bSGarrett D'Amore static ddi_device_acc_attr_t buf_attr = {
432bd78278bSGarrett D'Amore 	DDI_DEVICE_ATTR_V0,	/* devacc_attr_version */
433bd78278bSGarrett D'Amore 	DDI_NEVERSWAP_ACC,	/* devacc_attr_endian_flags */
434bd78278bSGarrett D'Amore 	DDI_STRICTORDER_ACC,	/* devacc_attr_dataorder */
435bd78278bSGarrett D'Amore 	DDI_DEFAULT_ACC,	/* devacc_attr_access */
436bd78278bSGarrett D'Amore };
437bd78278bSGarrett D'Amore 
438297a64e7Sgd78059 ddi_dma_lim_t eri_dma_limits = {
439297a64e7Sgd78059 	(uint64_t)ERI_LIMADDRLO, /* dlim_addr_lo */
440297a64e7Sgd78059 	(uint64_t)ERI_LIMADDRHI, /* dlim_addr_hi */
441297a64e7Sgd78059 	(uint64_t)ERI_LIMADDRHI, /* dlim_cntr_max */
442297a64e7Sgd78059 	(uint_t)0x00e000e0,	/* dlim_burstsizes for 32 and 64 bit xfers */
443297a64e7Sgd78059 	(uint32_t)0x1,		/* dlim_minxfer */
444297a64e7Sgd78059 	1024			/* dlim_speed */
445297a64e7Sgd78059 };
446297a64e7Sgd78059 
447297a64e7Sgd78059 /*
448297a64e7Sgd78059  * Link Configuration variables
449297a64e7Sgd78059  *
450297a64e7Sgd78059  * On Motherboard implementations, 10/100 Mbps speeds may be supported
451297a64e7Sgd78059  * by using both the Serial Link and the MII on Non-serial-link interface.
452297a64e7Sgd78059  * When both links are present, the driver automatically tries to bring up
453297a64e7Sgd78059  * both. If both are up, the Gigabit Serial Link is selected for use, by
454297a64e7Sgd78059  * default. The following configuration variable is used to force the selection
455297a64e7Sgd78059  * of one of the links when both are up.
456297a64e7Sgd78059  * To change the default selection to the MII link when both the Serial
457297a64e7Sgd78059  * Link and the MII link are up, change eri_default_link to 1.
458297a64e7Sgd78059  *
459297a64e7Sgd78059  * Once a link is in use, the driver will continue to use that link till it
460297a64e7Sgd78059  * goes down. When it goes down, the driver will look at the status of both the
461297a64e7Sgd78059  * links again for link selection.
462297a64e7Sgd78059  *
463297a64e7Sgd78059  * Currently the standard is not stable w.r.t. gigabit link configuration
464297a64e7Sgd78059  * using auto-negotiation procedures. Meanwhile, the link may be configured
465297a64e7Sgd78059  * in "forced" mode using the "autonegotiation enable" bit (bit-12) in the
466297a64e7Sgd78059  * PCS MII Command Register. In this mode the PCS sends "idles" until sees
467297a64e7Sgd78059  * "idles" as initialization instead of the Link Configuration protocol
468297a64e7Sgd78059  * where a Config register is exchanged. In this mode, the ERI is programmed
469297a64e7Sgd78059  * for full-duplex operation with both pauseTX and pauseRX (for flow control)
470297a64e7Sgd78059  * enabled.
471297a64e7Sgd78059  */
472297a64e7Sgd78059 
473297a64e7Sgd78059 static	int	select_link = 0; /* automatic selection */
474297a64e7Sgd78059 static	int	default_link = 0; /* Select Serial link if both are up */
475297a64e7Sgd78059 
476297a64e7Sgd78059 /*
477297a64e7Sgd78059  * The following variables are used for configuring link-operation
478297a64e7Sgd78059  * for all the "eri" interfaces in the system.
479297a64e7Sgd78059  * Later these parameters may be changed per interface using "ndd" command
480297a64e7Sgd78059  * These parameters may also be specified as properties using the .conf
481297a64e7Sgd78059  * file mechanism for each interface.
482297a64e7Sgd78059  */
483297a64e7Sgd78059 
484297a64e7Sgd78059 /*
485297a64e7Sgd78059  * The following variable value will be overridden by "link-pulse-disabled"
486297a64e7Sgd78059  * property which may be created by OBP or eri.conf file. This property is
487297a64e7Sgd78059  * applicable only for 10 Mbps links.
488297a64e7Sgd78059  */
489297a64e7Sgd78059 static	int	link_pulse_disabled = 0;	/* link pulse disabled */
490297a64e7Sgd78059 
491297a64e7Sgd78059 /* For MII-based FastEthernet links */
492297a64e7Sgd78059 static	int	adv_autoneg_cap = 1;
493297a64e7Sgd78059 static	int	adv_100T4_cap = 0;
494297a64e7Sgd78059 static	int	adv_100fdx_cap = 1;
495297a64e7Sgd78059 static	int	adv_100hdx_cap = 1;
496297a64e7Sgd78059 static	int	adv_10fdx_cap = 1;
497297a64e7Sgd78059 static	int	adv_10hdx_cap = 1;
498297a64e7Sgd78059 static	int	adv_pauseTX_cap =  0;
499297a64e7Sgd78059 static	int	adv_pauseRX_cap =  0;
500297a64e7Sgd78059 
501297a64e7Sgd78059 /*
502297a64e7Sgd78059  * The following gap parameters are in terms of byte times.
503297a64e7Sgd78059  */
504297a64e7Sgd78059 static	int	ipg0 = 8;
505297a64e7Sgd78059 static	int	ipg1 = 8;
506297a64e7Sgd78059 static	int	ipg2 = 4;
507297a64e7Sgd78059 
508297a64e7Sgd78059 static	int	lance_mode = 1;		/* to enable LANCE mode */
509297a64e7Sgd78059 static	int	mifpoll_enable = 0;	/* to enable mif poll */
510297a64e7Sgd78059 static	int	ngu_enable = 0;		/* to enable Never Give Up mode */
511297a64e7Sgd78059 
512297a64e7Sgd78059 static	int	eri_force_mlf = 0; 	/* to enable mif poll */
513297a64e7Sgd78059 static	int	eri_phy_mintrans = 1;	/* Lu3X31T mintrans algorithm */
514297a64e7Sgd78059 /*
515297a64e7Sgd78059  * For the MII interface, the External Transceiver is selected when present.
516297a64e7Sgd78059  * The following variable is used to select the Internal Transceiver even
517297a64e7Sgd78059  * when the External Transceiver is present.
518297a64e7Sgd78059  */
519297a64e7Sgd78059 static	int	use_int_xcvr = 0;
520297a64e7Sgd78059 static	int	pace_size = 0;	/* Do not use pacing for now */
521297a64e7Sgd78059 
522297a64e7Sgd78059 static	int	eri_use_dvma_rx = 0;	/* =1:use dvma */
523297a64e7Sgd78059 static	int	eri_rx_bcopy_max = RX_BCOPY_MAX;	/* =1:use bcopy() */
524297a64e7Sgd78059 static	int	eri_overflow_reset = 1;	/* global reset if rx_fifo_overflow */
525297a64e7Sgd78059 static	int	eri_tx_ring_size = 2048; /* number of entries in tx ring */
526297a64e7Sgd78059 static	int	eri_rx_ring_size = 1024; /* number of entries in rx ring */
527297a64e7Sgd78059 /*
528297a64e7Sgd78059  * The following parameters may be configured by the user. If they are not
529297a64e7Sgd78059  * configured by the user, the values will be based on the capabilities of
530297a64e7Sgd78059  * the transceiver.
531297a64e7Sgd78059  * The value "ERI_NOTUSR" is ORed with the parameter value to indicate values
532297a64e7Sgd78059  * which are NOT configured by the user.
533297a64e7Sgd78059  */
534297a64e7Sgd78059 
535297a64e7Sgd78059 #define	ERI_NOTUSR	0x0f000000
536297a64e7Sgd78059 #define	ERI_MASK_1BIT	0x1
537297a64e7Sgd78059 #define	ERI_MASK_2BIT	0x3
538297a64e7Sgd78059 #define	ERI_MASK_8BIT	0xff
539297a64e7Sgd78059 
540297a64e7Sgd78059 
541297a64e7Sgd78059 /*
542297a64e7Sgd78059  * Note:
543297a64e7Sgd78059  * ERI has all of the above capabilities.
544297a64e7Sgd78059  * Only when an External Transceiver is selected for MII-based FastEthernet
545297a64e7Sgd78059  * link operation, the capabilities depend upon the capabilities of the
546297a64e7Sgd78059  * External Transceiver.
547297a64e7Sgd78059  */
548297a64e7Sgd78059 
549297a64e7Sgd78059 /* ------------------------------------------------------------------------- */
550297a64e7Sgd78059 
551297a64e7Sgd78059 static  param_t	param_arr[] = {
552297a64e7Sgd78059 	/* min		max		value	r/w/hidden+name */
553297a64e7Sgd78059 	{  0,		2,		2,	"-transceiver_inuse"},
554297a64e7Sgd78059 	{  0,		1,		0,	"-link_status"},
555297a64e7Sgd78059 	{  0,		1,		0,	"-link_speed"},
556297a64e7Sgd78059 	{  0,		1,		0,	"-link_mode"},
557297a64e7Sgd78059 	{  0,		255,		8,	"+ipg1"},
558297a64e7Sgd78059 	{  0,		255,		4,	"+ipg2"},
559297a64e7Sgd78059 	{  0,		1,		0,	"+use_int_xcvr"},
560297a64e7Sgd78059 	{  0,		255,		0,	"+pace_size"},
561297a64e7Sgd78059 	{  0,		1,		1,	"+adv_autoneg_cap"},
562297a64e7Sgd78059 	{  0,		1,		1,	"+adv_100T4_cap"},
563297a64e7Sgd78059 	{  0,		1,		1,	"+adv_100fdx_cap"},
564297a64e7Sgd78059 	{  0,		1,		1,	"+adv_100hdx_cap"},
565297a64e7Sgd78059 	{  0,		1,		1,	"+adv_10fdx_cap"},
566297a64e7Sgd78059 	{  0,		1,		1,	"+adv_10hdx_cap"},
567297a64e7Sgd78059 	{  0,		1,		1,	"-autoneg_cap"},
568297a64e7Sgd78059 	{  0,		1,		1,	"-100T4_cap"},
569297a64e7Sgd78059 	{  0,		1,		1,	"-100fdx_cap"},
570297a64e7Sgd78059 	{  0,		1,		1,	"-100hdx_cap"},
571297a64e7Sgd78059 	{  0,		1,		1,	"-10fdx_cap"},
572297a64e7Sgd78059 	{  0,		1,		1,	"-10hdx_cap"},
573297a64e7Sgd78059 	{  0,		1,		0,	"-lp_autoneg_cap"},
574297a64e7Sgd78059 	{  0,		1,		0,	"-lp_100T4_cap"},
575297a64e7Sgd78059 	{  0,		1,		0,	"-lp_100fdx_cap"},
576297a64e7Sgd78059 	{  0,		1,		0,	"-lp_100hdx_cap"},
577297a64e7Sgd78059 	{  0,		1,		0,	"-lp_10fdx_cap"},
578297a64e7Sgd78059 	{  0,		1,		0,	"-lp_10hdx_cap"},
579297a64e7Sgd78059 	{  0,		1,		1,	"+lance_mode"},
580297a64e7Sgd78059 	{  0,		31,		8,	"+ipg0"},
581297a64e7Sgd78059 	{  0,		127,		6,	"+intr_blank_time"},
582297a64e7Sgd78059 	{  0,		255,		8,	"+intr_blank_packets"},
583297a64e7Sgd78059 	{  0,		1,		1,	"!serial-link"},
584297a64e7Sgd78059 	{  0,		2,		1,	"!non-serial-link"},
585297a64e7Sgd78059 	{  0,		1,		0,	"%select-link"},
586297a64e7Sgd78059 	{  0,		1,		0,	"%default-link"},
587297a64e7Sgd78059 	{  0,		2,		0,	"!link-in-use"},
588297a64e7Sgd78059 	{  0,		1,		1,	"%adv_asm_dir_cap"},
589297a64e7Sgd78059 	{  0,		1,		1,	"%adv_pause_cap"},
590297a64e7Sgd78059 	{  0,		1,		0,	"!asm_dir_cap"},
591297a64e7Sgd78059 	{  0,		1,		0,	"!pause_cap"},
592297a64e7Sgd78059 	{  0,		1,		0,	"!lp_asm_dir_cap"},
593297a64e7Sgd78059 	{  0,		1,		0,	"!lp_pause_cap"},
594297a64e7Sgd78059 };
595297a64e7Sgd78059 
596297a64e7Sgd78059 DDI_DEFINE_STREAM_OPS(eri_dev_ops, nulldev, nulldev, eri_attach, eri_detach,
59719397407SSherry Moore 	nodev, NULL, D_MP, NULL, ddi_quiesce_not_supported);
598297a64e7Sgd78059 
599297a64e7Sgd78059 /*
600297a64e7Sgd78059  * This is the loadable module wrapper.
601297a64e7Sgd78059  */
602297a64e7Sgd78059 #include <sys/modctl.h>
603297a64e7Sgd78059 
604297a64e7Sgd78059 /*
605297a64e7Sgd78059  * Module linkage information for the kernel.
606297a64e7Sgd78059  */
607297a64e7Sgd78059 static struct modldrv modldrv = {
608297a64e7Sgd78059 	&mod_driverops,	/* Type of module.  This one is a driver */
609297a64e7Sgd78059 	"Sun RIO 10/100 Mb Ethernet",
610297a64e7Sgd78059 	&eri_dev_ops,	/* driver ops */
611297a64e7Sgd78059 };
612297a64e7Sgd78059 
613297a64e7Sgd78059 static struct modlinkage modlinkage = {
614297a64e7Sgd78059 	MODREV_1, &modldrv, NULL
615297a64e7Sgd78059 };
616297a64e7Sgd78059 
617297a64e7Sgd78059 /*
618297a64e7Sgd78059  * Hardware Independent Functions
619297a64e7Sgd78059  * New Section
620297a64e7Sgd78059  */
621297a64e7Sgd78059 
622297a64e7Sgd78059 int
_init(void)623297a64e7Sgd78059 _init(void)
624297a64e7Sgd78059 {
625297a64e7Sgd78059 	int	status;
626297a64e7Sgd78059 
627297a64e7Sgd78059 	mac_init_ops(&eri_dev_ops, "eri");
628297a64e7Sgd78059 	if ((status = mod_install(&modlinkage)) != 0) {
629297a64e7Sgd78059 		mac_fini_ops(&eri_dev_ops);
630297a64e7Sgd78059 	}
631297a64e7Sgd78059 	return (status);
632297a64e7Sgd78059 }
633297a64e7Sgd78059 
634297a64e7Sgd78059 int
_fini(void)635297a64e7Sgd78059 _fini(void)
636297a64e7Sgd78059 {
637297a64e7Sgd78059 	int status;
638297a64e7Sgd78059 
639297a64e7Sgd78059 	status = mod_remove(&modlinkage);
640297a64e7Sgd78059 	if (status == 0) {
641297a64e7Sgd78059 		mac_fini_ops(&eri_dev_ops);
642297a64e7Sgd78059 	}
643297a64e7Sgd78059 	return (status);
644297a64e7Sgd78059 }
645297a64e7Sgd78059 
646297a64e7Sgd78059 int
_info(struct modinfo * modinfop)647297a64e7Sgd78059 _info(struct modinfo *modinfop)
648297a64e7Sgd78059 {
649297a64e7Sgd78059 	return (mod_info(&modlinkage, modinfop));
650297a64e7Sgd78059 }
651297a64e7Sgd78059 
652297a64e7Sgd78059 
653297a64e7Sgd78059 /*
654297a64e7Sgd78059  * Interface exists: make available by filling in network interface
655297a64e7Sgd78059  * record.  System will initialize the interface when it is ready
656297a64e7Sgd78059  * to accept packets.
657297a64e7Sgd78059  */
658297a64e7Sgd78059 static int
eri_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)659297a64e7Sgd78059 eri_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
660297a64e7Sgd78059 {
661297a64e7Sgd78059 	struct eri *erip = NULL;
662297a64e7Sgd78059 	mac_register_t *macp = NULL;
663297a64e7Sgd78059 	int	regno;
664297a64e7Sgd78059 	boolean_t	doinit;
665297a64e7Sgd78059 	boolean_t	mutex_inited = B_FALSE;
666297a64e7Sgd78059 	boolean_t	intr_add = B_FALSE;
667297a64e7Sgd78059 
668297a64e7Sgd78059 	switch (cmd) {
669297a64e7Sgd78059 	case DDI_ATTACH:
670297a64e7Sgd78059 		break;
671297a64e7Sgd78059 
672297a64e7Sgd78059 	case DDI_RESUME:
673297a64e7Sgd78059 		if ((erip = ddi_get_driver_private(dip)) == NULL)
674297a64e7Sgd78059 			return (DDI_FAILURE);
675297a64e7Sgd78059 
676297a64e7Sgd78059 		mutex_enter(&erip->intrlock);
677297a64e7Sgd78059 		erip->flags &= ~ERI_SUSPENDED;
678297a64e7Sgd78059 		erip->init_macregs = 1;
679297a64e7Sgd78059 		param_linkup = 0;
680297a64e7Sgd78059 		erip->stats.link_up = LINK_STATE_DOWN;
681297a64e7Sgd78059 		erip->linkcheck = 0;
682297a64e7Sgd78059 
683297a64e7Sgd78059 		doinit =  (erip->flags & ERI_STARTED) ? B_TRUE : B_FALSE;
684297a64e7Sgd78059 		mutex_exit(&erip->intrlock);
685297a64e7Sgd78059 
686297a64e7Sgd78059 		if (doinit && !eri_init(erip)) {
687297a64e7Sgd78059 			return (DDI_FAILURE);
688297a64e7Sgd78059 		}
689297a64e7Sgd78059 		return (DDI_SUCCESS);
690297a64e7Sgd78059 
691297a64e7Sgd78059 	default:
692297a64e7Sgd78059 		return (DDI_FAILURE);
693297a64e7Sgd78059 	}
694297a64e7Sgd78059 
695297a64e7Sgd78059 	/*
696297a64e7Sgd78059 	 * Allocate soft device data structure
697297a64e7Sgd78059 	 */
698297a64e7Sgd78059 	erip = kmem_zalloc(sizeof (struct eri), KM_SLEEP);
699297a64e7Sgd78059 
700297a64e7Sgd78059 	/*
701297a64e7Sgd78059 	 * Initialize as many elements as possible.
702297a64e7Sgd78059 	 */
703297a64e7Sgd78059 	ddi_set_driver_private(dip, erip);
704297a64e7Sgd78059 	erip->dip = dip;			/* dip	*/
705297a64e7Sgd78059 	erip->instance = ddi_get_instance(dip);	/* instance */
706297a64e7Sgd78059 	erip->flags = 0;
707297a64e7Sgd78059 	erip->multi_refcnt = 0;
708297a64e7Sgd78059 	erip->promisc = B_FALSE;
709297a64e7Sgd78059 
710297a64e7Sgd78059 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
711297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_HIGH, ERI_VERB_MSG,
712297a64e7Sgd78059 		    "mac_alloc failed");
713297a64e7Sgd78059 		goto attach_fail;
714297a64e7Sgd78059 	}
715297a64e7Sgd78059 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
716297a64e7Sgd78059 	macp->m_driver = erip;
717297a64e7Sgd78059 	macp->m_dip = dip;
718297a64e7Sgd78059 	macp->m_src_addr = erip->ouraddr;
719297a64e7Sgd78059 	macp->m_callbacks = &eri_m_callbacks;
720297a64e7Sgd78059 	macp->m_min_sdu = 0;
721297a64e7Sgd78059 	macp->m_max_sdu = ETHERMTU;
722297a64e7Sgd78059 	macp->m_margin = VLAN_TAGSZ;
723297a64e7Sgd78059 
724297a64e7Sgd78059 	/*
725297a64e7Sgd78059 	 * Map in the device registers.
726297a64e7Sgd78059 	 * Separate pointers will be set up for the following
727297a64e7Sgd78059 	 * register groups within the GEM Register Space:
728297a64e7Sgd78059 	 * 	Global register set
729297a64e7Sgd78059 	 * 	ETX register set
730297a64e7Sgd78059 	 * 	ERX register set
731297a64e7Sgd78059 	 * 	BigMAC register set.
732297a64e7Sgd78059 	 * 	MIF register set
733297a64e7Sgd78059 	 */
734297a64e7Sgd78059 
735297a64e7Sgd78059 	if (ddi_dev_nregs(dip, &regno) != (DDI_SUCCESS)) {
736297a64e7Sgd78059 		ERI_FAULT_MSG2(erip, SEVERITY_HIGH, ERI_VERB_MSG,
737297a64e7Sgd78059 		    "ddi_dev_nregs failed, returned %d", regno);
738297a64e7Sgd78059 		goto attach_fail;
739297a64e7Sgd78059 	}
740297a64e7Sgd78059 
741297a64e7Sgd78059 	/*
742297a64e7Sgd78059 	 * Map the PCI config space
743297a64e7Sgd78059 	 */
744297a64e7Sgd78059 	if (pci_config_setup(dip, &erip->pci_config_handle) != DDI_SUCCESS) {
745297a64e7Sgd78059 		ERI_FAULT_MSG2(erip, SEVERITY_HIGH, ERI_VERB_MSG,
746297a64e7Sgd78059 		    "%s pci_config_setup()", config_space_fatal_msg);
747297a64e7Sgd78059 		goto attach_fail;
748297a64e7Sgd78059 	}
749297a64e7Sgd78059 
750297a64e7Sgd78059 	/*
751297a64e7Sgd78059 	 * Initialize device attributes structure
752297a64e7Sgd78059 	 */
753297a64e7Sgd78059 	erip->dev_attr.devacc_attr_version =	DDI_DEVICE_ATTR_V0;
754297a64e7Sgd78059 	erip->dev_attr.devacc_attr_dataorder =	DDI_STRICTORDER_ACC;
755297a64e7Sgd78059 	erip->dev_attr.devacc_attr_endian_flags =	DDI_STRUCTURE_LE_ACC;
756297a64e7Sgd78059 
757297a64e7Sgd78059 	if (ddi_regs_map_setup(dip, 1, (caddr_t *)&(erip->globregp), 0, 0,
758297a64e7Sgd78059 	    &erip->dev_attr, &erip->globregh)) {
759297a64e7Sgd78059 		goto attach_fail;
760297a64e7Sgd78059 	}
761297a64e7Sgd78059 	erip->etxregh =		erip->globregh;
762297a64e7Sgd78059 	erip->erxregh =		erip->globregh;
763297a64e7Sgd78059 	erip->bmacregh =	erip->globregh;
764297a64e7Sgd78059 	erip->mifregh =		erip->globregh;
765297a64e7Sgd78059 
766297a64e7Sgd78059 	erip->etxregp =  (void *)(((caddr_t)erip->globregp) + 0x2000);
767297a64e7Sgd78059 	erip->erxregp =  (void *)(((caddr_t)erip->globregp) + 0x4000);
768297a64e7Sgd78059 	erip->bmacregp = (void *)(((caddr_t)erip->globregp) + 0x6000);
769297a64e7Sgd78059 	erip->mifregp =  (void *)(((caddr_t)erip->globregp) + 0x6200);
770297a64e7Sgd78059 
771297a64e7Sgd78059 	/*
772297a64e7Sgd78059 	 * Map the software reset register.
773297a64e7Sgd78059 	 */
774297a64e7Sgd78059 	if (ddi_regs_map_setup(dip, 1, (caddr_t *)&(erip->sw_reset_reg),
775297a64e7Sgd78059 	    0x1010, 4, &erip->dev_attr, &erip->sw_reset_regh)) {
776297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_MID, ERI_VERB_MSG,
777297a64e7Sgd78059 		    mregs_4soft_reset_fail_msg);
778297a64e7Sgd78059 		goto attach_fail;
779297a64e7Sgd78059 	}
780297a64e7Sgd78059 
781297a64e7Sgd78059 	/*
782297a64e7Sgd78059 	 * Try and stop the device.
783297a64e7Sgd78059 	 * This is done until we want to handle interrupts.
784297a64e7Sgd78059 	 */
785297a64e7Sgd78059 	if (eri_stop(erip))
786297a64e7Sgd78059 		goto attach_fail;
787297a64e7Sgd78059 
788297a64e7Sgd78059 	/*
789297a64e7Sgd78059 	 * set PCI latency timer register.
790297a64e7Sgd78059 	 */
791297a64e7Sgd78059 	pci_config_put8(erip->pci_config_handle, PCI_CONF_LATENCY_TIMER,
792297a64e7Sgd78059 	    (uchar_t)eri_pci_latency_timer);
793297a64e7Sgd78059 
794297a64e7Sgd78059 	if (ddi_intr_hilevel(dip, 0)) {
795297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
796297a64e7Sgd78059 		    " high-level interrupts are not supported");
797297a64e7Sgd78059 		goto attach_fail;
798297a64e7Sgd78059 	}
799297a64e7Sgd78059 
800297a64e7Sgd78059 	/*
801297a64e7Sgd78059 	 * Get the interrupt cookie so the mutexes can be
802297a64e7Sgd78059 	 * Initialized.
803297a64e7Sgd78059 	 */
804297a64e7Sgd78059 	if (ddi_get_iblock_cookie(dip, 0, &erip->cookie) != DDI_SUCCESS)
805297a64e7Sgd78059 		goto attach_fail;
806297a64e7Sgd78059 
807297a64e7Sgd78059 	/*
808297a64e7Sgd78059 	 * Initialize mutex's for this device.
809297a64e7Sgd78059 	 */
810297a64e7Sgd78059 	mutex_init(&erip->xmitlock, NULL, MUTEX_DRIVER, (void *)erip->cookie);
811297a64e7Sgd78059 	mutex_init(&erip->intrlock, NULL, MUTEX_DRIVER, (void *)erip->cookie);
812297a64e7Sgd78059 	mutex_init(&erip->linklock, NULL, MUTEX_DRIVER, (void *)erip->cookie);
813297a64e7Sgd78059 	mutex_init(&erip->xcvrlock, NULL, MUTEX_DRIVER, (void *)erip->cookie);
814297a64e7Sgd78059 
815297a64e7Sgd78059 	mutex_inited = B_TRUE;
816297a64e7Sgd78059 
817297a64e7Sgd78059 	/*
818297a64e7Sgd78059 	 * Add interrupt to system
819297a64e7Sgd78059 	 */
820297a64e7Sgd78059 	if (ddi_add_intr(dip, 0, &erip->cookie, 0, eri_intr, (caddr_t)erip) ==
821297a64e7Sgd78059 	    DDI_SUCCESS)
822297a64e7Sgd78059 		intr_add = B_TRUE;
823297a64e7Sgd78059 	else {
824297a64e7Sgd78059 		goto attach_fail;
825297a64e7Sgd78059 	}
826297a64e7Sgd78059 
827297a64e7Sgd78059 	/*
828297a64e7Sgd78059 	 * Set up the ethernet mac address.
829297a64e7Sgd78059 	 */
830297a64e7Sgd78059 	(void) eri_setup_mac_address(erip, dip);
831297a64e7Sgd78059 
832297a64e7Sgd78059 	if (eri_init_xfer_params(erip))
833297a64e7Sgd78059 		goto attach_fail;
834297a64e7Sgd78059 
835297a64e7Sgd78059 	if (eri_burstsize(erip) == DDI_FAILURE) {
836297a64e7Sgd78059 		goto attach_fail;
837297a64e7Sgd78059 	}
838297a64e7Sgd78059 
839297a64e7Sgd78059 	/*
840297a64e7Sgd78059 	 * Setup fewer receive bufers.
841297a64e7Sgd78059 	 */
842297a64e7Sgd78059 	ERI_RPENDING = eri_rx_ring_size;
843297a64e7Sgd78059 	ERI_TPENDING = eri_tx_ring_size;
844297a64e7Sgd78059 
845297a64e7Sgd78059 	erip->rpending_mask = ERI_RPENDING - 1;
846297a64e7Sgd78059 	erip->rmdmax_mask = ERI_RPENDING - 1;
847297a64e7Sgd78059 	erip->mif_config = (ERI_PHY_BMSR << ERI_MIF_CFGPR_SHIFT);
848297a64e7Sgd78059 
849297a64e7Sgd78059 	erip->stats.pmcap = ERI_PMCAP_NONE;
850297a64e7Sgd78059 	if (pci_report_pmcap(dip, PCI_PM_IDLESPEED, (void *)4000) ==
851297a64e7Sgd78059 	    DDI_SUCCESS)
852297a64e7Sgd78059 		erip->stats.pmcap = ERI_PMCAP_4MHZ;
853297a64e7Sgd78059 
854297a64e7Sgd78059 	if (mac_register(macp, &erip->mh) != 0)
855297a64e7Sgd78059 		goto attach_fail;
856297a64e7Sgd78059 
857297a64e7Sgd78059 	mac_free(macp);
858297a64e7Sgd78059 
859297a64e7Sgd78059 	return (DDI_SUCCESS);
860297a64e7Sgd78059 
861297a64e7Sgd78059 attach_fail:
862297a64e7Sgd78059 	if (erip->pci_config_handle)
863297a64e7Sgd78059 		(void) pci_config_teardown(&erip->pci_config_handle);
864297a64e7Sgd78059 
865297a64e7Sgd78059 	if (mutex_inited) {
866297a64e7Sgd78059 		mutex_destroy(&erip->xmitlock);
867297a64e7Sgd78059 		mutex_destroy(&erip->intrlock);
868297a64e7Sgd78059 		mutex_destroy(&erip->linklock);
869297a64e7Sgd78059 		mutex_destroy(&erip->xcvrlock);
870297a64e7Sgd78059 	}
871297a64e7Sgd78059 
872297a64e7Sgd78059 	ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG, attach_fail_msg);
873297a64e7Sgd78059 
874297a64e7Sgd78059 	if (intr_add)
875297a64e7Sgd78059 		ddi_remove_intr(dip, 0, erip->cookie);
876297a64e7Sgd78059 
877297a64e7Sgd78059 	if (erip->globregh)
878297a64e7Sgd78059 		ddi_regs_map_free(&erip->globregh);
879297a64e7Sgd78059 
880297a64e7Sgd78059 	if (macp != NULL)
881297a64e7Sgd78059 		mac_free(macp);
882297a64e7Sgd78059 	if (erip != NULL)
883297a64e7Sgd78059 		kmem_free(erip, sizeof (*erip));
884297a64e7Sgd78059 
885297a64e7Sgd78059 	return (DDI_FAILURE);
886297a64e7Sgd78059 }
887297a64e7Sgd78059 
888297a64e7Sgd78059 static int
eri_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)889297a64e7Sgd78059 eri_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
890297a64e7Sgd78059 {
891297a64e7Sgd78059 	struct eri 	*erip;
892297a64e7Sgd78059 	int i;
893297a64e7Sgd78059 
894297a64e7Sgd78059 	if ((erip = ddi_get_driver_private(dip)) == NULL) {
895297a64e7Sgd78059 		/*
896297a64e7Sgd78059 		 * No resources allocated.
897297a64e7Sgd78059 		 */
898297a64e7Sgd78059 		return (DDI_FAILURE);
899297a64e7Sgd78059 	}
900297a64e7Sgd78059 
901297a64e7Sgd78059 	switch (cmd) {
902297a64e7Sgd78059 	case DDI_DETACH:
903297a64e7Sgd78059 		break;
904297a64e7Sgd78059 
905297a64e7Sgd78059 	case DDI_SUSPEND:
906297a64e7Sgd78059 		erip->flags |= ERI_SUSPENDED;
907297a64e7Sgd78059 		eri_uninit(erip);
908297a64e7Sgd78059 		return (DDI_SUCCESS);
909297a64e7Sgd78059 
910297a64e7Sgd78059 	default:
911297a64e7Sgd78059 		return (DDI_FAILURE);
912297a64e7Sgd78059 	}
913297a64e7Sgd78059 
914297a64e7Sgd78059 	if (erip->flags & (ERI_RUNNING | ERI_SUSPENDED)) {
915297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG, busy_msg);
916297a64e7Sgd78059 		return (DDI_FAILURE);
917297a64e7Sgd78059 	}
918297a64e7Sgd78059 
919297a64e7Sgd78059 	if (mac_unregister(erip->mh) != 0) {
920297a64e7Sgd78059 		return (DDI_FAILURE);
921297a64e7Sgd78059 	}
922297a64e7Sgd78059 
923297a64e7Sgd78059 	/*
924297a64e7Sgd78059 	 * Make the device quiescent
925297a64e7Sgd78059 	 */
926297a64e7Sgd78059 	(void) eri_stop(erip);
927297a64e7Sgd78059 
928297a64e7Sgd78059 	/*
929297a64e7Sgd78059 	 * Remove instance of the intr
930297a64e7Sgd78059 	 */
931297a64e7Sgd78059 	ddi_remove_intr(dip, 0, erip->cookie);
932297a64e7Sgd78059 
933297a64e7Sgd78059 	if (erip->pci_config_handle)
934297a64e7Sgd78059 		(void) pci_config_teardown(&erip->pci_config_handle);
935297a64e7Sgd78059 
936297a64e7Sgd78059 	/*
937297a64e7Sgd78059 	 * Destroy all mutexes and data structures allocated during
938297a64e7Sgd78059 	 * attach time.
939297a64e7Sgd78059 	 */
940297a64e7Sgd78059 
941297a64e7Sgd78059 	if (erip->globregh)
942297a64e7Sgd78059 		ddi_regs_map_free(&erip->globregh);
943297a64e7Sgd78059 
944297a64e7Sgd78059 	erip->etxregh =		NULL;
945297a64e7Sgd78059 	erip->erxregh =		NULL;
946297a64e7Sgd78059 	erip->bmacregh =	NULL;
947297a64e7Sgd78059 	erip->mifregh =		NULL;
948297a64e7Sgd78059 	erip->globregh =	NULL;
949297a64e7Sgd78059 
950297a64e7Sgd78059 	if (erip->sw_reset_regh)
951297a64e7Sgd78059 		ddi_regs_map_free(&erip->sw_reset_regh);
952297a64e7Sgd78059 
953297a64e7Sgd78059 	if (erip->ksp)
954297a64e7Sgd78059 		kstat_delete(erip->ksp);
955297a64e7Sgd78059 
956297a64e7Sgd78059 	eri_stop_timer(erip); /* acquire linklock */
957297a64e7Sgd78059 	eri_start_timer(erip, eri_check_link, 0);
958297a64e7Sgd78059 	mutex_destroy(&erip->xmitlock);
959297a64e7Sgd78059 	mutex_destroy(&erip->intrlock);
960297a64e7Sgd78059 	mutex_destroy(&erip->linklock);
961297a64e7Sgd78059 	mutex_destroy(&erip->xcvrlock);
962297a64e7Sgd78059 
963297a64e7Sgd78059 	if (erip->md_h) {
964297a64e7Sgd78059 		if (ddi_dma_unbind_handle(erip->md_h) ==
965297a64e7Sgd78059 		    DDI_FAILURE)
966297a64e7Sgd78059 			return (DDI_FAILURE);
967297a64e7Sgd78059 		ddi_dma_mem_free(&erip->mdm_h);
968297a64e7Sgd78059 		ddi_dma_free_handle(&erip->md_h);
969297a64e7Sgd78059 	}
970297a64e7Sgd78059 
971297a64e7Sgd78059 	if (eri_freebufs(erip))
972297a64e7Sgd78059 		return (DDI_FAILURE);
973297a64e7Sgd78059 
974297a64e7Sgd78059 	/* dvma handle case */
975297a64e7Sgd78059 
976297a64e7Sgd78059 	if (erip->eri_dvmarh) {
977297a64e7Sgd78059 		(void) dvma_release(erip->eri_dvmarh);
978297a64e7Sgd78059 		erip->eri_dvmarh = NULL;
979297a64e7Sgd78059 	}
980297a64e7Sgd78059 /*
981297a64e7Sgd78059  *	xmit_dma_mode, erip->ndmaxh[i]=NULL for dvma
982297a64e7Sgd78059  */
983297a64e7Sgd78059 	else {
984297a64e7Sgd78059 		for (i = 0; i < ERI_RPENDING; i++)
985297a64e7Sgd78059 			if (erip->ndmarh[i])
986297a64e7Sgd78059 				ddi_dma_free_handle(&erip->ndmarh[i]);
987297a64e7Sgd78059 	}
988297a64e7Sgd78059 /*
989bd78278bSGarrett D'Amore  *	Release TX buffer
990297a64e7Sgd78059  */
991297a64e7Sgd78059 	if (erip->tbuf_ioaddr != 0) {
992297a64e7Sgd78059 		(void) ddi_dma_unbind_handle(erip->tbuf_handle);
993297a64e7Sgd78059 		erip->tbuf_ioaddr = 0;
994297a64e7Sgd78059 	}
995297a64e7Sgd78059 	if (erip->tbuf_kaddr != NULL) {
996bd78278bSGarrett D'Amore 		ddi_dma_mem_free(&erip->tbuf_acch);
997297a64e7Sgd78059 		erip->tbuf_kaddr = NULL;
998297a64e7Sgd78059 	}
999297a64e7Sgd78059 	if (erip->tbuf_handle != NULL) {
1000297a64e7Sgd78059 		ddi_dma_free_handle(&erip->tbuf_handle);
1001297a64e7Sgd78059 		erip->tbuf_handle = NULL;
1002297a64e7Sgd78059 	}
1003297a64e7Sgd78059 
1004297a64e7Sgd78059 	eri_param_cleanup(erip);
1005297a64e7Sgd78059 
1006297a64e7Sgd78059 	ddi_set_driver_private(dip, NULL);
1007297a64e7Sgd78059 	kmem_free((caddr_t)erip, sizeof (struct eri));
1008297a64e7Sgd78059 
1009297a64e7Sgd78059 	return (DDI_SUCCESS);
1010297a64e7Sgd78059 }
1011297a64e7Sgd78059 
1012297a64e7Sgd78059 /*
1013297a64e7Sgd78059  * To set up the mac address for the network interface:
1014297a64e7Sgd78059  * The adapter card may support a local mac address which is published
1015297a64e7Sgd78059  * in a device node property "local-mac-address". This mac address is
1016297a64e7Sgd78059  * treated as the factory-installed mac address for DLPI interface.
1017297a64e7Sgd78059  * If the adapter firmware has used the device for diskless boot
1018297a64e7Sgd78059  * operation it publishes a property called "mac-address" for use by
1019297a64e7Sgd78059  * inetboot and the device driver.
1020297a64e7Sgd78059  * If "mac-address" is not found, the system options property
1021297a64e7Sgd78059  * "local-mac-address" is used to select the mac-address. If this option
1022297a64e7Sgd78059  * is set to "true", and "local-mac-address" has been found, then
1023297a64e7Sgd78059  * local-mac-address is used; otherwise the system mac address is used
1024297a64e7Sgd78059  * by calling the "localetheraddr()" function.
1025297a64e7Sgd78059  */
1026297a64e7Sgd78059 
1027297a64e7Sgd78059 static void
eri_setup_mac_address(struct eri * erip,dev_info_t * dip)1028297a64e7Sgd78059 eri_setup_mac_address(struct eri *erip, dev_info_t *dip)
1029297a64e7Sgd78059 {
1030297a64e7Sgd78059 	uchar_t			*prop;
1031297a64e7Sgd78059 	char			*uselocal;
1032297a64e7Sgd78059 	unsigned		prop_len;
1033297a64e7Sgd78059 	uint32_t		addrflags = 0;
1034297a64e7Sgd78059 	struct ether_addr	factaddr;
1035297a64e7Sgd78059 
1036297a64e7Sgd78059 	/*
1037297a64e7Sgd78059 	 * Check if it is an adapter with its own local mac address
1038297a64e7Sgd78059 	 * If it is present, save it as the "factory-address"
1039297a64e7Sgd78059 	 * for this adapter.
1040297a64e7Sgd78059 	 */
1041297a64e7Sgd78059 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1042297a64e7Sgd78059 	    "local-mac-address", &prop, &prop_len) == DDI_PROP_SUCCESS) {
1043297a64e7Sgd78059 		if (prop_len == ETHERADDRL) {
1044297a64e7Sgd78059 			addrflags = ERI_FACTADDR_PRESENT;
1045297a64e7Sgd78059 			bcopy(prop, &factaddr, ETHERADDRL);
1046297a64e7Sgd78059 			ERI_FAULT_MSG2(erip, SEVERITY_NONE, ERI_VERB_MSG,
1047297a64e7Sgd78059 			    lether_addr_msg, ether_sprintf(&factaddr));
1048297a64e7Sgd78059 		}
1049297a64e7Sgd78059 		ddi_prop_free(prop);
1050297a64e7Sgd78059 	}
1051297a64e7Sgd78059 	/*
1052297a64e7Sgd78059 	 * Check if the adapter has published "mac-address" property.
1053297a64e7Sgd78059 	 * If it is present, use it as the mac address for this device.
1054297a64e7Sgd78059 	 */
1055297a64e7Sgd78059 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1056297a64e7Sgd78059 	    "mac-address", &prop, &prop_len) == DDI_PROP_SUCCESS) {
1057297a64e7Sgd78059 		if (prop_len >= ETHERADDRL) {
1058297a64e7Sgd78059 			bcopy(prop, erip->ouraddr, ETHERADDRL);
1059297a64e7Sgd78059 			ddi_prop_free(prop);
1060297a64e7Sgd78059 			return;
1061297a64e7Sgd78059 		}
1062297a64e7Sgd78059 		ddi_prop_free(prop);
1063297a64e7Sgd78059 	}
1064297a64e7Sgd78059 
1065297a64e7Sgd78059 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, "local-mac-address?",
1066297a64e7Sgd78059 	    &uselocal) == DDI_PROP_SUCCESS) {
1067297a64e7Sgd78059 		if ((strcmp("true", uselocal) == 0) &&
1068297a64e7Sgd78059 		    (addrflags & ERI_FACTADDR_PRESENT)) {
1069297a64e7Sgd78059 			addrflags |= ERI_FACTADDR_USE;
1070297a64e7Sgd78059 			bcopy(&factaddr, erip->ouraddr, ETHERADDRL);
1071297a64e7Sgd78059 			ddi_prop_free(uselocal);
1072297a64e7Sgd78059 			ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
1073297a64e7Sgd78059 			    lmac_addr_msg);
1074297a64e7Sgd78059 			return;
1075297a64e7Sgd78059 		}
1076297a64e7Sgd78059 		ddi_prop_free(uselocal);
1077297a64e7Sgd78059 	}
1078297a64e7Sgd78059 
1079297a64e7Sgd78059 	/*
1080297a64e7Sgd78059 	 * Get the system ethernet address.
1081297a64e7Sgd78059 	 */
1082297a64e7Sgd78059 	(void) localetheraddr(NULL, &factaddr);
1083297a64e7Sgd78059 	bcopy(&factaddr, erip->ouraddr, ETHERADDRL);
1084297a64e7Sgd78059 }
1085297a64e7Sgd78059 
1086297a64e7Sgd78059 
1087297a64e7Sgd78059 /*
1088297a64e7Sgd78059  * Calculate the bit in the multicast address filter that selects the given
1089297a64e7Sgd78059  * address.
1090297a64e7Sgd78059  * Note: For ERI, the last 8-bits are used.
1091297a64e7Sgd78059  */
1092297a64e7Sgd78059 
1093297a64e7Sgd78059 static uint32_t
eri_ladrf_bit(const uint8_t * addr)1094297a64e7Sgd78059 eri_ladrf_bit(const uint8_t *addr)
1095297a64e7Sgd78059 {
1096297a64e7Sgd78059 	uint32_t crc;
1097297a64e7Sgd78059 
1098297a64e7Sgd78059 	CRC32(crc, addr, ETHERADDRL, -1U, crc32_table);
1099297a64e7Sgd78059 
1100297a64e7Sgd78059 	/*
1101297a64e7Sgd78059 	 * Just want the 8 most significant bits.
1102297a64e7Sgd78059 	 */
1103297a64e7Sgd78059 	return ((~crc) >> 24);
1104297a64e7Sgd78059 }
1105297a64e7Sgd78059 
1106297a64e7Sgd78059 static void
eri_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)1107297a64e7Sgd78059 eri_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
1108297a64e7Sgd78059 {
1109297a64e7Sgd78059 	struct	eri	*erip = arg;
1110297a64e7Sgd78059 	struct	iocblk	*iocp = (void *)mp->b_rptr;
1111297a64e7Sgd78059 	int	err;
1112297a64e7Sgd78059 
1113297a64e7Sgd78059 	ASSERT(erip != NULL);
1114297a64e7Sgd78059 
1115297a64e7Sgd78059 	/*
1116297a64e7Sgd78059 	 * Privilege checks.
1117297a64e7Sgd78059 	 */
1118297a64e7Sgd78059 	switch (iocp->ioc_cmd) {
1119297a64e7Sgd78059 	case ERI_SET_LOOP_MODE:
1120297a64e7Sgd78059 	case ERI_ND_SET:
1121297a64e7Sgd78059 		err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
1122297a64e7Sgd78059 		if (err != 0) {
1123297a64e7Sgd78059 			miocnak(wq, mp, 0, err);
1124297a64e7Sgd78059 			return;
1125297a64e7Sgd78059 		}
1126297a64e7Sgd78059 		break;
1127297a64e7Sgd78059 	default:
1128297a64e7Sgd78059 		break;
1129297a64e7Sgd78059 	}
1130297a64e7Sgd78059 
1131297a64e7Sgd78059 	switch (iocp->ioc_cmd) {
1132297a64e7Sgd78059 	case ERI_ND_GET:
1133297a64e7Sgd78059 	case ERI_ND_SET:
1134297a64e7Sgd78059 		eri_process_ndd_ioctl(erip, wq, mp, iocp->ioc_cmd);
1135297a64e7Sgd78059 		break;
1136297a64e7Sgd78059 
1137297a64e7Sgd78059 	case ERI_SET_LOOP_MODE:
1138297a64e7Sgd78059 	case ERI_GET_LOOP_MODE:
1139297a64e7Sgd78059 		/*
1140297a64e7Sgd78059 		 * XXX: Consider updating this to the new netlb ioctls.
1141297a64e7Sgd78059 		 */
1142297a64e7Sgd78059 		eri_loopback(erip, wq, mp);
1143297a64e7Sgd78059 		break;
1144297a64e7Sgd78059 
1145297a64e7Sgd78059 	default:
1146297a64e7Sgd78059 		miocnak(wq, mp, 0, EINVAL);
1147297a64e7Sgd78059 		break;
1148297a64e7Sgd78059 	}
1149297a64e7Sgd78059 
1150297a64e7Sgd78059 	ASSERT(!MUTEX_HELD(&erip->linklock));
1151297a64e7Sgd78059 }
1152297a64e7Sgd78059 
1153297a64e7Sgd78059 static void
eri_loopback(struct eri * erip,queue_t * wq,mblk_t * mp)1154297a64e7Sgd78059 eri_loopback(struct eri *erip, queue_t *wq, mblk_t *mp)
1155297a64e7Sgd78059 {
1156297a64e7Sgd78059 	struct	iocblk	*iocp = (void *)mp->b_rptr;
1157297a64e7Sgd78059 	loopback_t	*al;
1158297a64e7Sgd78059 
1159297a64e7Sgd78059 	if (mp->b_cont == NULL || MBLKL(mp->b_cont) < sizeof (loopback_t)) {
1160297a64e7Sgd78059 		miocnak(wq, mp, 0, EINVAL);
1161297a64e7Sgd78059 		return;
1162297a64e7Sgd78059 	}
1163297a64e7Sgd78059 
1164297a64e7Sgd78059 	al = (void *)mp->b_cont->b_rptr;
1165297a64e7Sgd78059 
1166297a64e7Sgd78059 	switch (iocp->ioc_cmd) {
1167297a64e7Sgd78059 	case ERI_SET_LOOP_MODE:
1168297a64e7Sgd78059 		switch (al->loopback) {
1169297a64e7Sgd78059 		case ERI_LOOPBACK_OFF:
1170297a64e7Sgd78059 			erip->flags &= (~ERI_MACLOOPBACK & ~ERI_SERLOOPBACK);
1171297a64e7Sgd78059 			/* force link status to go down */
1172297a64e7Sgd78059 			param_linkup = 0;
1173297a64e7Sgd78059 			erip->stats.link_up = LINK_STATE_DOWN;
1174297a64e7Sgd78059 			erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
1175297a64e7Sgd78059 			(void) eri_init(erip);
1176297a64e7Sgd78059 			break;
1177297a64e7Sgd78059 
1178297a64e7Sgd78059 		case ERI_MAC_LOOPBACK_ON:
1179297a64e7Sgd78059 			erip->flags |= ERI_MACLOOPBACK;
1180297a64e7Sgd78059 			erip->flags &= ~ERI_SERLOOPBACK;
1181297a64e7Sgd78059 			param_linkup = 0;
1182297a64e7Sgd78059 			erip->stats.link_up = LINK_STATE_DOWN;
1183297a64e7Sgd78059 			erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
1184297a64e7Sgd78059 			(void) eri_init(erip);
1185297a64e7Sgd78059 			break;
1186297a64e7Sgd78059 
1187297a64e7Sgd78059 		case ERI_PCS_LOOPBACK_ON:
1188297a64e7Sgd78059 			break;
1189297a64e7Sgd78059 
1190297a64e7Sgd78059 		case ERI_SER_LOOPBACK_ON:
1191297a64e7Sgd78059 			erip->flags |= ERI_SERLOOPBACK;
1192297a64e7Sgd78059 			erip->flags &= ~ERI_MACLOOPBACK;
1193297a64e7Sgd78059 			/* force link status to go down */
1194297a64e7Sgd78059 			param_linkup = 0;
1195297a64e7Sgd78059 			erip->stats.link_up = LINK_STATE_DOWN;
1196297a64e7Sgd78059 			erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
1197297a64e7Sgd78059 			(void) eri_init(erip);
1198297a64e7Sgd78059 			break;
1199297a64e7Sgd78059 
1200297a64e7Sgd78059 		default:
1201297a64e7Sgd78059 			ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
1202297a64e7Sgd78059 			    loopback_val_default);
1203297a64e7Sgd78059 			miocnak(wq, mp, 0, EINVAL);
1204297a64e7Sgd78059 			return;
1205297a64e7Sgd78059 		}
1206297a64e7Sgd78059 		miocnak(wq, mp, 0, 0);
1207297a64e7Sgd78059 		break;
1208297a64e7Sgd78059 
1209297a64e7Sgd78059 	case ERI_GET_LOOP_MODE:
1210297a64e7Sgd78059 		al->loopback =	ERI_MAC_LOOPBACK_ON | ERI_PCS_LOOPBACK_ON |
1211297a64e7Sgd78059 		    ERI_SER_LOOPBACK_ON;
1212297a64e7Sgd78059 		miocack(wq, mp, sizeof (loopback_t), 0);
1213297a64e7Sgd78059 		break;
1214297a64e7Sgd78059 
1215297a64e7Sgd78059 	default:
1216297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
1217297a64e7Sgd78059 		    loopback_cmd_default);
1218297a64e7Sgd78059 	}
1219297a64e7Sgd78059 }
1220297a64e7Sgd78059 
1221297a64e7Sgd78059 static int
eri_m_promisc(void * arg,boolean_t on)1222297a64e7Sgd78059 eri_m_promisc(void *arg, boolean_t on)
1223297a64e7Sgd78059 {
1224297a64e7Sgd78059 	struct	eri	*erip = arg;
1225297a64e7Sgd78059 
1226297a64e7Sgd78059 	mutex_enter(&erip->intrlock);
1227297a64e7Sgd78059 	erip->promisc = on;
1228297a64e7Sgd78059 	eri_init_rx(erip);
1229297a64e7Sgd78059 	mutex_exit(&erip->intrlock);
1230297a64e7Sgd78059 	return (0);
1231297a64e7Sgd78059 }
1232297a64e7Sgd78059 
1233297a64e7Sgd78059 /*
1234297a64e7Sgd78059  * This is to support unlimited number of members
1235297a64e7Sgd78059  * in Multicast.
1236297a64e7Sgd78059  */
1237297a64e7Sgd78059 static int
eri_m_multicst(void * arg,boolean_t add,const uint8_t * mca)1238297a64e7Sgd78059 eri_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
1239297a64e7Sgd78059 {
1240297a64e7Sgd78059 	struct eri		*erip = arg;
1241297a64e7Sgd78059 	uint32_t 		ladrf_bit;
1242297a64e7Sgd78059 
1243297a64e7Sgd78059 	/*
1244297a64e7Sgd78059 	 * If this address's bit was not already set in the local address
1245297a64e7Sgd78059 	 * filter, add it and re-initialize the Hardware.
1246297a64e7Sgd78059 	 */
1247297a64e7Sgd78059 	ladrf_bit = eri_ladrf_bit(mca);
1248297a64e7Sgd78059 
1249297a64e7Sgd78059 	mutex_enter(&erip->intrlock);
1250297a64e7Sgd78059 	if (add) {
1251297a64e7Sgd78059 		erip->ladrf_refcnt[ladrf_bit]++;
1252297a64e7Sgd78059 		if (erip->ladrf_refcnt[ladrf_bit] == 1) {
1253297a64e7Sgd78059 			LADRF_SET(erip, ladrf_bit);
1254297a64e7Sgd78059 			erip->multi_refcnt++;
1255297a64e7Sgd78059 			eri_init_rx(erip);
1256297a64e7Sgd78059 		}
1257297a64e7Sgd78059 	} else {
1258297a64e7Sgd78059 		erip->ladrf_refcnt[ladrf_bit]--;
1259297a64e7Sgd78059 		if (erip->ladrf_refcnt[ladrf_bit] == 0) {
1260297a64e7Sgd78059 			LADRF_CLR(erip, ladrf_bit);
1261297a64e7Sgd78059 			erip->multi_refcnt--;
1262297a64e7Sgd78059 			eri_init_rx(erip);
1263297a64e7Sgd78059 		}
1264297a64e7Sgd78059 	}
1265297a64e7Sgd78059 	mutex_exit(&erip->intrlock);
1266297a64e7Sgd78059 	return (0);
1267297a64e7Sgd78059 }
1268297a64e7Sgd78059 
1269297a64e7Sgd78059 static int
eri_m_unicst(void * arg,const uint8_t * macaddr)1270297a64e7Sgd78059 eri_m_unicst(void *arg, const uint8_t *macaddr)
1271297a64e7Sgd78059 {
1272297a64e7Sgd78059 	struct	eri	*erip = arg;
1273297a64e7Sgd78059 
1274297a64e7Sgd78059 	/*
1275297a64e7Sgd78059 	 * Set new interface local address and re-init device.
1276297a64e7Sgd78059 	 * This is destructive to any other streams attached
1277297a64e7Sgd78059 	 * to this device.
1278297a64e7Sgd78059 	 */
1279297a64e7Sgd78059 	mutex_enter(&erip->intrlock);
1280297a64e7Sgd78059 	bcopy(macaddr, &erip->ouraddr, ETHERADDRL);
1281297a64e7Sgd78059 	eri_init_rx(erip);
1282297a64e7Sgd78059 	mutex_exit(&erip->intrlock);
1283297a64e7Sgd78059 	return (0);
1284297a64e7Sgd78059 }
1285297a64e7Sgd78059 
1286297a64e7Sgd78059 /*ARGSUSED*/
1287297a64e7Sgd78059 static boolean_t
eri_m_getcapab(void * arg,mac_capab_t cap,void * cap_data)1288297a64e7Sgd78059 eri_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
1289297a64e7Sgd78059 {
1290297a64e7Sgd78059 	switch (cap) {
1291297a64e7Sgd78059 	case MAC_CAPAB_HCKSUM: {
1292297a64e7Sgd78059 		uint32_t *hcksum_txflags = cap_data;
1293297a64e7Sgd78059 		*hcksum_txflags = HCKSUM_INET_PARTIAL;
1294297a64e7Sgd78059 		return (B_TRUE);
1295297a64e7Sgd78059 	}
1296297a64e7Sgd78059 	default:
1297297a64e7Sgd78059 		return (B_FALSE);
1298297a64e7Sgd78059 	}
1299297a64e7Sgd78059 }
1300297a64e7Sgd78059 
1301297a64e7Sgd78059 static int
eri_m_start(void * arg)1302297a64e7Sgd78059 eri_m_start(void *arg)
1303297a64e7Sgd78059 {
1304297a64e7Sgd78059 	struct eri	*erip = arg;
1305297a64e7Sgd78059 
1306297a64e7Sgd78059 	mutex_enter(&erip->intrlock);
1307297a64e7Sgd78059 	erip->flags |= ERI_STARTED;
1308297a64e7Sgd78059 	mutex_exit(&erip->intrlock);
1309297a64e7Sgd78059 
1310297a64e7Sgd78059 	if (!eri_init(erip)) {
1311297a64e7Sgd78059 		mutex_enter(&erip->intrlock);
1312297a64e7Sgd78059 		erip->flags &= ~ERI_STARTED;
1313297a64e7Sgd78059 		mutex_exit(&erip->intrlock);
1314297a64e7Sgd78059 		return (EIO);
1315297a64e7Sgd78059 	}
1316297a64e7Sgd78059 	return (0);
1317297a64e7Sgd78059 }
1318297a64e7Sgd78059 
1319297a64e7Sgd78059 static void
eri_m_stop(void * arg)1320297a64e7Sgd78059 eri_m_stop(void *arg)
1321297a64e7Sgd78059 {
1322297a64e7Sgd78059 	struct eri	*erip = arg;
1323297a64e7Sgd78059 
1324297a64e7Sgd78059 	mutex_enter(&erip->intrlock);
1325297a64e7Sgd78059 	erip->flags &= ~ERI_STARTED;
1326297a64e7Sgd78059 	mutex_exit(&erip->intrlock);
1327297a64e7Sgd78059 	eri_uninit(erip);
1328297a64e7Sgd78059 }
1329297a64e7Sgd78059 
1330297a64e7Sgd78059 static int
eri_m_stat(void * arg,uint_t stat,uint64_t * val)1331297a64e7Sgd78059 eri_m_stat(void *arg, uint_t stat, uint64_t *val)
1332297a64e7Sgd78059 {
1333297a64e7Sgd78059 	struct eri	*erip = arg;
1334297a64e7Sgd78059 	struct stats	*esp;
1335297a64e7Sgd78059 	boolean_t	macupdate = B_FALSE;
1336297a64e7Sgd78059 
1337297a64e7Sgd78059 	esp = &erip->stats;
1338297a64e7Sgd78059 
1339297a64e7Sgd78059 	mutex_enter(&erip->xmitlock);
1340297a64e7Sgd78059 	if ((erip->flags & ERI_RUNNING) && (erip->flags & ERI_TXINIT)) {
1341297a64e7Sgd78059 		erip->tx_completion =
1342297a64e7Sgd78059 		    GET_ETXREG(tx_completion) & ETX_COMPLETION_MASK;
1343297a64e7Sgd78059 		macupdate |= eri_reclaim(erip, erip->tx_completion);
1344297a64e7Sgd78059 	}
1345297a64e7Sgd78059 	mutex_exit(&erip->xmitlock);
1346297a64e7Sgd78059 	if (macupdate)
1347297a64e7Sgd78059 		mac_tx_update(erip->mh);
1348297a64e7Sgd78059 
1349297a64e7Sgd78059 	eri_savecntrs(erip);
1350297a64e7Sgd78059 
1351297a64e7Sgd78059 	switch (stat) {
1352297a64e7Sgd78059 	case MAC_STAT_IFSPEED:
1353297a64e7Sgd78059 		*val = esp->ifspeed * 1000000ULL;
1354297a64e7Sgd78059 		break;
1355297a64e7Sgd78059 	case MAC_STAT_MULTIRCV:
1356297a64e7Sgd78059 		*val = esp->multircv;
1357297a64e7Sgd78059 		break;
1358297a64e7Sgd78059 	case MAC_STAT_BRDCSTRCV:
1359297a64e7Sgd78059 		*val = esp->brdcstrcv;
1360297a64e7Sgd78059 		break;
1361297a64e7Sgd78059 	case MAC_STAT_IPACKETS:
1362297a64e7Sgd78059 		*val = esp->ipackets64;
1363297a64e7Sgd78059 		break;
1364297a64e7Sgd78059 	case MAC_STAT_RBYTES:
1365297a64e7Sgd78059 		*val = esp->rbytes64;
1366297a64e7Sgd78059 		break;
1367297a64e7Sgd78059 	case MAC_STAT_OBYTES:
1368297a64e7Sgd78059 		*val = esp->obytes64;
1369297a64e7Sgd78059 		break;
1370297a64e7Sgd78059 	case MAC_STAT_OPACKETS:
1371297a64e7Sgd78059 		*val = esp->opackets64;
1372297a64e7Sgd78059 		break;
1373297a64e7Sgd78059 	case MAC_STAT_IERRORS:
1374297a64e7Sgd78059 		*val = esp->ierrors;
1375297a64e7Sgd78059 		break;
1376297a64e7Sgd78059 	case MAC_STAT_OERRORS:
1377297a64e7Sgd78059 		*val = esp->oerrors;
1378297a64e7Sgd78059 		break;
1379297a64e7Sgd78059 	case MAC_STAT_MULTIXMT:
1380297a64e7Sgd78059 		*val = esp->multixmt;
1381297a64e7Sgd78059 		break;
1382297a64e7Sgd78059 	case MAC_STAT_BRDCSTXMT:
1383297a64e7Sgd78059 		*val = esp->brdcstxmt;
1384297a64e7Sgd78059 		break;
1385297a64e7Sgd78059 	case MAC_STAT_NORCVBUF:
1386297a64e7Sgd78059 		*val = esp->norcvbuf;
1387297a64e7Sgd78059 		break;
1388297a64e7Sgd78059 	case MAC_STAT_NOXMTBUF:
1389297a64e7Sgd78059 		*val = esp->noxmtbuf;
1390297a64e7Sgd78059 		break;
1391297a64e7Sgd78059 	case MAC_STAT_UNDERFLOWS:
1392297a64e7Sgd78059 		*val = esp->txmac_urun;
1393297a64e7Sgd78059 		break;
1394297a64e7Sgd78059 	case MAC_STAT_OVERFLOWS:
1395297a64e7Sgd78059 		*val = esp->rx_overflow;
1396297a64e7Sgd78059 		break;
1397297a64e7Sgd78059 	case MAC_STAT_COLLISIONS:
1398297a64e7Sgd78059 		*val = esp->collisions;
1399297a64e7Sgd78059 		break;
1400297a64e7Sgd78059 	case ETHER_STAT_ALIGN_ERRORS:
1401297a64e7Sgd78059 		*val = esp->rx_align_err;
1402297a64e7Sgd78059 		break;
1403297a64e7Sgd78059 	case ETHER_STAT_FCS_ERRORS:
1404297a64e7Sgd78059 		*val = esp->rx_crc_err;
1405297a64e7Sgd78059 		break;
1406297a64e7Sgd78059 	case ETHER_STAT_EX_COLLISIONS:
1407297a64e7Sgd78059 		*val = esp->excessive_coll;
1408297a64e7Sgd78059 		break;
1409297a64e7Sgd78059 	case ETHER_STAT_TX_LATE_COLLISIONS:
1410297a64e7Sgd78059 		*val = esp->late_coll;
1411297a64e7Sgd78059 		break;
1412297a64e7Sgd78059 	case ETHER_STAT_FIRST_COLLISIONS:
1413297a64e7Sgd78059 		*val = esp->first_coll;
1414297a64e7Sgd78059 		break;
1415297a64e7Sgd78059 	case ETHER_STAT_LINK_DUPLEX:
1416297a64e7Sgd78059 		*val = esp->link_duplex;
1417297a64e7Sgd78059 		break;
1418297a64e7Sgd78059 	case ETHER_STAT_TOOLONG_ERRORS:
1419297a64e7Sgd78059 		*val = esp->rx_toolong_pkts;
1420297a64e7Sgd78059 		break;
1421297a64e7Sgd78059 	case ETHER_STAT_TOOSHORT_ERRORS:
1422297a64e7Sgd78059 		*val = esp->rx_runt;
1423297a64e7Sgd78059 		break;
1424297a64e7Sgd78059 
1425297a64e7Sgd78059 	case ETHER_STAT_XCVR_ADDR:
1426297a64e7Sgd78059 		*val = erip->phyad;
1427297a64e7Sgd78059 		break;
1428297a64e7Sgd78059 
1429297a64e7Sgd78059 	case ETHER_STAT_XCVR_INUSE:
1430297a64e7Sgd78059 		*val = XCVR_100X;	/* should always be 100X for now */
1431297a64e7Sgd78059 		break;
1432297a64e7Sgd78059 
1433297a64e7Sgd78059 	case ETHER_STAT_CAP_100FDX:
1434297a64e7Sgd78059 		*val = param_bmsr_100fdx;
1435297a64e7Sgd78059 		break;
1436297a64e7Sgd78059 	case ETHER_STAT_CAP_100HDX:
1437297a64e7Sgd78059 		*val = param_bmsr_100hdx;
1438297a64e7Sgd78059 		break;
1439297a64e7Sgd78059 	case ETHER_STAT_CAP_10FDX:
1440297a64e7Sgd78059 		*val = param_bmsr_10fdx;
1441297a64e7Sgd78059 		break;
1442297a64e7Sgd78059 	case ETHER_STAT_CAP_10HDX:
1443297a64e7Sgd78059 		*val = param_bmsr_10hdx;
1444297a64e7Sgd78059 		break;
1445297a64e7Sgd78059 	case ETHER_STAT_CAP_AUTONEG:
1446297a64e7Sgd78059 		*val = param_bmsr_ancap;
1447297a64e7Sgd78059 		break;
1448297a64e7Sgd78059 	case ETHER_STAT_CAP_ASMPAUSE:
1449297a64e7Sgd78059 		*val = param_bmsr_asm_dir;
1450297a64e7Sgd78059 		break;
1451297a64e7Sgd78059 	case ETHER_STAT_CAP_PAUSE:
1452297a64e7Sgd78059 		*val = param_bmsr_pause;
1453297a64e7Sgd78059 		break;
1454297a64e7Sgd78059 	case ETHER_STAT_ADV_CAP_100FDX:
1455297a64e7Sgd78059 		*val = param_anar_100fdx;
1456297a64e7Sgd78059 		break;
1457297a64e7Sgd78059 	case ETHER_STAT_ADV_CAP_100HDX:
1458297a64e7Sgd78059 		*val = param_anar_100hdx;
1459297a64e7Sgd78059 		break;
1460297a64e7Sgd78059 	case ETHER_STAT_ADV_CAP_10FDX:
1461297a64e7Sgd78059 		*val = param_anar_10fdx;
1462297a64e7Sgd78059 		break;
1463297a64e7Sgd78059 	case ETHER_STAT_ADV_CAP_10HDX:
1464297a64e7Sgd78059 		*val = param_anar_10hdx;
1465297a64e7Sgd78059 		break;
1466297a64e7Sgd78059 	case ETHER_STAT_ADV_CAP_AUTONEG:
1467297a64e7Sgd78059 		*val = param_autoneg;
1468297a64e7Sgd78059 		break;
1469297a64e7Sgd78059 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
1470297a64e7Sgd78059 		*val = param_anar_asm_dir;
1471297a64e7Sgd78059 		break;
1472297a64e7Sgd78059 	case ETHER_STAT_ADV_CAP_PAUSE:
1473297a64e7Sgd78059 		*val = param_anar_pause;
1474297a64e7Sgd78059 		break;
1475297a64e7Sgd78059 	case ETHER_STAT_LP_CAP_100FDX:
1476297a64e7Sgd78059 		*val = param_anlpar_100fdx;
1477297a64e7Sgd78059 		break;
1478297a64e7Sgd78059 	case ETHER_STAT_LP_CAP_100HDX:
1479297a64e7Sgd78059 		*val = param_anlpar_100hdx;
1480297a64e7Sgd78059 		break;
1481297a64e7Sgd78059 	case ETHER_STAT_LP_CAP_10FDX:
1482297a64e7Sgd78059 		*val = param_anlpar_10fdx;
1483297a64e7Sgd78059 		break;
1484297a64e7Sgd78059 	case ETHER_STAT_LP_CAP_10HDX:
1485297a64e7Sgd78059 		*val = param_anlpar_10hdx;
1486297a64e7Sgd78059 		break;
1487297a64e7Sgd78059 	case ETHER_STAT_LP_CAP_AUTONEG:
1488297a64e7Sgd78059 		*val = param_aner_lpancap;
1489297a64e7Sgd78059 		break;
1490297a64e7Sgd78059 	case ETHER_STAT_LP_CAP_ASMPAUSE:
1491297a64e7Sgd78059 		*val = param_anlpar_pauseTX;
1492297a64e7Sgd78059 		break;
1493297a64e7Sgd78059 	case ETHER_STAT_LP_CAP_PAUSE:
1494297a64e7Sgd78059 		*val = param_anlpar_pauseRX;
1495297a64e7Sgd78059 		break;
1496297a64e7Sgd78059 	case ETHER_STAT_LINK_PAUSE:
1497297a64e7Sgd78059 		*val = esp->pausing;
1498297a64e7Sgd78059 		break;
1499297a64e7Sgd78059 	case ETHER_STAT_LINK_ASMPAUSE:
1500297a64e7Sgd78059 		*val = param_anar_asm_dir &&
1501297a64e7Sgd78059 		    param_anlpar_pauseTX &&
1502297a64e7Sgd78059 		    (param_anar_pause != param_anlpar_pauseRX);
1503297a64e7Sgd78059 		break;
1504297a64e7Sgd78059 	case ETHER_STAT_LINK_AUTONEG:
1505297a64e7Sgd78059 		*val = param_autoneg && param_aner_lpancap;
1506297a64e7Sgd78059 		break;
1507297a64e7Sgd78059 	}
1508297a64e7Sgd78059 	return (0);
1509297a64e7Sgd78059 }
1510297a64e7Sgd78059 
1511297a64e7Sgd78059 /*
1512297a64e7Sgd78059  * Hardware Functions
1513297a64e7Sgd78059  * New Section
1514297a64e7Sgd78059  */
1515297a64e7Sgd78059 
1516297a64e7Sgd78059 /*
1517297a64e7Sgd78059  * Initialize the MAC registers. Some of of the MAC  registers are initialized
1518297a64e7Sgd78059  * just once since  Global Reset or MAC reset doesn't clear them. Others (like
1519297a64e7Sgd78059  * Host MAC Address Registers) are cleared on every reset and have to be
1520297a64e7Sgd78059  * reinitialized.
1521297a64e7Sgd78059  */
1522297a64e7Sgd78059 static void
eri_init_macregs_generic(struct eri * erip)1523297a64e7Sgd78059 eri_init_macregs_generic(struct eri *erip)
1524297a64e7Sgd78059 {
1525297a64e7Sgd78059 	/*
1526297a64e7Sgd78059 	 * set up the MAC parameter registers once
1527297a64e7Sgd78059 	 * after power cycle. SUSPEND/RESUME also requires
1528297a64e7Sgd78059 	 * setting these registers.
1529297a64e7Sgd78059 	 */
1530297a64e7Sgd78059 	if ((erip->stats.inits == 1) || (erip->init_macregs)) {
1531297a64e7Sgd78059 		erip->init_macregs = 0;
1532297a64e7Sgd78059 		PUT_MACREG(ipg0, param_ipg0);
1533297a64e7Sgd78059 		PUT_MACREG(ipg1, param_ipg1);
1534297a64e7Sgd78059 		PUT_MACREG(ipg2, param_ipg2);
1535297a64e7Sgd78059 		PUT_MACREG(macmin, BMAC_MIN_FRAME_SIZE);
1536297a64e7Sgd78059 #ifdef	ERI_RX_TAG_ERROR_WORKAROUND
1537297a64e7Sgd78059 		PUT_MACREG(macmax, BMAC_MAX_FRAME_SIZE_TAG | BMAC_MAX_BURST);
1538297a64e7Sgd78059 #else
1539297a64e7Sgd78059 		PUT_MACREG(macmax, BMAC_MAX_FRAME_SIZE | BMAC_MAX_BURST);
1540297a64e7Sgd78059 #endif
1541297a64e7Sgd78059 		PUT_MACREG(palen, BMAC_PREAMBLE_SIZE);
1542297a64e7Sgd78059 		PUT_MACREG(jam, BMAC_JAM_SIZE);
1543297a64e7Sgd78059 		PUT_MACREG(alimit, BMAC_ATTEMPT_LIMIT);
1544297a64e7Sgd78059 		PUT_MACREG(macctl_type, BMAC_CONTROL_TYPE);
1545297a64e7Sgd78059 		PUT_MACREG(rseed,
1546297a64e7Sgd78059 		    ((erip->ouraddr[0] & 0x3) << 8) | erip->ouraddr[1]);
1547297a64e7Sgd78059 
1548297a64e7Sgd78059 		PUT_MACREG(madd3, BMAC_ADDRESS_3);
1549297a64e7Sgd78059 		PUT_MACREG(madd4, BMAC_ADDRESS_4);
1550297a64e7Sgd78059 		PUT_MACREG(madd5, BMAC_ADDRESS_5);
1551297a64e7Sgd78059 
1552297a64e7Sgd78059 		/* Program MAC Control address */
1553297a64e7Sgd78059 		PUT_MACREG(madd6, BMAC_ADDRESS_6);
1554297a64e7Sgd78059 		PUT_MACREG(madd7, BMAC_ADDRESS_7);
1555297a64e7Sgd78059 		PUT_MACREG(madd8, BMAC_ADDRESS_8);
1556297a64e7Sgd78059 
1557297a64e7Sgd78059 		PUT_MACREG(afr0, BMAC_AF_0);
1558297a64e7Sgd78059 		PUT_MACREG(afr1, BMAC_AF_1);
1559297a64e7Sgd78059 		PUT_MACREG(afr2, BMAC_AF_2);
1560297a64e7Sgd78059 		PUT_MACREG(afmr1_2, BMAC_AF21_MASK);
1561297a64e7Sgd78059 		PUT_MACREG(afmr0, BMAC_AF0_MASK);
1562297a64e7Sgd78059 	}
1563297a64e7Sgd78059 
1564297a64e7Sgd78059 	/* The counters need to be zeroed */
1565297a64e7Sgd78059 	PUT_MACREG(nccnt, 0);
1566297a64e7Sgd78059 	PUT_MACREG(fccnt, 0);
1567297a64e7Sgd78059 	PUT_MACREG(excnt, 0);
1568297a64e7Sgd78059 	PUT_MACREG(ltcnt, 0);
1569297a64e7Sgd78059 	PUT_MACREG(dcnt,  0);
1570297a64e7Sgd78059 	PUT_MACREG(frcnt, 0);
1571297a64e7Sgd78059 	PUT_MACREG(lecnt, 0);
1572297a64e7Sgd78059 	PUT_MACREG(aecnt, 0);
1573297a64e7Sgd78059 	PUT_MACREG(fecnt, 0);
1574297a64e7Sgd78059 	PUT_MACREG(rxcv,  0);
1575297a64e7Sgd78059 
1576297a64e7Sgd78059 	if (erip->pauseTX)
1577297a64e7Sgd78059 		PUT_MACREG(spcmd, BMAC_SEND_PAUSE_CMD);
1578297a64e7Sgd78059 	else
1579297a64e7Sgd78059 		PUT_MACREG(spcmd, 0);
1580297a64e7Sgd78059 
1581297a64e7Sgd78059 	/*
1582297a64e7Sgd78059 	 * Program BigMAC with local individual ethernet address.
1583297a64e7Sgd78059 	 */
1584297a64e7Sgd78059 
1585297a64e7Sgd78059 	PUT_MACREG(madd0, (erip->ouraddr[4] << 8) | erip->ouraddr[5]);
1586297a64e7Sgd78059 	PUT_MACREG(madd1, (erip->ouraddr[2] << 8) | erip->ouraddr[3]);
1587297a64e7Sgd78059 	PUT_MACREG(madd2, (erip->ouraddr[0] << 8) | erip->ouraddr[1]);
1588297a64e7Sgd78059 
1589297a64e7Sgd78059 	/*
1590297a64e7Sgd78059 	 * Install multicast address filter.
1591297a64e7Sgd78059 	 */
1592297a64e7Sgd78059 
1593297a64e7Sgd78059 	PUT_MACREG(hash0, erip->ladrf[0]);
1594297a64e7Sgd78059 	PUT_MACREG(hash1, erip->ladrf[1]);
1595297a64e7Sgd78059 	PUT_MACREG(hash2, erip->ladrf[2]);
1596297a64e7Sgd78059 	PUT_MACREG(hash3, erip->ladrf[3]);
1597297a64e7Sgd78059 	PUT_MACREG(hash4, erip->ladrf[4]);
1598297a64e7Sgd78059 	PUT_MACREG(hash5, erip->ladrf[5]);
1599297a64e7Sgd78059 	PUT_MACREG(hash6, erip->ladrf[6]);
1600297a64e7Sgd78059 	PUT_MACREG(hash7, erip->ladrf[7]);
1601297a64e7Sgd78059 	PUT_MACREG(hash8, erip->ladrf[8]);
1602297a64e7Sgd78059 	PUT_MACREG(hash9, erip->ladrf[9]);
1603297a64e7Sgd78059 	PUT_MACREG(hash10, erip->ladrf[10]);
1604297a64e7Sgd78059 	PUT_MACREG(hash11, erip->ladrf[11]);
1605297a64e7Sgd78059 	PUT_MACREG(hash12, erip->ladrf[12]);
1606297a64e7Sgd78059 	PUT_MACREG(hash13, erip->ladrf[13]);
1607297a64e7Sgd78059 	PUT_MACREG(hash14, erip->ladrf[14]);
1608297a64e7Sgd78059 }
1609297a64e7Sgd78059 
1610297a64e7Sgd78059 static int
eri_flush_rxbufs(struct eri * erip)1611297a64e7Sgd78059 eri_flush_rxbufs(struct eri *erip)
1612297a64e7Sgd78059 {
1613297a64e7Sgd78059 	uint_t	i;
1614297a64e7Sgd78059 	int	status = 0;
1615297a64e7Sgd78059 	/*
1616297a64e7Sgd78059 	 * Free and dvma_unload pending recv buffers.
1617297a64e7Sgd78059 	 * Maintaining the 1-to-1 ordered sequence of
1618297a64e7Sgd78059 	 * dvma_load() followed by dvma_unload() is critical.
1619297a64e7Sgd78059 	 * Always unload anything before loading it again.
1620297a64e7Sgd78059 	 * Never unload anything twice.  Always unload
1621297a64e7Sgd78059 	 * before freeing the buffer.  We satisfy these
1622297a64e7Sgd78059 	 * requirements by unloading only those descriptors
1623297a64e7Sgd78059 	 * which currently have an mblk associated with them.
1624297a64e7Sgd78059 	 */
1625297a64e7Sgd78059 	for (i = 0; i < ERI_RPENDING; i++) {
1626297a64e7Sgd78059 		if (erip->rmblkp[i]) {
1627297a64e7Sgd78059 			if (erip->eri_dvmarh)
1628297a64e7Sgd78059 				dvma_unload(erip->eri_dvmarh, 2 * i,
1629297a64e7Sgd78059 				    DDI_DMA_SYNC_FORCPU);
1630297a64e7Sgd78059 			else if ((ddi_dma_unbind_handle(erip->ndmarh[i]) ==
1631297a64e7Sgd78059 			    DDI_FAILURE))
1632297a64e7Sgd78059 				status = -1;
1633297a64e7Sgd78059 			freeb(erip->rmblkp[i]);
1634297a64e7Sgd78059 			erip->rmblkp[i] = NULL;
1635297a64e7Sgd78059 		}
1636297a64e7Sgd78059 	}
1637297a64e7Sgd78059 	return (status);
1638297a64e7Sgd78059 }
1639297a64e7Sgd78059 
1640297a64e7Sgd78059 static void
eri_init_txbufs(struct eri * erip)1641297a64e7Sgd78059 eri_init_txbufs(struct eri *erip)
1642297a64e7Sgd78059 {
1643297a64e7Sgd78059 	/*
1644297a64e7Sgd78059 	 * Clear TX descriptors.
1645297a64e7Sgd78059 	 */
1646297a64e7Sgd78059 	bzero((caddr_t)erip->eri_tmdp, ERI_TPENDING * sizeof (struct eri_tmd));
1647297a64e7Sgd78059 
1648297a64e7Sgd78059 	/*
1649297a64e7Sgd78059 	 * sync TXDMA descriptors.
1650297a64e7Sgd78059 	 */
1651297a64e7Sgd78059 	ERI_SYNCIOPB(erip, erip->eri_tmdp,
1652297a64e7Sgd78059 	    (ERI_TPENDING * sizeof (struct eri_tmd)), DDI_DMA_SYNC_FORDEV);
1653297a64e7Sgd78059 	/*
1654297a64e7Sgd78059 	 * Reset TMD 'walking' pointers.
1655297a64e7Sgd78059 	 */
1656297a64e7Sgd78059 	erip->tcurp = erip->eri_tmdp;
1657297a64e7Sgd78059 	erip->tnextp = erip->eri_tmdp;
1658297a64e7Sgd78059 	erip->tx_cur_cnt = 0;
1659297a64e7Sgd78059 	erip->tx_kick = 0;
1660297a64e7Sgd78059 	erip->tx_completion = 0;
1661297a64e7Sgd78059 }
1662297a64e7Sgd78059 
1663297a64e7Sgd78059 static int
eri_init_rxbufs(struct eri * erip)1664297a64e7Sgd78059 eri_init_rxbufs(struct eri *erip)
1665297a64e7Sgd78059 {
1666297a64e7Sgd78059 
1667297a64e7Sgd78059 	ddi_dma_cookie_t	dma_cookie;
1668297a64e7Sgd78059 	mblk_t			*bp;
1669297a64e7Sgd78059 	int			i, status = 0;
1670297a64e7Sgd78059 	uint32_t		ccnt;
1671297a64e7Sgd78059 
1672297a64e7Sgd78059 	/*
1673297a64e7Sgd78059 	 * clear rcv descriptors
1674297a64e7Sgd78059 	 */
1675297a64e7Sgd78059 	bzero((caddr_t)erip->rmdp, ERI_RPENDING * sizeof (struct rmd));
1676297a64e7Sgd78059 
1677297a64e7Sgd78059 	for (i = 0; i < ERI_RPENDING; i++) {
1678297a64e7Sgd78059 		if ((bp = eri_allocb(ERI_BUFSIZE)) == NULL) {
1679297a64e7Sgd78059 			status = -1;
1680297a64e7Sgd78059 			continue;
1681297a64e7Sgd78059 		}
1682297a64e7Sgd78059 		/* Load data buffer to DVMA space */
1683297a64e7Sgd78059 		if (erip->eri_dvmarh)
1684297a64e7Sgd78059 			dvma_kaddr_load(erip->eri_dvmarh,
1685297a64e7Sgd78059 			    (caddr_t)bp->b_rptr, ERI_BUFSIZE,
1686297a64e7Sgd78059 			    2 * i, &dma_cookie);
1687297a64e7Sgd78059 /*
1688297a64e7Sgd78059  *		Bind data buffer to DMA handle
1689297a64e7Sgd78059  */
1690297a64e7Sgd78059 		else if (ddi_dma_addr_bind_handle(erip->ndmarh[i], NULL,
1691297a64e7Sgd78059 		    (caddr_t)bp->b_rptr, ERI_BUFSIZE,
1692297a64e7Sgd78059 		    DDI_DMA_READ | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, 0,
1693297a64e7Sgd78059 		    &dma_cookie, &ccnt) != DDI_DMA_MAPPED)
1694297a64e7Sgd78059 			status = -1;
1695297a64e7Sgd78059 
1696297a64e7Sgd78059 		PUT_RMD((&erip->rmdp[i]), dma_cookie);
1697297a64e7Sgd78059 		erip->rmblkp[i] = bp;	/* save for later use */
1698297a64e7Sgd78059 	}
1699297a64e7Sgd78059 
1700297a64e7Sgd78059 	/*
1701297a64e7Sgd78059 	 * sync RXDMA descriptors.
1702297a64e7Sgd78059 	 */
1703297a64e7Sgd78059 	ERI_SYNCIOPB(erip, erip->rmdp, (ERI_RPENDING * sizeof (struct rmd)),
1704297a64e7Sgd78059 	    DDI_DMA_SYNC_FORDEV);
1705297a64e7Sgd78059 	/*
1706297a64e7Sgd78059 	 * Reset RMD 'walking' pointers.
1707297a64e7Sgd78059 	 */
1708297a64e7Sgd78059 	erip->rnextp = erip->rmdp;
1709297a64e7Sgd78059 	erip->rx_completion = 0;
1710297a64e7Sgd78059 	erip->rx_kick = ERI_RPENDING - 4;
1711297a64e7Sgd78059 	return (status);
1712297a64e7Sgd78059 }
1713297a64e7Sgd78059 
1714297a64e7Sgd78059 static uint32_t
eri_txmac_disable(struct eri * erip)1715297a64e7Sgd78059 eri_txmac_disable(struct eri *erip)
1716297a64e7Sgd78059 {
1717297a64e7Sgd78059 	int	n;
1718297a64e7Sgd78059 
1719297a64e7Sgd78059 	PUT_MACREG(txcfg, GET_MACREG(txcfg) & ~BMAC_TXCFG_ENAB);
1720297a64e7Sgd78059 	n = (BMACTXRSTDELAY * 10) / ERI_WAITPERIOD;
1721297a64e7Sgd78059 
1722297a64e7Sgd78059 	while (--n > 0) {
1723297a64e7Sgd78059 		drv_usecwait(ERI_WAITPERIOD);
1724297a64e7Sgd78059 		if ((GET_MACREG(txcfg) & 1) == 0)
1725297a64e7Sgd78059 			return (0);
1726297a64e7Sgd78059 	}
1727297a64e7Sgd78059 	return (1);
1728297a64e7Sgd78059 }
1729297a64e7Sgd78059 
1730297a64e7Sgd78059 static uint32_t
eri_rxmac_disable(struct eri * erip)1731297a64e7Sgd78059 eri_rxmac_disable(struct eri *erip)
1732297a64e7Sgd78059 {
1733297a64e7Sgd78059 	int	n;
1734297a64e7Sgd78059 	PUT_MACREG(rxcfg, GET_MACREG(rxcfg) & ~BMAC_RXCFG_ENAB);
1735297a64e7Sgd78059 	n = BMACRXRSTDELAY / ERI_WAITPERIOD;
1736297a64e7Sgd78059 
1737297a64e7Sgd78059 	while (--n > 0) {
1738297a64e7Sgd78059 		drv_usecwait(ERI_WAITPERIOD);
1739297a64e7Sgd78059 		if ((GET_MACREG(rxcfg) & 1) == 0)
1740297a64e7Sgd78059 			return (0);
1741297a64e7Sgd78059 	}
1742297a64e7Sgd78059 	return (1);
1743297a64e7Sgd78059 }
1744297a64e7Sgd78059 
1745297a64e7Sgd78059 /*
1746297a64e7Sgd78059  * Return 0 upon success, 1 on failure.
1747297a64e7Sgd78059  */
1748297a64e7Sgd78059 static int
eri_stop(struct eri * erip)1749297a64e7Sgd78059 eri_stop(struct eri *erip)
1750297a64e7Sgd78059 {
1751297a64e7Sgd78059 	(void) eri_erx_reset(erip);
1752297a64e7Sgd78059 	(void) eri_etx_reset(erip);
1753297a64e7Sgd78059 
1754297a64e7Sgd78059 	/*
1755297a64e7Sgd78059 	 * set up cache line to 16 for 64 bytes of pci burst size
1756297a64e7Sgd78059 	 */
1757297a64e7Sgd78059 	PUT_SWRSTREG(reset, ERI_G_RESET_GLOBAL | ERI_CACHE_LINE_SIZE);
1758297a64e7Sgd78059 
1759297a64e7Sgd78059 	if (erip->linkcheck) {
1760297a64e7Sgd78059 		erip->linkcheck = 0;
1761297a64e7Sgd78059 		erip->global_reset_issued = 2;
1762297a64e7Sgd78059 	} else {
1763297a64e7Sgd78059 		param_linkup = 0;
1764297a64e7Sgd78059 		erip->stats.link_up = LINK_STATE_DOWN;
1765297a64e7Sgd78059 		erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
1766297a64e7Sgd78059 		erip->global_reset_issued = -1;
1767297a64e7Sgd78059 	}
1768297a64e7Sgd78059 
1769297a64e7Sgd78059 	ERI_DELAY((GET_SWRSTREG(reset) == ERI_CACHE_LINE_SIZE),
1770297a64e7Sgd78059 	    ERI_MAX_RST_DELAY);
1771297a64e7Sgd78059 	erip->rx_reset_issued = -1;
1772297a64e7Sgd78059 	erip->tx_reset_issued = -1;
1773297a64e7Sgd78059 
1774297a64e7Sgd78059 	/*
1775297a64e7Sgd78059 	 * workaround for RIO not resetting the interrupt mask
1776297a64e7Sgd78059 	 * register to default value 0xffffffff.
1777297a64e7Sgd78059 	 */
1778297a64e7Sgd78059 	PUT_GLOBREG(intmask, ERI_G_MASK_ALL);
1779297a64e7Sgd78059 
1780297a64e7Sgd78059 	if (GET_SWRSTREG(reset) == ERI_CACHE_LINE_SIZE) {
1781297a64e7Sgd78059 		return (0);
1782297a64e7Sgd78059 	} else {
1783297a64e7Sgd78059 		return (1);
1784297a64e7Sgd78059 	}
1785297a64e7Sgd78059 }
1786297a64e7Sgd78059 
1787297a64e7Sgd78059 /*
1788297a64e7Sgd78059  * Reset Just the RX Portion
1789297a64e7Sgd78059  * Return 0 upon success, 1 on failure.
1790297a64e7Sgd78059  *
1791297a64e7Sgd78059  * Resetting the rxdma while there is a rx dma transaction going on the
1792297a64e7Sgd78059  * bus, will cause bus hang or parity errors. To avoid this, we would first
1793297a64e7Sgd78059  * disable the rxdma by clearing the ENABLE bit (bit 0). To make sure it is
1794297a64e7Sgd78059  * disabled, we will poll it until it realy clears. Furthermore, to verify
1795297a64e7Sgd78059  * any RX DMA activity is subsided, we delay for 5 msec.
1796297a64e7Sgd78059  */
1797297a64e7Sgd78059 static uint32_t
eri_erx_reset(struct eri * erip)1798297a64e7Sgd78059 eri_erx_reset(struct eri *erip)
1799297a64e7Sgd78059 {
1800297a64e7Sgd78059 	(void) eri_rxmac_disable(erip); /* Disable the RX MAC */
1801297a64e7Sgd78059 
1802297a64e7Sgd78059 	/* Disable the RX DMA */
1803297a64e7Sgd78059 	PUT_ERXREG(config, GET_ERXREG(config) & ~GET_CONFIG_RXDMA_EN);
1804297a64e7Sgd78059 	ERI_DELAY(((GET_ERXREG(config) &  1) == 0), ERI_MAX_RST_DELAY);
1805297a64e7Sgd78059 	if ((GET_ERXREG(config) & 1) != 0)
1806297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
1807297a64e7Sgd78059 		    disable_erx_msg);
1808297a64e7Sgd78059 
1809297a64e7Sgd78059 	drv_usecwait(5000); /* Delay to insure no RX DMA activity */
1810297a64e7Sgd78059 
1811297a64e7Sgd78059 	PUT_SWRSTREG(reset, ERI_G_RESET_ERX | ERI_CACHE_LINE_SIZE);
1812297a64e7Sgd78059 	/*
1813297a64e7Sgd78059 	 * Wait until the reset is completed which is indicated by
1814297a64e7Sgd78059 	 * the reset bit cleared or time out..
1815297a64e7Sgd78059 	 */
1816297a64e7Sgd78059 	ERI_DELAY(((GET_SWRSTREG(reset) & (ERI_G_RESET_ERX)) ==
1817297a64e7Sgd78059 	    ERI_CACHE_LINE_SIZE), ERI_MAX_RST_DELAY);
1818297a64e7Sgd78059 	erip->rx_reset_issued = -1;
1819297a64e7Sgd78059 
1820297a64e7Sgd78059 	return ((GET_SWRSTREG(reset) & (ERI_G_RESET_ERX)) ? 1 : 0);
1821297a64e7Sgd78059 }
1822297a64e7Sgd78059 
1823297a64e7Sgd78059 /*
1824297a64e7Sgd78059  * Reset Just the TX Portion
1825297a64e7Sgd78059  * Return 0 upon success, 1 on failure.
1826297a64e7Sgd78059  * Resetting the txdma while there is a tx dma transaction on the bus, may cause
1827297a64e7Sgd78059  * bus hang or parity errors. To avoid this we would first disable the txdma by
1828297a64e7Sgd78059  * clearing the ENABLE bit (bit 0). To make sure it is disabled, we will poll
1829297a64e7Sgd78059  * it until it realy clears. Furthermore, to any TX DMA activity is subsided,
1830297a64e7Sgd78059  * we delay for 1 msec.
1831297a64e7Sgd78059  */
1832297a64e7Sgd78059 static uint32_t
eri_etx_reset(struct eri * erip)1833297a64e7Sgd78059 eri_etx_reset(struct eri *erip)
1834297a64e7Sgd78059 {
1835297a64e7Sgd78059 	(void) eri_txmac_disable(erip);
1836297a64e7Sgd78059 
1837297a64e7Sgd78059 	/* Disable the TX DMA */
1838297a64e7Sgd78059 	PUT_ETXREG(config, GET_ETXREG(config) & ~GET_CONFIG_TXDMA_EN);
1839297a64e7Sgd78059 #ifdef ORIG
1840297a64e7Sgd78059 	ERI_DELAY(((GET_ETXREG(config) &  1) == 0), ERI_MAX_RST_DELAY);
1841297a64e7Sgd78059 	if ((GET_ETXREG(config) &  1) != 0)
1842297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
1843297a64e7Sgd78059 		    disable_etx_msg);
1844297a64e7Sgd78059 	drv_usecwait(5000); /* Delay  to ensure DMA completed (if any). */
1845297a64e7Sgd78059 #endif
1846297a64e7Sgd78059 	drv_usecwait(5000); /* Delay  to ensure DMA completed (if any). */
1847297a64e7Sgd78059 	ERI_DELAY(((GET_ETXREG(config) &  1) == 0), ERI_MAX_RST_DELAY);
1848297a64e7Sgd78059 	if ((GET_ETXREG(config) &  1) != 0)
1849297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
1850297a64e7Sgd78059 		    disable_etx_msg);
1851297a64e7Sgd78059 
1852297a64e7Sgd78059 	PUT_SWRSTREG(reset, ERI_G_RESET_ETX | ERI_CACHE_LINE_SIZE);
1853297a64e7Sgd78059 
1854297a64e7Sgd78059 	/*
1855297a64e7Sgd78059 	 * Wait until the reset is completed which is indicated by the reset bit
1856297a64e7Sgd78059 	 * cleared or time out..
1857297a64e7Sgd78059 	 */
1858297a64e7Sgd78059 	ERI_DELAY(((GET_SWRSTREG(reset) & (ERI_G_RESET_ETX)) ==
1859297a64e7Sgd78059 	    ERI_CACHE_LINE_SIZE), ERI_MAX_RST_DELAY);
1860297a64e7Sgd78059 	erip->tx_reset_issued = -1;
1861297a64e7Sgd78059 
1862297a64e7Sgd78059 	if (GET_SWRSTREG(reset) &  (ERI_G_RESET_ETX)) {
1863297a64e7Sgd78059 		return (1);
1864297a64e7Sgd78059 	} else
1865297a64e7Sgd78059 		return (0);
1866297a64e7Sgd78059 }
1867297a64e7Sgd78059 
1868297a64e7Sgd78059 
1869297a64e7Sgd78059 /*
1870297a64e7Sgd78059  * Initialize the TX DMA registers and Enable the TX DMA.
1871297a64e7Sgd78059  */
1872297a64e7Sgd78059 static uint32_t
eri_init_txregs(struct eri * erip)1873297a64e7Sgd78059 eri_init_txregs(struct eri *erip)
1874297a64e7Sgd78059 {
1875297a64e7Sgd78059 
1876297a64e7Sgd78059 	uint32_t	i;
1877297a64e7Sgd78059 	uint64_t	tx_ring;
1878297a64e7Sgd78059 
1879297a64e7Sgd78059 	/*
1880297a64e7Sgd78059 	 * Initialize ETX Registers:
1881297a64e7Sgd78059 	 * config, txring_lo, txring_hi
1882297a64e7Sgd78059 	 */
1883297a64e7Sgd78059 	tx_ring = ERI_IOPBIOADDR(erip, erip->eri_tmdp);
1884297a64e7Sgd78059 	PUT_ETXREG(txring_lo, (uint32_t)(tx_ring));
1885297a64e7Sgd78059 	PUT_ETXREG(txring_hi, (uint32_t)(tx_ring >> 32));
1886297a64e7Sgd78059 
1887297a64e7Sgd78059 	/*
1888297a64e7Sgd78059 	 * Get TX Ring Size Masks.
1889297a64e7Sgd78059 	 * The ring size ERI_TPENDING is defined in eri_mac.h.
1890297a64e7Sgd78059 	 */
1891297a64e7Sgd78059 	switch (ERI_TPENDING) {
1892297a64e7Sgd78059 	case 32: i = ETX_RINGSZ_32;
1893297a64e7Sgd78059 		break;
1894297a64e7Sgd78059 	case 64: i = ETX_RINGSZ_64;
1895297a64e7Sgd78059 		break;
1896297a64e7Sgd78059 	case 128: i = ETX_RINGSZ_128;
1897297a64e7Sgd78059 		break;
1898297a64e7Sgd78059 	case 256: i = ETX_RINGSZ_256;
1899297a64e7Sgd78059 		break;
1900297a64e7Sgd78059 	case 512: i = ETX_RINGSZ_512;
1901297a64e7Sgd78059 		break;
1902297a64e7Sgd78059 	case 1024: i = ETX_RINGSZ_1024;
1903297a64e7Sgd78059 		break;
1904297a64e7Sgd78059 	case 2048: i = ETX_RINGSZ_2048;
1905297a64e7Sgd78059 		break;
1906297a64e7Sgd78059 	case 4096: i = ETX_RINGSZ_4096;
1907297a64e7Sgd78059 		break;
1908297a64e7Sgd78059 	default:
1909297a64e7Sgd78059 		ERI_FAULT_MSG2(erip, SEVERITY_HIGH, ERI_VERB_MSG,
1910297a64e7Sgd78059 		    unk_tx_descr_sze_msg, ERI_TPENDING);
1911297a64e7Sgd78059 		return (1);
1912297a64e7Sgd78059 	}
1913297a64e7Sgd78059 
1914297a64e7Sgd78059 	i <<= ERI_TX_RINGSZ_SHIFT;
1915297a64e7Sgd78059 	PUT_ETXREG(config, ETX_CONFIG_THRESHOLD | i);
1916297a64e7Sgd78059 	ENABLE_TXDMA(erip);
1917297a64e7Sgd78059 	ENABLE_MAC(erip);
1918297a64e7Sgd78059 	return (0);
1919297a64e7Sgd78059 }
1920297a64e7Sgd78059 
1921297a64e7Sgd78059 
1922297a64e7Sgd78059 /*
1923297a64e7Sgd78059  * Initialize the RX DMA registers and Enable the RX DMA.
1924297a64e7Sgd78059  */
1925297a64e7Sgd78059 static uint32_t
eri_init_rxregs(struct eri * erip)1926297a64e7Sgd78059 eri_init_rxregs(struct eri *erip)
1927297a64e7Sgd78059 {
1928297a64e7Sgd78059 	int i;
1929297a64e7Sgd78059 	uint64_t	rx_ring;
1930297a64e7Sgd78059 
1931297a64e7Sgd78059 	/*
1932297a64e7Sgd78059 	 * Initialize ERX Registers:
1933297a64e7Sgd78059 	 * rxring_lo, rxring_hi, config, rx_blanking, rx_pause_threshold.
1934297a64e7Sgd78059 	 * Also, rx_kick
1935297a64e7Sgd78059 	 * Read and save rxfifo_size.
1936297a64e7Sgd78059 	 * XXX: Use this to properly configure PAUSE threshold values.
1937297a64e7Sgd78059 	 */
1938297a64e7Sgd78059 	rx_ring = ERI_IOPBIOADDR(erip, erip->rmdp);
1939297a64e7Sgd78059 	PUT_ERXREG(rxring_lo, (uint32_t)(rx_ring));
1940297a64e7Sgd78059 	PUT_ERXREG(rxring_hi, (uint32_t)(rx_ring >> 32));
1941297a64e7Sgd78059 	PUT_ERXREG(rx_kick, erip->rx_kick);
1942297a64e7Sgd78059 
1943297a64e7Sgd78059 	/*
1944297a64e7Sgd78059 	 * The Max ring size, ERI_RMDMAX is defined in eri_mac.h.
1945297a64e7Sgd78059 	 * More ERI_RPENDING will provide better performance but requires more
1946297a64e7Sgd78059 	 * system DVMA memory.
1947297a64e7Sgd78059 	 * eri_rx_ring_size can be used to tune this value from /etc/system
1948297a64e7Sgd78059 	 * eri_rx_ring_size cannot be NDD'able due to non-recoverable errors
1949297a64e7Sgd78059 	 * which cannot be detected from NDD operations
1950297a64e7Sgd78059 	 */
1951297a64e7Sgd78059 
1952297a64e7Sgd78059 	/*
1953297a64e7Sgd78059 	 * get the rxring size bits
1954297a64e7Sgd78059 	 */
1955297a64e7Sgd78059 	switch (ERI_RPENDING) {
1956297a64e7Sgd78059 	case 32: i = ERX_RINGSZ_32;
1957297a64e7Sgd78059 		break;
1958297a64e7Sgd78059 	case 64: i = ERX_RINGSZ_64;
1959297a64e7Sgd78059 		break;
1960297a64e7Sgd78059 	case 128: i = ERX_RINGSZ_128;
1961297a64e7Sgd78059 		break;
1962297a64e7Sgd78059 	case 256: i = ERX_RINGSZ_256;
1963297a64e7Sgd78059 		break;
1964297a64e7Sgd78059 	case 512: i = ERX_RINGSZ_512;
1965297a64e7Sgd78059 		break;
1966297a64e7Sgd78059 	case 1024: i = ERX_RINGSZ_1024;
1967297a64e7Sgd78059 		break;
1968297a64e7Sgd78059 	case 2048: i = ERX_RINGSZ_2048;
1969297a64e7Sgd78059 		break;
1970297a64e7Sgd78059 	case 4096: i = ERX_RINGSZ_4096;
1971297a64e7Sgd78059 		break;
1972297a64e7Sgd78059 	default:
1973297a64e7Sgd78059 		ERI_FAULT_MSG2(erip, SEVERITY_HIGH, ERI_VERB_MSG,
1974297a64e7Sgd78059 		    unk_rx_descr_sze_msg, ERI_RPENDING);
1975297a64e7Sgd78059 		return (1);
1976297a64e7Sgd78059 	}
1977297a64e7Sgd78059 
1978297a64e7Sgd78059 	i <<= ERI_RX_RINGSZ_SHIFT;
1979297a64e7Sgd78059 	i |=  (ERI_FSTBYTE_OFFSET << ERI_RX_CONFIG_FBO_SHIFT) |
1980297a64e7Sgd78059 	    (ETHERHEADER_SIZE << ERI_RX_CONFIG_RX_CSSTART_SHIFT) |
1981297a64e7Sgd78059 	    (ERI_RX_FIFOTH_1024 << ERI_RX_CONFIG_RXFIFOTH_SHIFT);
1982297a64e7Sgd78059 
1983297a64e7Sgd78059 	PUT_ERXREG(config, i);
1984297a64e7Sgd78059 	PUT_ERXREG(rx_blanking,
1985297a64e7Sgd78059 	    (param_intr_blank_time << ERI_RX_BLNK_INTR_TIME_SHIFT) |
1986297a64e7Sgd78059 	    param_intr_blank_packets);
1987297a64e7Sgd78059 
1988297a64e7Sgd78059 	PUT_ERXREG(rx_pause_threshold, rx_pause_threshold);
1989297a64e7Sgd78059 	erip->rxfifo_size = GET_ERXREG(rxfifo_size);
1990297a64e7Sgd78059 	ENABLE_RXDMA(erip);
1991297a64e7Sgd78059 	return (0);
1992297a64e7Sgd78059 }
1993297a64e7Sgd78059 
1994297a64e7Sgd78059 static int
eri_freebufs(struct eri * erip)1995297a64e7Sgd78059 eri_freebufs(struct eri *erip)
1996297a64e7Sgd78059 {
1997297a64e7Sgd78059 	int status = 0;
1998297a64e7Sgd78059 
1999bd78278bSGarrett D'Amore 	status = eri_flush_rxbufs(erip);
2000297a64e7Sgd78059 	return (status);
2001297a64e7Sgd78059 }
2002297a64e7Sgd78059 
2003297a64e7Sgd78059 static void
eri_update_rxbufs(struct eri * erip)2004297a64e7Sgd78059 eri_update_rxbufs(struct eri *erip)
2005297a64e7Sgd78059 {
2006297a64e7Sgd78059 	int		i;
2007297a64e7Sgd78059 	volatile struct rmd  *rmdp, *rmdpbase;
2008297a64e7Sgd78059 
2009297a64e7Sgd78059 	/*
2010297a64e7Sgd78059 	 * Hang out receive buffers.
2011297a64e7Sgd78059 	 */
2012297a64e7Sgd78059 	rmdpbase = erip->rmdp;
2013297a64e7Sgd78059 	for (i = 0; i < ERI_RPENDING; i++) {
2014297a64e7Sgd78059 		rmdp = rmdpbase + i;
2015297a64e7Sgd78059 		UPDATE_RMD(rmdp);
2016297a64e7Sgd78059 	}
2017297a64e7Sgd78059 
2018297a64e7Sgd78059 	/*
2019297a64e7Sgd78059 	 * sync RXDMA descriptors.
2020297a64e7Sgd78059 	 */
2021297a64e7Sgd78059 	ERI_SYNCIOPB(erip, erip->rmdp, (ERI_RPENDING * sizeof (struct rmd)),
2022297a64e7Sgd78059 	    DDI_DMA_SYNC_FORDEV);
2023297a64e7Sgd78059 	/*
2024297a64e7Sgd78059 	 * Reset RMD 'walking' pointers.
2025297a64e7Sgd78059 	 */
2026297a64e7Sgd78059 	erip->rnextp =	erip->rmdp;
2027297a64e7Sgd78059 	erip->rx_completion = 0;
2028297a64e7Sgd78059 	erip->rx_kick =	ERI_RPENDING - 4;
2029297a64e7Sgd78059 }
2030297a64e7Sgd78059 
2031297a64e7Sgd78059 /*
2032297a64e7Sgd78059  * This routine is used to reset the RX DMA only. In the case of RX
2033297a64e7Sgd78059  * failures such as RX Tag Error, RX hang etc... we don't want to
2034297a64e7Sgd78059  * do global reset which takes down the link and clears the FIFO's
2035297a64e7Sgd78059  * By doing RX only reset, we leave the TX and the link intact.
2036297a64e7Sgd78059  */
2037297a64e7Sgd78059 static uint32_t
eri_init_rx_channel(struct eri * erip)2038297a64e7Sgd78059 eri_init_rx_channel(struct eri *erip)
2039297a64e7Sgd78059 {
2040297a64e7Sgd78059 	erip->flags &= ~ERI_RXINIT;
2041297a64e7Sgd78059 	(void) eri_erx_reset(erip);
2042297a64e7Sgd78059 	eri_update_rxbufs(erip);
2043297a64e7Sgd78059 	if (eri_init_rxregs(erip))
2044297a64e7Sgd78059 		return (1);
2045297a64e7Sgd78059 	PUT_MACREG(rxmask, BMAC_RXINTR_MASK);
2046297a64e7Sgd78059 	PUT_MACREG(rxcfg, GET_MACREG(rxcfg) | BMAC_RXCFG_ENAB);
2047297a64e7Sgd78059 	erip->rx_reset_issued = 0;
2048297a64e7Sgd78059 	HSTAT(erip, rx_inits);
2049297a64e7Sgd78059 	erip->flags |= ERI_RXINIT;
2050297a64e7Sgd78059 	return (0);
2051297a64e7Sgd78059 }
2052297a64e7Sgd78059 
2053297a64e7Sgd78059 static void
eri_init_rx(struct eri * erip)2054297a64e7Sgd78059 eri_init_rx(struct eri *erip)
2055297a64e7Sgd78059 {
2056297a64e7Sgd78059 	uint16_t	*ladrf;
2057297a64e7Sgd78059 
2058297a64e7Sgd78059 	/*
2059297a64e7Sgd78059 	 * First of all make sure the Receive MAC is stop.
2060297a64e7Sgd78059 	 */
2061297a64e7Sgd78059 	(void) eri_rxmac_disable(erip); /* Disable the RX MAC */
2062297a64e7Sgd78059 
2063297a64e7Sgd78059 	/*
2064297a64e7Sgd78059 	 * Program BigMAC with local individual ethernet address.
2065297a64e7Sgd78059 	 */
2066297a64e7Sgd78059 
2067297a64e7Sgd78059 	PUT_MACREG(madd0, (erip->ouraddr[4] << 8) | erip->ouraddr[5]);
2068297a64e7Sgd78059 	PUT_MACREG(madd1, (erip->ouraddr[2] << 8) | erip->ouraddr[3]);
2069297a64e7Sgd78059 	PUT_MACREG(madd2, (erip->ouraddr[0] << 8) | erip->ouraddr[1]);
2070297a64e7Sgd78059 
2071297a64e7Sgd78059 	/*
2072297a64e7Sgd78059 	 * Set up multicast address filter by passing all multicast
2073297a64e7Sgd78059 	 * addresses through a crc generator, and then using the
2074297a64e7Sgd78059 	 * low order 8 bits as a index into the 256 bit logical
2075297a64e7Sgd78059 	 * address filter. The high order four bits select the word,
2076297a64e7Sgd78059 	 * while the rest of the bits select the bit within the word.
2077297a64e7Sgd78059 	 */
2078297a64e7Sgd78059 
2079297a64e7Sgd78059 	ladrf = erip->ladrf;
2080297a64e7Sgd78059 
2081297a64e7Sgd78059 	PUT_MACREG(hash0, ladrf[0]);
2082297a64e7Sgd78059 	PUT_MACREG(hash1, ladrf[1]);
2083297a64e7Sgd78059 	PUT_MACREG(hash2, ladrf[2]);
2084297a64e7Sgd78059 	PUT_MACREG(hash3, ladrf[3]);
2085297a64e7Sgd78059 	PUT_MACREG(hash4, ladrf[4]);
2086297a64e7Sgd78059 	PUT_MACREG(hash5, ladrf[5]);
2087297a64e7Sgd78059 	PUT_MACREG(hash6, ladrf[6]);
2088297a64e7Sgd78059 	PUT_MACREG(hash7, ladrf[7]);
2089297a64e7Sgd78059 	PUT_MACREG(hash8, ladrf[8]);
2090297a64e7Sgd78059 	PUT_MACREG(hash9, ladrf[9]);
2091297a64e7Sgd78059 	PUT_MACREG(hash10, ladrf[10]);
2092297a64e7Sgd78059 	PUT_MACREG(hash11, ladrf[11]);
2093297a64e7Sgd78059 	PUT_MACREG(hash12, ladrf[12]);
2094297a64e7Sgd78059 	PUT_MACREG(hash13, ladrf[13]);
2095297a64e7Sgd78059 	PUT_MACREG(hash14, ladrf[14]);
2096297a64e7Sgd78059 	PUT_MACREG(hash15, ladrf[15]);
2097297a64e7Sgd78059 
2098297a64e7Sgd78059 #ifdef ERI_DONT_STRIP_CRC
2099297a64e7Sgd78059 	PUT_MACREG(rxcfg,
2100297a64e7Sgd78059 	    ((erip->promisc ? BMAC_RXCFG_PROMIS : 0) |
2101297a64e7Sgd78059 	    (erip->multi_refcnt ? BMAC_RXCFG_HASH : 0) |
2102297a64e7Sgd78059 	    BMAC_RXCFG_ENAB));
2103297a64e7Sgd78059 #else
2104297a64e7Sgd78059 	PUT_MACREG(rxcfg,
2105297a64e7Sgd78059 	    ((erip->promisc ? BMAC_RXCFG_PROMIS : 0) |
2106297a64e7Sgd78059 	    (erip->multi_refcnt ? BMAC_RXCFG_HASH : 0) |
2107297a64e7Sgd78059 	    BMAC_RXCFG_ENAB | BMAC_RXCFG_STRIP_CRC));
2108297a64e7Sgd78059 #endif
2109297a64e7Sgd78059 	/* wait after setting Hash Enable bit */
2110297a64e7Sgd78059 	/* drv_usecwait(10); */
2111297a64e7Sgd78059 
2112297a64e7Sgd78059 	HSTAT(erip, rx_inits);
2113297a64e7Sgd78059 }
2114297a64e7Sgd78059 
2115297a64e7Sgd78059 /*
2116297a64e7Sgd78059  * This routine is used to init the TX MAC only.
2117297a64e7Sgd78059  *	&erip->xmitlock is held before calling this routine.
2118297a64e7Sgd78059  */
2119297a64e7Sgd78059 void
eri_init_txmac(struct eri * erip)2120297a64e7Sgd78059 eri_init_txmac(struct eri *erip)
2121297a64e7Sgd78059 {
2122297a64e7Sgd78059 	uint32_t carrier_ext = 0;
2123297a64e7Sgd78059 
2124297a64e7Sgd78059 	erip->flags &= ~ERI_TXINIT;
2125297a64e7Sgd78059 	/*
2126297a64e7Sgd78059 	 * Stop the Transmit MAC.
2127297a64e7Sgd78059 	 */
2128297a64e7Sgd78059 	(void) eri_txmac_disable(erip);
2129297a64e7Sgd78059 
2130297a64e7Sgd78059 	/*
2131297a64e7Sgd78059 	 * Must be Internal Transceiver
2132297a64e7Sgd78059 	 */
2133297a64e7Sgd78059 	if (param_mode)
2134297a64e7Sgd78059 		PUT_MACREG(xifc, ((param_transceiver == EXTERNAL_XCVR ?
2135297a64e7Sgd78059 		    BMAC_XIFC_MIIBUF_OE : 0) | BMAC_XIFC_TX_MII_OE));
2136297a64e7Sgd78059 	else
2137297a64e7Sgd78059 		PUT_MACREG(xifc, ((param_transceiver == EXTERNAL_XCVR ?
2138297a64e7Sgd78059 		    BMAC_XIFC_MIIBUF_OE : 0) | BMAC_XIFC_TX_MII_OE |
2139297a64e7Sgd78059 		    BMAC_XIFC_DIS_ECHO));
2140297a64e7Sgd78059 
2141297a64e7Sgd78059 	/*
2142297a64e7Sgd78059 	 * Initialize the interpacket gap registers
2143297a64e7Sgd78059 	 */
2144297a64e7Sgd78059 	PUT_MACREG(ipg1, param_ipg1);
2145297a64e7Sgd78059 	PUT_MACREG(ipg2, param_ipg2);
2146297a64e7Sgd78059 
2147297a64e7Sgd78059 	if (erip->ngu_enable)
2148297a64e7Sgd78059 		PUT_MACREG(txcfg, ((param_mode ? BMAC_TXCFG_FDX: 0) |
2149297a64e7Sgd78059 		    ((param_lance_mode && (erip->lance_mode_enable)) ?
2150297a64e7Sgd78059 		    BMAC_TXCFG_ENIPG0 : 0) |
2151297a64e7Sgd78059 		    (carrier_ext ? BMAC_TXCFG_CARR_EXT : 0) |
2152297a64e7Sgd78059 		    BMAC_TXCFG_NGU));
2153297a64e7Sgd78059 	else
2154297a64e7Sgd78059 		PUT_MACREG(txcfg, ((param_mode ? BMAC_TXCFG_FDX: 0) |
2155297a64e7Sgd78059 		    ((param_lance_mode && (erip->lance_mode_enable)) ?
2156297a64e7Sgd78059 		    BMAC_TXCFG_ENIPG0 : 0) |
2157297a64e7Sgd78059 		    (carrier_ext ? BMAC_TXCFG_CARR_EXT : 0)));
2158297a64e7Sgd78059 
2159297a64e7Sgd78059 	ENABLE_TXDMA(erip);
2160297a64e7Sgd78059 	ENABLE_TXMAC(erip);
2161297a64e7Sgd78059 
2162297a64e7Sgd78059 	HSTAT(erip, tx_inits);
2163297a64e7Sgd78059 	erip->flags |= ERI_TXINIT;
2164297a64e7Sgd78059 }
2165297a64e7Sgd78059 
2166297a64e7Sgd78059 static void
eri_unallocthings(struct eri * erip)2167297a64e7Sgd78059 eri_unallocthings(struct eri *erip)
2168297a64e7Sgd78059 {
2169297a64e7Sgd78059 	uint32_t	flag;
2170297a64e7Sgd78059 	uint32_t	i;
2171297a64e7Sgd78059 
2172297a64e7Sgd78059 	flag = erip->alloc_flag;
2173297a64e7Sgd78059 
2174297a64e7Sgd78059 	if (flag & ERI_DESC_MEM_MAP)
2175297a64e7Sgd78059 		(void) ddi_dma_unbind_handle(erip->md_h);
2176297a64e7Sgd78059 
2177297a64e7Sgd78059 	if (flag & ERI_DESC_MEM_ALLOC) {
2178297a64e7Sgd78059 		ddi_dma_mem_free(&erip->mdm_h);
2179297a64e7Sgd78059 		erip->rmdp = NULL;
2180297a64e7Sgd78059 		erip->eri_tmdp = NULL;
2181297a64e7Sgd78059 	}
2182297a64e7Sgd78059 
2183297a64e7Sgd78059 	if (flag & ERI_DESC_HANDLE_ALLOC)
2184297a64e7Sgd78059 		ddi_dma_free_handle(&erip->md_h);
2185297a64e7Sgd78059 
2186297a64e7Sgd78059 	(void) eri_freebufs(erip);
2187297a64e7Sgd78059 
2188297a64e7Sgd78059 	if (flag & ERI_RCV_HANDLE_ALLOC)
2189297a64e7Sgd78059 		for (i = 0; i < erip->rcv_handle_cnt; i++)
2190297a64e7Sgd78059 			ddi_dma_free_handle(&erip->ndmarh[i]);
2191297a64e7Sgd78059 
2192297a64e7Sgd78059 	if (flag & ERI_RCV_DVMA_ALLOC) {
2193297a64e7Sgd78059 		(void) dvma_release(erip->eri_dvmarh);
2194297a64e7Sgd78059 		erip->eri_dvmarh = NULL;
2195297a64e7Sgd78059 	}
2196297a64e7Sgd78059 
2197297a64e7Sgd78059 	if (flag & ERI_XBUFS_KMEM_DMABIND) {
2198297a64e7Sgd78059 		(void) ddi_dma_unbind_handle(erip->tbuf_handle);
2199297a64e7Sgd78059 		erip->tbuf_ioaddr = 0;
2200297a64e7Sgd78059 	}
2201297a64e7Sgd78059 
2202297a64e7Sgd78059 	if (flag & ERI_XBUFS_KMEM_ALLOC) {
2203bd78278bSGarrett D'Amore 		ddi_dma_mem_free(&erip->tbuf_acch);
2204297a64e7Sgd78059 		erip->tbuf_kaddr = NULL;
2205297a64e7Sgd78059 	}
2206297a64e7Sgd78059 
2207297a64e7Sgd78059 	if (flag & ERI_XBUFS_HANDLE_ALLOC) {
2208297a64e7Sgd78059 		ddi_dma_free_handle(&erip->tbuf_handle);
2209297a64e7Sgd78059 		erip->tbuf_handle = NULL;
2210297a64e7Sgd78059 	}
2211297a64e7Sgd78059 
2212297a64e7Sgd78059 }
2213297a64e7Sgd78059 
2214297a64e7Sgd78059 /*
2215297a64e7Sgd78059  * Initialize channel.
2216297a64e7Sgd78059  * Return true on success, false on error.
2217297a64e7Sgd78059  *
2218297a64e7Sgd78059  * The recommended sequence for initialization is:
2219297a64e7Sgd78059  * 1. Issue a Global Reset command to the Ethernet Channel.
2220297a64e7Sgd78059  * 2. Poll the Global_Reset bits until the execution of the reset has been
2221297a64e7Sgd78059  *    completed.
2222297a64e7Sgd78059  * 2(a). Use the MIF Frame/Output register to reset the transceiver.
2223297a64e7Sgd78059  *	 Poll Register 0 to till the Resetbit is 0.
2224297a64e7Sgd78059  * 2(b). Use the MIF Frame/Output register to set the PHY in in Normal-Op,
2225297a64e7Sgd78059  *	 100Mbps and Non-Isolated mode. The main point here is to bring the
2226297a64e7Sgd78059  *	 PHY out of Isolate mode so that it can generate the rx_clk and tx_clk
2227297a64e7Sgd78059  *	 to the MII interface so that the Bigmac core can correctly reset
2228297a64e7Sgd78059  *	 upon a software reset.
2229297a64e7Sgd78059  * 2(c).  Issue another Global Reset command to the Ethernet Channel and poll
2230297a64e7Sgd78059  *	  the Global_Reset bits till completion.
2231297a64e7Sgd78059  * 3. Set up all the data structures in the host memory.
2232297a64e7Sgd78059  * 4. Program the TX_MAC registers/counters (excluding the TX_MAC Configuration
2233297a64e7Sgd78059  *    Register).
2234297a64e7Sgd78059  * 5. Program the RX_MAC registers/counters (excluding the RX_MAC Configuration
2235297a64e7Sgd78059  *    Register).
2236297a64e7Sgd78059  * 6. Program the Transmit Descriptor Ring Base Address in the ETX.
2237297a64e7Sgd78059  * 7. Program the Receive Descriptor Ring Base Address in the ERX.
2238297a64e7Sgd78059  * 8. Program the Global Configuration and the Global Interrupt Mask Registers.
2239297a64e7Sgd78059  * 9. Program the ETX Configuration register (enable the Transmit DMA channel).
2240297a64e7Sgd78059  * 10. Program the ERX Configuration register (enable the Receive DMA channel).
2241297a64e7Sgd78059  * 11. Program the XIF Configuration Register (enable the XIF).
2242297a64e7Sgd78059  * 12. Program the RX_MAC Configuration Register (Enable the RX_MAC).
2243297a64e7Sgd78059  * 13. Program the TX_MAC Configuration Register (Enable the TX_MAC).
2244297a64e7Sgd78059  */
2245297a64e7Sgd78059 /*
2246297a64e7Sgd78059  * lock order:
2247297a64e7Sgd78059  *	intrlock->linklock->xmitlock->xcvrlock
2248297a64e7Sgd78059  */
2249297a64e7Sgd78059 static boolean_t
eri_init(struct eri * erip)2250297a64e7Sgd78059 eri_init(struct eri *erip)
2251297a64e7Sgd78059 {
2252297a64e7Sgd78059 	uint32_t	init_stat = 0;
2253297a64e7Sgd78059 	uint32_t	partial_init = 0;
2254297a64e7Sgd78059 	uint32_t	carrier_ext = 0;
2255297a64e7Sgd78059 	uint32_t	mac_ctl = 0;
2256297a64e7Sgd78059 	boolean_t	ret;
2257297a64e7Sgd78059 	uint32_t 	link_timeout = ERI_LINKCHECK_TIMER;
2258297a64e7Sgd78059 	link_state_t	linkupdate = LINK_STATE_UNKNOWN;
2259297a64e7Sgd78059 
2260297a64e7Sgd78059 	/*
2261297a64e7Sgd78059 	 * Just return successfully if device is suspended.
2262297a64e7Sgd78059 	 * eri_init() will be called again from resume.
2263297a64e7Sgd78059 	 */
2264297a64e7Sgd78059 	ASSERT(erip != NULL);
2265297a64e7Sgd78059 
2266297a64e7Sgd78059 	if (erip->flags & ERI_SUSPENDED) {
2267297a64e7Sgd78059 		ret = B_TRUE;
2268297a64e7Sgd78059 		goto init_exit;
2269297a64e7Sgd78059 	}
2270297a64e7Sgd78059 
2271297a64e7Sgd78059 	mutex_enter(&erip->intrlock);
2272297a64e7Sgd78059 	eri_stop_timer(erip);	/* acquire linklock */
2273297a64e7Sgd78059 	mutex_enter(&erip->xmitlock);
2274297a64e7Sgd78059 	erip->flags &= (ERI_DLPI_LINKUP | ERI_STARTED);
2275297a64e7Sgd78059 	erip->wantw = B_FALSE;
2276297a64e7Sgd78059 	HSTAT(erip, inits);
2277297a64e7Sgd78059 	erip->txhung = 0;
2278297a64e7Sgd78059 
2279297a64e7Sgd78059 	if ((erip->stats.inits > 1) && (erip->init_macregs == 0))
2280297a64e7Sgd78059 		eri_savecntrs(erip);
2281297a64e7Sgd78059 
2282297a64e7Sgd78059 	mutex_enter(&erip->xcvrlock);
2283297a64e7Sgd78059 	if (!param_linkup || erip->linkcheck) {
2284297a64e7Sgd78059 		if (!erip->linkcheck)
2285297a64e7Sgd78059 			linkupdate = LINK_STATE_DOWN;
2286297a64e7Sgd78059 		(void) eri_stop(erip);
2287297a64e7Sgd78059 	}
2288297a64e7Sgd78059 	if (!(erip->flags & ERI_DLPI_LINKUP) || !param_linkup) {
2289297a64e7Sgd78059 		erip->flags |= ERI_DLPI_LINKUP;
2290297a64e7Sgd78059 		eri_mif_poll(erip, MIF_POLL_STOP);
2291297a64e7Sgd78059 		(void) eri_new_xcvr(erip);
2292297a64e7Sgd78059 		ERI_DEBUG_MSG1(erip, XCVR_MSG, "New transceiver detected.");
2293297a64e7Sgd78059 		if (param_transceiver != NO_XCVR) {
2294297a64e7Sgd78059 			/*
2295297a64e7Sgd78059 			 * Reset the new PHY and bring up the
2296297a64e7Sgd78059 			 * link
2297297a64e7Sgd78059 			 */
2298297a64e7Sgd78059 			if (eri_reset_xcvr(erip)) {
2299297a64e7Sgd78059 				ERI_FAULT_MSG1(erip, SEVERITY_NONE,
2300297a64e7Sgd78059 				    ERI_VERB_MSG, "In Init after reset");
2301297a64e7Sgd78059 				mutex_exit(&erip->xcvrlock);
2302297a64e7Sgd78059 				link_timeout = 0;
2303297a64e7Sgd78059 				goto done;
2304297a64e7Sgd78059 			}
2305297a64e7Sgd78059 			if (erip->stats.link_up == LINK_STATE_UP)
2306297a64e7Sgd78059 				linkupdate = LINK_STATE_UP;
2307297a64e7Sgd78059 		} else {
2308297a64e7Sgd78059 			erip->flags |= (ERI_RUNNING | ERI_INITIALIZED);
2309297a64e7Sgd78059 			param_linkup = 0;
2310297a64e7Sgd78059 			erip->stats.link_up = LINK_STATE_DOWN;
2311297a64e7Sgd78059 			erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
2312297a64e7Sgd78059 			linkupdate = LINK_STATE_DOWN;
2313297a64e7Sgd78059 			/*
2314297a64e7Sgd78059 			 * Still go on and complete the MAC initialization as
2315297a64e7Sgd78059 			 * xcvr might show up later.
2316297a64e7Sgd78059 			 * you must return to their mutex ordering.
2317297a64e7Sgd78059 			 */
2318297a64e7Sgd78059 		}
2319297a64e7Sgd78059 		eri_mif_poll(erip, MIF_POLL_START);
2320297a64e7Sgd78059 	}
2321297a64e7Sgd78059 
2322297a64e7Sgd78059 	mutex_exit(&erip->xcvrlock);
2323297a64e7Sgd78059 
2324297a64e7Sgd78059 	/*
2325297a64e7Sgd78059 	 * Allocate data structures.
2326297a64e7Sgd78059 	 */
2327297a64e7Sgd78059 	if (erip->global_reset_issued) {
2328297a64e7Sgd78059 		if (erip->global_reset_issued == 2) { /* fast path */
2329bd78278bSGarrett D'Amore 
2330297a64e7Sgd78059 			/*
2331297a64e7Sgd78059 			 * Hang out/Initialize descriptors and buffers.
2332297a64e7Sgd78059 			 */
2333297a64e7Sgd78059 			eri_init_txbufs(erip);
2334297a64e7Sgd78059 
2335297a64e7Sgd78059 			eri_update_rxbufs(erip);
2336297a64e7Sgd78059 		} else {
2337297a64e7Sgd78059 			init_stat = eri_allocthings(erip);
2338297a64e7Sgd78059 			if (init_stat)
2339297a64e7Sgd78059 				goto done;
2340297a64e7Sgd78059 
2341297a64e7Sgd78059 			if (eri_freebufs(erip))
2342297a64e7Sgd78059 				goto done;
2343297a64e7Sgd78059 			/*
2344297a64e7Sgd78059 			 * Hang out/Initialize descriptors and buffers.
2345297a64e7Sgd78059 			 */
2346297a64e7Sgd78059 			eri_init_txbufs(erip);
2347297a64e7Sgd78059 			if (eri_init_rxbufs(erip))
2348297a64e7Sgd78059 				goto done;
2349297a64e7Sgd78059 		}
2350297a64e7Sgd78059 	}
2351297a64e7Sgd78059 
2352297a64e7Sgd78059 	/*
2353297a64e7Sgd78059 	 * BigMAC requires that we confirm that tx, rx and hash are in
2354297a64e7Sgd78059 	 * quiescent state.
2355297a64e7Sgd78059 	 * MAC will not reset successfully if the transceiver is not reset and
2356297a64e7Sgd78059 	 * brought out of Isolate mode correctly. TXMAC reset may fail if the
2357297a64e7Sgd78059 	 * ext. transceiver is just disconnected. If it fails, try again by
2358297a64e7Sgd78059 	 * checking the transceiver.
2359297a64e7Sgd78059 	 */
2360297a64e7Sgd78059 	if (eri_txmac_disable(erip)) {
2361297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
2362297a64e7Sgd78059 		    disable_txmac_msg);
2363297a64e7Sgd78059 		param_linkup = 0;	/* force init again */
2364297a64e7Sgd78059 		erip->stats.link_up = LINK_STATE_DOWN;
2365297a64e7Sgd78059 		erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
2366297a64e7Sgd78059 		linkupdate = LINK_STATE_DOWN;
2367297a64e7Sgd78059 		goto done;
2368297a64e7Sgd78059 	}
2369297a64e7Sgd78059 
2370297a64e7Sgd78059 	if (eri_rxmac_disable(erip)) {
2371297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
2372297a64e7Sgd78059 		    disable_rxmac_msg);
2373297a64e7Sgd78059 		param_linkup = 0;	/* force init again */
2374297a64e7Sgd78059 		erip->stats.link_up = LINK_STATE_DOWN;
2375297a64e7Sgd78059 		erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
2376297a64e7Sgd78059 		linkupdate = LINK_STATE_DOWN;
2377297a64e7Sgd78059 		goto done;
2378297a64e7Sgd78059 	}
2379297a64e7Sgd78059 
2380297a64e7Sgd78059 	eri_init_macregs_generic(erip);
2381297a64e7Sgd78059 
2382297a64e7Sgd78059 	/*
2383297a64e7Sgd78059 	 * Initialize ERI Global registers :
2384297a64e7Sgd78059 	 * config
2385297a64e7Sgd78059 	 * For PCI :  err_mask, bif_cfg
2386297a64e7Sgd78059 	 *
2387297a64e7Sgd78059 	 * Use user-configurable parameter for enabling 64-bit transfers.
2388297a64e7Sgd78059 	 * Note:For PCI, burst sizes are in multiples of 64-bytes.
2389297a64e7Sgd78059 	 */
2390297a64e7Sgd78059 
2391297a64e7Sgd78059 	/*
2392297a64e7Sgd78059 	 * Significant performance improvements can be achieved by
2393297a64e7Sgd78059 	 * disabling transmit interrupt. Thus TMD's are reclaimed
2394297a64e7Sgd78059 	 * only very infrequently.
2395297a64e7Sgd78059 	 * The PCS Interrupt is masked here. It is enabled only when
2396297a64e7Sgd78059 	 * a PCS link is brought up because there is no second level
2397297a64e7Sgd78059 	 * mask for this interrupt..
2398297a64e7Sgd78059 	 * Init GLOBAL, TXMAC, RXMAC and MACCTL interrupt masks here.
2399297a64e7Sgd78059 	 */
2400297a64e7Sgd78059 	if (! partial_init) {
2401297a64e7Sgd78059 		PUT_GLOBREG(intmask, ERI_G_MASK_INTR);
2402297a64e7Sgd78059 		erip->tx_int_me = 0;
2403297a64e7Sgd78059 		PUT_MACREG(txmask, BMAC_TXINTR_MASK);
2404297a64e7Sgd78059 		PUT_MACREG(rxmask, BMAC_RXINTR_MASK);
2405297a64e7Sgd78059 		PUT_MACREG(macctl_mask, ERI_MACCTL_INTR_MASK);
2406297a64e7Sgd78059 	}
2407297a64e7Sgd78059 
2408297a64e7Sgd78059 	if (erip->global_reset_issued) {
2409297a64e7Sgd78059 		/*
2410297a64e7Sgd78059 		 * Initialize ETX Registers:
2411297a64e7Sgd78059 		 * config, txring_lo, txring_hi
2412297a64e7Sgd78059 		 */
2413297a64e7Sgd78059 		if (eri_init_txregs(erip))
2414297a64e7Sgd78059 			goto done;
2415297a64e7Sgd78059 		/*
2416297a64e7Sgd78059 		 * Initialize ERX Registers:
2417297a64e7Sgd78059 		 * rxring_lo, rxring_hi, config, rx_blanking,
2418297a64e7Sgd78059 		 * rx_pause_threshold.  Also, rx_kick
2419297a64e7Sgd78059 		 * Read and save rxfifo_size.
2420297a64e7Sgd78059 		 */
2421297a64e7Sgd78059 		if (eri_init_rxregs(erip))
2422297a64e7Sgd78059 			goto done;
2423297a64e7Sgd78059 	}
2424297a64e7Sgd78059 
2425297a64e7Sgd78059 	PUT_MACREG(macctl_mask, ERI_MACCTL_INTR_MASK);
2426297a64e7Sgd78059 
2427297a64e7Sgd78059 	/*
2428297a64e7Sgd78059 	 * Set up the slottime,and  rxconfig, txconfig without enabling
2429297a64e7Sgd78059 	 * the latter two at this time
2430297a64e7Sgd78059 	 */
2431297a64e7Sgd78059 	PUT_MACREG(slot, BMAC_SLOT_TIME);
2432297a64e7Sgd78059 	carrier_ext = 0;
2433297a64e7Sgd78059 
2434297a64e7Sgd78059 #ifdef ERI_DONT_STRIP_CRC
2435297a64e7Sgd78059 	PUT_MACREG(rxcfg,
2436297a64e7Sgd78059 	    ((erip->promisc ? BMAC_RXCFG_PROMIS : 0) |
2437297a64e7Sgd78059 	    (erip->multi_refcnt ? BMAC_RXCFG_HASH : 0) |
2438297a64e7Sgd78059 	    (carrier_ext ? BMAC_RXCFG_CARR_EXT : 0)));
2439297a64e7Sgd78059 #else
2440297a64e7Sgd78059 	PUT_MACREG(rxcfg,
2441297a64e7Sgd78059 	    ((erip->promisc ? BMAC_RXCFG_PROMIS : 0) |
2442297a64e7Sgd78059 	    (erip->multi_refcnt ? BMAC_RXCFG_HASH : 0) |
2443297a64e7Sgd78059 	    BMAC_RXCFG_STRIP_CRC |
2444297a64e7Sgd78059 	    (carrier_ext ? BMAC_RXCFG_CARR_EXT : 0)));
2445297a64e7Sgd78059 #endif
2446297a64e7Sgd78059 	drv_usecwait(10);	/* wait after setting Hash Enable bit */
2447297a64e7Sgd78059 
2448297a64e7Sgd78059 	if (erip->ngu_enable)
2449297a64e7Sgd78059 		PUT_MACREG(txcfg,
2450297a64e7Sgd78059 		    ((param_mode ? BMAC_TXCFG_FDX: 0) |
2451297a64e7Sgd78059 		    ((param_lance_mode && (erip->lance_mode_enable)) ?
2452297a64e7Sgd78059 		    BMAC_TXCFG_ENIPG0 : 0) |
2453297a64e7Sgd78059 		    (carrier_ext ? BMAC_TXCFG_CARR_EXT : 0) |
2454297a64e7Sgd78059 		    BMAC_TXCFG_NGU));
2455297a64e7Sgd78059 	else
2456297a64e7Sgd78059 		PUT_MACREG(txcfg,
2457297a64e7Sgd78059 		    ((param_mode ? BMAC_TXCFG_FDX: 0) |
2458297a64e7Sgd78059 		    ((param_lance_mode && (erip->lance_mode_enable)) ?
2459297a64e7Sgd78059 		    BMAC_TXCFG_ENIPG0 : 0) |
2460297a64e7Sgd78059 		    (carrier_ext ? BMAC_TXCFG_CARR_EXT : 0)));
2461297a64e7Sgd78059 
2462297a64e7Sgd78059 	if (erip->pauseRX)
2463297a64e7Sgd78059 		mac_ctl = ERI_MCTLCFG_RXPAUSE;
2464297a64e7Sgd78059 	if (erip->pauseTX)
2465297a64e7Sgd78059 		mac_ctl |= ERI_MCTLCFG_TXPAUSE;
2466297a64e7Sgd78059 
2467297a64e7Sgd78059 	PUT_MACREG(macctl_cfg, mac_ctl);
2468297a64e7Sgd78059 
2469297a64e7Sgd78059 	/*
2470297a64e7Sgd78059 	 * Must be Internal Transceiver
2471297a64e7Sgd78059 	 */
2472297a64e7Sgd78059 	if (param_mode)
2473297a64e7Sgd78059 		PUT_MACREG(xifc, ((param_transceiver == EXTERNAL_XCVR ?
2474297a64e7Sgd78059 		    BMAC_XIFC_MIIBUF_OE : 0) | BMAC_XIFC_TX_MII_OE));
2475297a64e7Sgd78059 	else {
2476297a64e7Sgd78059 		PUT_MACREG(xifc, ((param_transceiver == EXTERNAL_XCVR ?
2477297a64e7Sgd78059 		    BMAC_XIFC_MIIBUF_OE : 0) | BMAC_XIFC_TX_MII_OE |
2478297a64e7Sgd78059 		    BMAC_XIFC_DIS_ECHO));
2479297a64e7Sgd78059 
2480297a64e7Sgd78059 		link_timeout = ERI_CHECK_HANG_TIMER;
2481297a64e7Sgd78059 	}
2482297a64e7Sgd78059 
2483297a64e7Sgd78059 	/*
2484297a64e7Sgd78059 	 * if MAC int loopback flag is set, put xifc reg in mii loopback
2485297a64e7Sgd78059 	 * mode {DIAG}
2486297a64e7Sgd78059 	 */
2487297a64e7Sgd78059 	if (erip->flags & ERI_MACLOOPBACK) {
2488297a64e7Sgd78059 		PUT_MACREG(xifc, GET_MACREG(xifc) | BMAC_XIFC_MIILPBK);
2489297a64e7Sgd78059 	}
2490297a64e7Sgd78059 
2491297a64e7Sgd78059 	/*
2492297a64e7Sgd78059 	 * Enable TX and RX MACs.
2493297a64e7Sgd78059 	 */
2494297a64e7Sgd78059 	ENABLE_MAC(erip);
2495297a64e7Sgd78059 	erip->flags |= (ERI_RUNNING | ERI_INITIALIZED |
2496297a64e7Sgd78059 	    ERI_TXINIT | ERI_RXINIT);
2497297a64e7Sgd78059 	mac_tx_update(erip->mh);
2498297a64e7Sgd78059 	erip->global_reset_issued = 0;
2499297a64e7Sgd78059 
2500297a64e7Sgd78059 #ifdef	ERI_10_10_FORCE_SPEED_WORKAROUND
2501297a64e7Sgd78059 	eri_xcvr_force_mode(erip, &link_timeout);
2502297a64e7Sgd78059 #endif
2503297a64e7Sgd78059 
2504297a64e7Sgd78059 done:
2505297a64e7Sgd78059 	if (init_stat)
2506297a64e7Sgd78059 		eri_unallocthings(erip);
2507297a64e7Sgd78059 
2508297a64e7Sgd78059 	mutex_exit(&erip->xmitlock);
2509297a64e7Sgd78059 	eri_start_timer(erip, eri_check_link, link_timeout);
2510297a64e7Sgd78059 	mutex_exit(&erip->intrlock);
2511297a64e7Sgd78059 
2512297a64e7Sgd78059 	if (linkupdate != LINK_STATE_UNKNOWN)
2513297a64e7Sgd78059 		mac_link_update(erip->mh, linkupdate);
2514297a64e7Sgd78059 
2515297a64e7Sgd78059 	ret = (erip->flags & ERI_RUNNING) ? B_TRUE : B_FALSE;
2516297a64e7Sgd78059 	if (!ret) {
2517297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
2518297a64e7Sgd78059 		    "eri_init failed");
2519297a64e7Sgd78059 	}
2520297a64e7Sgd78059 
2521297a64e7Sgd78059 init_exit:
2522297a64e7Sgd78059 	ASSERT(!MUTEX_HELD(&erip->linklock));
2523297a64e7Sgd78059 	return (ret);
2524297a64e7Sgd78059 }
2525297a64e7Sgd78059 
2526297a64e7Sgd78059 /*
2527297a64e7Sgd78059  * 0 as burstsize upon failure as it signifies no burst size.
2528297a64e7Sgd78059  */
2529297a64e7Sgd78059 static int
eri_burstsize(struct eri * erip)2530297a64e7Sgd78059 eri_burstsize(struct eri *erip)
2531297a64e7Sgd78059 {
2532297a64e7Sgd78059 	ddi_dma_handle_t handle;
2533297a64e7Sgd78059 
2534297a64e7Sgd78059 	if (ddi_dma_alloc_handle(erip->dip, &dma_attr, DDI_DMA_DONTWAIT,
2535297a64e7Sgd78059 	    NULL, &handle))
2536297a64e7Sgd78059 		return (DDI_FAILURE);
2537297a64e7Sgd78059 
2538297a64e7Sgd78059 	erip->burstsizes = ddi_dma_burstsizes(handle);
2539297a64e7Sgd78059 	ddi_dma_free_handle(&handle);
2540297a64e7Sgd78059 
2541297a64e7Sgd78059 	if (erip->burstsizes)
2542297a64e7Sgd78059 		return (DDI_SUCCESS);
2543297a64e7Sgd78059 
2544297a64e7Sgd78059 	return (DDI_FAILURE);
2545297a64e7Sgd78059 }
2546297a64e7Sgd78059 
2547297a64e7Sgd78059 /*
2548297a64e7Sgd78059  * Un-initialize (STOP) ERI channel.
2549297a64e7Sgd78059  */
2550297a64e7Sgd78059 static void
eri_uninit(struct eri * erip)2551297a64e7Sgd78059 eri_uninit(struct eri *erip)
2552297a64e7Sgd78059 {
2553297a64e7Sgd78059 	boolean_t needind;
2554297a64e7Sgd78059 
2555297a64e7Sgd78059 	/*
2556297a64e7Sgd78059 	 * Allow up to 'ERI_DRAINTIME' for pending xmit's to complete.
2557297a64e7Sgd78059 	 */
2558297a64e7Sgd78059 	ERI_DELAY((erip->tcurp == erip->tnextp), ERI_DRAINTIME);
2559297a64e7Sgd78059 
2560297a64e7Sgd78059 	mutex_enter(&erip->intrlock);
2561297a64e7Sgd78059 	eri_stop_timer(erip);   /* acquire linklock */
2562297a64e7Sgd78059 	mutex_enter(&erip->xmitlock);
2563297a64e7Sgd78059 	mutex_enter(&erip->xcvrlock);
2564297a64e7Sgd78059 	eri_mif_poll(erip, MIF_POLL_STOP);
2565297a64e7Sgd78059 	erip->flags &= ~ERI_DLPI_LINKUP;
2566297a64e7Sgd78059 	mutex_exit(&erip->xcvrlock);
2567297a64e7Sgd78059 
2568297a64e7Sgd78059 	needind = !erip->linkcheck;
2569297a64e7Sgd78059 	(void) eri_stop(erip);
2570297a64e7Sgd78059 	erip->flags &= ~ERI_RUNNING;
2571297a64e7Sgd78059 
2572297a64e7Sgd78059 	mutex_exit(&erip->xmitlock);
2573297a64e7Sgd78059 	eri_start_timer(erip, eri_check_link, 0);
2574297a64e7Sgd78059 	mutex_exit(&erip->intrlock);
2575297a64e7Sgd78059 
2576297a64e7Sgd78059 	if (needind)
2577297a64e7Sgd78059 		mac_link_update(erip->mh, LINK_STATE_DOWN);
2578297a64e7Sgd78059 }
2579297a64e7Sgd78059 
2580297a64e7Sgd78059 /*
2581297a64e7Sgd78059  * Allocate CONSISTENT memory for rmds and tmds with appropriate alignment and
2582297a64e7Sgd78059  * map it in IO space.
2583297a64e7Sgd78059  *
2584297a64e7Sgd78059  * The driver allocates STREAMS buffers which will be mapped in DVMA
2585297a64e7Sgd78059  * space using DDI DMA resources.
2586297a64e7Sgd78059  *
2587297a64e7Sgd78059  */
2588297a64e7Sgd78059 static int
eri_allocthings(struct eri * erip)2589297a64e7Sgd78059 eri_allocthings(struct eri *erip)
2590297a64e7Sgd78059 {
2591297a64e7Sgd78059 
2592297a64e7Sgd78059 	uintptr_t	a;
2593297a64e7Sgd78059 	int		size;
2594297a64e7Sgd78059 	uint32_t	rval;
2595297a64e7Sgd78059 	int		i;
2596297a64e7Sgd78059 	size_t		real_len;
2597297a64e7Sgd78059 	uint32_t	cookiec;
2598297a64e7Sgd78059 	int		alloc_stat = 0;
2599297a64e7Sgd78059 	ddi_dma_cookie_t dma_cookie;
2600297a64e7Sgd78059 
2601297a64e7Sgd78059 	/*
2602297a64e7Sgd78059 	 * Return if resources are already allocated.
2603297a64e7Sgd78059 	 */
2604297a64e7Sgd78059 	if (erip->rmdp)
2605297a64e7Sgd78059 		return (alloc_stat);
2606297a64e7Sgd78059 
2607297a64e7Sgd78059 	erip->alloc_flag = 0;
2608297a64e7Sgd78059 
2609297a64e7Sgd78059 	/*
2610297a64e7Sgd78059 	 * Allocate the TMD and RMD descriptors and extra for alignments.
2611297a64e7Sgd78059 	 */
2612297a64e7Sgd78059 	size = (ERI_RPENDING * sizeof (struct rmd) +
2613297a64e7Sgd78059 	    ERI_TPENDING * sizeof (struct eri_tmd)) + ERI_GMDALIGN;
2614297a64e7Sgd78059 
2615297a64e7Sgd78059 	rval = ddi_dma_alloc_handle(erip->dip, &desc_dma_attr,
2616297a64e7Sgd78059 	    DDI_DMA_DONTWAIT, 0, &erip->md_h);
2617297a64e7Sgd78059 	if (rval != DDI_SUCCESS) {
2618297a64e7Sgd78059 		return (++alloc_stat);
2619297a64e7Sgd78059 	}
2620297a64e7Sgd78059 	erip->alloc_flag |= ERI_DESC_HANDLE_ALLOC;
2621297a64e7Sgd78059 
2622297a64e7Sgd78059 	rval = ddi_dma_mem_alloc(erip->md_h, size, &erip->dev_attr,
2623297a64e7Sgd78059 	    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, 0,
2624297a64e7Sgd78059 	    (caddr_t *)&erip->iopbkbase, &real_len, &erip->mdm_h);
2625297a64e7Sgd78059 	if (rval != DDI_SUCCESS) {
2626297a64e7Sgd78059 		return (++alloc_stat);
2627297a64e7Sgd78059 	}
2628297a64e7Sgd78059 	erip->alloc_flag |= ERI_DESC_MEM_ALLOC;
2629297a64e7Sgd78059 
2630297a64e7Sgd78059 	rval = ddi_dma_addr_bind_handle(erip->md_h, NULL,
2631297a64e7Sgd78059 	    (caddr_t)erip->iopbkbase, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
2632297a64e7Sgd78059 	    DDI_DMA_DONTWAIT, 0, &erip->md_c, &cookiec);
2633297a64e7Sgd78059 
2634297a64e7Sgd78059 	if (rval != DDI_DMA_MAPPED)
2635297a64e7Sgd78059 		return (++alloc_stat);
2636297a64e7Sgd78059 
2637297a64e7Sgd78059 	erip->alloc_flag |= ERI_DESC_MEM_MAP;
2638297a64e7Sgd78059 
2639297a64e7Sgd78059 	if (cookiec != 1)
2640297a64e7Sgd78059 		return (++alloc_stat);
2641297a64e7Sgd78059 
2642297a64e7Sgd78059 	erip->iopbiobase = erip->md_c.dmac_address;
2643297a64e7Sgd78059 
2644297a64e7Sgd78059 	a = erip->iopbkbase;
2645297a64e7Sgd78059 	a = ROUNDUP(a, ERI_GMDALIGN);
2646297a64e7Sgd78059 	erip->rmdp = (struct rmd *)a;
2647297a64e7Sgd78059 	a += ERI_RPENDING * sizeof (struct rmd);
2648297a64e7Sgd78059 	erip->eri_tmdp = (struct eri_tmd *)a;
2649297a64e7Sgd78059 /*
2650297a64e7Sgd78059  *	Specifically we reserve n (ERI_TPENDING + ERI_RPENDING)
2651297a64e7Sgd78059  *	pagetable entries. Therefore we have 2 ptes for each
2652297a64e7Sgd78059  *	descriptor. Since the ethernet buffers are 1518 bytes
2653297a64e7Sgd78059  *	so they can at most use 2 ptes.
2654297a64e7Sgd78059  * 	Will do a ddi_dma_addr_setup for each bufer
2655297a64e7Sgd78059  */
2656297a64e7Sgd78059 	/*
2657297a64e7Sgd78059 	 * In the current implementation, we use the ddi compliant
2658bd78278bSGarrett D'Amore 	 * dma interface. We allocate ERI_RPENDING dma handles for receive
2659bd78278bSGarrett D'Amore 	 * activity. The actual dma mapping is done in the io function
2660bd78278bSGarrett D'Amore 	 * eri_read_dma(), by calling the ddi_dma_addr_bind_handle.
2661297a64e7Sgd78059 	 * Dma resources are deallocated by calling ddi_dma_unbind_handle
2662297a64e7Sgd78059 	 * in eri_reclaim() for transmit and eri_read_dma(), for receive io.
2663297a64e7Sgd78059 	 */
2664297a64e7Sgd78059 
2665297a64e7Sgd78059 	if (eri_use_dvma_rx &&
2666297a64e7Sgd78059 	    (dvma_reserve(erip->dip, &eri_dma_limits, (ERI_RPENDING * 2),
2667297a64e7Sgd78059 	    &erip->eri_dvmarh)) == DDI_SUCCESS) {
2668297a64e7Sgd78059 		erip->alloc_flag |= ERI_RCV_DVMA_ALLOC;
2669297a64e7Sgd78059 	} else {
2670297a64e7Sgd78059 		erip->eri_dvmarh = NULL;
2671297a64e7Sgd78059 
2672297a64e7Sgd78059 		for (i = 0; i < ERI_RPENDING; i++) {
2673297a64e7Sgd78059 			rval = ddi_dma_alloc_handle(erip->dip,
2674297a64e7Sgd78059 			    &dma_attr, DDI_DMA_DONTWAIT,
2675297a64e7Sgd78059 			    0, &erip->ndmarh[i]);
2676297a64e7Sgd78059 
2677297a64e7Sgd78059 			if (rval != DDI_SUCCESS) {
2678297a64e7Sgd78059 				ERI_FAULT_MSG1(erip, SEVERITY_HIGH,
2679297a64e7Sgd78059 				    ERI_VERB_MSG, alloc_rx_dmah_msg);
2680297a64e7Sgd78059 				alloc_stat++;
2681297a64e7Sgd78059 				break;
2682297a64e7Sgd78059 			}
2683297a64e7Sgd78059 		}
2684297a64e7Sgd78059 
2685297a64e7Sgd78059 		erip->rcv_handle_cnt = i;
2686297a64e7Sgd78059 
2687297a64e7Sgd78059 		if (i)
2688297a64e7Sgd78059 			erip->alloc_flag |= ERI_RCV_HANDLE_ALLOC;
2689297a64e7Sgd78059 
2690297a64e7Sgd78059 		if (alloc_stat)
2691297a64e7Sgd78059 			return (alloc_stat);
2692297a64e7Sgd78059 
2693297a64e7Sgd78059 	}
2694297a64e7Sgd78059 
2695297a64e7Sgd78059 /*
2696bd78278bSGarrett D'Amore  *	Allocate TX buffer
2697bd78278bSGarrett D'Amore  *	Note: buffers must always be allocated in the native
2698297a64e7Sgd78059  *	ordering of the CPU (always big-endian for Sparc).
2699297a64e7Sgd78059  *	ddi_dma_mem_alloc returns memory in the native ordering
2700297a64e7Sgd78059  *	of the bus (big endian for SBus, little endian for PCI).
2701297a64e7Sgd78059  *	So we cannot use ddi_dma_mem_alloc(, &erip->ge_dev_attr)
2702297a64e7Sgd78059  *	because we'll get little endian memory on PCI.
2703297a64e7Sgd78059  */
2704297a64e7Sgd78059 	if (ddi_dma_alloc_handle(erip->dip, &desc_dma_attr, DDI_DMA_DONTWAIT,
2705297a64e7Sgd78059 	    0, &erip->tbuf_handle) != DDI_SUCCESS) {
2706297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_HIGH, ERI_VERB_MSG,
2707297a64e7Sgd78059 		    alloc_tx_dmah_msg);
2708297a64e7Sgd78059 		return (++alloc_stat);
2709297a64e7Sgd78059 	}
2710297a64e7Sgd78059 	erip->alloc_flag |= ERI_XBUFS_HANDLE_ALLOC;
2711bd78278bSGarrett D'Amore 	size = ERI_TPENDING * ERI_BUFSIZE;
2712bd78278bSGarrett D'Amore 	if (ddi_dma_mem_alloc(erip->tbuf_handle, size, &buf_attr,
2713bd78278bSGarrett D'Amore 	    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL, &erip->tbuf_kaddr,
2714bd78278bSGarrett D'Amore 	    &real_len, &erip->tbuf_acch) != DDI_SUCCESS) {
2715297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_HIGH, ERI_VERB_MSG,
2716297a64e7Sgd78059 		    alloc_tx_dmah_msg);
2717297a64e7Sgd78059 		return (++alloc_stat);
2718297a64e7Sgd78059 	}
2719297a64e7Sgd78059 	erip->alloc_flag |= ERI_XBUFS_KMEM_ALLOC;
2720297a64e7Sgd78059 	if (ddi_dma_addr_bind_handle(erip->tbuf_handle, NULL,
2721297a64e7Sgd78059 	    erip->tbuf_kaddr, size, DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
2722297a64e7Sgd78059 	    DDI_DMA_DONTWAIT, 0, &dma_cookie, &cookiec) != DDI_DMA_MAPPED) {
2723297a64e7Sgd78059 			return (++alloc_stat);
2724297a64e7Sgd78059 	}
2725297a64e7Sgd78059 	erip->tbuf_ioaddr = dma_cookie.dmac_address;
2726297a64e7Sgd78059 	erip->alloc_flag |= ERI_XBUFS_KMEM_DMABIND;
2727297a64e7Sgd78059 	if (cookiec != 1)
2728297a64e7Sgd78059 		return (++alloc_stat);
2729297a64e7Sgd78059 
2730297a64e7Sgd78059 	/*
2731297a64e7Sgd78059 	 * Keep handy limit values for RMD, TMD, and Buffers.
2732297a64e7Sgd78059 	 */
2733297a64e7Sgd78059 	erip->rmdlimp = &((erip->rmdp)[ERI_RPENDING]);
2734297a64e7Sgd78059 	erip->eri_tmdlimp = &((erip->eri_tmdp)[ERI_TPENDING]);
2735297a64e7Sgd78059 
2736297a64e7Sgd78059 	/*
2737bd78278bSGarrett D'Amore 	 * Zero out RCV holders.
2738297a64e7Sgd78059 	 */
2739297a64e7Sgd78059 	bzero((caddr_t)erip->rmblkp, sizeof (erip->rmblkp));
2740297a64e7Sgd78059 	return (alloc_stat);
2741297a64e7Sgd78059 }
2742297a64e7Sgd78059 
2743297a64e7Sgd78059 /* <<<<<<<<<<<<<<<<<	INTERRUPT HANDLING FUNCTION	>>>>>>>>>>>>>>>>>>>> */
2744297a64e7Sgd78059 /*
2745297a64e7Sgd78059  *	First check to see if it is our device interrupting.
2746297a64e7Sgd78059  */
2747297a64e7Sgd78059 static uint_t
eri_intr(caddr_t arg)2748297a64e7Sgd78059 eri_intr(caddr_t arg)
2749297a64e7Sgd78059 {
2750297a64e7Sgd78059 	struct eri *erip = (void *)arg;
2751297a64e7Sgd78059 	uint32_t erisbits;
2752297a64e7Sgd78059 	uint32_t mif_status;
2753297a64e7Sgd78059 	uint32_t serviced = DDI_INTR_UNCLAIMED;
2754297a64e7Sgd78059 	link_state_t linkupdate = LINK_STATE_UNKNOWN;
2755297a64e7Sgd78059 	boolean_t macupdate = B_FALSE;
2756297a64e7Sgd78059 	mblk_t *mp;
2757297a64e7Sgd78059 	mblk_t *head;
2758297a64e7Sgd78059 	mblk_t **tail;
2759297a64e7Sgd78059 
2760297a64e7Sgd78059 	head = NULL;
2761297a64e7Sgd78059 	tail = &head;
2762297a64e7Sgd78059 
2763297a64e7Sgd78059 	mutex_enter(&erip->intrlock);
2764297a64e7Sgd78059 
2765297a64e7Sgd78059 	erisbits = GET_GLOBREG(status);
2766297a64e7Sgd78059 
2767297a64e7Sgd78059 	/*
2768297a64e7Sgd78059 	 * Check if it is only the RX_DONE interrupt, which is
2769297a64e7Sgd78059 	 * the most frequent one.
2770297a64e7Sgd78059 	 */
2771297a64e7Sgd78059 	if (((erisbits & ERI_G_STATUS_RX_INT) == ERI_G_STATUS_RX_DONE) &&
2772297a64e7Sgd78059 	    (erip->flags & ERI_RUNNING)) {
2773297a64e7Sgd78059 		serviced = DDI_INTR_CLAIMED;
2774297a64e7Sgd78059 		goto rx_done_int;
2775297a64e7Sgd78059 	}
2776297a64e7Sgd78059 
2777297a64e7Sgd78059 	/* Claim the first interrupt after initialization */
2778297a64e7Sgd78059 	if (erip->flags & ERI_INITIALIZED) {
2779297a64e7Sgd78059 		erip->flags &= ~ERI_INITIALIZED;
2780297a64e7Sgd78059 		serviced = DDI_INTR_CLAIMED;
2781297a64e7Sgd78059 	}
2782297a64e7Sgd78059 
2783297a64e7Sgd78059 	/* Check for interesting events */
2784297a64e7Sgd78059 	if ((erisbits & ERI_G_STATUS_INTR) == 0) {
2785297a64e7Sgd78059 #ifdef	ESTAR_WORKAROUND
2786297a64e7Sgd78059 		uint32_t linkupdate;
2787297a64e7Sgd78059 #endif
2788297a64e7Sgd78059 
2789297a64e7Sgd78059 		ERI_DEBUG_MSG2(erip, DIAG_MSG,
2790297a64e7Sgd78059 		    "eri_intr: Interrupt Not Claimed gsbits  %X", erisbits);
2791297a64e7Sgd78059 #ifdef	DEBUG
2792297a64e7Sgd78059 		noteri++;
2793297a64e7Sgd78059 #endif
2794297a64e7Sgd78059 		ERI_DEBUG_MSG2(erip, DIAG_MSG, "eri_intr:MIF Config = 0x%X",
2795297a64e7Sgd78059 		    GET_MIFREG(mif_cfg));
2796297a64e7Sgd78059 		ERI_DEBUG_MSG2(erip, DIAG_MSG, "eri_intr:MIF imask = 0x%X",
2797297a64e7Sgd78059 		    GET_MIFREG(mif_imask));
2798297a64e7Sgd78059 		ERI_DEBUG_MSG2(erip, DIAG_MSG, "eri_intr:INT imask = 0x%X",
2799297a64e7Sgd78059 		    GET_GLOBREG(intmask));
2800297a64e7Sgd78059 		ERI_DEBUG_MSG2(erip, DIAG_MSG, "eri_intr:alias %X",
2801297a64e7Sgd78059 		    GET_GLOBREG(status_alias));
2802297a64e7Sgd78059 #ifdef	ESTAR_WORKAROUND
2803297a64e7Sgd78059 		linkupdate = eri_check_link_noind(erip);
2804297a64e7Sgd78059 #endif
2805297a64e7Sgd78059 		mutex_exit(&erip->intrlock);
2806297a64e7Sgd78059 #ifdef	ESTAR_WORKAROUND
2807297a64e7Sgd78059 		if (linkupdate != LINK_STATE_UNKNOWN)
2808297a64e7Sgd78059 			mac_link_update(erip->mh, linkupdate);
2809297a64e7Sgd78059 #endif
2810297a64e7Sgd78059 		return (serviced);
2811297a64e7Sgd78059 	}
2812297a64e7Sgd78059 	serviced = DDI_INTR_CLAIMED;
2813297a64e7Sgd78059 
2814297a64e7Sgd78059 	if (!(erip->flags & ERI_RUNNING)) {
2815297a64e7Sgd78059 		mutex_exit(&erip->intrlock);
2816297a64e7Sgd78059 		eri_uninit(erip);
2817297a64e7Sgd78059 		return (serviced);
2818297a64e7Sgd78059 	}
2819297a64e7Sgd78059 
2820297a64e7Sgd78059 	if (erisbits & ERI_G_STATUS_FATAL_ERR) {
2821297a64e7Sgd78059 		ERI_DEBUG_MSG2(erip, INTR_MSG,
2822297a64e7Sgd78059 		    "eri_intr: fatal error: erisbits = %X", erisbits);
2823297a64e7Sgd78059 		(void) eri_fatal_err(erip, erisbits);
2824297a64e7Sgd78059 		eri_reinit_fatal++;
2825297a64e7Sgd78059 
2826297a64e7Sgd78059 		if (erip->rx_reset_issued) {
2827297a64e7Sgd78059 			erip->rx_reset_issued = 0;
2828297a64e7Sgd78059 			(void) eri_init_rx_channel(erip);
2829297a64e7Sgd78059 			mutex_exit(&erip->intrlock);
2830297a64e7Sgd78059 		} else {
2831297a64e7Sgd78059 			param_linkup = 0;
2832297a64e7Sgd78059 			erip->stats.link_up = LINK_STATE_DOWN;
2833297a64e7Sgd78059 			erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
2834297a64e7Sgd78059 			DISABLE_MAC(erip);
2835297a64e7Sgd78059 			mutex_exit(&erip->intrlock);
2836297a64e7Sgd78059 			(void) eri_init(erip);
2837297a64e7Sgd78059 		}
2838297a64e7Sgd78059 		return (serviced);
2839297a64e7Sgd78059 	}
2840297a64e7Sgd78059 
2841297a64e7Sgd78059 	if (erisbits & ERI_G_STATUS_NONFATAL_ERR) {
2842297a64e7Sgd78059 		ERI_DEBUG_MSG2(erip, INTR_MSG,
2843297a64e7Sgd78059 		    "eri_intr: non-fatal error: erisbits = %X", erisbits);
2844297a64e7Sgd78059 		(void) eri_nonfatal_err(erip, erisbits);
2845297a64e7Sgd78059 		if (erip->linkcheck) {
2846297a64e7Sgd78059 			mutex_exit(&erip->intrlock);
2847297a64e7Sgd78059 			(void) eri_init(erip);
2848297a64e7Sgd78059 			return (serviced);
2849297a64e7Sgd78059 		}
2850297a64e7Sgd78059 	}
2851297a64e7Sgd78059 
2852297a64e7Sgd78059 	if (erisbits & ERI_G_STATUS_MIF_INT) {
2853297a64e7Sgd78059 		uint16_t stat;
2854297a64e7Sgd78059 		ERI_DEBUG_MSG2(erip, XCVR_MSG,
2855297a64e7Sgd78059 		    "eri_intr:MIF Interrupt:mii_status %X", erip->mii_status);
2856297a64e7Sgd78059 		eri_stop_timer(erip);   /* acquire linklock */
2857297a64e7Sgd78059 
2858297a64e7Sgd78059 		mutex_enter(&erip->xmitlock);
2859297a64e7Sgd78059 		mutex_enter(&erip->xcvrlock);
2860297a64e7Sgd78059 #ifdef	ERI_MIF_POLL_STATUS_WORKAROUND
2861297a64e7Sgd78059 		mif_status = GET_MIFREG(mif_bsts);
2862297a64e7Sgd78059 		eri_mif_poll(erip, MIF_POLL_STOP);
2863297a64e7Sgd78059 		ERI_DEBUG_MSG3(erip, XCVR_MSG,
2864297a64e7Sgd78059 		    "eri_intr: new MIF interrupt status %X XCVR status %X",
2865297a64e7Sgd78059 		    mif_status, erip->mii_status);
2866297a64e7Sgd78059 		(void) eri_mii_read(erip, ERI_PHY_BMSR, &stat);
2867297a64e7Sgd78059 		linkupdate = eri_mif_check(erip, stat, stat);
2868297a64e7Sgd78059 
2869297a64e7Sgd78059 #else
2870297a64e7Sgd78059 		mif_status = GET_MIFREG(mif_bsts);
2871297a64e7Sgd78059 		eri_mif_poll(erip, MIF_POLL_STOP);
2872297a64e7Sgd78059 		linkupdate = eri_mif_check(erip, (uint16_t)mif_status,
2873297a64e7Sgd78059 		    (uint16_t)(mif_status >> 16));
2874297a64e7Sgd78059 #endif
2875297a64e7Sgd78059 		eri_mif_poll(erip, MIF_POLL_START);
2876297a64e7Sgd78059 		mutex_exit(&erip->xcvrlock);
2877297a64e7Sgd78059 		mutex_exit(&erip->xmitlock);
2878297a64e7Sgd78059 
2879297a64e7Sgd78059 		if (!erip->openloop_autoneg)
2880297a64e7Sgd78059 			eri_start_timer(erip, eri_check_link,
2881297a64e7Sgd78059 			    ERI_LINKCHECK_TIMER);
2882297a64e7Sgd78059 		else
2883297a64e7Sgd78059 			eri_start_timer(erip, eri_check_link,
2884297a64e7Sgd78059 			    ERI_P_FAULT_TIMER);
2885297a64e7Sgd78059 	}
2886297a64e7Sgd78059 
2887297a64e7Sgd78059 	ERI_DEBUG_MSG2(erip, INTR_MSG,
2888297a64e7Sgd78059 	    "eri_intr:May have Read Interrupt status:status %X", erisbits);
2889297a64e7Sgd78059 
2890297a64e7Sgd78059 rx_done_int:
2891297a64e7Sgd78059 	if ((erisbits & (ERI_G_STATUS_TX_INT_ME)) ||
2892297a64e7Sgd78059 	    (erip->tx_cur_cnt >= tx_interrupt_rate)) {
2893297a64e7Sgd78059 		mutex_enter(&erip->xmitlock);
2894297a64e7Sgd78059 		erip->tx_completion = (uint32_t)(GET_ETXREG(tx_completion) &
2895297a64e7Sgd78059 		    ETX_COMPLETION_MASK);
2896297a64e7Sgd78059 
2897297a64e7Sgd78059 		macupdate |= eri_reclaim(erip, erip->tx_completion);
28986213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic 		if (macupdate)
28996213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic 			erip->wantw = B_FALSE;
29006213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic 
2901297a64e7Sgd78059 		mutex_exit(&erip->xmitlock);
2902297a64e7Sgd78059 	}
2903297a64e7Sgd78059 
2904297a64e7Sgd78059 	if (erisbits & ERI_G_STATUS_RX_DONE) {
2905297a64e7Sgd78059 		volatile struct	rmd	*rmdp, *rmdpbase;
2906297a64e7Sgd78059 		volatile uint32_t rmdi;
2907297a64e7Sgd78059 		uint8_t loop_limit = 0x20;
2908297a64e7Sgd78059 		uint64_t flags;
2909297a64e7Sgd78059 		uint32_t rmdmax_mask = erip->rmdmax_mask;
2910297a64e7Sgd78059 
2911297a64e7Sgd78059 		rmdpbase = erip->rmdp;
2912297a64e7Sgd78059 		rmdi = erip->rx_completion;
2913297a64e7Sgd78059 		rmdp = rmdpbase + rmdi;
2914297a64e7Sgd78059 
2915297a64e7Sgd78059 		/*
2916297a64e7Sgd78059 		 * Sync RMD before looking at it.
2917297a64e7Sgd78059 		 */
2918297a64e7Sgd78059 		ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
2919297a64e7Sgd78059 		    DDI_DMA_SYNC_FORCPU);
2920297a64e7Sgd78059 		/*
2921297a64e7Sgd78059 		 * Loop through each RMD.
2922297a64e7Sgd78059 		 */
2923297a64e7Sgd78059 
2924297a64e7Sgd78059 		flags = GET_RMD_FLAGS(rmdp);
2925297a64e7Sgd78059 		while (((flags & ERI_RMD_OWN) == 0) && (loop_limit)) {
2926297a64e7Sgd78059 			/* process one packet */
2927297a64e7Sgd78059 			mp = eri_read_dma(erip, rmdp, rmdi, flags);
2928297a64e7Sgd78059 			rmdi =  (rmdi + 1) & rmdmax_mask;
2929297a64e7Sgd78059 			rmdp = rmdpbase + rmdi;
2930297a64e7Sgd78059 
2931297a64e7Sgd78059 			if (mp != NULL) {
2932297a64e7Sgd78059 				*tail = mp;
2933297a64e7Sgd78059 				tail = &mp->b_next;
2934297a64e7Sgd78059 			}
2935297a64e7Sgd78059 
2936297a64e7Sgd78059 			/*
2937297a64e7Sgd78059 			 * ERI RCV DMA fetches or updates four descriptors
2938297a64e7Sgd78059 			 * a time. Also we don't want to update the desc.
2939297a64e7Sgd78059 			 * batch we just received packet on. So we update
2940297a64e7Sgd78059 			 * descriptors for every 4 packets and we update
2941297a64e7Sgd78059 			 * the group of 4 after the current batch.
2942297a64e7Sgd78059 			 */
2943297a64e7Sgd78059 
2944297a64e7Sgd78059 			if (!(rmdi % 4)) {
2945297a64e7Sgd78059 				if (eri_overflow_reset &&
2946297a64e7Sgd78059 				    (GET_GLOBREG(status_alias) &
2947297a64e7Sgd78059 				    ERI_G_STATUS_NONFATAL_ERR)) {
2948297a64e7Sgd78059 					loop_limit = 1;
2949297a64e7Sgd78059 				} else {
2950297a64e7Sgd78059 					erip->rx_kick =
2951297a64e7Sgd78059 					    (rmdi + ERI_RPENDING - 4) &
2952297a64e7Sgd78059 					    rmdmax_mask;
2953297a64e7Sgd78059 					PUT_ERXREG(rx_kick, erip->rx_kick);
2954297a64e7Sgd78059 				}
2955297a64e7Sgd78059 			}
2956297a64e7Sgd78059 
2957297a64e7Sgd78059 			/*
2958297a64e7Sgd78059 			 * Sync the next RMD before looking at it.
2959297a64e7Sgd78059 			 */
2960297a64e7Sgd78059 			ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
2961297a64e7Sgd78059 			    DDI_DMA_SYNC_FORCPU);
2962297a64e7Sgd78059 			flags = GET_RMD_FLAGS(rmdp);
2963297a64e7Sgd78059 			loop_limit--;
2964297a64e7Sgd78059 		}
2965297a64e7Sgd78059 		erip->rx_completion = rmdi;
2966297a64e7Sgd78059 	}
2967297a64e7Sgd78059 
2968297a64e7Sgd78059 	mutex_exit(&erip->intrlock);
2969297a64e7Sgd78059 
2970297a64e7Sgd78059 	if (head)
2971297a64e7Sgd78059 		mac_rx(erip->mh, NULL, head);
2972297a64e7Sgd78059 
2973297a64e7Sgd78059 	if (macupdate)
2974297a64e7Sgd78059 		mac_tx_update(erip->mh);
2975297a64e7Sgd78059 
2976297a64e7Sgd78059 	if (linkupdate != LINK_STATE_UNKNOWN)
2977297a64e7Sgd78059 		mac_link_update(erip->mh, linkupdate);
2978297a64e7Sgd78059 
2979297a64e7Sgd78059 	return (serviced);
2980297a64e7Sgd78059 }
2981297a64e7Sgd78059 
2982297a64e7Sgd78059 /*
2983297a64e7Sgd78059  * Handle interrupts for fatal errors
2984297a64e7Sgd78059  * Need reinitialization.
2985297a64e7Sgd78059  */
2986297a64e7Sgd78059 #define	PCI_DATA_PARITY_REP	(1 << 8)
2987297a64e7Sgd78059 #define	PCI_SING_TARGET_ABORT	(1 << 11)
2988297a64e7Sgd78059 #define	PCI_RCV_TARGET_ABORT	(1 << 12)
2989297a64e7Sgd78059 #define	PCI_RCV_MASTER_ABORT	(1 << 13)
2990297a64e7Sgd78059 #define	PCI_SING_SYSTEM_ERR	(1 << 14)
2991297a64e7Sgd78059 #define	PCI_DATA_PARITY_ERR	(1 << 15)
2992297a64e7Sgd78059 
2993297a64e7Sgd78059 /* called with intrlock held */
2994297a64e7Sgd78059 static void
eri_fatal_err(struct eri * erip,uint32_t erisbits)2995297a64e7Sgd78059 eri_fatal_err(struct eri *erip, uint32_t erisbits)
2996297a64e7Sgd78059 {
2997297a64e7Sgd78059 	uint16_t	pci_status;
2998297a64e7Sgd78059 	uint32_t	pci_error_int = 0;
2999297a64e7Sgd78059 
3000297a64e7Sgd78059 	if (erisbits & ERI_G_STATUS_RX_TAG_ERR) {
3001297a64e7Sgd78059 		erip->rx_reset_issued = 1;
3002297a64e7Sgd78059 		HSTAT(erip, rxtag_err);
3003297a64e7Sgd78059 	} else {
3004297a64e7Sgd78059 		erip->global_reset_issued = 1;
3005297a64e7Sgd78059 		if (erisbits & ERI_G_STATUS_BUS_ERR_INT) {
3006297a64e7Sgd78059 			pci_error_int = 1;
3007297a64e7Sgd78059 			HSTAT(erip, pci_error_int);
3008297a64e7Sgd78059 		} else if (erisbits & ERI_G_STATUS_PERR_INT) {
3009297a64e7Sgd78059 			HSTAT(erip, parity_error);
3010297a64e7Sgd78059 		} else {
3011297a64e7Sgd78059 			HSTAT(erip, unknown_fatal);
3012297a64e7Sgd78059 		}
3013297a64e7Sgd78059 	}
3014297a64e7Sgd78059 
3015297a64e7Sgd78059 	/*
3016297a64e7Sgd78059 	 * PCI bus error
3017297a64e7Sgd78059 	 */
3018297a64e7Sgd78059 	if (pci_error_int && erip->pci_config_handle) {
3019297a64e7Sgd78059 		pci_status = pci_config_get16(erip->pci_config_handle,
3020297a64e7Sgd78059 		    PCI_CONF_STAT);
3021297a64e7Sgd78059 		ERI_DEBUG_MSG2(erip, FATAL_ERR_MSG, "Bus Error Status %x",
3022297a64e7Sgd78059 		    pci_status);
3023297a64e7Sgd78059 		if (pci_status & PCI_DATA_PARITY_REP)
3024297a64e7Sgd78059 			HSTAT(erip, pci_data_parity_err);
3025297a64e7Sgd78059 		if (pci_status & PCI_SING_TARGET_ABORT)
3026297a64e7Sgd78059 			HSTAT(erip, pci_signal_target_abort);
3027297a64e7Sgd78059 		if (pci_status & PCI_RCV_TARGET_ABORT)
3028297a64e7Sgd78059 			HSTAT(erip, pci_rcvd_target_abort);
3029297a64e7Sgd78059 		if (pci_status & PCI_RCV_MASTER_ABORT)
3030297a64e7Sgd78059 			HSTAT(erip, pci_rcvd_master_abort);
3031297a64e7Sgd78059 		if (pci_status & PCI_SING_SYSTEM_ERR)
3032297a64e7Sgd78059 			HSTAT(erip, pci_signal_system_err);
3033297a64e7Sgd78059 		if (pci_status & PCI_DATA_PARITY_ERR)
3034297a64e7Sgd78059 			HSTAT(erip, pci_signal_system_err);
3035297a64e7Sgd78059 		/*
3036297a64e7Sgd78059 		 * clear it by writing the value that was read back.
3037297a64e7Sgd78059 		 */
3038297a64e7Sgd78059 		pci_config_put16(erip->pci_config_handle, PCI_CONF_STAT,
3039297a64e7Sgd78059 		    pci_status);
3040297a64e7Sgd78059 	}
3041297a64e7Sgd78059 }
3042297a64e7Sgd78059 
3043297a64e7Sgd78059 /*
3044297a64e7Sgd78059  * Handle interrupts regarding non-fatal events.
3045297a64e7Sgd78059  * TXMAC, RXMAC and MACCTL events
3046297a64e7Sgd78059  */
3047297a64e7Sgd78059 static void
eri_nonfatal_err(struct eri * erip,uint32_t erisbits)3048297a64e7Sgd78059 eri_nonfatal_err(struct eri *erip, uint32_t erisbits)
3049297a64e7Sgd78059 {
3050297a64e7Sgd78059 
3051297a64e7Sgd78059 	uint32_t	txmac_sts, rxmac_sts, macctl_sts, pause_time;
3052297a64e7Sgd78059 
3053297a64e7Sgd78059 #ifdef ERI_PM_WORKAROUND
3054297a64e7Sgd78059 	if (pci_report_pmcap(erip->dip, PCI_PM_IDLESPEED,
3055297a64e7Sgd78059 	    PCI_PM_IDLESPEED_NONE) == DDI_SUCCESS)
3056297a64e7Sgd78059 		erip->stats.pmcap = ERI_PMCAP_NONE;
3057297a64e7Sgd78059 #endif
3058297a64e7Sgd78059 
3059297a64e7Sgd78059 	if (erisbits & ERI_G_STATUS_TX_MAC_INT) {
3060297a64e7Sgd78059 		txmac_sts = GET_MACREG(txsts);
3061297a64e7Sgd78059 		if (txmac_sts & BMAC_TXSTS_TX_URUN) {
3062297a64e7Sgd78059 			erip->linkcheck = 1;
3063297a64e7Sgd78059 			HSTAT(erip, txmac_urun);
3064297a64e7Sgd78059 			HSTAT(erip, oerrors);
3065297a64e7Sgd78059 		}
3066297a64e7Sgd78059 
3067297a64e7Sgd78059 		if (txmac_sts & BMAC_TXSTS_MAXPKT_ERR) {
3068297a64e7Sgd78059 			erip->linkcheck = 1;
3069297a64e7Sgd78059 			HSTAT(erip, txmac_maxpkt_err);
3070297a64e7Sgd78059 			HSTAT(erip, oerrors);
3071297a64e7Sgd78059 		}
3072297a64e7Sgd78059 		if (txmac_sts & BMAC_TXSTS_NCC_EXP) {
3073297a64e7Sgd78059 			erip->stats.collisions += 0x10000;
3074297a64e7Sgd78059 		}
3075297a64e7Sgd78059 
3076297a64e7Sgd78059 		if (txmac_sts & BMAC_TXSTS_ECC_EXP) {
3077297a64e7Sgd78059 			erip->stats.excessive_coll += 0x10000;
3078297a64e7Sgd78059 		}
3079297a64e7Sgd78059 
3080297a64e7Sgd78059 		if (txmac_sts & BMAC_TXSTS_LCC_EXP) {
3081297a64e7Sgd78059 			erip->stats.late_coll += 0x10000;
3082297a64e7Sgd78059 		}
3083297a64e7Sgd78059 
3084297a64e7Sgd78059 		if (txmac_sts & BMAC_TXSTS_FCC_EXP) {
3085297a64e7Sgd78059 			erip->stats.first_coll += 0x10000;
3086297a64e7Sgd78059 		}
3087297a64e7Sgd78059 
3088297a64e7Sgd78059 		if (txmac_sts & BMAC_TXSTS_DEFER_EXP) {
3089297a64e7Sgd78059 			HSTAT(erip, defer_timer_exp);
3090297a64e7Sgd78059 		}
3091297a64e7Sgd78059 
3092297a64e7Sgd78059 		if (txmac_sts & BMAC_TXSTS_PEAK_EXP) {
3093297a64e7Sgd78059 			erip->stats.peak_attempt_cnt += 0x100;
3094297a64e7Sgd78059 		}
3095297a64e7Sgd78059 	}
3096297a64e7Sgd78059 
3097297a64e7Sgd78059 	if (erisbits & ERI_G_STATUS_RX_NO_BUF) {
3098297a64e7Sgd78059 		ERI_DEBUG_MSG1(erip, NONFATAL_MSG, "rx dropped/no free desc");
3099297a64e7Sgd78059 
3100297a64e7Sgd78059 		if (eri_overflow_reset)
3101297a64e7Sgd78059 			erip->linkcheck = 1;
3102297a64e7Sgd78059 
3103297a64e7Sgd78059 		HSTAT(erip, no_free_rx_desc);
3104297a64e7Sgd78059 		HSTAT(erip, ierrors);
3105297a64e7Sgd78059 	}
3106297a64e7Sgd78059 	if (erisbits & ERI_G_STATUS_RX_MAC_INT) {
3107297a64e7Sgd78059 		rxmac_sts = GET_MACREG(rxsts);
3108297a64e7Sgd78059 		if (rxmac_sts & BMAC_RXSTS_RX_OVF) {
3109297a64e7Sgd78059 #ifndef ERI_RMAC_HANG_WORKAROUND
3110297a64e7Sgd78059 			eri_stop_timer(erip);   /* acquire linklock */
3111297a64e7Sgd78059 			erip->check_rmac_hang ++;
3112297a64e7Sgd78059 			erip->check2_rmac_hang = 0;
3113297a64e7Sgd78059 			erip->rxfifo_wr_ptr = GET_ERXREG(rxfifo_wr_ptr);
3114297a64e7Sgd78059 			erip->rxfifo_rd_ptr = GET_ERXREG(rxfifo_rd_ptr);
3115297a64e7Sgd78059 
3116297a64e7Sgd78059 			ERI_DEBUG_MSG5(erip, NONFATAL_MSG,
3117297a64e7Sgd78059 			    "overflow intr %d: %8x wr:%2x rd:%2x",
3118297a64e7Sgd78059 			    erip->check_rmac_hang,
3119297a64e7Sgd78059 			    GET_MACREG(macsm),
3120297a64e7Sgd78059 			    GET_ERXREG(rxfifo_wr_ptr),
3121297a64e7Sgd78059 			    GET_ERXREG(rxfifo_rd_ptr));
3122297a64e7Sgd78059 
3123297a64e7Sgd78059 			eri_start_timer(erip, eri_check_link,
3124297a64e7Sgd78059 			    ERI_CHECK_HANG_TIMER);
3125297a64e7Sgd78059 #endif
3126297a64e7Sgd78059 			if (eri_overflow_reset)
3127297a64e7Sgd78059 				erip->linkcheck = 1;
3128297a64e7Sgd78059 
3129297a64e7Sgd78059 			HSTAT(erip, rx_overflow);
3130297a64e7Sgd78059 			HSTAT(erip, ierrors);
3131297a64e7Sgd78059 		}
3132297a64e7Sgd78059 
3133297a64e7Sgd78059 		if (rxmac_sts & BMAC_RXSTS_ALE_EXP) {
3134297a64e7Sgd78059 			erip->stats.rx_align_err += 0x10000;
3135297a64e7Sgd78059 			erip->stats.ierrors += 0x10000;
3136297a64e7Sgd78059 		}
3137297a64e7Sgd78059 
3138297a64e7Sgd78059 		if (rxmac_sts & BMAC_RXSTS_CRC_EXP) {
3139297a64e7Sgd78059 			erip->stats.rx_crc_err += 0x10000;
3140297a64e7Sgd78059 			erip->stats.ierrors += 0x10000;
3141297a64e7Sgd78059 		}
3142297a64e7Sgd78059 
3143297a64e7Sgd78059 		if (rxmac_sts & BMAC_RXSTS_LEN_EXP) {
3144297a64e7Sgd78059 			erip->stats.rx_length_err += 0x10000;
3145297a64e7Sgd78059 			erip->stats.ierrors += 0x10000;
3146297a64e7Sgd78059 		}
3147297a64e7Sgd78059 
3148297a64e7Sgd78059 		if (rxmac_sts & BMAC_RXSTS_CVI_EXP) {
3149297a64e7Sgd78059 			erip->stats.rx_code_viol_err += 0x10000;
3150297a64e7Sgd78059 			erip->stats.ierrors += 0x10000;
3151297a64e7Sgd78059 		}
3152297a64e7Sgd78059 	}
3153297a64e7Sgd78059 
3154297a64e7Sgd78059 	if (erisbits & ERI_G_STATUS_MAC_CTRL_INT) {
3155297a64e7Sgd78059 
3156297a64e7Sgd78059 		macctl_sts = GET_MACREG(macctl_sts);
3157297a64e7Sgd78059 		if (macctl_sts & ERI_MCTLSTS_PAUSE_RCVD) {
3158297a64e7Sgd78059 			pause_time = ((macctl_sts &
3159297a64e7Sgd78059 			    ERI_MCTLSTS_PAUSE_TIME) >> 16);
3160297a64e7Sgd78059 			ERI_DEBUG_MSG2(erip, NONFATAL_MSG,
3161297a64e7Sgd78059 			    "PAUSE Received. pause time = %X slot_times",
3162297a64e7Sgd78059 			    pause_time);
3163297a64e7Sgd78059 			HSTAT(erip, pause_rxcount);
3164297a64e7Sgd78059 			erip->stats.pause_time_count += pause_time;
3165297a64e7Sgd78059 		}
3166297a64e7Sgd78059 
3167297a64e7Sgd78059 		if (macctl_sts & ERI_MCTLSTS_PAUSE_STATE) {
3168297a64e7Sgd78059 			HSTAT(erip, pause_oncount);
3169297a64e7Sgd78059 			erip->stats.pausing = 1;
3170297a64e7Sgd78059 		}
3171297a64e7Sgd78059 
3172297a64e7Sgd78059 		if (macctl_sts & ERI_MCTLSTS_NONPAUSE) {
3173297a64e7Sgd78059 			HSTAT(erip, pause_offcount);
3174297a64e7Sgd78059 			erip->stats.pausing = 0;
3175297a64e7Sgd78059 		}
3176297a64e7Sgd78059 	}
3177297a64e7Sgd78059 
3178297a64e7Sgd78059 }
3179297a64e7Sgd78059 
3180297a64e7Sgd78059 /*
3181297a64e7Sgd78059  * if this is the first init do not bother to save the
3182297a64e7Sgd78059  * counters.
3183297a64e7Sgd78059  */
3184297a64e7Sgd78059 static void
eri_savecntrs(struct eri * erip)3185297a64e7Sgd78059 eri_savecntrs(struct eri *erip)
3186297a64e7Sgd78059 {
3187297a64e7Sgd78059 	uint32_t	fecnt, aecnt, lecnt, rxcv;
3188297a64e7Sgd78059 	uint32_t	ltcnt, excnt, fccnt;
3189297a64e7Sgd78059 
3190297a64e7Sgd78059 	/* XXX What all gets added in ierrors and oerrors? */
3191297a64e7Sgd78059 	fecnt = GET_MACREG(fecnt);
3192297a64e7Sgd78059 	HSTATN(erip, rx_crc_err, fecnt);
3193297a64e7Sgd78059 	PUT_MACREG(fecnt, 0);
3194297a64e7Sgd78059 
3195297a64e7Sgd78059 	aecnt = GET_MACREG(aecnt);
3196297a64e7Sgd78059 	HSTATN(erip, rx_align_err, aecnt);
3197297a64e7Sgd78059 	PUT_MACREG(aecnt, 0);
3198297a64e7Sgd78059 
3199297a64e7Sgd78059 	lecnt = GET_MACREG(lecnt);
3200297a64e7Sgd78059 	HSTATN(erip, rx_length_err, lecnt);
3201297a64e7Sgd78059 	PUT_MACREG(lecnt, 0);
3202297a64e7Sgd78059 
3203297a64e7Sgd78059 	rxcv = GET_MACREG(rxcv);
3204297a64e7Sgd78059 	HSTATN(erip, rx_code_viol_err, rxcv);
3205297a64e7Sgd78059 	PUT_MACREG(rxcv, 0);
3206297a64e7Sgd78059 
3207297a64e7Sgd78059 	ltcnt = GET_MACREG(ltcnt);
3208297a64e7Sgd78059 	HSTATN(erip, late_coll, ltcnt);
3209297a64e7Sgd78059 	PUT_MACREG(ltcnt, 0);
3210297a64e7Sgd78059 
3211297a64e7Sgd78059 	erip->stats.collisions += (GET_MACREG(nccnt) + ltcnt);
3212297a64e7Sgd78059 	PUT_MACREG(nccnt, 0);
3213297a64e7Sgd78059 
3214297a64e7Sgd78059 	excnt = GET_MACREG(excnt);
3215297a64e7Sgd78059 	HSTATN(erip, excessive_coll, excnt);
3216297a64e7Sgd78059 	PUT_MACREG(excnt, 0);
3217297a64e7Sgd78059 
3218297a64e7Sgd78059 	fccnt = GET_MACREG(fccnt);
3219297a64e7Sgd78059 	HSTATN(erip, first_coll, fccnt);
3220297a64e7Sgd78059 	PUT_MACREG(fccnt, 0);
3221297a64e7Sgd78059 
3222297a64e7Sgd78059 	/*
3223297a64e7Sgd78059 	 * Do not add code violations to input errors.
3224297a64e7Sgd78059 	 * They are already counted in CRC errors
3225297a64e7Sgd78059 	 */
3226297a64e7Sgd78059 	HSTATN(erip, ierrors, (fecnt + aecnt + lecnt));
3227297a64e7Sgd78059 	HSTATN(erip, oerrors, (ltcnt + excnt));
3228297a64e7Sgd78059 }
3229297a64e7Sgd78059 
3230297a64e7Sgd78059 mblk_t *
eri_allocb_sp(size_t size)3231297a64e7Sgd78059 eri_allocb_sp(size_t size)
3232297a64e7Sgd78059 {
3233297a64e7Sgd78059 	mblk_t  *mp;
3234297a64e7Sgd78059 
3235297a64e7Sgd78059 	size += 128;
3236297a64e7Sgd78059 	if ((mp = allocb(size + 3 * ERI_BURSTSIZE, BPRI_HI)) == NULL) {
3237297a64e7Sgd78059 		return (NULL);
3238297a64e7Sgd78059 	}
3239297a64e7Sgd78059 	mp->b_wptr += 128;
3240297a64e7Sgd78059 	mp->b_wptr = (uint8_t *)ROUNDUP2(mp->b_wptr, ERI_BURSTSIZE);
3241297a64e7Sgd78059 	mp->b_rptr = mp->b_wptr;
3242297a64e7Sgd78059 
3243297a64e7Sgd78059 	return (mp);
3244297a64e7Sgd78059 }
3245297a64e7Sgd78059 
3246297a64e7Sgd78059 mblk_t *
eri_allocb(size_t size)3247297a64e7Sgd78059 eri_allocb(size_t size)
3248297a64e7Sgd78059 {
3249297a64e7Sgd78059 	mblk_t  *mp;
3250297a64e7Sgd78059 
3251297a64e7Sgd78059 	if ((mp = allocb(size + 3 * ERI_BURSTSIZE, BPRI_HI)) == NULL) {
3252297a64e7Sgd78059 		return (NULL);
3253297a64e7Sgd78059 	}
3254297a64e7Sgd78059 	mp->b_wptr = (uint8_t *)ROUNDUP2(mp->b_wptr, ERI_BURSTSIZE);
3255297a64e7Sgd78059 	mp->b_rptr = mp->b_wptr;
3256297a64e7Sgd78059 
3257297a64e7Sgd78059 	return (mp);
3258297a64e7Sgd78059 }
3259297a64e7Sgd78059 
3260297a64e7Sgd78059 /*
3261297a64e7Sgd78059  * Hardware Dependent Functions
3262297a64e7Sgd78059  * New Section.
3263297a64e7Sgd78059  */
3264297a64e7Sgd78059 
3265297a64e7Sgd78059 /* <<<<<<<<<<<<<<<< Fast Ethernet PHY Bit Bang Operations >>>>>>>>>>>>>>>>>> */
3266297a64e7Sgd78059 
3267297a64e7Sgd78059 static void
send_bit(struct eri * erip,uint32_t x)3268297a64e7Sgd78059 send_bit(struct eri *erip, uint32_t x)
3269297a64e7Sgd78059 {
3270297a64e7Sgd78059 	PUT_MIFREG(mif_bbdata, x);
3271297a64e7Sgd78059 	PUT_MIFREG(mif_bbclk, ERI_BBCLK_LOW);
3272297a64e7Sgd78059 	PUT_MIFREG(mif_bbclk, ERI_BBCLK_HIGH);
3273297a64e7Sgd78059 }
3274297a64e7Sgd78059 
3275297a64e7Sgd78059 /*
3276297a64e7Sgd78059  * To read the MII register bits according to the IEEE Standard
3277297a64e7Sgd78059  */
3278297a64e7Sgd78059 static uint32_t
get_bit_std(struct eri * erip)3279297a64e7Sgd78059 get_bit_std(struct eri *erip)
3280297a64e7Sgd78059 {
3281297a64e7Sgd78059 	uint32_t	x;
3282297a64e7Sgd78059 
3283297a64e7Sgd78059 	PUT_MIFREG(mif_bbclk, ERI_BBCLK_LOW);
3284297a64e7Sgd78059 	drv_usecwait(1);	/* wait for  >330 ns for stable data */
3285297a64e7Sgd78059 	if (param_transceiver == INTERNAL_XCVR)
3286297a64e7Sgd78059 		x = (GET_MIFREG(mif_cfg) & ERI_MIF_CFGM0) ? 1 : 0;
3287297a64e7Sgd78059 	else
3288297a64e7Sgd78059 		x = (GET_MIFREG(mif_cfg) & ERI_MIF_CFGM1) ? 1 : 0;
3289297a64e7Sgd78059 	PUT_MIFREG(mif_bbclk, ERI_BBCLK_HIGH);
3290297a64e7Sgd78059 	return (x);
3291297a64e7Sgd78059 }
3292297a64e7Sgd78059 
3293297a64e7Sgd78059 #define	SEND_BIT(x)		send_bit(erip, x)
3294297a64e7Sgd78059 #define	GET_BIT_STD(x)		x = get_bit_std(erip)
3295297a64e7Sgd78059 
3296297a64e7Sgd78059 
3297297a64e7Sgd78059 static void
eri_bb_mii_write(struct eri * erip,uint8_t regad,uint16_t data)3298297a64e7Sgd78059 eri_bb_mii_write(struct eri *erip, uint8_t regad, uint16_t data)
3299297a64e7Sgd78059 {
3300297a64e7Sgd78059 	uint8_t	phyad;
3301297a64e7Sgd78059 	int		i;
3302297a64e7Sgd78059 
3303297a64e7Sgd78059 	PUT_MIFREG(mif_bbopenb, 1);	/* Enable the MII driver */
3304297a64e7Sgd78059 	phyad = erip->phyad;
3305297a64e7Sgd78059 	(void) eri_bb_force_idle(erip);
3306297a64e7Sgd78059 	SEND_BIT(0); SEND_BIT(1);	/* <ST> */
3307297a64e7Sgd78059 	SEND_BIT(0); SEND_BIT(1);	/* <OP> */
3308297a64e7Sgd78059 	for (i = 4; i >= 0; i--) {		/* <AAAAA> */
3309297a64e7Sgd78059 		SEND_BIT((phyad >> i) & 1);
3310297a64e7Sgd78059 	}
3311297a64e7Sgd78059 	for (i = 4; i >= 0; i--) {		/* <RRRRR> */
3312297a64e7Sgd78059 		SEND_BIT((regad >> i) & 1);
3313297a64e7Sgd78059 	}
3314297a64e7Sgd78059 	SEND_BIT(1); SEND_BIT(0);	/* <TA> */
3315297a64e7Sgd78059 	for (i = 0xf; i >= 0; i--) {	/* <DDDDDDDDDDDDDDDD> */
3316297a64e7Sgd78059 		SEND_BIT((data >> i) & 1);
3317297a64e7Sgd78059 	}
3318297a64e7Sgd78059 	PUT_MIFREG(mif_bbopenb, 0);	/* Disable the MII driver */
3319297a64e7Sgd78059 }
3320297a64e7Sgd78059 
3321297a64e7Sgd78059 /* Return 0 if OK, 1 if error (Transceiver does not talk management) */
3322297a64e7Sgd78059 static uint32_t
eri_bb_mii_read(struct eri * erip,uint8_t regad,uint16_t * datap)3323297a64e7Sgd78059 eri_bb_mii_read(struct eri *erip, uint8_t regad, uint16_t *datap)
3324297a64e7Sgd78059 {
3325297a64e7Sgd78059 	uint8_t	phyad;
3326297a64e7Sgd78059 	int	i;
3327297a64e7Sgd78059 	uint32_t	x;
3328297a64e7Sgd78059 	uint32_t	y;
3329297a64e7Sgd78059 
3330297a64e7Sgd78059 	*datap = 0;
3331297a64e7Sgd78059 
3332297a64e7Sgd78059 	PUT_MIFREG(mif_bbopenb, 1);	/* Enable the MII driver */
3333297a64e7Sgd78059 	phyad = erip->phyad;
3334297a64e7Sgd78059 	(void) eri_bb_force_idle(erip);
3335297a64e7Sgd78059 	SEND_BIT(0); SEND_BIT(1);	/* <ST> */
3336297a64e7Sgd78059 	SEND_BIT(1); SEND_BIT(0);	/* <OP> */
3337297a64e7Sgd78059 	for (i = 4; i >= 0; i--) {		/* <AAAAA> */
3338297a64e7Sgd78059 		SEND_BIT((phyad >> i) & 1);
3339297a64e7Sgd78059 	}
3340297a64e7Sgd78059 	for (i = 4; i >= 0; i--) {		/* <RRRRR> */
3341297a64e7Sgd78059 		SEND_BIT((regad >> i) & 1);
3342297a64e7Sgd78059 	}
3343297a64e7Sgd78059 
3344297a64e7Sgd78059 	PUT_MIFREG(mif_bbopenb, 0);	/* Disable the MII driver */
3345297a64e7Sgd78059 
3346297a64e7Sgd78059 	GET_BIT_STD(x);
3347297a64e7Sgd78059 	GET_BIT_STD(y);		/* <TA> */
3348297a64e7Sgd78059 	for (i = 0xf; i >= 0; i--) {	/* <DDDDDDDDDDDDDDDD> */
3349297a64e7Sgd78059 		GET_BIT_STD(x);
3350297a64e7Sgd78059 		*datap += (x << i);
3351297a64e7Sgd78059 	}
3352297a64e7Sgd78059 	/* Kludge to get the Transceiver out of hung mode */
3353297a64e7Sgd78059 	/* XXX: Test if this is still needed */
3354297a64e7Sgd78059 	GET_BIT_STD(x);
3355297a64e7Sgd78059 	GET_BIT_STD(x);
3356297a64e7Sgd78059 	GET_BIT_STD(x);
3357297a64e7Sgd78059 
3358297a64e7Sgd78059 	return (y);
3359297a64e7Sgd78059 }
3360297a64e7Sgd78059 
3361297a64e7Sgd78059 static void
eri_bb_force_idle(struct eri * erip)3362297a64e7Sgd78059 eri_bb_force_idle(struct eri *erip)
3363297a64e7Sgd78059 {
3364297a64e7Sgd78059 	int		i;
3365297a64e7Sgd78059 
3366297a64e7Sgd78059 	for (i = 0; i < 33; i++) {
3367297a64e7Sgd78059 		SEND_BIT(1);
3368297a64e7Sgd78059 	}
3369297a64e7Sgd78059 }
3370297a64e7Sgd78059 
3371297a64e7Sgd78059 /* <<<<<<<<<<<<<<<<<<<<End of Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */
3372297a64e7Sgd78059 
3373297a64e7Sgd78059 
3374297a64e7Sgd78059 /* <<<<<<<<<<<<< Frame Register used for MII operations >>>>>>>>>>>>>>>>>>>> */
3375297a64e7Sgd78059 
3376297a64e7Sgd78059 #ifdef ERI_FRM_DEBUG
3377297a64e7Sgd78059 int frame_flag = 0;
3378297a64e7Sgd78059 #endif
3379297a64e7Sgd78059 
3380297a64e7Sgd78059 /* Return 0 if OK, 1 if error (Transceiver does not talk management) */
3381297a64e7Sgd78059 static uint32_t
eri_mii_read(struct eri * erip,uint8_t regad,uint16_t * datap)3382297a64e7Sgd78059 eri_mii_read(struct eri	*erip, uint8_t regad, uint16_t *datap)
3383297a64e7Sgd78059 {
3384297a64e7Sgd78059 	uint32_t frame;
3385297a64e7Sgd78059 	uint8_t phyad;
3386297a64e7Sgd78059 
3387297a64e7Sgd78059 	if (param_transceiver == NO_XCVR)
3388297a64e7Sgd78059 		return (1);	/* No xcvr present */
3389297a64e7Sgd78059 
3390297a64e7Sgd78059 	if (!erip->frame_enable)
3391297a64e7Sgd78059 		return (eri_bb_mii_read(erip, regad, datap));
3392297a64e7Sgd78059 
3393297a64e7Sgd78059 	phyad = erip->phyad;
3394297a64e7Sgd78059 #ifdef ERI_FRM_DEBUG
3395297a64e7Sgd78059 	if (!frame_flag) {
3396297a64e7Sgd78059 		eri_errror(erip->dip, "Frame Register used for MII");
3397297a64e7Sgd78059 		frame_flag = 1;
3398297a64e7Sgd78059 	}
3399297a64e7Sgd78059 #endif
3400297a64e7Sgd78059 	ERI_DEBUG_MSG3(erip, FRM_MSG,
3401297a64e7Sgd78059 	    "Frame Reg :mii_read: phyad = %X reg = %X ", phyad, regad);
3402297a64e7Sgd78059 
3403297a64e7Sgd78059 	PUT_MIFREG(mif_frame, ERI_MIF_FRREAD |
3404297a64e7Sgd78059 	    (phyad << ERI_MIF_FRPHYAD_SHIFT) |
3405297a64e7Sgd78059 	    (regad << ERI_MIF_FRREGAD_SHIFT));
3406297a64e7Sgd78059 	MIF_ERIDELAY(300,  phyad, regad);
3407297a64e7Sgd78059 	frame = GET_MIFREG(mif_frame);
3408297a64e7Sgd78059 	if ((frame & ERI_MIF_FRTA0) == 0) {
3409297a64e7Sgd78059 		return (1);
3410297a64e7Sgd78059 	} else {
3411297a64e7Sgd78059 		*datap = (uint16_t)(frame & ERI_MIF_FRDATA);
3412297a64e7Sgd78059 		return (0);
3413297a64e7Sgd78059 	}
3414297a64e7Sgd78059 
3415297a64e7Sgd78059 }
3416297a64e7Sgd78059 
3417297a64e7Sgd78059 static void
eri_mii_write(struct eri * erip,uint8_t regad,uint16_t data)3418297a64e7Sgd78059 eri_mii_write(struct eri *erip, uint8_t regad, uint16_t data)
3419297a64e7Sgd78059 {
3420297a64e7Sgd78059 	uint8_t	phyad;
3421297a64e7Sgd78059 
3422297a64e7Sgd78059 	if (!erip->frame_enable) {
3423297a64e7Sgd78059 		eri_bb_mii_write(erip, regad, data);
3424297a64e7Sgd78059 		return;
3425297a64e7Sgd78059 	}
3426297a64e7Sgd78059 
3427297a64e7Sgd78059 	phyad = erip->phyad;
3428297a64e7Sgd78059 
3429297a64e7Sgd78059 	PUT_MIFREG(mif_frame, (ERI_MIF_FRWRITE |
3430297a64e7Sgd78059 	    (phyad << ERI_MIF_FRPHYAD_SHIFT) |
3431297a64e7Sgd78059 	    (regad << ERI_MIF_FRREGAD_SHIFT) | data));
3432297a64e7Sgd78059 	MIF_ERIDELAY(300,  phyad, regad);
3433297a64e7Sgd78059 	(void) GET_MIFREG(mif_frame);
3434297a64e7Sgd78059 }
3435297a64e7Sgd78059 
3436297a64e7Sgd78059 
3437297a64e7Sgd78059 /* <<<<<<<<<<<<<<<<<	PACKET TRANSMIT FUNCTIONS	>>>>>>>>>>>>>>>>>>>> */
3438297a64e7Sgd78059 
3439297a64e7Sgd78059 #define	ERI_CROSS_PAGE_BOUNDRY(i, size, pagesize) \
3440297a64e7Sgd78059 	((i & pagesize) != ((i + size) & pagesize))
3441297a64e7Sgd78059 
3442297a64e7Sgd78059 /*
3443297a64e7Sgd78059  * Send a single mblk.  Returns B_TRUE if the packet is sent, or disposed of
3444297a64e7Sgd78059  * by freemsg.  Returns B_FALSE if the packet was not sent or queued, and
3445297a64e7Sgd78059  * should be retried later (due to tx resource exhaustion.)
3446297a64e7Sgd78059  */
3447297a64e7Sgd78059 static boolean_t
eri_send_msg(struct eri * erip,mblk_t * mp)3448297a64e7Sgd78059 eri_send_msg(struct eri *erip, mblk_t *mp)
3449297a64e7Sgd78059 {
3450297a64e7Sgd78059 	volatile struct	eri_tmd	*tmdp = NULL;
3451297a64e7Sgd78059 	volatile struct	eri_tmd	*tbasep = NULL;
3452bd78278bSGarrett D'Amore 	uint32_t	len_msg = 0;
3453bd78278bSGarrett D'Amore 	uint32_t	i;
3454297a64e7Sgd78059 	uint64_t	int_me = 0;
3455297a64e7Sgd78059 	uint_t		tmdcsum = 0;
3456297a64e7Sgd78059 	uint_t		start_offset = 0;
3457297a64e7Sgd78059 	uint_t		stuff_offset = 0;
3458297a64e7Sgd78059 	uint_t		flags = 0;
3459297a64e7Sgd78059 
3460297a64e7Sgd78059 	caddr_t	ptr;
3461297a64e7Sgd78059 	uint32_t	offset;
3462297a64e7Sgd78059 	uint64_t	ctrl;
3463297a64e7Sgd78059 	ddi_dma_cookie_t	c;
3464297a64e7Sgd78059 
3465297a64e7Sgd78059 	if (!param_linkup) {
3466297a64e7Sgd78059 		freemsg(mp);
3467297a64e7Sgd78059 		HSTAT(erip, tnocar);
3468297a64e7Sgd78059 		HSTAT(erip, oerrors);
3469297a64e7Sgd78059 		return (B_TRUE);
3470297a64e7Sgd78059 	}
3471297a64e7Sgd78059 
3472297a64e7Sgd78059 #ifdef ERI_HWCSUM
3473*0dc2366fSVenugopal Iyer 	mac_hcksum_get(mp, &start_offset, &stuff_offset, NULL, NULL, &flags);
3474297a64e7Sgd78059 
3475297a64e7Sgd78059 	if (flags & HCK_PARTIALCKSUM) {
3476297a64e7Sgd78059 		if (get_ether_type(mp->b_rptr) == ETHERTYPE_VLAN) {
3477297a64e7Sgd78059 			start_offset += ETHERHEADER_SIZE + 4;
3478297a64e7Sgd78059 			stuff_offset += ETHERHEADER_SIZE + 4;
3479297a64e7Sgd78059 		} else {
3480297a64e7Sgd78059 			start_offset += ETHERHEADER_SIZE;
3481297a64e7Sgd78059 			stuff_offset += ETHERHEADER_SIZE;
3482297a64e7Sgd78059 		}
3483297a64e7Sgd78059 		tmdcsum = ERI_TMD_CSENABL;
3484297a64e7Sgd78059 	}
3485297a64e7Sgd78059 #endif /* ERI_HWCSUM */
3486bd78278bSGarrett D'Amore 
3487bd78278bSGarrett D'Amore 	if ((len_msg = msgsize(mp)) > ERI_BUFSIZE) {
3488bd78278bSGarrett D'Amore 		/*
3489bd78278bSGarrett D'Amore 		 * This sholdn't ever occur, as GLD should not send us
3490bd78278bSGarrett D'Amore 		 * packets that are too big.
3491bd78278bSGarrett D'Amore 		 */
3492bd78278bSGarrett D'Amore 		HSTAT(erip, oerrors);
3493bd78278bSGarrett D'Amore 		freemsg(mp);
3494bd78278bSGarrett D'Amore 		return (B_TRUE);
3495297a64e7Sgd78059 	}
3496297a64e7Sgd78059 
3497297a64e7Sgd78059 	/*
3498297a64e7Sgd78059 	 * update MIB II statistics
3499297a64e7Sgd78059 	 */
3500297a64e7Sgd78059 	BUMP_OutNUcast(erip, mp->b_rptr);
3501297a64e7Sgd78059 
3502297a64e7Sgd78059 	mutex_enter(&erip->xmitlock);
3503297a64e7Sgd78059 
3504297a64e7Sgd78059 	tbasep = erip->eri_tmdp;
3505297a64e7Sgd78059 
3506297a64e7Sgd78059 	/* Check if there are enough descriptors for this packet */
3507297a64e7Sgd78059 	tmdp = erip->tnextp;
3508297a64e7Sgd78059 
3509297a64e7Sgd78059 	if (tmdp >=  erip->tcurp) /* check notmds */
3510297a64e7Sgd78059 		i = tmdp - erip->tcurp;
3511297a64e7Sgd78059 	else
3512297a64e7Sgd78059 		i = tmdp + ERI_TPENDING - erip->tcurp;
3513297a64e7Sgd78059 
3514297a64e7Sgd78059 	if (i > (ERI_TPENDING - 4))
3515297a64e7Sgd78059 		goto notmds;
3516297a64e7Sgd78059 
35176213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic 	if (i >= (ERI_TPENDING >> 1) && !(erip->starts & 0x7)) {
3518297a64e7Sgd78059 		int_me = ERI_TMD_INTME;
3519297a64e7Sgd78059 
35206213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic 		if (!erip->tx_int_me) {
35216213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic 			PUT_GLOBREG(intmask, GET_GLOBREG(intmask) &
35226213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic 			    ~(ERI_G_MASK_TX_INT_ME));
35236213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic 			erip->tx_int_me = 1;
35246213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic 		}
35256213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic 	}
35266213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic 
3527297a64e7Sgd78059 	i = tmdp - tbasep; /* index */
3528297a64e7Sgd78059 
3529bd78278bSGarrett D'Amore 	offset = (i * ERI_BUFSIZE);
3530297a64e7Sgd78059 	ptr = erip->tbuf_kaddr + offset;
3531297a64e7Sgd78059 
3532297a64e7Sgd78059 	mcopymsg(mp, ptr);
3533297a64e7Sgd78059 
3534297a64e7Sgd78059 #ifdef	ERI_HDX_BUG_WORKAROUND
3535297a64e7Sgd78059 	if ((param_mode) || (eri_hdx_pad_enable == 0)) {
3536297a64e7Sgd78059 		if (len_msg < ETHERMIN) {
3537bd78278bSGarrett D'Amore 			bzero((ptr + len_msg), (ETHERMIN - len_msg));
3538297a64e7Sgd78059 			len_msg = ETHERMIN;
3539297a64e7Sgd78059 		}
3540297a64e7Sgd78059 	} else {
3541297a64e7Sgd78059 		if (len_msg < 97) {
3542297a64e7Sgd78059 			bzero((ptr + len_msg), (97 - len_msg));
3543297a64e7Sgd78059 			len_msg = 97;
3544297a64e7Sgd78059 		}
3545297a64e7Sgd78059 	}
3546297a64e7Sgd78059 #endif
3547297a64e7Sgd78059 	c.dmac_address = erip->tbuf_ioaddr + offset;
3548297a64e7Sgd78059 	(void) ddi_dma_sync(erip->tbuf_handle,
3549297a64e7Sgd78059 	    (off_t)offset, len_msg, DDI_DMA_SYNC_FORDEV);
3550297a64e7Sgd78059 
3551bd78278bSGarrett D'Amore 		/* first and last (and only!) descr of packet */
3552bd78278bSGarrett D'Amore 	ctrl = ERI_TMD_SOP | ERI_TMD_EOP | int_me | tmdcsum |
3553297a64e7Sgd78059 	    (start_offset << ERI_TMD_CSSTART_SHIFT) |
3554297a64e7Sgd78059 	    (stuff_offset << ERI_TMD_CSSTUFF_SHIFT);
3555297a64e7Sgd78059 
3556bd78278bSGarrett D'Amore 	PUT_TMD(tmdp, c, len_msg, ctrl);
3557297a64e7Sgd78059 	ERI_SYNCIOPB(erip, tmdp, sizeof (struct eri_tmd),
3558297a64e7Sgd78059 	    DDI_DMA_SYNC_FORDEV);
3559297a64e7Sgd78059 
3560297a64e7Sgd78059 	tmdp = NEXTTMD(erip, tmdp);
3561297a64e7Sgd78059 	erip->tx_cur_cnt++;
3562297a64e7Sgd78059 
3563297a64e7Sgd78059 	erip->tx_kick = tmdp - tbasep;
3564297a64e7Sgd78059 	PUT_ETXREG(tx_kick, erip->tx_kick);
3565297a64e7Sgd78059 	erip->tnextp = tmdp;
3566297a64e7Sgd78059 
3567297a64e7Sgd78059 	erip->starts++;
3568297a64e7Sgd78059 
3569297a64e7Sgd78059 	if (erip->tx_cur_cnt >= tx_interrupt_rate) {
3570297a64e7Sgd78059 		erip->tx_completion = (uint32_t)(GET_ETXREG(tx_completion) &
3571297a64e7Sgd78059 		    ETX_COMPLETION_MASK);
35726213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic 		(void) eri_reclaim(erip, erip->tx_completion);
3573297a64e7Sgd78059 	}
3574297a64e7Sgd78059 	mutex_exit(&erip->xmitlock);
3575297a64e7Sgd78059 
3576297a64e7Sgd78059 	return (B_TRUE);
3577297a64e7Sgd78059 
3578297a64e7Sgd78059 notmds:
3579297a64e7Sgd78059 	HSTAT(erip, notmds);
3580297a64e7Sgd78059 	erip->wantw = B_TRUE;
3581297a64e7Sgd78059 
3582297a64e7Sgd78059 	mutex_exit(&erip->xmitlock);
3583297a64e7Sgd78059 
3584297a64e7Sgd78059 	return (B_FALSE);
3585297a64e7Sgd78059 }
3586297a64e7Sgd78059 
3587297a64e7Sgd78059 static mblk_t *
eri_m_tx(void * arg,mblk_t * mp)3588297a64e7Sgd78059 eri_m_tx(void *arg, mblk_t *mp)
3589297a64e7Sgd78059 {
3590297a64e7Sgd78059 	struct eri *erip = arg;
3591297a64e7Sgd78059 	mblk_t *next;
3592297a64e7Sgd78059 
3593297a64e7Sgd78059 	while (mp != NULL) {
3594297a64e7Sgd78059 		next = mp->b_next;
3595297a64e7Sgd78059 		mp->b_next = NULL;
3596297a64e7Sgd78059 		if (!eri_send_msg(erip, mp)) {
3597297a64e7Sgd78059 			mp->b_next = next;
3598297a64e7Sgd78059 			break;
3599297a64e7Sgd78059 		}
3600297a64e7Sgd78059 		mp = next;
3601297a64e7Sgd78059 	}
3602297a64e7Sgd78059 
3603297a64e7Sgd78059 	return (mp);
3604297a64e7Sgd78059 }
3605297a64e7Sgd78059 
3606297a64e7Sgd78059 /*
3607297a64e7Sgd78059  * Transmit completion reclaiming.
3608297a64e7Sgd78059  */
3609297a64e7Sgd78059 static boolean_t
eri_reclaim(struct eri * erip,uint32_t tx_completion)3610297a64e7Sgd78059 eri_reclaim(struct eri *erip, uint32_t tx_completion)
3611297a64e7Sgd78059 {
3612297a64e7Sgd78059 	volatile struct	eri_tmd	*tmdp;
3613297a64e7Sgd78059 	struct	eri_tmd	*tcomp;
3614297a64e7Sgd78059 	struct	eri_tmd	*tbasep;
3615297a64e7Sgd78059 	struct	eri_tmd	*tlimp;
3616297a64e7Sgd78059 	uint64_t	flags;
3617297a64e7Sgd78059 	uint_t reclaimed = 0;
3618297a64e7Sgd78059 
3619297a64e7Sgd78059 	tbasep = erip->eri_tmdp;
3620297a64e7Sgd78059 	tlimp = erip->eri_tmdlimp;
3621297a64e7Sgd78059 
3622297a64e7Sgd78059 	tmdp = erip->tcurp;
3623297a64e7Sgd78059 	tcomp = tbasep + tx_completion; /* pointer to completion tmd */
3624297a64e7Sgd78059 
3625297a64e7Sgd78059 	/*
3626297a64e7Sgd78059 	 * Loop through each TMD starting from tcurp and upto tcomp.
3627297a64e7Sgd78059 	 */
3628297a64e7Sgd78059 	while (tmdp != tcomp) {
3629297a64e7Sgd78059 		flags = GET_TMD_FLAGS(tmdp);
3630297a64e7Sgd78059 		if (flags & (ERI_TMD_SOP))
3631297a64e7Sgd78059 			HSTAT(erip, opackets64);
3632297a64e7Sgd78059 
3633297a64e7Sgd78059 		HSTATN(erip, obytes64, (flags & ERI_TMD_BUFSIZE));
3634297a64e7Sgd78059 
3635297a64e7Sgd78059 		tmdp = NEXTTMDP(tbasep, tlimp, tmdp);
3636297a64e7Sgd78059 		reclaimed++;
3637297a64e7Sgd78059 	}
3638297a64e7Sgd78059 
3639297a64e7Sgd78059 	erip->tcurp = tmdp;
3640297a64e7Sgd78059 	erip->tx_cur_cnt -= reclaimed;
3641297a64e7Sgd78059 
3642297a64e7Sgd78059 	return (erip->wantw && reclaimed ? B_TRUE : B_FALSE);
3643297a64e7Sgd78059 }
3644297a64e7Sgd78059 
3645297a64e7Sgd78059 
3646297a64e7Sgd78059 /* <<<<<<<<<<<<<<<<<<<	PACKET RECEIVE FUNCTIONS	>>>>>>>>>>>>>>>>>>> */
3647297a64e7Sgd78059 static mblk_t *
eri_read_dma(struct eri * erip,volatile struct rmd * rmdp,int rmdi,uint64_t flags)3648297a64e7Sgd78059 eri_read_dma(struct eri *erip, volatile struct rmd *rmdp,
3649297a64e7Sgd78059 	int rmdi, uint64_t flags)
3650297a64e7Sgd78059 {
3651297a64e7Sgd78059 	mblk_t	*bp, *nbp;
3652297a64e7Sgd78059 	int	len;
3653297a64e7Sgd78059 	uint_t ccnt;
3654297a64e7Sgd78059 	ddi_dma_cookie_t	c;
3655297a64e7Sgd78059 #ifdef ERI_RCV_CKSUM
3656297a64e7Sgd78059 	ushort_t sum;
3657297a64e7Sgd78059 #endif /* ERI_RCV_CKSUM */
3658297a64e7Sgd78059 	mblk_t *retmp = NULL;
3659297a64e7Sgd78059 
3660297a64e7Sgd78059 	bp = erip->rmblkp[rmdi];
3661297a64e7Sgd78059 	len = (flags & ERI_RMD_BUFSIZE) >> ERI_RMD_BUFSIZE_SHIFT;
3662297a64e7Sgd78059 #ifdef	ERI_DONT_STRIP_CRC
3663297a64e7Sgd78059 	len -= 4;
3664297a64e7Sgd78059 #endif
3665297a64e7Sgd78059 	/*
3666297a64e7Sgd78059 	 * In the event of RX FIFO overflow error, ERI REV 1.0 ASIC can
3667297a64e7Sgd78059 	 * corrupt packets following the descriptor corresponding the
3668297a64e7Sgd78059 	 * overflow. To detect the corrupted packets, we disable the
3669297a64e7Sgd78059 	 * dropping of the "bad" packets at the MAC. The descriptor
3670297a64e7Sgd78059 	 * then would have the "BAD" bit set. We drop the overflowing
3671297a64e7Sgd78059 	 * packet and the packet following it. We could have done some sort
3672297a64e7Sgd78059 	 * of checking to determine if the second packet was indeed bad
3673297a64e7Sgd78059 	 * (using CRC or checksum) but it would be expensive in this
3674297a64e7Sgd78059 	 * routine, since it is run in interrupt context.
3675297a64e7Sgd78059 	 */
3676297a64e7Sgd78059 	if ((flags & ERI_RMD_BAD) || (len  < ETHERMIN) || (len > ETHERMAX+4)) {
3677297a64e7Sgd78059 
3678297a64e7Sgd78059 		HSTAT(erip, rx_bad_pkts);
3679297a64e7Sgd78059 		if ((flags & ERI_RMD_BAD) == 0)
3680297a64e7Sgd78059 			HSTAT(erip, ierrors);
3681297a64e7Sgd78059 		if (len < ETHERMIN) {
3682297a64e7Sgd78059 			HSTAT(erip, rx_runt);
3683297a64e7Sgd78059 		} else if (len > ETHERMAX+4) {
3684297a64e7Sgd78059 			HSTAT(erip, rx_toolong_pkts);
3685297a64e7Sgd78059 		}
3686297a64e7Sgd78059 		HSTAT(erip, drop);
3687297a64e7Sgd78059 		UPDATE_RMD(rmdp);
3688297a64e7Sgd78059 
3689297a64e7Sgd78059 		ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
3690297a64e7Sgd78059 		    DDI_DMA_SYNC_FORDEV);
3691297a64e7Sgd78059 		return (NULL);
3692297a64e7Sgd78059 	}
3693297a64e7Sgd78059 #ifdef  ERI_DONT_STRIP_CRC
3694297a64e7Sgd78059 	{
3695297a64e7Sgd78059 		uint32_t hw_fcs, tail_fcs;
3696297a64e7Sgd78059 		/*
3697297a64e7Sgd78059 		 * since we don't let the hardware strip the CRC in hdx
3698297a64e7Sgd78059 		 * then the driver needs to do it.
3699297a64e7Sgd78059 		 * this is to workaround a hardware bug
3700297a64e7Sgd78059 		 */
3701297a64e7Sgd78059 		bp->b_wptr = bp->b_rptr + ERI_FSTBYTE_OFFSET + len;
3702297a64e7Sgd78059 		/*
3703297a64e7Sgd78059 		 * Get the Checksum calculated by the hardware.
3704297a64e7Sgd78059 		 */
3705297a64e7Sgd78059 		hw_fcs = flags & ERI_RMD_CKSUM;
3706297a64e7Sgd78059 		/*
3707297a64e7Sgd78059 		 * Catch the case when the CRC starts on an odd
3708297a64e7Sgd78059 		 * boundary.
3709297a64e7Sgd78059 		 */
3710297a64e7Sgd78059 		tail_fcs = bp->b_wptr[0] << 8 | bp->b_wptr[1];
3711297a64e7Sgd78059 		tail_fcs += bp->b_wptr[2] << 8 | bp->b_wptr[3];
3712297a64e7Sgd78059 		tail_fcs = (tail_fcs & 0xffff) + (tail_fcs >> 16);
3713297a64e7Sgd78059 		if ((uintptr_t)(bp->b_wptr) & 1) {
3714297a64e7Sgd78059 			tail_fcs = (tail_fcs << 8) & 0xffff  | (tail_fcs >> 8);
3715297a64e7Sgd78059 		}
3716297a64e7Sgd78059 		hw_fcs += tail_fcs;
3717297a64e7Sgd78059 		hw_fcs = (hw_fcs & 0xffff) + (hw_fcs >> 16);
3718297a64e7Sgd78059 		hw_fcs &= 0xffff;
3719297a64e7Sgd78059 		/*
3720297a64e7Sgd78059 		 * Now we can replace what the hardware wrote, make believe
3721297a64e7Sgd78059 		 * it got it right in the first place.
3722297a64e7Sgd78059 		 */
3723297a64e7Sgd78059 		flags = (flags & ~(uint64_t)ERI_RMD_CKSUM) | hw_fcs;
3724297a64e7Sgd78059 	}
3725297a64e7Sgd78059 #endif
3726297a64e7Sgd78059 	/*
3727297a64e7Sgd78059 	 * Packet Processing
3728297a64e7Sgd78059 	 * Once we get a packet bp, we try allocate a new mblk, nbp
3729297a64e7Sgd78059 	 * to replace this one. If we succeed, we map it to the current
3730297a64e7Sgd78059 	 * dma handle and update the descriptor with the new cookie. We
3731297a64e7Sgd78059 	 * then put bp in our read service queue erip->ipq, if it exists
3732297a64e7Sgd78059 	 * or we just bp to the streams expecting it.
3733297a64e7Sgd78059 	 * If allocation of the new mblk fails, we implicitly drop the
3734297a64e7Sgd78059 	 * current packet, i.e do not pass up the mblk and re-use it.
3735297a64e7Sgd78059 	 * Re-mapping is not required.
3736297a64e7Sgd78059 	 */
3737297a64e7Sgd78059 
3738297a64e7Sgd78059 	if (len < eri_rx_bcopy_max) {
3739297a64e7Sgd78059 		if ((nbp = eri_allocb_sp(len + ERI_FSTBYTE_OFFSET))) {
3740297a64e7Sgd78059 			(void) ddi_dma_sync(erip->ndmarh[rmdi], 0,
3741297a64e7Sgd78059 			    len + ERI_FSTBYTE_OFFSET, DDI_DMA_SYNC_FORCPU);
3742297a64e7Sgd78059 			DB_TYPE(nbp) = M_DATA;
3743297a64e7Sgd78059 			bcopy(bp->b_rptr, nbp->b_rptr,
3744297a64e7Sgd78059 			    len + ERI_FSTBYTE_OFFSET);
3745297a64e7Sgd78059 			UPDATE_RMD(rmdp);
3746297a64e7Sgd78059 			ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
3747297a64e7Sgd78059 			    DDI_DMA_SYNC_FORDEV);
3748297a64e7Sgd78059 
3749297a64e7Sgd78059 			/* Add the First Byte offset to the b_rptr */
3750297a64e7Sgd78059 			nbp->b_rptr += ERI_FSTBYTE_OFFSET;
3751297a64e7Sgd78059 			nbp->b_wptr = nbp->b_rptr + len;
3752297a64e7Sgd78059 
3753297a64e7Sgd78059 #ifdef ERI_RCV_CKSUM
3754297a64e7Sgd78059 			sum = ~(uint16_t)(flags & ERI_RMD_CKSUM);
3755297a64e7Sgd78059 			ERI_PROCESS_READ(erip, nbp, sum);
3756297a64e7Sgd78059 #else
3757297a64e7Sgd78059 			ERI_PROCESS_READ(erip, nbp);
3758297a64e7Sgd78059 #endif
3759297a64e7Sgd78059 			retmp = nbp;
3760297a64e7Sgd78059 		} else {
3761297a64e7Sgd78059 
3762297a64e7Sgd78059 			/*
3763297a64e7Sgd78059 			 * mblk allocation has failed. Re-use the old mblk for
3764297a64e7Sgd78059 			 * the next packet. Re-mapping is not required since
3765297a64e7Sgd78059 			 * the same mblk and dma cookie is to be used again.
3766297a64e7Sgd78059 			 */
3767297a64e7Sgd78059 			HSTAT(erip, ierrors);
3768297a64e7Sgd78059 			HSTAT(erip, allocbfail);
3769297a64e7Sgd78059 			HSTAT(erip, norcvbuf);
3770297a64e7Sgd78059 
3771297a64e7Sgd78059 			UPDATE_RMD(rmdp);
3772297a64e7Sgd78059 			ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
3773297a64e7Sgd78059 			    DDI_DMA_SYNC_FORDEV);
3774297a64e7Sgd78059 			ERI_DEBUG_MSG1(erip, RESOURCE_MSG, "allocb fail");
3775297a64e7Sgd78059 		}
3776297a64e7Sgd78059 	} else {
3777297a64e7Sgd78059 		/* Use dma unmap/map */
3778297a64e7Sgd78059 		if ((nbp = eri_allocb_sp(ERI_BUFSIZE))) {
3779297a64e7Sgd78059 			/*
3780297a64e7Sgd78059 			 * How do we harden this, specially if unbind
3781297a64e7Sgd78059 			 * succeeds and then bind fails?
3782297a64e7Sgd78059 			 *  If Unbind fails, we can leave without updating
3783297a64e7Sgd78059 			 * the descriptor but would it continue to work on
3784297a64e7Sgd78059 			 * next round?
3785297a64e7Sgd78059 			 */
3786297a64e7Sgd78059 			(void) ddi_dma_unbind_handle(erip->ndmarh[rmdi]);
3787297a64e7Sgd78059 			(void) ddi_dma_addr_bind_handle(erip->ndmarh[rmdi],
3788297a64e7Sgd78059 			    NULL, (caddr_t)nbp->b_rptr, ERI_BUFSIZE,
3789297a64e7Sgd78059 			    DDI_DMA_READ | DDI_DMA_CONSISTENT,
3790297a64e7Sgd78059 			    DDI_DMA_DONTWAIT, 0, &c, &ccnt);
3791297a64e7Sgd78059 
3792297a64e7Sgd78059 			erip->rmblkp[rmdi] = nbp;
3793297a64e7Sgd78059 			PUT_RMD(rmdp, c);
3794297a64e7Sgd78059 			ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
3795297a64e7Sgd78059 			    DDI_DMA_SYNC_FORDEV);
3796297a64e7Sgd78059 
3797297a64e7Sgd78059 			/* Add the First Byte offset to the b_rptr */
3798297a64e7Sgd78059 
3799297a64e7Sgd78059 			bp->b_rptr += ERI_FSTBYTE_OFFSET;
3800297a64e7Sgd78059 			bp->b_wptr = bp->b_rptr + len;
3801297a64e7Sgd78059 
3802297a64e7Sgd78059 #ifdef ERI_RCV_CKSUM
3803297a64e7Sgd78059 			sum = ~(uint16_t)(flags & ERI_RMD_CKSUM);
3804297a64e7Sgd78059 			ERI_PROCESS_READ(erip, bp, sum);
3805297a64e7Sgd78059 #else
3806297a64e7Sgd78059 			ERI_PROCESS_READ(erip, bp);
3807297a64e7Sgd78059 #endif
3808297a64e7Sgd78059 			retmp = bp;
3809297a64e7Sgd78059 		} else {
3810297a64e7Sgd78059 
3811297a64e7Sgd78059 			/*
3812297a64e7Sgd78059 			 * mblk allocation has failed. Re-use the old mblk for
3813297a64e7Sgd78059 			 * the next packet. Re-mapping is not required since
3814297a64e7Sgd78059 			 * the same mblk and dma cookie is to be used again.
3815297a64e7Sgd78059 			 */
3816297a64e7Sgd78059 			HSTAT(erip, ierrors);
3817297a64e7Sgd78059 			HSTAT(erip, allocbfail);
3818297a64e7Sgd78059 			HSTAT(erip, norcvbuf);
3819297a64e7Sgd78059 
3820297a64e7Sgd78059 			UPDATE_RMD(rmdp);
3821297a64e7Sgd78059 			ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
3822297a64e7Sgd78059 			    DDI_DMA_SYNC_FORDEV);
3823297a64e7Sgd78059 			ERI_DEBUG_MSG1(erip, RESOURCE_MSG, "allocb fail");
3824297a64e7Sgd78059 		}
3825297a64e7Sgd78059 	}
3826297a64e7Sgd78059 
3827297a64e7Sgd78059 	return (retmp);
3828297a64e7Sgd78059 }
3829297a64e7Sgd78059 
3830297a64e7Sgd78059 #define	LINK_STAT_DISPLAY_TIME	20
3831297a64e7Sgd78059 
3832297a64e7Sgd78059 static int
eri_init_xfer_params(struct eri * erip)3833297a64e7Sgd78059 eri_init_xfer_params(struct eri *erip)
3834297a64e7Sgd78059 {
3835297a64e7Sgd78059 	int	i;
3836297a64e7Sgd78059 	dev_info_t *dip;
3837297a64e7Sgd78059 
3838297a64e7Sgd78059 	dip = erip->dip;
3839297a64e7Sgd78059 
3840297a64e7Sgd78059 	for (i = 0; i < A_CNT(param_arr); i++)
3841297a64e7Sgd78059 		erip->param_arr[i] = param_arr[i];
3842297a64e7Sgd78059 
3843297a64e7Sgd78059 	erip->xmit_dma_mode = 0;
3844297a64e7Sgd78059 	erip->rcv_dma_mode = 0;
3845297a64e7Sgd78059 	erip->mifpoll_enable = mifpoll_enable;
3846297a64e7Sgd78059 	erip->lance_mode_enable = lance_mode;
3847297a64e7Sgd78059 	erip->frame_enable = 1;
3848297a64e7Sgd78059 	erip->ngu_enable = ngu_enable;
3849297a64e7Sgd78059 
3850297a64e7Sgd78059 	if (!erip->g_nd && !eri_param_register(erip,
3851297a64e7Sgd78059 	    erip->param_arr, A_CNT(param_arr))) {
3852297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
3853297a64e7Sgd78059 		    param_reg_fail_msg);
3854297a64e7Sgd78059 			return (-1);
3855297a64e7Sgd78059 		}
3856297a64e7Sgd78059 
3857297a64e7Sgd78059 	/*
3858297a64e7Sgd78059 	 * Set up the start-up values for user-configurable parameters
3859297a64e7Sgd78059 	 * Get the values from the global variables first.
3860297a64e7Sgd78059 	 * Use the MASK to limit the value to allowed maximum.
3861297a64e7Sgd78059 	 */
3862297a64e7Sgd78059 
3863297a64e7Sgd78059 	param_transceiver = NO_XCVR;
3864297a64e7Sgd78059 
3865297a64e7Sgd78059 /*
3866297a64e7Sgd78059  * The link speed may be forced to either 10 Mbps or 100 Mbps using the
3867297a64e7Sgd78059  * property "transfer-speed". This may be done in OBP by using the command
3868297a64e7Sgd78059  * "apply transfer-speed=<speed> <device>". The speed may be either 10 or 100.
3869297a64e7Sgd78059  */
3870297a64e7Sgd78059 	i = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "transfer-speed", 0);
3871297a64e7Sgd78059 	if (i != 0) {
3872297a64e7Sgd78059 		param_autoneg = 0;	/* force speed */
3873297a64e7Sgd78059 		param_anar_100T4 = 0;
3874297a64e7Sgd78059 		param_anar_10fdx = 0;
3875297a64e7Sgd78059 		param_anar_10hdx = 0;
3876297a64e7Sgd78059 		param_anar_100fdx = 0;
3877297a64e7Sgd78059 		param_anar_100hdx = 0;
3878297a64e7Sgd78059 		param_anar_asm_dir = 0;
3879297a64e7Sgd78059 		param_anar_pause = 0;
3880297a64e7Sgd78059 
3881297a64e7Sgd78059 		if (i == 10)
3882297a64e7Sgd78059 			param_anar_10hdx = 1;
3883297a64e7Sgd78059 		else if (i == 100)
3884297a64e7Sgd78059 			param_anar_100hdx = 1;
3885297a64e7Sgd78059 	}
3886297a64e7Sgd78059 
3887297a64e7Sgd78059 	/*
3888297a64e7Sgd78059 	 * Get the parameter values configured in .conf file.
3889297a64e7Sgd78059 	 */
3890297a64e7Sgd78059 	param_ipg1 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "ipg1", ipg1) &
3891297a64e7Sgd78059 	    ERI_MASK_8BIT;
3892297a64e7Sgd78059 
3893297a64e7Sgd78059 	param_ipg2 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "ipg2", ipg2) &
3894297a64e7Sgd78059 	    ERI_MASK_8BIT;
3895297a64e7Sgd78059 
3896297a64e7Sgd78059 	param_use_intphy = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3897297a64e7Sgd78059 	    "use_int_xcvr", use_int_xcvr) & ERI_MASK_1BIT;
3898297a64e7Sgd78059 
3899297a64e7Sgd78059 	param_use_intphy = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3900297a64e7Sgd78059 	    "pace_size", pace_size) & ERI_MASK_8BIT;
3901297a64e7Sgd78059 
3902297a64e7Sgd78059 	param_autoneg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3903297a64e7Sgd78059 	    "adv_autoneg_cap", adv_autoneg_cap) & ERI_MASK_1BIT;
3904297a64e7Sgd78059 
3905297a64e7Sgd78059 	param_autoneg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3906297a64e7Sgd78059 	    "adv_autoneg_cap", adv_autoneg_cap) & ERI_MASK_1BIT;
3907297a64e7Sgd78059 
3908297a64e7Sgd78059 	param_anar_100T4 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3909297a64e7Sgd78059 	    "adv_100T4_cap", adv_100T4_cap) & ERI_MASK_1BIT;
3910297a64e7Sgd78059 
3911297a64e7Sgd78059 	param_anar_100fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3912297a64e7Sgd78059 	    "adv_100fdx_cap", adv_100fdx_cap) & ERI_MASK_1BIT;
3913297a64e7Sgd78059 
3914297a64e7Sgd78059 	param_anar_100hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3915297a64e7Sgd78059 	    "adv_100hdx_cap", adv_100hdx_cap) & ERI_MASK_1BIT;
3916297a64e7Sgd78059 
3917297a64e7Sgd78059 	param_anar_10fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3918297a64e7Sgd78059 	    "adv_10fdx_cap", adv_10fdx_cap) & ERI_MASK_1BIT;
3919297a64e7Sgd78059 
3920297a64e7Sgd78059 	param_anar_10hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3921297a64e7Sgd78059 	    "adv_10hdx_cap", adv_10hdx_cap) & ERI_MASK_1BIT;
3922297a64e7Sgd78059 
3923297a64e7Sgd78059 	param_ipg0 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "ipg0", ipg0) &
3924297a64e7Sgd78059 	    ERI_MASK_8BIT;
3925297a64e7Sgd78059 
3926297a64e7Sgd78059 	param_intr_blank_time = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3927297a64e7Sgd78059 	    "intr_blank_time", intr_blank_time) & ERI_MASK_8BIT;
3928297a64e7Sgd78059 
3929297a64e7Sgd78059 	param_intr_blank_packets = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3930297a64e7Sgd78059 	    "intr_blank_packets", intr_blank_packets) & ERI_MASK_8BIT;
3931297a64e7Sgd78059 
3932297a64e7Sgd78059 	param_lance_mode = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3933297a64e7Sgd78059 	    "lance_mode", lance_mode) & ERI_MASK_1BIT;
3934297a64e7Sgd78059 
3935297a64e7Sgd78059 	param_select_link = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3936297a64e7Sgd78059 	    "select_link", select_link) & ERI_MASK_1BIT;
3937297a64e7Sgd78059 
3938297a64e7Sgd78059 	param_default_link = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3939297a64e7Sgd78059 	    "default_link", default_link) & ERI_MASK_1BIT;
3940297a64e7Sgd78059 
3941297a64e7Sgd78059 	param_anar_asm_dir = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3942297a64e7Sgd78059 	    "adv_asm_dir_cap", adv_pauseTX_cap) & ERI_MASK_1BIT;
3943297a64e7Sgd78059 
3944297a64e7Sgd78059 	param_anar_pause = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3945297a64e7Sgd78059 	    "adv_pause_cap", adv_pauseRX_cap) & ERI_MASK_1BIT;
3946297a64e7Sgd78059 
3947297a64e7Sgd78059 	if (link_pulse_disabled)
3948297a64e7Sgd78059 		erip->link_pulse_disabled = 1;
3949297a64e7Sgd78059 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, 0, "link-pulse-disabled"))
3950297a64e7Sgd78059 		erip->link_pulse_disabled = 1;
3951297a64e7Sgd78059 
3952297a64e7Sgd78059 	eri_statinit(erip);
3953297a64e7Sgd78059 	return (0);
3954297a64e7Sgd78059 
3955297a64e7Sgd78059 }
3956297a64e7Sgd78059 
3957297a64e7Sgd78059 static void
eri_process_ndd_ioctl(struct eri * erip,queue_t * wq,mblk_t * mp,int cmd)3958297a64e7Sgd78059 eri_process_ndd_ioctl(struct eri *erip, queue_t *wq, mblk_t *mp, int cmd)
3959297a64e7Sgd78059 {
3960297a64e7Sgd78059 
3961297a64e7Sgd78059 	uint32_t old_ipg1, old_ipg2, old_use_int_xcvr, old_autoneg;
3962297a64e7Sgd78059 	uint32_t old_100T4;
3963297a64e7Sgd78059 	uint32_t old_100fdx, old_100hdx, old_10fdx, old_10hdx;
3964297a64e7Sgd78059 	uint32_t old_ipg0, old_lance_mode;
3965297a64e7Sgd78059 	uint32_t old_intr_blank_time, old_intr_blank_packets;
3966297a64e7Sgd78059 	uint32_t old_asm_dir, old_pause;
3967297a64e7Sgd78059 	uint32_t old_select_link, old_default_link;
3968297a64e7Sgd78059 
3969297a64e7Sgd78059 	switch (cmd) {
3970297a64e7Sgd78059 	case ERI_ND_GET:
3971297a64e7Sgd78059 
3972297a64e7Sgd78059 		old_autoneg =	param_autoneg;
3973297a64e7Sgd78059 		old_100T4 =	param_anar_100T4;
3974297a64e7Sgd78059 		old_100fdx =	param_anar_100fdx;
3975297a64e7Sgd78059 		old_100hdx =	param_anar_100hdx;
3976297a64e7Sgd78059 		old_10fdx =	param_anar_10fdx;
3977297a64e7Sgd78059 		old_10hdx =	param_anar_10hdx;
3978297a64e7Sgd78059 		old_asm_dir =	param_anar_asm_dir;
3979297a64e7Sgd78059 		old_pause =	param_anar_pause;
3980297a64e7Sgd78059 
3981297a64e7Sgd78059 		param_autoneg = old_autoneg & ~ERI_NOTUSR;
3982297a64e7Sgd78059 		param_anar_100T4 = old_100T4 & ~ERI_NOTUSR;
3983297a64e7Sgd78059 		param_anar_100fdx = old_100fdx & ~ERI_NOTUSR;
3984297a64e7Sgd78059 		param_anar_100hdx = old_100hdx & ~ERI_NOTUSR;
3985297a64e7Sgd78059 		param_anar_10fdx = old_10fdx & ~ERI_NOTUSR;
3986297a64e7Sgd78059 		param_anar_10hdx = old_10hdx & ~ERI_NOTUSR;
3987297a64e7Sgd78059 		param_anar_asm_dir = old_asm_dir & ~ERI_NOTUSR;
3988297a64e7Sgd78059 		param_anar_pause = old_pause & ~ERI_NOTUSR;
3989297a64e7Sgd78059 
3990297a64e7Sgd78059 		if (!eri_nd_getset(wq, erip->g_nd, mp)) {
3991297a64e7Sgd78059 			param_autoneg = old_autoneg;
3992297a64e7Sgd78059 			param_anar_100T4 = old_100T4;
3993297a64e7Sgd78059 			param_anar_100fdx = old_100fdx;
3994297a64e7Sgd78059 			param_anar_100hdx = old_100hdx;
3995297a64e7Sgd78059 			param_anar_10fdx = old_10fdx;
3996297a64e7Sgd78059 			param_anar_10hdx = old_10hdx;
3997297a64e7Sgd78059 			param_anar_asm_dir = old_asm_dir;
3998297a64e7Sgd78059 			param_anar_pause = old_pause;
3999297a64e7Sgd78059 			miocnak(wq, mp, 0, EINVAL);
4000297a64e7Sgd78059 			return;
4001297a64e7Sgd78059 		}
4002297a64e7Sgd78059 		param_autoneg = old_autoneg;
4003297a64e7Sgd78059 		param_anar_100T4 = old_100T4;
4004297a64e7Sgd78059 		param_anar_100fdx = old_100fdx;
4005297a64e7Sgd78059 		param_anar_100hdx = old_100hdx;
4006297a64e7Sgd78059 		param_anar_10fdx = old_10fdx;
4007297a64e7Sgd78059 		param_anar_10hdx = old_10hdx;
4008297a64e7Sgd78059 		param_anar_asm_dir = old_asm_dir;
4009297a64e7Sgd78059 		param_anar_pause = old_pause;
4010297a64e7Sgd78059 
4011297a64e7Sgd78059 		qreply(wq, mp);
4012297a64e7Sgd78059 		break;
4013297a64e7Sgd78059 
4014297a64e7Sgd78059 	case ERI_ND_SET:
4015297a64e7Sgd78059 		old_ipg0 = param_ipg0;
4016297a64e7Sgd78059 		old_intr_blank_time = param_intr_blank_time;
4017297a64e7Sgd78059 		old_intr_blank_packets = param_intr_blank_packets;
4018297a64e7Sgd78059 		old_lance_mode = param_lance_mode;
4019297a64e7Sgd78059 		old_ipg1 = param_ipg1;
4020297a64e7Sgd78059 		old_ipg2 = param_ipg2;
4021297a64e7Sgd78059 		old_use_int_xcvr = param_use_intphy;
4022297a64e7Sgd78059 		old_autoneg = param_autoneg;
4023297a64e7Sgd78059 		old_100T4 =	param_anar_100T4;
4024297a64e7Sgd78059 		old_100fdx =	param_anar_100fdx;
4025297a64e7Sgd78059 		old_100hdx =	param_anar_100hdx;
4026297a64e7Sgd78059 		old_10fdx =	param_anar_10fdx;
4027297a64e7Sgd78059 		old_10hdx =	param_anar_10hdx;
4028297a64e7Sgd78059 		param_autoneg = 0xff;
4029297a64e7Sgd78059 		old_asm_dir = param_anar_asm_dir;
4030297a64e7Sgd78059 		param_anar_asm_dir = 0xff;
4031297a64e7Sgd78059 		old_pause = param_anar_pause;
4032297a64e7Sgd78059 		param_anar_pause = 0xff;
4033297a64e7Sgd78059 		old_select_link = param_select_link;
4034297a64e7Sgd78059 		old_default_link = param_default_link;
4035297a64e7Sgd78059 
4036297a64e7Sgd78059 		if (!eri_nd_getset(wq, erip->g_nd, mp)) {
4037297a64e7Sgd78059 			param_autoneg = old_autoneg;
4038297a64e7Sgd78059 			miocnak(wq, mp, 0, EINVAL);
4039297a64e7Sgd78059 			return;
4040297a64e7Sgd78059 		}
4041297a64e7Sgd78059 
4042297a64e7Sgd78059 		qreply(wq, mp);
4043297a64e7Sgd78059 
4044297a64e7Sgd78059 		if (param_autoneg != 0xff) {
4045297a64e7Sgd78059 			ERI_DEBUG_MSG2(erip, NDD_MSG,
4046297a64e7Sgd78059 			    "ndd_ioctl: new param_autoneg %d", param_autoneg);
4047297a64e7Sgd78059 			param_linkup = 0;
4048297a64e7Sgd78059 			erip->stats.link_up = LINK_STATE_DOWN;
4049297a64e7Sgd78059 			erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
4050297a64e7Sgd78059 			(void) eri_init(erip);
4051297a64e7Sgd78059 		} else {
4052297a64e7Sgd78059 			param_autoneg = old_autoneg;
4053297a64e7Sgd78059 			if ((old_use_int_xcvr != param_use_intphy) ||
4054297a64e7Sgd78059 			    (old_default_link != param_default_link) ||
4055297a64e7Sgd78059 			    (old_select_link != param_select_link)) {
4056297a64e7Sgd78059 				param_linkup = 0;
4057297a64e7Sgd78059 				erip->stats.link_up = LINK_STATE_DOWN;
4058297a64e7Sgd78059 				erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
4059297a64e7Sgd78059 				(void) eri_init(erip);
4060297a64e7Sgd78059 			} else if ((old_ipg1 != param_ipg1) ||
4061297a64e7Sgd78059 			    (old_ipg2 != param_ipg2) ||
4062297a64e7Sgd78059 			    (old_ipg0 != param_ipg0) ||
4063297a64e7Sgd78059 			    (old_intr_blank_time != param_intr_blank_time) ||
4064297a64e7Sgd78059 			    (old_intr_blank_packets !=
4065297a64e7Sgd78059 			    param_intr_blank_packets) ||
4066297a64e7Sgd78059 			    (old_lance_mode != param_lance_mode)) {
4067297a64e7Sgd78059 				param_linkup = 0;
4068297a64e7Sgd78059 				erip->stats.link_up = LINK_STATE_DOWN;
4069297a64e7Sgd78059 				erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
4070297a64e7Sgd78059 				(void) eri_init(erip);
4071297a64e7Sgd78059 			}
4072297a64e7Sgd78059 		}
4073297a64e7Sgd78059 		break;
4074297a64e7Sgd78059 	}
4075297a64e7Sgd78059 }
4076297a64e7Sgd78059 
4077297a64e7Sgd78059 
4078297a64e7Sgd78059 static int
eri_stat_kstat_update(kstat_t * ksp,int rw)4079297a64e7Sgd78059 eri_stat_kstat_update(kstat_t *ksp, int rw)
4080297a64e7Sgd78059 {
4081297a64e7Sgd78059 	struct eri *erip;
4082297a64e7Sgd78059 	struct erikstat *erikp;
4083297a64e7Sgd78059 	struct stats *esp;
4084297a64e7Sgd78059 	boolean_t macupdate = B_FALSE;
4085297a64e7Sgd78059 
4086297a64e7Sgd78059 	erip = (struct eri *)ksp->ks_private;
4087297a64e7Sgd78059 	erikp = (struct erikstat *)ksp->ks_data;
4088297a64e7Sgd78059 
4089297a64e7Sgd78059 	if (rw != KSTAT_READ)
4090297a64e7Sgd78059 		return (EACCES);
4091297a64e7Sgd78059 	/*
4092297a64e7Sgd78059 	 * Update all the stats by reading all the counter registers.
4093297a64e7Sgd78059 	 * Counter register stats are not updated till they overflow
4094297a64e7Sgd78059 	 * and interrupt.
4095297a64e7Sgd78059 	 */
4096297a64e7Sgd78059 
4097297a64e7Sgd78059 	mutex_enter(&erip->xmitlock);
4098297a64e7Sgd78059 	if ((erip->flags & ERI_RUNNING) && (erip->flags & ERI_TXINIT)) {
4099297a64e7Sgd78059 		erip->tx_completion =
4100297a64e7Sgd78059 		    GET_ETXREG(tx_completion) & ETX_COMPLETION_MASK;
4101297a64e7Sgd78059 		macupdate |= eri_reclaim(erip, erip->tx_completion);
4102297a64e7Sgd78059 	}
4103297a64e7Sgd78059 	mutex_exit(&erip->xmitlock);
4104297a64e7Sgd78059 	if (macupdate)
4105297a64e7Sgd78059 		mac_tx_update(erip->mh);
4106297a64e7Sgd78059 
4107297a64e7Sgd78059 	eri_savecntrs(erip);
4108297a64e7Sgd78059 
4109297a64e7Sgd78059 	esp = &erip->stats;
4110297a64e7Sgd78059 
4111297a64e7Sgd78059 	erikp->erik_txmac_maxpkt_err.value.ul = esp->txmac_maxpkt_err;
4112297a64e7Sgd78059 	erikp->erik_defer_timer_exp.value.ul = esp->defer_timer_exp;
4113297a64e7Sgd78059 	erikp->erik_peak_attempt_cnt.value.ul = esp->peak_attempt_cnt;
4114297a64e7Sgd78059 	erikp->erik_tx_hang.value.ul	= esp->tx_hang;
4115297a64e7Sgd78059 
4116297a64e7Sgd78059 	erikp->erik_no_free_rx_desc.value.ul	= esp->no_free_rx_desc;
4117297a64e7Sgd78059 
4118297a64e7Sgd78059 	erikp->erik_rx_hang.value.ul		= esp->rx_hang;
4119297a64e7Sgd78059 	erikp->erik_rx_length_err.value.ul	= esp->rx_length_err;
4120297a64e7Sgd78059 	erikp->erik_rx_code_viol_err.value.ul	= esp->rx_code_viol_err;
4121297a64e7Sgd78059 	erikp->erik_pause_rxcount.value.ul	= esp->pause_rxcount;
4122297a64e7Sgd78059 	erikp->erik_pause_oncount.value.ul	= esp->pause_oncount;
4123297a64e7Sgd78059 	erikp->erik_pause_offcount.value.ul	= esp->pause_offcount;
4124297a64e7Sgd78059 	erikp->erik_pause_time_count.value.ul	= esp->pause_time_count;
4125297a64e7Sgd78059 
4126297a64e7Sgd78059 	erikp->erik_inits.value.ul		= esp->inits;
4127297a64e7Sgd78059 	erikp->erik_jab.value.ul		= esp->jab;
4128297a64e7Sgd78059 	erikp->erik_notmds.value.ul		= esp->notmds;
4129297a64e7Sgd78059 	erikp->erik_allocbfail.value.ul		= esp->allocbfail;
4130297a64e7Sgd78059 	erikp->erik_drop.value.ul		= esp->drop;
4131297a64e7Sgd78059 	erikp->erik_rx_bad_pkts.value.ul	= esp->rx_bad_pkts;
4132297a64e7Sgd78059 	erikp->erik_rx_inits.value.ul		= esp->rx_inits;
4133297a64e7Sgd78059 	erikp->erik_tx_inits.value.ul		= esp->tx_inits;
4134297a64e7Sgd78059 	erikp->erik_rxtag_err.value.ul		= esp->rxtag_err;
4135297a64e7Sgd78059 	erikp->erik_parity_error.value.ul	= esp->parity_error;
4136297a64e7Sgd78059 	erikp->erik_pci_error_int.value.ul	= esp->pci_error_int;
4137297a64e7Sgd78059 	erikp->erik_unknown_fatal.value.ul	= esp->unknown_fatal;
4138297a64e7Sgd78059 	erikp->erik_pci_data_parity_err.value.ul = esp->pci_data_parity_err;
4139297a64e7Sgd78059 	erikp->erik_pci_signal_target_abort.value.ul =
4140297a64e7Sgd78059 	    esp->pci_signal_target_abort;
4141297a64e7Sgd78059 	erikp->erik_pci_rcvd_target_abort.value.ul =
4142297a64e7Sgd78059 	    esp->pci_rcvd_target_abort;
4143297a64e7Sgd78059 	erikp->erik_pci_rcvd_master_abort.value.ul =
4144297a64e7Sgd78059 	    esp->pci_rcvd_master_abort;
4145297a64e7Sgd78059 	erikp->erik_pci_signal_system_err.value.ul =
4146297a64e7Sgd78059 	    esp->pci_signal_system_err;
4147297a64e7Sgd78059 	erikp->erik_pci_det_parity_err.value.ul = esp->pci_det_parity_err;
4148297a64e7Sgd78059 
4149297a64e7Sgd78059 	erikp->erik_pmcap.value.ul = esp->pmcap;
4150297a64e7Sgd78059 
4151297a64e7Sgd78059 	return (0);
4152297a64e7Sgd78059 }
4153297a64e7Sgd78059 
4154297a64e7Sgd78059 static void
eri_statinit(struct eri * erip)4155297a64e7Sgd78059 eri_statinit(struct eri *erip)
4156297a64e7Sgd78059 {
4157297a64e7Sgd78059 	struct	kstat	*ksp;
4158297a64e7Sgd78059 	struct	erikstat	*erikp;
4159297a64e7Sgd78059 
4160297a64e7Sgd78059 	if ((ksp = kstat_create("eri", erip->instance, "driver_info", "net",
4161297a64e7Sgd78059 	    KSTAT_TYPE_NAMED,
4162297a64e7Sgd78059 	    sizeof (struct erikstat) / sizeof (kstat_named_t), 0)) == NULL) {
4163297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
4164297a64e7Sgd78059 		    kstat_create_fail_msg);
4165297a64e7Sgd78059 		return;
4166297a64e7Sgd78059 	}
4167297a64e7Sgd78059 
4168297a64e7Sgd78059 	erip->ksp = ksp;
4169297a64e7Sgd78059 	erikp = (struct erikstat *)(ksp->ks_data);
4170297a64e7Sgd78059 	/*
4171297a64e7Sgd78059 	 * MIB II kstat variables
4172297a64e7Sgd78059 	 */
4173297a64e7Sgd78059 
4174297a64e7Sgd78059 	kstat_named_init(&erikp->erik_inits, "inits", KSTAT_DATA_ULONG);
4175297a64e7Sgd78059 
4176297a64e7Sgd78059 	kstat_named_init(&erikp->erik_txmac_maxpkt_err,	"txmac_maxpkt_err",
4177297a64e7Sgd78059 	    KSTAT_DATA_ULONG);
4178297a64e7Sgd78059 	kstat_named_init(&erikp->erik_defer_timer_exp, "defer_timer_exp",
4179297a64e7Sgd78059 	    KSTAT_DATA_ULONG);
4180297a64e7Sgd78059 	kstat_named_init(&erikp->erik_peak_attempt_cnt,	"peak_attempt_cnt",
4181297a64e7Sgd78059 	    KSTAT_DATA_ULONG);
4182297a64e7Sgd78059 	kstat_named_init(&erikp->erik_tx_hang, "tx_hang", KSTAT_DATA_ULONG);
4183297a64e7Sgd78059 
4184297a64e7Sgd78059 	kstat_named_init(&erikp->erik_no_free_rx_desc, "no_free_rx_desc",
4185297a64e7Sgd78059 	    KSTAT_DATA_ULONG);
4186297a64e7Sgd78059 	kstat_named_init(&erikp->erik_rx_hang, "rx_hang", KSTAT_DATA_ULONG);
4187297a64e7Sgd78059 	kstat_named_init(&erikp->erik_rx_length_err, "rx_length_err",
4188297a64e7Sgd78059 	    KSTAT_DATA_ULONG);
4189297a64e7Sgd78059 	kstat_named_init(&erikp->erik_rx_code_viol_err,	"rx_code_viol_err",
4190297a64e7Sgd78059 	    KSTAT_DATA_ULONG);
4191297a64e7Sgd78059 
4192297a64e7Sgd78059 	kstat_named_init(&erikp->erik_pause_rxcount, "pause_rcv_cnt",
4193297a64e7Sgd78059 	    KSTAT_DATA_ULONG);
4194297a64e7Sgd78059 
4195297a64e7Sgd78059 	kstat_named_init(&erikp->erik_pause_oncount, "pause_on_cnt",
4196297a64e7Sgd78059 	    KSTAT_DATA_ULONG);
4197297a64e7Sgd78059 
4198297a64e7Sgd78059 	kstat_named_init(&erikp->erik_pause_offcount, "pause_off_cnt",
4199297a64e7Sgd78059 	    KSTAT_DATA_ULONG);
4200297a64e7Sgd78059 	kstat_named_init(&erikp->erik_pause_time_count,	"pause_time_cnt",
4201297a64e7Sgd78059 	    KSTAT_DATA_ULONG);
4202297a64e7Sgd78059 
4203297a64e7Sgd78059 	kstat_named_init(&erikp->erik_jab, "jabber", KSTAT_DATA_ULONG);
4204297a64e7Sgd78059 	kstat_named_init(&erikp->erik_notmds, "no_tmds", KSTAT_DATA_ULONG);
4205297a64e7Sgd78059 	kstat_named_init(&erikp->erik_allocbfail, "allocbfail",
4206297a64e7Sgd78059 	    KSTAT_DATA_ULONG);
4207297a64e7Sgd78059 
4208297a64e7Sgd78059 	kstat_named_init(&erikp->erik_drop, "drop", KSTAT_DATA_ULONG);
4209297a64e7Sgd78059 
4210297a64e7Sgd78059 	kstat_named_init(&erikp->erik_rx_bad_pkts, "bad_pkts",
4211297a64e7Sgd78059 	    KSTAT_DATA_ULONG);
4212297a64e7Sgd78059 
4213297a64e7Sgd78059 	kstat_named_init(&erikp->erik_rx_inits, "rx_inits", KSTAT_DATA_ULONG);
4214297a64e7Sgd78059 
4215297a64e7Sgd78059 	kstat_named_init(&erikp->erik_tx_inits, "tx_inits", KSTAT_DATA_ULONG);
4216297a64e7Sgd78059 
4217297a64e7Sgd78059 	kstat_named_init(&erikp->erik_rxtag_err, "rxtag_error",
4218297a64e7Sgd78059 	    KSTAT_DATA_ULONG);
4219297a64e7Sgd78059 
4220297a64e7Sgd78059 	kstat_named_init(&erikp->erik_parity_error, "parity_error",
4221297a64e7Sgd78059 	    KSTAT_DATA_ULONG);
4222297a64e7Sgd78059 
4223297a64e7Sgd78059 	kstat_named_init(&erikp->erik_pci_error_int, "pci_error_interrupt",
4224297a64e7Sgd78059 	    KSTAT_DATA_ULONG);
4225297a64e7Sgd78059 	kstat_named_init(&erikp->erik_unknown_fatal, "unknown_fatal",
4226297a64e7Sgd78059 	    KSTAT_DATA_ULONG);
4227297a64e7Sgd78059 	kstat_named_init(&erikp->erik_pci_data_parity_err,
4228297a64e7Sgd78059 	    "pci_data_parity_err", KSTAT_DATA_ULONG);
4229297a64e7Sgd78059 	kstat_named_init(&erikp->erik_pci_signal_target_abort,
4230297a64e7Sgd78059 	    "pci_signal_target_abort", KSTAT_DATA_ULONG);
4231297a64e7Sgd78059 	kstat_named_init(&erikp->erik_pci_rcvd_target_abort,
4232297a64e7Sgd78059 	    "pci_rcvd_target_abort", KSTAT_DATA_ULONG);
4233297a64e7Sgd78059 	kstat_named_init(&erikp->erik_pci_rcvd_master_abort,
4234297a64e7Sgd78059 	    "pci_rcvd_master_abort", KSTAT_DATA_ULONG);
4235297a64e7Sgd78059 	kstat_named_init(&erikp->erik_pci_signal_system_err,
4236297a64e7Sgd78059 	    "pci_signal_system_err", KSTAT_DATA_ULONG);
4237297a64e7Sgd78059 	kstat_named_init(&erikp->erik_pci_det_parity_err,
4238297a64e7Sgd78059 	    "pci_det_parity_err", KSTAT_DATA_ULONG);
4239297a64e7Sgd78059 
4240297a64e7Sgd78059 	kstat_named_init(&erikp->erik_pmcap, "pmcap", KSTAT_DATA_ULONG);
4241297a64e7Sgd78059 
4242297a64e7Sgd78059 
4243297a64e7Sgd78059 	ksp->ks_update = eri_stat_kstat_update;
4244297a64e7Sgd78059 	ksp->ks_private = (void *) erip;
4245297a64e7Sgd78059 	kstat_install(ksp);
4246297a64e7Sgd78059 }
4247297a64e7Sgd78059 
4248297a64e7Sgd78059 
4249297a64e7Sgd78059 /* <<<<<<<<<<<<<<<<<<<<<<< NDD SUPPORT FUNCTIONS	>>>>>>>>>>>>>>>>>>> */
4250297a64e7Sgd78059 /*
4251297a64e7Sgd78059  * ndd support functions to get/set parameters
4252297a64e7Sgd78059  */
4253297a64e7Sgd78059 /* Free the Named Dispatch Table by calling eri_nd_free */
4254297a64e7Sgd78059 static void
eri_param_cleanup(struct eri * erip)4255297a64e7Sgd78059 eri_param_cleanup(struct eri *erip)
4256297a64e7Sgd78059 {
4257297a64e7Sgd78059 	if (erip->g_nd)
4258297a64e7Sgd78059 		(void) eri_nd_free(&erip->g_nd);
4259297a64e7Sgd78059 }
4260297a64e7Sgd78059 
4261297a64e7Sgd78059 /*
4262297a64e7Sgd78059  * Extracts the value from the eri parameter array and prints the
4263297a64e7Sgd78059  * parameter value. cp points to the required parameter.
4264297a64e7Sgd78059  */
4265297a64e7Sgd78059 /* ARGSUSED */
4266297a64e7Sgd78059 static int
eri_param_get(queue_t * q,mblk_t * mp,caddr_t cp)4267297a64e7Sgd78059 eri_param_get(queue_t *q, mblk_t *mp, caddr_t cp)
4268297a64e7Sgd78059 {
4269297a64e7Sgd78059 	param_t		*eripa = (void *)cp;
4270297a64e7Sgd78059 	int		param_len = 1;
4271297a64e7Sgd78059 	uint32_t	param_val;
4272297a64e7Sgd78059 	mblk_t		*nmp;
4273297a64e7Sgd78059 	int		ok;
4274297a64e7Sgd78059 
4275297a64e7Sgd78059 	param_val = eripa->param_val;
4276297a64e7Sgd78059 	/*
4277297a64e7Sgd78059 	 * Calculate space required in mblk.
4278297a64e7Sgd78059 	 * Remember to include NULL terminator.
4279297a64e7Sgd78059 	 */
4280297a64e7Sgd78059 	do {
4281297a64e7Sgd78059 		param_len++;
4282297a64e7Sgd78059 		param_val /= 10;
4283297a64e7Sgd78059 	} while (param_val);
4284297a64e7Sgd78059 
4285297a64e7Sgd78059 	ok = eri_mk_mblk_tail_space(mp, &nmp, param_len);
4286297a64e7Sgd78059 	if (ok == 0) {
4287297a64e7Sgd78059 		(void) sprintf((char *)nmp->b_wptr, "%d", eripa->param_val);
4288297a64e7Sgd78059 		nmp->b_wptr += param_len;
4289297a64e7Sgd78059 	}
4290297a64e7Sgd78059 
4291297a64e7Sgd78059 	return (ok);
4292297a64e7Sgd78059 }
4293297a64e7Sgd78059 
4294297a64e7Sgd78059 /*
4295297a64e7Sgd78059  * Check if there is space for p_val at the end if mblk.
4296297a64e7Sgd78059  * If not, allocate new 1k mblk.
4297297a64e7Sgd78059  */
4298297a64e7Sgd78059 static int
eri_mk_mblk_tail_space(mblk_t * mp,mblk_t ** nmp,size_t sz)4299297a64e7Sgd78059 eri_mk_mblk_tail_space(mblk_t *mp, mblk_t **nmp, size_t sz)
4300297a64e7Sgd78059 {
4301297a64e7Sgd78059 	mblk_t *tmp = mp;
4302297a64e7Sgd78059 
4303297a64e7Sgd78059 	while (tmp->b_cont)
4304297a64e7Sgd78059 		tmp = tmp->b_cont;
4305297a64e7Sgd78059 
4306297a64e7Sgd78059 	if (MBLKTAIL(tmp) < sz) {
4307297a64e7Sgd78059 		if ((tmp->b_cont = allocb(1024, BPRI_HI)) == NULL)
4308297a64e7Sgd78059 			return (ENOMEM);
4309297a64e7Sgd78059 		tmp = tmp->b_cont;
4310297a64e7Sgd78059 	}
4311297a64e7Sgd78059 	*nmp = tmp;
4312297a64e7Sgd78059 	return (0);
4313297a64e7Sgd78059 }
4314297a64e7Sgd78059 
4315297a64e7Sgd78059 /*
4316297a64e7Sgd78059  * Register each element of the parameter array with the
4317297a64e7Sgd78059  * named dispatch handler. Each element is loaded using
4318297a64e7Sgd78059  * eri_nd_load()
4319297a64e7Sgd78059  */
4320297a64e7Sgd78059 static int
eri_param_register(struct eri * erip,param_t * eripa,int cnt)4321297a64e7Sgd78059 eri_param_register(struct eri *erip, param_t *eripa, int cnt)
4322297a64e7Sgd78059 {
4323297a64e7Sgd78059 	/* cnt gives the count of the number of */
4324297a64e7Sgd78059 	/* elements present in the parameter array */
4325297a64e7Sgd78059 
4326297a64e7Sgd78059 	int i;
4327297a64e7Sgd78059 
4328297a64e7Sgd78059 	for (i = 0; i < cnt; i++, eripa++) {
4329297a64e7Sgd78059 		pfi_t	setter = (pfi_t)eri_param_set;
4330297a64e7Sgd78059 
4331297a64e7Sgd78059 		switch (eripa->param_name[0]) {
4332297a64e7Sgd78059 		case '+':	/* read-write */
4333297a64e7Sgd78059 			setter = (pfi_t)eri_param_set;
4334297a64e7Sgd78059 			break;
4335297a64e7Sgd78059 
4336297a64e7Sgd78059 		case '-':	/* read-only */
4337297a64e7Sgd78059 			setter = NULL;
4338297a64e7Sgd78059 			break;
4339297a64e7Sgd78059 
4340297a64e7Sgd78059 		case '!':	/* read-only, not displayed */
4341297a64e7Sgd78059 		case '%':	/* read-write, not displayed */
4342297a64e7Sgd78059 			continue;
4343297a64e7Sgd78059 		}
4344297a64e7Sgd78059 
4345297a64e7Sgd78059 		if (!eri_nd_load(&erip->g_nd, eripa->param_name + 1,
4346297a64e7Sgd78059 		    (pfi_t)eri_param_get, setter, (caddr_t)eripa)) {
4347297a64e7Sgd78059 			(void) eri_nd_free(&erip->g_nd);
4348297a64e7Sgd78059 			return (B_FALSE);
4349297a64e7Sgd78059 		}
4350297a64e7Sgd78059 	}
4351297a64e7Sgd78059 
4352297a64e7Sgd78059 	return (B_TRUE);
4353297a64e7Sgd78059 }
4354297a64e7Sgd78059 
4355297a64e7Sgd78059 /*
4356297a64e7Sgd78059  * Sets the eri parameter to the value in the param_register using
4357297a64e7Sgd78059  * eri_nd_load().
4358297a64e7Sgd78059  */
4359297a64e7Sgd78059 /* ARGSUSED */
4360297a64e7Sgd78059 static int
eri_param_set(queue_t * q,mblk_t * mp,char * value,caddr_t cp)4361297a64e7Sgd78059 eri_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp)
4362297a64e7Sgd78059 {
4363297a64e7Sgd78059 	char *end;
4364297a64e7Sgd78059 	long new_value;
4365297a64e7Sgd78059 	param_t	*eripa = (void *)cp;
4366297a64e7Sgd78059 
4367297a64e7Sgd78059 	if (ddi_strtol(value, &end, 10, &new_value) != 0)
4368297a64e7Sgd78059 		return (EINVAL);
4369297a64e7Sgd78059 	if (end == value || new_value < eripa->param_min ||
4370297a64e7Sgd78059 	    new_value > eripa->param_max) {
4371297a64e7Sgd78059 			return (EINVAL);
4372297a64e7Sgd78059 	}
4373297a64e7Sgd78059 	eripa->param_val = (uint32_t)new_value;
4374297a64e7Sgd78059 	return (0);
4375297a64e7Sgd78059 
4376297a64e7Sgd78059 }
4377297a64e7Sgd78059 
4378297a64e7Sgd78059 /* Free the table pointed to by 'ndp' */
4379297a64e7Sgd78059 static void
eri_nd_free(caddr_t * nd_pparam)4380297a64e7Sgd78059 eri_nd_free(caddr_t *nd_pparam)
4381297a64e7Sgd78059 {
4382297a64e7Sgd78059 	ND	*nd;
4383297a64e7Sgd78059 
4384297a64e7Sgd78059 	if ((nd = (void *)(*nd_pparam)) != NULL) {
4385297a64e7Sgd78059 		if (nd->nd_tbl)
4386297a64e7Sgd78059 			kmem_free(nd->nd_tbl, nd->nd_size);
4387297a64e7Sgd78059 		kmem_free(nd, sizeof (ND));
4388297a64e7Sgd78059 		*nd_pparam = NULL;
4389297a64e7Sgd78059 	}
4390297a64e7Sgd78059 }
4391297a64e7Sgd78059 
4392297a64e7Sgd78059 static int
eri_nd_getset(queue_t * q,caddr_t nd_param,MBLKP mp)4393297a64e7Sgd78059 eri_nd_getset(queue_t *q, caddr_t nd_param, MBLKP mp)
4394297a64e7Sgd78059 {
4395297a64e7Sgd78059 	int	err;
4396297a64e7Sgd78059 	IOCP	iocp;
4397297a64e7Sgd78059 	MBLKP	mp1;
4398297a64e7Sgd78059 	ND	*nd;
4399297a64e7Sgd78059 	NDE	*nde;
4400297a64e7Sgd78059 	char	*valp;
4401297a64e7Sgd78059 	size_t	avail;
4402297a64e7Sgd78059 	mblk_t	*nmp;
4403297a64e7Sgd78059 
4404297a64e7Sgd78059 	if (!nd_param)
4405297a64e7Sgd78059 		return (B_FALSE);
4406297a64e7Sgd78059 
4407297a64e7Sgd78059 	nd = (void *)nd_param;
4408297a64e7Sgd78059 	iocp = (void *)mp->b_rptr;
4409297a64e7Sgd78059 	if ((iocp->ioc_count == 0) || !(mp1 = mp->b_cont)) {
4410297a64e7Sgd78059 		mp->b_datap->db_type = M_IOCACK;
4411297a64e7Sgd78059 		iocp->ioc_count = 0;
4412297a64e7Sgd78059 		iocp->ioc_error = EINVAL;
4413297a64e7Sgd78059 		return (B_TRUE);
4414297a64e7Sgd78059 	}
4415297a64e7Sgd78059 	/*
4416297a64e7Sgd78059 	 * NOTE - logic throughout nd_xxx assumes single data block for ioctl.
4417297a64e7Sgd78059 	 *	However, existing code sends in some big buffers.
4418297a64e7Sgd78059 	 */
4419297a64e7Sgd78059 	avail = iocp->ioc_count;
4420297a64e7Sgd78059 	if (mp1->b_cont) {
4421297a64e7Sgd78059 		freemsg(mp1->b_cont);
4422297a64e7Sgd78059 		mp1->b_cont = NULL;
4423297a64e7Sgd78059 	}
4424297a64e7Sgd78059 
4425297a64e7Sgd78059 	mp1->b_datap->db_lim[-1] = '\0';	/* Force null termination */
4426297a64e7Sgd78059 	valp = (char *)mp1->b_rptr;
4427297a64e7Sgd78059 
4428297a64e7Sgd78059 	for (nde = nd->nd_tbl; /* */; nde++) {
4429297a64e7Sgd78059 		if (!nde->nde_name)
4430297a64e7Sgd78059 			return (B_FALSE);
4431297a64e7Sgd78059 		if (strcmp(nde->nde_name, valp) == 0)
4432297a64e7Sgd78059 			break;
4433297a64e7Sgd78059 	}
4434297a64e7Sgd78059 	err = EINVAL;
4435297a64e7Sgd78059 
4436297a64e7Sgd78059 	while (*valp++)
4437297a64e7Sgd78059 		;
4438297a64e7Sgd78059 
4439297a64e7Sgd78059 	if (!*valp || valp >= (char *)mp1->b_wptr)
4440297a64e7Sgd78059 		valp = NULL;
4441297a64e7Sgd78059 
4442297a64e7Sgd78059 	switch (iocp->ioc_cmd) {
4443297a64e7Sgd78059 	case ND_GET:
4444297a64e7Sgd78059 	/*
4445297a64e7Sgd78059 	 * (XXX) hack: "*valp" is size of user buffer for copyout. If result
4446297a64e7Sgd78059 	 * of action routine is too big, free excess and return ioc_rval as buf
4447297a64e7Sgd78059 	 * size needed.  Return as many mblocks as will fit, free the rest.  For
4448297a64e7Sgd78059 	 * backward compatibility, assume size of orig ioctl buffer if "*valp"
4449297a64e7Sgd78059 	 * bad or not given.
4450297a64e7Sgd78059 	 */
4451297a64e7Sgd78059 		if (valp)
4452297a64e7Sgd78059 			(void) ddi_strtol(valp, NULL, 10, (long *)&avail);
4453297a64e7Sgd78059 		/* We overwrite the name/value with the reply data */
4454297a64e7Sgd78059 		{
4455297a64e7Sgd78059 			mblk_t *mp2 = mp1;
4456297a64e7Sgd78059 
4457297a64e7Sgd78059 			while (mp2) {
4458297a64e7Sgd78059 				mp2->b_wptr = mp2->b_rptr;
4459297a64e7Sgd78059 				mp2 = mp2->b_cont;
4460297a64e7Sgd78059 			}
4461297a64e7Sgd78059 		}
4462297a64e7Sgd78059 		err = (*nde->nde_get_pfi)(q, mp1, nde->nde_data, iocp->ioc_cr);
4463297a64e7Sgd78059 		if (!err) {
4464297a64e7Sgd78059 			size_t	size_out;
4465297a64e7Sgd78059 			ssize_t	excess;
4466297a64e7Sgd78059 
4467297a64e7Sgd78059 			iocp->ioc_rval = 0;
4468297a64e7Sgd78059 
4469297a64e7Sgd78059 			/* Tack on the null */
4470297a64e7Sgd78059 			err = eri_mk_mblk_tail_space(mp1, &nmp, 1);
4471297a64e7Sgd78059 			if (!err) {
4472297a64e7Sgd78059 				*nmp->b_wptr++ = '\0';
4473297a64e7Sgd78059 				size_out = msgdsize(mp1);
4474297a64e7Sgd78059 				excess = size_out - avail;
4475297a64e7Sgd78059 				if (excess > 0) {
4476297a64e7Sgd78059 					iocp->ioc_rval = (unsigned)size_out;
4477297a64e7Sgd78059 					size_out -= excess;
4478297a64e7Sgd78059 					(void) adjmsg(mp1, -(excess + 1));
4479297a64e7Sgd78059 					err = eri_mk_mblk_tail_space(mp1,
4480297a64e7Sgd78059 					    &nmp, 1);
4481297a64e7Sgd78059 					if (!err)
4482297a64e7Sgd78059 						*nmp->b_wptr++ = '\0';
4483297a64e7Sgd78059 					else
4484297a64e7Sgd78059 						size_out = 0;
4485297a64e7Sgd78059 				}
4486297a64e7Sgd78059 
4487297a64e7Sgd78059 			} else
4488297a64e7Sgd78059 				size_out = 0;
4489297a64e7Sgd78059 
4490297a64e7Sgd78059 			iocp->ioc_count = size_out;
4491297a64e7Sgd78059 		}
4492297a64e7Sgd78059 		break;
4493297a64e7Sgd78059 
4494297a64e7Sgd78059 	case ND_SET:
4495297a64e7Sgd78059 		if (valp) {
4496297a64e7Sgd78059 			err = (*nde->nde_set_pfi)(q, mp1, valp,
4497297a64e7Sgd78059 			    nde->nde_data, iocp->ioc_cr);
4498297a64e7Sgd78059 			iocp->ioc_count = 0;
4499297a64e7Sgd78059 			freemsg(mp1);
4500297a64e7Sgd78059 			mp->b_cont = NULL;
4501297a64e7Sgd78059 		}
4502297a64e7Sgd78059 		break;
4503297a64e7Sgd78059 	}
4504297a64e7Sgd78059 
4505297a64e7Sgd78059 	iocp->ioc_error = err;
4506297a64e7Sgd78059 	mp->b_datap->db_type = M_IOCACK;
4507297a64e7Sgd78059 	return (B_TRUE);
4508297a64e7Sgd78059 }
4509297a64e7Sgd78059 
4510297a64e7Sgd78059 /*
4511297a64e7Sgd78059  * Load 'name' into the named dispatch table pointed to by 'ndp'.
4512297a64e7Sgd78059  * 'ndp' should be the address of a char pointer cell.  If the table
4513297a64e7Sgd78059  * does not exist (*ndp == 0), a new table is allocated and 'ndp'
4514297a64e7Sgd78059  * is stuffed.  If there is not enough space in the table for a new
4515297a64e7Sgd78059  * entry, more space is allocated.
4516297a64e7Sgd78059  */
4517297a64e7Sgd78059 static boolean_t
eri_nd_load(caddr_t * nd_pparam,char * name,pfi_t get_pfi,pfi_t set_pfi,caddr_t data)4518297a64e7Sgd78059 eri_nd_load(caddr_t *nd_pparam, char *name, pfi_t get_pfi,
4519297a64e7Sgd78059     pfi_t set_pfi, caddr_t data)
4520297a64e7Sgd78059 {
4521297a64e7Sgd78059 	ND	*nd;
4522297a64e7Sgd78059 	NDE	*nde;
4523297a64e7Sgd78059 
4524297a64e7Sgd78059 	if (!nd_pparam)
4525297a64e7Sgd78059 		return (B_FALSE);
4526297a64e7Sgd78059 
4527297a64e7Sgd78059 	if ((nd = (void *)(*nd_pparam)) == NULL) {
4528297a64e7Sgd78059 		if ((nd = (ND *)kmem_zalloc(sizeof (ND), KM_NOSLEEP))
4529297a64e7Sgd78059 		    == NULL)
4530297a64e7Sgd78059 			return (B_FALSE);
4531297a64e7Sgd78059 		*nd_pparam = (caddr_t)nd;
4532297a64e7Sgd78059 	}
4533297a64e7Sgd78059 	if (nd->nd_tbl) {
4534297a64e7Sgd78059 		for (nde = nd->nd_tbl; nde->nde_name; nde++) {
4535297a64e7Sgd78059 			if (strcmp(name, nde->nde_name) == 0)
4536297a64e7Sgd78059 				goto fill_it;
4537297a64e7Sgd78059 		}
4538297a64e7Sgd78059 	}
4539297a64e7Sgd78059 	if (nd->nd_free_count <= 1) {
4540297a64e7Sgd78059 		if ((nde = (NDE *)kmem_zalloc(nd->nd_size +
4541297a64e7Sgd78059 		    NDE_ALLOC_SIZE, KM_NOSLEEP)) == NULL)
4542297a64e7Sgd78059 			return (B_FALSE);
4543297a64e7Sgd78059 
4544297a64e7Sgd78059 		nd->nd_free_count += NDE_ALLOC_COUNT;
4545297a64e7Sgd78059 		if (nd->nd_tbl) {
4546297a64e7Sgd78059 			bcopy((char *)nd->nd_tbl, (char *)nde, nd->nd_size);
4547297a64e7Sgd78059 			kmem_free((char *)nd->nd_tbl, nd->nd_size);
4548297a64e7Sgd78059 		} else {
4549297a64e7Sgd78059 			nd->nd_free_count--;
4550297a64e7Sgd78059 			nde->nde_name = "?";
4551297a64e7Sgd78059 			nde->nde_get_pfi = nd_get_names;
4552297a64e7Sgd78059 			nde->nde_set_pfi = nd_set_default;
4553297a64e7Sgd78059 		}
4554297a64e7Sgd78059 		nde->nde_data = (caddr_t)nd;
4555297a64e7Sgd78059 		nd->nd_tbl = nde;
4556297a64e7Sgd78059 		nd->nd_size += NDE_ALLOC_SIZE;
4557297a64e7Sgd78059 	}
4558297a64e7Sgd78059 	for (nde = nd->nd_tbl; nde->nde_name; nde++)
4559297a64e7Sgd78059 		;
4560297a64e7Sgd78059 	nd->nd_free_count--;
4561297a64e7Sgd78059 fill_it:
4562297a64e7Sgd78059 	nde->nde_name = name;
4563297a64e7Sgd78059 	nde->nde_get_pfi = get_pfi ? get_pfi : nd_get_default;
4564297a64e7Sgd78059 	nde->nde_set_pfi = set_pfi ? set_pfi : nd_set_default;
4565297a64e7Sgd78059 	nde->nde_data = data;
4566297a64e7Sgd78059 	return (B_TRUE);
4567297a64e7Sgd78059 }
4568297a64e7Sgd78059 
4569297a64e7Sgd78059 /*
4570297a64e7Sgd78059  * Hardening Functions
4571297a64e7Sgd78059  * New Section
4572297a64e7Sgd78059  */
4573297a64e7Sgd78059 #ifdef  DEBUG
4574297a64e7Sgd78059 /*PRINTFLIKE5*/
4575297a64e7Sgd78059 static void
eri_debug_msg(const char * file,int line,struct eri * erip,debug_msg_t type,const char * fmt,...)4576297a64e7Sgd78059 eri_debug_msg(const char *file, int line, struct eri *erip,
4577297a64e7Sgd78059     debug_msg_t type, const char *fmt, ...)
4578297a64e7Sgd78059 {
4579297a64e7Sgd78059 	char	msg_buffer[255];
4580297a64e7Sgd78059 	va_list ap;
4581297a64e7Sgd78059 
4582297a64e7Sgd78059 	va_start(ap, fmt);
4583297a64e7Sgd78059 	(void) vsprintf(msg_buffer, fmt, ap);
4584297a64e7Sgd78059 	va_end(ap);
4585297a64e7Sgd78059 
4586297a64e7Sgd78059 	if (eri_msg_out & ERI_CON_MSG) {
4587297a64e7Sgd78059 		if (((type <= eri_debug_level) && eri_debug_all) ||
4588297a64e7Sgd78059 		    ((type == eri_debug_level) && !eri_debug_all)) {
4589297a64e7Sgd78059 			if (erip)
4590297a64e7Sgd78059 				cmn_err(CE_CONT, "D: %s %s%d:(%s%d) %s\n",
4591297a64e7Sgd78059 				    debug_msg_string[type], file, line,
4592297a64e7Sgd78059 				    ddi_driver_name(erip->dip), erip->instance,
4593297a64e7Sgd78059 				    msg_buffer);
4594297a64e7Sgd78059 			else
4595297a64e7Sgd78059 				cmn_err(CE_CONT, "D: %s %s(%d): %s\n",
4596297a64e7Sgd78059 				    debug_msg_string[type], file,
4597297a64e7Sgd78059 				    line, msg_buffer);
4598297a64e7Sgd78059 		}
4599297a64e7Sgd78059 	}
4600297a64e7Sgd78059 }
4601297a64e7Sgd78059 #endif
4602297a64e7Sgd78059 
4603297a64e7Sgd78059 
4604297a64e7Sgd78059 /*PRINTFLIKE4*/
4605297a64e7Sgd78059 static void
eri_fault_msg(struct eri * erip,uint_t severity,msg_t type,const char * fmt,...)4606297a64e7Sgd78059 eri_fault_msg(struct eri *erip, uint_t severity, msg_t type,
4607297a64e7Sgd78059 	const char *fmt, ...)
4608297a64e7Sgd78059 {
4609297a64e7Sgd78059 	char	msg_buffer[255];
4610297a64e7Sgd78059 	va_list	ap;
4611297a64e7Sgd78059 
4612297a64e7Sgd78059 	va_start(ap, fmt);
4613297a64e7Sgd78059 	(void) vsprintf(msg_buffer, fmt, ap);
4614297a64e7Sgd78059 	va_end(ap);
4615297a64e7Sgd78059 
4616297a64e7Sgd78059 	if (erip == NULL) {
4617297a64e7Sgd78059 		cmn_err(CE_NOTE, "eri : %s", msg_buffer);
4618297a64e7Sgd78059 		return;
4619297a64e7Sgd78059 	}
4620297a64e7Sgd78059 
4621297a64e7Sgd78059 	if (severity == SEVERITY_HIGH) {
4622297a64e7Sgd78059 		cmn_err(CE_WARN, "%s%d : %s", ddi_driver_name(erip->dip),
4623297a64e7Sgd78059 		    erip->instance, msg_buffer);
4624297a64e7Sgd78059 	} else switch (type) {
4625297a64e7Sgd78059 	case ERI_VERB_MSG:
4626297a64e7Sgd78059 		cmn_err(CE_CONT, "?%s%d : %s", ddi_driver_name(erip->dip),
4627297a64e7Sgd78059 		    erip->instance, msg_buffer);
4628297a64e7Sgd78059 		break;
4629297a64e7Sgd78059 	case ERI_LOG_MSG:
4630297a64e7Sgd78059 		cmn_err(CE_NOTE, "^%s%d : %s", ddi_driver_name(erip->dip),
4631297a64e7Sgd78059 		    erip->instance, msg_buffer);
4632297a64e7Sgd78059 		break;
4633297a64e7Sgd78059 	case ERI_BUF_MSG:
4634297a64e7Sgd78059 		cmn_err(CE_NOTE, "!%s%d : %s", ddi_driver_name(erip->dip),
4635297a64e7Sgd78059 		    erip->instance, msg_buffer);
4636297a64e7Sgd78059 		break;
4637297a64e7Sgd78059 	case ERI_CON_MSG:
4638297a64e7Sgd78059 		cmn_err(CE_CONT, "%s%d : %s", ddi_driver_name(erip->dip),
4639297a64e7Sgd78059 		    erip->instance, msg_buffer);
4640297a64e7Sgd78059 	default:
4641297a64e7Sgd78059 		break;
4642297a64e7Sgd78059 	}
4643297a64e7Sgd78059 }
4644297a64e7Sgd78059 
4645297a64e7Sgd78059 /*
4646297a64e7Sgd78059  * Transceiver (xcvr) Functions
4647297a64e7Sgd78059  * New Section
4648297a64e7Sgd78059  */
4649297a64e7Sgd78059 /*
4650297a64e7Sgd78059  * eri_stop_timer function is used by a function before doing link-related
4651297a64e7Sgd78059  * processing. It locks the "linklock" to protect the link-related data
4652297a64e7Sgd78059  * structures. This lock will be subsequently released in eri_start_timer().
4653297a64e7Sgd78059  */
4654297a64e7Sgd78059 static void
eri_stop_timer(struct eri * erip)4655297a64e7Sgd78059 eri_stop_timer(struct eri *erip)
4656297a64e7Sgd78059 {
4657297a64e7Sgd78059 	timeout_id_t id;
4658297a64e7Sgd78059 	mutex_enter(&erip->linklock);
4659297a64e7Sgd78059 	if (erip->timerid) {
4660297a64e7Sgd78059 		erip->flags |= ERI_NOTIMEOUTS; /* prevent multiple timeout */
4661297a64e7Sgd78059 		id = erip->timerid;
4662297a64e7Sgd78059 		erip->timerid = 0; /* prevent other thread do untimeout */
4663297a64e7Sgd78059 		mutex_exit(&erip->linklock); /* no mutex across untimeout() */
4664297a64e7Sgd78059 
4665297a64e7Sgd78059 		(void) untimeout(id);
4666297a64e7Sgd78059 		mutex_enter(&erip->linklock); /* acquire mutex again */
4667297a64e7Sgd78059 		erip->flags &= ~ERI_NOTIMEOUTS;
4668297a64e7Sgd78059 	}
4669297a64e7Sgd78059 }
4670297a64e7Sgd78059 
4671297a64e7Sgd78059 /*
4672297a64e7Sgd78059  * If msec parameter is zero, just release "linklock".
4673297a64e7Sgd78059  */
4674297a64e7Sgd78059 static void
eri_start_timer(struct eri * erip,fptrv_t func,clock_t msec)4675297a64e7Sgd78059 eri_start_timer(struct eri *erip, fptrv_t func, clock_t msec)
4676297a64e7Sgd78059 {
4677297a64e7Sgd78059 	if (msec) {
4678297a64e7Sgd78059 		if (!(erip->flags & ERI_NOTIMEOUTS) &&
4679297a64e7Sgd78059 		    (erip->flags & ERI_RUNNING)) {
4680297a64e7Sgd78059 			erip->timerid = timeout(func, (caddr_t)erip,
4681297a64e7Sgd78059 			    drv_usectohz(1000*msec));
4682297a64e7Sgd78059 		}
4683297a64e7Sgd78059 	}
4684297a64e7Sgd78059 
4685297a64e7Sgd78059 	mutex_exit(&erip->linklock);
4686297a64e7Sgd78059 }
4687297a64e7Sgd78059 
4688297a64e7Sgd78059 static int
eri_new_xcvr(struct eri * erip)4689297a64e7Sgd78059 eri_new_xcvr(struct eri *erip)
4690297a64e7Sgd78059 {
4691297a64e7Sgd78059 	int		status;
4692297a64e7Sgd78059 	uint32_t 	cfg;
4693297a64e7Sgd78059 	int		old_transceiver;
4694297a64e7Sgd78059 
4695297a64e7Sgd78059 	if (pci_report_pmcap(erip->dip, PCI_PM_IDLESPEED,
4696297a64e7Sgd78059 	    PCI_PM_IDLESPEED_NONE) == DDI_SUCCESS)
4697297a64e7Sgd78059 		erip->stats.pmcap = ERI_PMCAP_NONE;
4698297a64e7Sgd78059 
4699297a64e7Sgd78059 	status = B_FALSE;			/* no change */
4700297a64e7Sgd78059 	cfg = GET_MIFREG(mif_cfg);
4701297a64e7Sgd78059 	ERI_DEBUG_MSG2(erip, MIF_MSG, "cfg value = %X", cfg);
4702297a64e7Sgd78059 	old_transceiver = param_transceiver;
4703297a64e7Sgd78059 
4704297a64e7Sgd78059 	if ((cfg & ERI_MIF_CFGM1) && !use_int_xcvr) {
4705297a64e7Sgd78059 		ERI_DEBUG_MSG1(erip, PHY_MSG, "Found External XCVR");
4706297a64e7Sgd78059 		/*
4707297a64e7Sgd78059 		 * An External Transceiver was found and it takes priority
4708297a64e7Sgd78059 		 * over an internal, given the use_int_xcvr flag
4709297a64e7Sgd78059 		 * is false.
4710297a64e7Sgd78059 		 */
4711297a64e7Sgd78059 		if (old_transceiver != EXTERNAL_XCVR) {
4712297a64e7Sgd78059 			/*
4713297a64e7Sgd78059 			 * External transceiver has just been plugged
4714297a64e7Sgd78059 			 * in. Isolate the internal Transceiver.
4715297a64e7Sgd78059 			 */
4716297a64e7Sgd78059 			if (old_transceiver == INTERNAL_XCVR) {
4717297a64e7Sgd78059 				eri_mii_write(erip, ERI_PHY_BMCR,
4718297a64e7Sgd78059 				    (PHY_BMCR_ISOLATE | PHY_BMCR_PWRDN |
4719297a64e7Sgd78059 				    PHY_BMCR_LPBK));
4720297a64e7Sgd78059 			}
4721297a64e7Sgd78059 			status = B_TRUE;
4722297a64e7Sgd78059 		}
4723297a64e7Sgd78059 		/*
4724297a64e7Sgd78059 		 * Select the external Transceiver.
4725297a64e7Sgd78059 		 */
4726297a64e7Sgd78059 		erip->phyad = ERI_EXTERNAL_PHYAD;
4727297a64e7Sgd78059 		param_transceiver = EXTERNAL_XCVR;
4728297a64e7Sgd78059 		erip->mif_config &= ~ERI_MIF_CFGPD;
4729297a64e7Sgd78059 		erip->mif_config |= (erip->phyad << ERI_MIF_CFGPD_SHIFT);
4730297a64e7Sgd78059 		erip->mif_config |= ERI_MIF_CFGPS;
4731297a64e7Sgd78059 		PUT_MIFREG(mif_cfg, erip->mif_config);
4732297a64e7Sgd78059 
4733297a64e7Sgd78059 		PUT_MACREG(xifc, GET_MACREG(xifc) | BMAC_XIFC_MIIBUF_OE);
4734297a64e7Sgd78059 		drv_usecwait(ERI_MIF_POLL_DELAY);
4735297a64e7Sgd78059 	} else if (cfg & ERI_MIF_CFGM0) {
4736297a64e7Sgd78059 		ERI_DEBUG_MSG1(erip, PHY_MSG, "Found Internal XCVR");
4737297a64e7Sgd78059 		/*
4738297a64e7Sgd78059 		 * An Internal Transceiver was found or the
4739297a64e7Sgd78059 		 * use_int_xcvr flag is true.
4740297a64e7Sgd78059 		 */
4741297a64e7Sgd78059 		if (old_transceiver != INTERNAL_XCVR) {
4742297a64e7Sgd78059 			/*
4743297a64e7Sgd78059 			 * The external transceiver has just been
4744297a64e7Sgd78059 			 * disconnected or we're moving from a no
4745297a64e7Sgd78059 			 * transceiver state.
4746297a64e7Sgd78059 			 */
4747297a64e7Sgd78059 			if ((old_transceiver == EXTERNAL_XCVR) &&
4748297a64e7Sgd78059 			    (cfg & ERI_MIF_CFGM0)) {
4749297a64e7Sgd78059 				eri_mii_write(erip, ERI_PHY_BMCR,
4750297a64e7Sgd78059 				    (PHY_BMCR_ISOLATE | PHY_BMCR_PWRDN |
4751297a64e7Sgd78059 				    PHY_BMCR_LPBK));
4752297a64e7Sgd78059 			}
4753297a64e7Sgd78059 			status = B_TRUE;
4754297a64e7Sgd78059 		}
4755297a64e7Sgd78059 		/*
4756297a64e7Sgd78059 		 * Select the internal transceiver.
4757297a64e7Sgd78059 		 */
4758297a64e7Sgd78059 		erip->phyad = ERI_INTERNAL_PHYAD;
4759297a64e7Sgd78059 		param_transceiver = INTERNAL_XCVR;
4760297a64e7Sgd78059 		erip->mif_config &= ~ERI_MIF_CFGPD;
4761297a64e7Sgd78059 		erip->mif_config |= (erip->phyad << ERI_MIF_CFGPD_SHIFT);
4762297a64e7Sgd78059 		erip->mif_config &= ~ERI_MIF_CFGPS;
4763297a64e7Sgd78059 		PUT_MIFREG(mif_cfg, erip->mif_config);
4764297a64e7Sgd78059 
4765297a64e7Sgd78059 		PUT_MACREG(xifc, GET_MACREG(xifc) & ~ BMAC_XIFC_MIIBUF_OE);
4766297a64e7Sgd78059 		drv_usecwait(ERI_MIF_POLL_DELAY);
4767297a64e7Sgd78059 	} else {
4768297a64e7Sgd78059 		/*
4769297a64e7Sgd78059 		 * Did not find a valid xcvr.
4770297a64e7Sgd78059 		 */
4771297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
4772297a64e7Sgd78059 		    "Eri_new_xcvr : Select None");
4773297a64e7Sgd78059 		param_transceiver = NO_XCVR;
4774297a64e7Sgd78059 		erip->xcvr_status = PHY_LINK_DOWN;
4775297a64e7Sgd78059 	}
4776297a64e7Sgd78059 
4777297a64e7Sgd78059 	if (erip->stats.pmcap == ERI_PMCAP_NONE) {
4778297a64e7Sgd78059 		if (pci_report_pmcap(erip->dip, PCI_PM_IDLESPEED,
4779297a64e7Sgd78059 		    (void *)4000) == DDI_SUCCESS)
4780297a64e7Sgd78059 			erip->stats.pmcap = ERI_PMCAP_4MHZ;
4781297a64e7Sgd78059 	}
4782297a64e7Sgd78059 
4783297a64e7Sgd78059 	return (status);
4784297a64e7Sgd78059 }
4785297a64e7Sgd78059 
4786297a64e7Sgd78059 /*
4787297a64e7Sgd78059  * This function is used for timers.  No locks are held on timer expiry.
4788297a64e7Sgd78059  */
4789297a64e7Sgd78059 static void
eri_check_link(struct eri * erip)4790297a64e7Sgd78059 eri_check_link(struct eri *erip)
4791297a64e7Sgd78059 {
4792297a64e7Sgd78059 	link_state_t	linkupdate = eri_check_link_noind(erip);
4793297a64e7Sgd78059 
4794297a64e7Sgd78059 	if (linkupdate != LINK_STATE_UNKNOWN)
4795297a64e7Sgd78059 		mac_link_update(erip->mh, linkupdate);
4796297a64e7Sgd78059 }
4797297a64e7Sgd78059 
4798297a64e7Sgd78059 /*
4799297a64e7Sgd78059  * Compare our xcvr in our structure to the xcvr that we get from
4800297a64e7Sgd78059  * eri_check_mii_xcvr(). If they are different then mark the
4801297a64e7Sgd78059  * link down, reset xcvr, and return.
4802297a64e7Sgd78059  *
4803297a64e7Sgd78059  * Note without the MII connector, conditions can not change that
4804297a64e7Sgd78059  * will then use a external phy, thus this code has been cleaned
4805297a64e7Sgd78059  * to not even call the function or to possibly change the xcvr.
4806297a64e7Sgd78059  */
4807297a64e7Sgd78059 static uint32_t
eri_check_link_noind(struct eri * erip)4808297a64e7Sgd78059 eri_check_link_noind(struct eri *erip)
4809297a64e7Sgd78059 {
4810297a64e7Sgd78059 	uint16_t stat, control, mif_ints;
4811297a64e7Sgd78059 	uint32_t link_timeout	= ERI_LINKCHECK_TIMER;
4812297a64e7Sgd78059 	uint32_t linkupdate = 0;
4813297a64e7Sgd78059 
4814297a64e7Sgd78059 	eri_stop_timer(erip);	/* acquire linklock */
4815297a64e7Sgd78059 
4816297a64e7Sgd78059 	mutex_enter(&erip->xmitlock);
4817297a64e7Sgd78059 	mutex_enter(&erip->xcvrlock);
4818297a64e7Sgd78059 	eri_mif_poll(erip, MIF_POLL_STOP);
4819297a64e7Sgd78059 
4820297a64e7Sgd78059 	(void) eri_mii_read(erip, ERI_PHY_BMSR, &stat);
4821297a64e7Sgd78059 	mif_ints = erip->mii_status ^ stat;
4822297a64e7Sgd78059 
4823297a64e7Sgd78059 	if (erip->openloop_autoneg) {
4824297a64e7Sgd78059 		(void) eri_mii_read(erip, ERI_PHY_BMSR, &stat);
4825297a64e7Sgd78059 		ERI_DEBUG_MSG3(erip, XCVR_MSG,
4826297a64e7Sgd78059 		    "eri_check_link:openloop stat %X mii_status %X",
4827297a64e7Sgd78059 		    stat, erip->mii_status);
4828297a64e7Sgd78059 		(void) eri_mii_read(erip, ERI_PHY_BMCR, &control);
4829297a64e7Sgd78059 		if (!(stat & PHY_BMSR_LNKSTS) &&
4830297a64e7Sgd78059 		    (erip->openloop_autoneg < 2)) {
4831297a64e7Sgd78059 			if (param_speed) {
4832297a64e7Sgd78059 				control &= ~PHY_BMCR_100M;
4833297a64e7Sgd78059 				param_anlpar_100hdx = 0;
4834297a64e7Sgd78059 				param_anlpar_10hdx = 1;
4835297a64e7Sgd78059 				param_speed = 0;
4836297a64e7Sgd78059 				erip->stats.ifspeed = 10;
4837297a64e7Sgd78059 
4838297a64e7Sgd78059 			} else {
4839297a64e7Sgd78059 				control |= PHY_BMCR_100M;
4840297a64e7Sgd78059 				param_anlpar_100hdx = 1;
4841297a64e7Sgd78059 				param_anlpar_10hdx = 0;
4842297a64e7Sgd78059 				param_speed = 1;
4843297a64e7Sgd78059 				erip->stats.ifspeed = 100;
4844297a64e7Sgd78059 			}
4845297a64e7Sgd78059 			ERI_DEBUG_MSG3(erip, XCVR_MSG,
4846297a64e7Sgd78059 			    "eri_check_link: trying speed %X stat %X",
4847297a64e7Sgd78059 			    param_speed, stat);
4848297a64e7Sgd78059 
4849297a64e7Sgd78059 			erip->openloop_autoneg ++;
4850297a64e7Sgd78059 			eri_mii_write(erip, ERI_PHY_BMCR, control);
4851297a64e7Sgd78059 			link_timeout = ERI_P_FAULT_TIMER;
4852297a64e7Sgd78059 		} else {
4853297a64e7Sgd78059 			erip->openloop_autoneg = 0;
4854297a64e7Sgd78059 			linkupdate = eri_mif_check(erip, stat, stat);
4855297a64e7Sgd78059 			if (erip->openloop_autoneg)
4856297a64e7Sgd78059 				link_timeout = ERI_P_FAULT_TIMER;
4857297a64e7Sgd78059 		}
4858297a64e7Sgd78059 		eri_mif_poll(erip, MIF_POLL_START);
4859297a64e7Sgd78059 		mutex_exit(&erip->xcvrlock);
4860297a64e7Sgd78059 		mutex_exit(&erip->xmitlock);
4861297a64e7Sgd78059 
4862297a64e7Sgd78059 		eri_start_timer(erip, eri_check_link, link_timeout);
4863297a64e7Sgd78059 		return (linkupdate);
4864297a64e7Sgd78059 	}
4865297a64e7Sgd78059 
4866297a64e7Sgd78059 	linkupdate = eri_mif_check(erip, mif_ints, stat);
4867297a64e7Sgd78059 	eri_mif_poll(erip, MIF_POLL_START);
4868297a64e7Sgd78059 	mutex_exit(&erip->xcvrlock);
4869297a64e7Sgd78059 	mutex_exit(&erip->xmitlock);
4870297a64e7Sgd78059 
4871297a64e7Sgd78059 #ifdef ERI_RMAC_HANG_WORKAROUND
4872297a64e7Sgd78059 	/*
4873297a64e7Sgd78059 	 * Check if rx hung.
4874297a64e7Sgd78059 	 */
4875297a64e7Sgd78059 	if ((erip->flags & ERI_RUNNING) && param_linkup) {
4876297a64e7Sgd78059 		if (erip->check_rmac_hang) {
4877297a64e7Sgd78059 			ERI_DEBUG_MSG5(erip,
4878297a64e7Sgd78059 			    NONFATAL_MSG,
4879297a64e7Sgd78059 			    "check1 %d: macsm:%8x wr:%2x rd:%2x",
4880297a64e7Sgd78059 			    erip->check_rmac_hang,
4881297a64e7Sgd78059 			    GET_MACREG(macsm),
4882297a64e7Sgd78059 			    GET_ERXREG(rxfifo_wr_ptr),
4883297a64e7Sgd78059 			    GET_ERXREG(rxfifo_rd_ptr));
4884297a64e7Sgd78059 
4885297a64e7Sgd78059 			erip->check_rmac_hang = 0;
4886297a64e7Sgd78059 			erip->check2_rmac_hang ++;
4887297a64e7Sgd78059 
4888297a64e7Sgd78059 			erip->rxfifo_wr_ptr_c = GET_ERXREG(rxfifo_wr_ptr);
4889297a64e7Sgd78059 			erip->rxfifo_rd_ptr_c = GET_ERXREG(rxfifo_rd_ptr);
4890297a64e7Sgd78059 
4891297a64e7Sgd78059 			eri_start_timer(erip, eri_check_link,
4892297a64e7Sgd78059 			    ERI_CHECK_HANG_TIMER);
4893297a64e7Sgd78059 			return (linkupdate);
4894297a64e7Sgd78059 		}
4895297a64e7Sgd78059 
4896297a64e7Sgd78059 		if (erip->check2_rmac_hang) {
4897297a64e7Sgd78059 			ERI_DEBUG_MSG5(erip,
4898297a64e7Sgd78059 			    NONFATAL_MSG,
4899297a64e7Sgd78059 			    "check2 %d: macsm:%8x wr:%2x rd:%2x",
4900297a64e7Sgd78059 			    erip->check2_rmac_hang,
4901297a64e7Sgd78059 			    GET_MACREG(macsm),
4902297a64e7Sgd78059 			    GET_ERXREG(rxfifo_wr_ptr),
4903297a64e7Sgd78059 			    GET_ERXREG(rxfifo_rd_ptr));
4904297a64e7Sgd78059 
4905297a64e7Sgd78059 			erip->check2_rmac_hang = 0;
4906297a64e7Sgd78059 
4907297a64e7Sgd78059 			erip->rxfifo_wr_ptr = GET_ERXREG(rxfifo_wr_ptr);
4908297a64e7Sgd78059 			erip->rxfifo_rd_ptr = GET_ERXREG(rxfifo_rd_ptr);
4909297a64e7Sgd78059 
4910297a64e7Sgd78059 			if (((GET_MACREG(macsm) & BMAC_OVERFLOW_STATE) ==
4911297a64e7Sgd78059 			    BMAC_OVERFLOW_STATE) &&
4912297a64e7Sgd78059 			    ((erip->rxfifo_wr_ptr_c == erip->rxfifo_rd_ptr_c) ||
4913297a64e7Sgd78059 			    ((erip->rxfifo_rd_ptr == erip->rxfifo_rd_ptr_c) &&
4914297a64e7Sgd78059 			    (erip->rxfifo_wr_ptr == erip->rxfifo_wr_ptr_c)))) {
4915297a64e7Sgd78059 				ERI_DEBUG_MSG1(erip,
4916297a64e7Sgd78059 				    NONFATAL_MSG,
4917297a64e7Sgd78059 				    "RX hang: Reset mac");
4918297a64e7Sgd78059 
4919297a64e7Sgd78059 				HSTAT(erip, rx_hang);
4920297a64e7Sgd78059 				erip->linkcheck = 1;
4921297a64e7Sgd78059 
4922297a64e7Sgd78059 				eri_start_timer(erip, eri_check_link,
4923297a64e7Sgd78059 				    ERI_LINKCHECK_TIMER);
4924297a64e7Sgd78059 				(void) eri_init(erip);
4925297a64e7Sgd78059 				return (linkupdate);
4926297a64e7Sgd78059 			}
4927297a64e7Sgd78059 		}
4928297a64e7Sgd78059 	}
4929297a64e7Sgd78059 #endif
4930297a64e7Sgd78059 
4931297a64e7Sgd78059 	/*
4932297a64e7Sgd78059 	 * Check if tx hung.
4933297a64e7Sgd78059 	 */
4934297a64e7Sgd78059 #ifdef	ERI_TX_HUNG
4935297a64e7Sgd78059 	if ((erip->flags & ERI_RUNNING) && param_linkup &&
4936297a64e7Sgd78059 	    (eri_check_txhung(erip))) {
4937297a64e7Sgd78059 		HSTAT(erip, tx_hang);
4938297a64e7Sgd78059 		eri_reinit_txhung++;
4939297a64e7Sgd78059 		erip->linkcheck = 1;
4940297a64e7Sgd78059 		eri_start_timer(erip, eri_check_link, ERI_CHECK_HANG_TIMER);
4941297a64e7Sgd78059 		(void) eri_init(erip);
4942297a64e7Sgd78059 		return (linkupdate);
4943297a64e7Sgd78059 	}
4944297a64e7Sgd78059 #endif
4945297a64e7Sgd78059 
4946297a64e7Sgd78059 #ifdef ERI_PM_WORKAROUND
4947297a64e7Sgd78059 	if (erip->stats.pmcap == ERI_PMCAP_NONE) {
4948297a64e7Sgd78059 		if (pci_report_pmcap(erip->dip, PCI_PM_IDLESPEED,
4949297a64e7Sgd78059 		    (void *)4000) == DDI_SUCCESS)
4950297a64e7Sgd78059 			erip->stats.pmcap = ERI_PMCAP_4MHZ;
4951297a64e7Sgd78059 
4952297a64e7Sgd78059 		ERI_DEBUG_MSG2(erip, NONFATAL_MSG,
4953297a64e7Sgd78059 		    "eri_check_link: PMCAP %d", erip->stats.pmcap);
4954297a64e7Sgd78059 	}
4955297a64e7Sgd78059 #endif
4956297a64e7Sgd78059 	if ((!param_mode) && (param_transceiver != NO_XCVR))
4957297a64e7Sgd78059 		eri_start_timer(erip, eri_check_link, ERI_CHECK_HANG_TIMER);
4958297a64e7Sgd78059 	else
4959297a64e7Sgd78059 		eri_start_timer(erip, eri_check_link, ERI_LINKCHECK_TIMER);
4960297a64e7Sgd78059 	return (linkupdate);
4961297a64e7Sgd78059 }
4962297a64e7Sgd78059 
4963297a64e7Sgd78059 static link_state_t
eri_mif_check(struct eri * erip,uint16_t mif_ints,uint16_t mif_data)4964297a64e7Sgd78059 eri_mif_check(struct eri *erip, uint16_t mif_ints, uint16_t mif_data)
4965297a64e7Sgd78059 {
4966297a64e7Sgd78059 	uint16_t control, aner, anlpar, anar, an_common;
4967297a64e7Sgd78059 	uint16_t old_mintrans;
4968297a64e7Sgd78059 	int restart_autoneg = 0;
4969297a64e7Sgd78059 	link_state_t retv;
4970297a64e7Sgd78059 
4971297a64e7Sgd78059 	ERI_DEBUG_MSG4(erip, XCVR_MSG, "eri_mif_check: mif_mask: %X, %X, %X",
4972297a64e7Sgd78059 	    erip->mif_mask, mif_ints, mif_data);
4973297a64e7Sgd78059 
4974297a64e7Sgd78059 	mif_ints &= ~erip->mif_mask;
4975297a64e7Sgd78059 	erip->mii_status = mif_data;
4976297a64e7Sgd78059 	/*
4977297a64e7Sgd78059 	 * Now check if someone has pulled the xcvr or
4978297a64e7Sgd78059 	 * a new xcvr has shown up
4979297a64e7Sgd78059 	 * If so try to find out what the new xcvr setup is.
4980297a64e7Sgd78059 	 */
4981297a64e7Sgd78059 	if (((mif_ints & PHY_BMSR_RES1) && (mif_data == 0xFFFF)) ||
4982297a64e7Sgd78059 	    (param_transceiver == NO_XCVR)) {
4983297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
4984297a64e7Sgd78059 		    "No status transceiver gone");
4985297a64e7Sgd78059 		if (eri_new_xcvr(erip)) {
4986297a64e7Sgd78059 			if (param_transceiver != NO_XCVR) {
4987297a64e7Sgd78059 				/*
4988297a64e7Sgd78059 				 * Reset the new PHY and bring up the link
4989297a64e7Sgd78059 				 */
4990297a64e7Sgd78059 				(void) eri_reset_xcvr(erip);
4991297a64e7Sgd78059 			}
4992297a64e7Sgd78059 		}
4993297a64e7Sgd78059 		return (LINK_STATE_UNKNOWN);
4994297a64e7Sgd78059 	}
4995297a64e7Sgd78059 
4996297a64e7Sgd78059 	if (param_autoneg && (mif_ints & PHY_BMSR_LNKSTS) &&
4997297a64e7Sgd78059 	    (mif_data & PHY_BMSR_LNKSTS) && (mif_data & PHY_BMSR_ANC)) {
4998297a64e7Sgd78059 		mif_ints |= PHY_BMSR_ANC;
4999297a64e7Sgd78059 		ERI_DEBUG_MSG3(erip, PHY_MSG,
5000297a64e7Sgd78059 		    "eri_mif_check: Set ANC bit mif_data %X mig_ints %X",
5001297a64e7Sgd78059 		    mif_data, mif_ints);
5002297a64e7Sgd78059 	}
5003297a64e7Sgd78059 
5004297a64e7Sgd78059 	if ((mif_ints & PHY_BMSR_ANC) && (mif_data & PHY_BMSR_ANC)) {
5005297a64e7Sgd78059 		ERI_DEBUG_MSG1(erip, PHY_MSG, "Auto-negotiation interrupt.");
5006297a64e7Sgd78059 
5007297a64e7Sgd78059 		/*
5008297a64e7Sgd78059 		 * Switch off Auto-negotiation interrupts and switch on
5009297a64e7Sgd78059 		 * Link ststus interrupts.
5010297a64e7Sgd78059 		 */
5011297a64e7Sgd78059 		erip->mif_mask |= PHY_BMSR_ANC;
5012297a64e7Sgd78059 		erip->mif_mask &= ~PHY_BMSR_LNKSTS;
5013297a64e7Sgd78059 		(void) eri_mii_read(erip, ERI_PHY_ANER, &aner);
5014297a64e7Sgd78059 		param_aner_lpancap = 1 && (aner & PHY_ANER_LPNW);
5015297a64e7Sgd78059 		if ((aner & PHY_ANER_MLF) || (eri_force_mlf)) {
5016297a64e7Sgd78059 			ERI_DEBUG_MSG1(erip, XCVR_MSG,
5017297a64e7Sgd78059 			    "parallel detection fault");
5018297a64e7Sgd78059 			/*
5019297a64e7Sgd78059 			 * Consider doing open loop auto-negotiation.
5020297a64e7Sgd78059 			 */
5021297a64e7Sgd78059 			ERI_DEBUG_MSG1(erip, XCVR_MSG,
5022297a64e7Sgd78059 			    "Going into Open loop Auto-neg");
5023297a64e7Sgd78059 			(void) eri_mii_read(erip, ERI_PHY_BMCR, &control);
5024297a64e7Sgd78059 
5025297a64e7Sgd78059 			control &= ~(PHY_BMCR_ANE | PHY_BMCR_RAN |
5026297a64e7Sgd78059 			    PHY_BMCR_FDX);
5027297a64e7Sgd78059 			if (param_anar_100fdx || param_anar_100hdx) {
5028297a64e7Sgd78059 				control |= PHY_BMCR_100M;
5029297a64e7Sgd78059 				param_anlpar_100hdx = 1;
5030297a64e7Sgd78059 				param_anlpar_10hdx = 0;
5031297a64e7Sgd78059 				param_speed = 1;
5032297a64e7Sgd78059 				erip->stats.ifspeed = 100;
5033297a64e7Sgd78059 
5034297a64e7Sgd78059 			} else if (param_anar_10fdx || param_anar_10hdx) {
5035297a64e7Sgd78059 				control &= ~PHY_BMCR_100M;
5036297a64e7Sgd78059 				param_anlpar_100hdx = 0;
5037297a64e7Sgd78059 				param_anlpar_10hdx = 1;
5038297a64e7Sgd78059 				param_speed = 0;
5039297a64e7Sgd78059 				erip->stats.ifspeed = 10;
5040297a64e7Sgd78059 			} else {
5041297a64e7Sgd78059 				ERI_FAULT_MSG1(erip, SEVERITY_NONE,
5042297a64e7Sgd78059 				    ERI_VERB_MSG,
5043297a64e7Sgd78059 				    "Transceiver speed set incorrectly.");
5044297a64e7Sgd78059 				return (0);
5045297a64e7Sgd78059 			}
5046297a64e7Sgd78059 
5047297a64e7Sgd78059 			(void) eri_mii_write(erip, ERI_PHY_BMCR, control);
5048297a64e7Sgd78059 			param_anlpar_100fdx = 0;
5049297a64e7Sgd78059 			param_anlpar_10fdx = 0;
5050297a64e7Sgd78059 			param_mode = 0;
5051297a64e7Sgd78059 			erip->openloop_autoneg = 1;
5052297a64e7Sgd78059 			return (0);
5053297a64e7Sgd78059 		}
5054297a64e7Sgd78059 		(void) eri_mii_read(erip, ERI_PHY_ANLPAR, &anlpar);
5055297a64e7Sgd78059 		(void) eri_mii_read(erip, ERI_PHY_ANAR, &anar);
5056297a64e7Sgd78059 		an_common = anar & anlpar;
5057297a64e7Sgd78059 
5058297a64e7Sgd78059 		ERI_DEBUG_MSG2(erip, XCVR_MSG, "an_common = 0x%X", an_common);
5059297a64e7Sgd78059 
5060297a64e7Sgd78059 		if (an_common & (PHY_ANLPAR_TXFDX | PHY_ANLPAR_TX)) {
5061297a64e7Sgd78059 			param_speed = 1;
5062297a64e7Sgd78059 			erip->stats.ifspeed = 100;
5063297a64e7Sgd78059 			param_mode = 1 && (an_common & PHY_ANLPAR_TXFDX);
5064297a64e7Sgd78059 
5065297a64e7Sgd78059 		} else if (an_common & (PHY_ANLPAR_10FDX | PHY_ANLPAR_10)) {
5066297a64e7Sgd78059 			param_speed = 0;
5067297a64e7Sgd78059 			erip->stats.ifspeed = 10;
5068297a64e7Sgd78059 			param_mode = 1 && (an_common & PHY_ANLPAR_10FDX);
5069297a64e7Sgd78059 
5070297a64e7Sgd78059 		} else an_common = 0x0;
5071297a64e7Sgd78059 
5072297a64e7Sgd78059 		if (!an_common) {
5073297a64e7Sgd78059 			ERI_FAULT_MSG1(erip, SEVERITY_MID, ERI_VERB_MSG,
5074297a64e7Sgd78059 			    "Transceiver: anar not set with speed selection");
5075297a64e7Sgd78059 		}
5076297a64e7Sgd78059 		param_anlpar_100T4 = 1 && (anlpar & PHY_ANLPAR_T4);
5077297a64e7Sgd78059 		param_anlpar_100fdx = 1 && (anlpar & PHY_ANLPAR_TXFDX);
5078297a64e7Sgd78059 		param_anlpar_100hdx = 1 && (anlpar & PHY_ANLPAR_TX);
5079297a64e7Sgd78059 		param_anlpar_10fdx = 1 && (anlpar & PHY_ANLPAR_10FDX);
5080297a64e7Sgd78059 		param_anlpar_10hdx = 1 && (anlpar & PHY_ANLPAR_10);
5081297a64e7Sgd78059 
5082297a64e7Sgd78059 		ERI_DEBUG_MSG2(erip, PHY_MSG,
5083297a64e7Sgd78059 		    "Link duplex = 0x%X", param_mode);
5084297a64e7Sgd78059 		ERI_DEBUG_MSG2(erip, PHY_MSG,
5085297a64e7Sgd78059 		    "Link speed = 0x%X", param_speed);
5086297a64e7Sgd78059 	/*	mif_ints |= PHY_BMSR_LNKSTS; prevent double msg */
5087297a64e7Sgd78059 	/*	mif_data |= PHY_BMSR_LNKSTS; prevent double msg */
5088297a64e7Sgd78059 	}
5089297a64e7Sgd78059 	retv = LINK_STATE_UNKNOWN;
5090297a64e7Sgd78059 	if (mif_ints & PHY_BMSR_LNKSTS) {
5091297a64e7Sgd78059 		if (mif_data & PHY_BMSR_LNKSTS) {
5092297a64e7Sgd78059 			ERI_DEBUG_MSG1(erip, PHY_MSG, "Link Up");
5093297a64e7Sgd78059 			/*
5094297a64e7Sgd78059 			 * Program Lu3X31T for mininum transition
5095297a64e7Sgd78059 			 */
5096297a64e7Sgd78059 			if (eri_phy_mintrans) {
5097297a64e7Sgd78059 				eri_mii_write(erip, 31, 0x8000);
5098297a64e7Sgd78059 				(void) eri_mii_read(erip, 0, &old_mintrans);
5099297a64e7Sgd78059 				eri_mii_write(erip, 0, 0x00F1);
5100297a64e7Sgd78059 				eri_mii_write(erip, 31, 0x0000);
5101297a64e7Sgd78059 			}
5102297a64e7Sgd78059 			/*
5103297a64e7Sgd78059 			 * The link is up.
5104297a64e7Sgd78059 			 */
5105297a64e7Sgd78059 			eri_init_txmac(erip);
5106297a64e7Sgd78059 			param_linkup = 1;
5107297a64e7Sgd78059 			erip->stats.link_up = LINK_STATE_UP;
5108297a64e7Sgd78059 			if (param_mode)
5109297a64e7Sgd78059 				erip->stats.link_duplex = LINK_DUPLEX_FULL;
5110297a64e7Sgd78059 			else
5111297a64e7Sgd78059 				erip->stats.link_duplex = LINK_DUPLEX_HALF;
5112297a64e7Sgd78059 
5113297a64e7Sgd78059 			retv = LINK_STATE_UP;
5114297a64e7Sgd78059 		} else {
5115297a64e7Sgd78059 			ERI_DEBUG_MSG1(erip, PHY_MSG, "Link down.");
5116297a64e7Sgd78059 			param_linkup = 0;
5117297a64e7Sgd78059 			erip->stats.link_up = LINK_STATE_DOWN;
5118297a64e7Sgd78059 			erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
5119297a64e7Sgd78059 			retv = LINK_STATE_DOWN;
5120297a64e7Sgd78059 			if (param_autoneg) {
5121297a64e7Sgd78059 				restart_autoneg = 1;
5122297a64e7Sgd78059 			}
5123297a64e7Sgd78059 		}
5124297a64e7Sgd78059 	} else {
5125297a64e7Sgd78059 		if (mif_data & PHY_BMSR_LNKSTS) {
5126297a64e7Sgd78059 			if (!param_linkup) {
5127297a64e7Sgd78059 				ERI_DEBUG_MSG1(erip, PHY_MSG,
5128297a64e7Sgd78059 				    "eri_mif_check: MIF data link up");
5129297a64e7Sgd78059 				/*
5130297a64e7Sgd78059 				 * Program Lu3X31T for minimum transition
5131297a64e7Sgd78059 				 */
5132297a64e7Sgd78059 				if (eri_phy_mintrans) {
5133297a64e7Sgd78059 					eri_mii_write(erip, 31, 0x8000);
5134297a64e7Sgd78059 					(void) eri_mii_read(erip, 0,
5135297a64e7Sgd78059 					    &old_mintrans);
5136297a64e7Sgd78059 					eri_mii_write(erip, 0, 0x00F1);
5137297a64e7Sgd78059 					eri_mii_write(erip, 31, 0x0000);
5138297a64e7Sgd78059 				}
5139297a64e7Sgd78059 				/*
5140297a64e7Sgd78059 				 * The link is up.
5141297a64e7Sgd78059 				 */
5142297a64e7Sgd78059 				eri_init_txmac(erip);
5143297a64e7Sgd78059 
5144297a64e7Sgd78059 				param_linkup = 1;
5145297a64e7Sgd78059 				erip->stats.link_up = LINK_STATE_UP;
5146297a64e7Sgd78059 				if (param_mode)
5147297a64e7Sgd78059 					erip->stats.link_duplex =
5148297a64e7Sgd78059 					    LINK_DUPLEX_FULL;
5149297a64e7Sgd78059 				else
5150297a64e7Sgd78059 					erip->stats.link_duplex =
5151297a64e7Sgd78059 					    LINK_DUPLEX_HALF;
5152297a64e7Sgd78059 
5153297a64e7Sgd78059 				retv = LINK_STATE_UP;
5154297a64e7Sgd78059 			}
5155297a64e7Sgd78059 		} else if (param_linkup) {
5156297a64e7Sgd78059 			/*
5157297a64e7Sgd78059 			 * The link is down now.
5158297a64e7Sgd78059 			 */
5159297a64e7Sgd78059 			ERI_DEBUG_MSG1(erip, PHY_MSG,
5160297a64e7Sgd78059 			    "eri_mif_check:Link was up and went down");
5161297a64e7Sgd78059 			param_linkup = 0;
5162297a64e7Sgd78059 			erip->stats.link_up = LINK_STATE_DOWN;
5163297a64e7Sgd78059 			erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
5164297a64e7Sgd78059 			retv = LINK_STATE_DOWN;
5165297a64e7Sgd78059 			if (param_autoneg)
5166297a64e7Sgd78059 				restart_autoneg = 1;
5167297a64e7Sgd78059 		}
5168297a64e7Sgd78059 	}
5169297a64e7Sgd78059 	if (restart_autoneg) {
5170297a64e7Sgd78059 		/*
5171297a64e7Sgd78059 		 * Restart normal auto-negotiation.
5172297a64e7Sgd78059 		 */
5173297a64e7Sgd78059 		ERI_DEBUG_MSG1(erip, PHY_MSG,
5174297a64e7Sgd78059 		    "eri_mif_check:Restart AUto Negotiation");
5175297a64e7Sgd78059 		erip->openloop_autoneg = 0;
5176297a64e7Sgd78059 		param_mode = 0;
5177297a64e7Sgd78059 		param_speed = 0;
5178297a64e7Sgd78059 		param_anlpar_100T4 = 0;
5179297a64e7Sgd78059 		param_anlpar_100fdx = 0;
5180297a64e7Sgd78059 		param_anlpar_100hdx = 0;
5181297a64e7Sgd78059 		param_anlpar_10fdx = 0;
5182297a64e7Sgd78059 		param_anlpar_10hdx = 0;
5183297a64e7Sgd78059 		param_aner_lpancap = 0;
5184297a64e7Sgd78059 		(void) eri_mii_read(erip, ERI_PHY_BMCR, &control);
5185297a64e7Sgd78059 		control |= (PHY_BMCR_ANE | PHY_BMCR_RAN);
5186297a64e7Sgd78059 		eri_mii_write(erip, ERI_PHY_BMCR, control);
5187297a64e7Sgd78059 	}
5188297a64e7Sgd78059 	if (mif_ints & PHY_BMSR_JABDET) {
5189297a64e7Sgd78059 		if (mif_data & PHY_BMSR_JABDET) {
5190297a64e7Sgd78059 			ERI_DEBUG_MSG1(erip, PHY_MSG, "Jabber detected.");
5191297a64e7Sgd78059 			HSTAT(erip, jab);
5192297a64e7Sgd78059 			/*
5193297a64e7Sgd78059 			 * Reset the new PHY and bring up the link
5194297a64e7Sgd78059 			 * (Check for failure?)
5195297a64e7Sgd78059 			 */
5196297a64e7Sgd78059 			(void) eri_reset_xcvr(erip);
5197297a64e7Sgd78059 		}
5198297a64e7Sgd78059 	}
5199297a64e7Sgd78059 	return (retv);
5200297a64e7Sgd78059 }
5201297a64e7Sgd78059 
5202297a64e7Sgd78059 #define	PHYRST_PERIOD 500
5203297a64e7Sgd78059 static int
eri_reset_xcvr(struct eri * erip)5204297a64e7Sgd78059 eri_reset_xcvr(struct eri *erip)
5205297a64e7Sgd78059 {
5206297a64e7Sgd78059 	uint16_t	stat;
5207297a64e7Sgd78059 	uint16_t	anar;
5208297a64e7Sgd78059 	uint16_t	control;
5209297a64e7Sgd78059 	uint16_t	idr1;
5210297a64e7Sgd78059 	uint16_t	idr2;
5211297a64e7Sgd78059 	uint16_t	nicr;
5212297a64e7Sgd78059 	uint32_t	speed_100;
5213297a64e7Sgd78059 	uint32_t	speed_10;
5214297a64e7Sgd78059 	int n;
5215297a64e7Sgd78059 
5216297a64e7Sgd78059 #ifdef	ERI_10_10_FORCE_SPEED_WORKAROUND
5217297a64e7Sgd78059 	erip->ifspeed_old = erip->stats.ifspeed;
5218297a64e7Sgd78059 #endif
5219297a64e7Sgd78059 	/*
5220297a64e7Sgd78059 	 * Reset Open loop auto-negotiation this means you can try
5221297a64e7Sgd78059 	 * Normal auto-negotiation, until you get a Multiple Link fault
5222297a64e7Sgd78059 	 * at which point you try 100M half duplex then 10M half duplex
5223297a64e7Sgd78059 	 * until you get a Link up.
5224297a64e7Sgd78059 	 */
5225297a64e7Sgd78059 	erip->openloop_autoneg = 0;
5226297a64e7Sgd78059 
5227297a64e7Sgd78059 	/*
5228297a64e7Sgd78059 	 * Reset the xcvr.
5229297a64e7Sgd78059 	 */
5230297a64e7Sgd78059 	eri_mii_write(erip, ERI_PHY_BMCR, PHY_BMCR_RESET);
5231297a64e7Sgd78059 
5232297a64e7Sgd78059 	/* Check for transceiver reset completion */
5233297a64e7Sgd78059 
5234297a64e7Sgd78059 	n = 1000;
5235297a64e7Sgd78059 	while (--n > 0) {
5236297a64e7Sgd78059 		drv_usecwait((clock_t)PHYRST_PERIOD);
5237297a64e7Sgd78059 		if (eri_mii_read(erip, ERI_PHY_BMCR, &control) == 1) {
5238297a64e7Sgd78059 			/* Transceiver does not talk MII */
5239297a64e7Sgd78059 			ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
5240297a64e7Sgd78059 			    "eri_reset_xcvr: no mii");
5241297a64e7Sgd78059 		}
5242297a64e7Sgd78059 		if ((control & PHY_BMCR_RESET) == 0)
5243297a64e7Sgd78059 			goto reset_done;
5244297a64e7Sgd78059 	}
5245297a64e7Sgd78059 	ERI_FAULT_MSG2(erip, SEVERITY_NONE, ERI_VERB_MSG,
5246297a64e7Sgd78059 	    "eri_reset_xcvr:reset_failed n == 0, control %x", control);
5247297a64e7Sgd78059 	goto eri_reset_xcvr_failed;
5248297a64e7Sgd78059 
5249297a64e7Sgd78059 reset_done:
5250297a64e7Sgd78059 
5251297a64e7Sgd78059 	ERI_DEBUG_MSG2(erip, AUTOCONFIG_MSG,
5252297a64e7Sgd78059 	    "eri_reset_xcvr: reset complete in %d us",
5253297a64e7Sgd78059 	    (1000 - n) * PHYRST_PERIOD);
5254297a64e7Sgd78059 
5255297a64e7Sgd78059 	(void) eri_mii_read(erip, ERI_PHY_BMSR, &stat);
5256297a64e7Sgd78059 	(void) eri_mii_read(erip, ERI_PHY_ANAR, &anar);
5257297a64e7Sgd78059 	(void) eri_mii_read(erip, ERI_PHY_IDR1, &idr1);
5258297a64e7Sgd78059 	(void) eri_mii_read(erip, ERI_PHY_IDR2, &idr2);
5259297a64e7Sgd78059 
5260297a64e7Sgd78059 	ERI_DEBUG_MSG4(erip, XCVR_MSG,
5261297a64e7Sgd78059 	    "eri_reset_xcvr: control %x stat %x anar %x", control, stat, anar);
5262297a64e7Sgd78059 
5263297a64e7Sgd78059 	/*
5264297a64e7Sgd78059 	 * Initialize the read only transceiver ndd information
5265297a64e7Sgd78059 	 * the values are either 0 or 1.
5266297a64e7Sgd78059 	 */
5267297a64e7Sgd78059 	param_bmsr_ancap = 1 && (stat & PHY_BMSR_ACFG);
5268297a64e7Sgd78059 	param_bmsr_100T4 = 1 && (stat & PHY_BMSR_100T4);
5269297a64e7Sgd78059 	param_bmsr_100fdx = 1 && (stat & PHY_BMSR_100FDX);
5270297a64e7Sgd78059 	param_bmsr_100hdx = 1 && (stat & PHY_BMSR_100HDX);
5271297a64e7Sgd78059 	param_bmsr_10fdx = 1 && (stat & PHY_BMSR_10FDX);
5272297a64e7Sgd78059 	param_bmsr_10hdx = 1 && (stat & PHY_BMSR_10HDX);
5273297a64e7Sgd78059 
5274297a64e7Sgd78059 	/*
5275297a64e7Sgd78059 	 * Match up the ndd capabilities with the transceiver.
5276297a64e7Sgd78059 	 */
5277297a64e7Sgd78059 	param_autoneg &= param_bmsr_ancap;
5278297a64e7Sgd78059 	param_anar_100fdx &= param_bmsr_100fdx;
5279297a64e7Sgd78059 	param_anar_100hdx &= param_bmsr_100hdx;
5280297a64e7Sgd78059 	param_anar_10fdx &= param_bmsr_10fdx;
5281297a64e7Sgd78059 	param_anar_10hdx &= param_bmsr_10hdx;
5282297a64e7Sgd78059 
5283297a64e7Sgd78059 	/*
5284297a64e7Sgd78059 	 * Select the operation mode of the transceiver.
5285297a64e7Sgd78059 	 */
5286297a64e7Sgd78059 	if (param_autoneg) {
5287297a64e7Sgd78059 		/*
5288297a64e7Sgd78059 		 * Initialize our auto-negotiation capabilities.
5289297a64e7Sgd78059 		 */
5290297a64e7Sgd78059 		anar = PHY_SELECTOR;
5291297a64e7Sgd78059 		if (param_anar_100T4)
5292297a64e7Sgd78059 			anar |= PHY_ANAR_T4;
5293297a64e7Sgd78059 		if (param_anar_100fdx)
5294297a64e7Sgd78059 			anar |= PHY_ANAR_TXFDX;
5295297a64e7Sgd78059 		if (param_anar_100hdx)
5296297a64e7Sgd78059 			anar |= PHY_ANAR_TX;
5297297a64e7Sgd78059 		if (param_anar_10fdx)
5298297a64e7Sgd78059 			anar |= PHY_ANAR_10FDX;
5299297a64e7Sgd78059 		if (param_anar_10hdx)
5300297a64e7Sgd78059 			anar |= PHY_ANAR_10;
5301297a64e7Sgd78059 		ERI_DEBUG_MSG2(erip, XCVR_MSG, "anar = %x", anar);
5302297a64e7Sgd78059 		eri_mii_write(erip, ERI_PHY_ANAR, anar);
5303297a64e7Sgd78059 	}
5304297a64e7Sgd78059 
5305297a64e7Sgd78059 	/* Place the Transceiver in normal operation mode */
5306297a64e7Sgd78059 	if ((control & PHY_BMCR_ISOLATE) || (control & PHY_BMCR_LPBK)) {
5307297a64e7Sgd78059 		control &= ~(PHY_BMCR_ISOLATE | PHY_BMCR_LPBK);
5308297a64e7Sgd78059 		eri_mii_write(erip, ERI_PHY_BMCR,
5309297a64e7Sgd78059 		    (control & ~PHY_BMCR_ISOLATE));
5310297a64e7Sgd78059 	}
5311297a64e7Sgd78059 
5312297a64e7Sgd78059 	/*
5313297a64e7Sgd78059 	 * If Lu3X31T then allow nonzero eri_phy_mintrans
5314297a64e7Sgd78059 	 */
5315297a64e7Sgd78059 	if (eri_phy_mintrans &&
5316297a64e7Sgd78059 	    (idr1 != 0x43 || (idr2 & 0xFFF0) != 0x7420)) {
5317297a64e7Sgd78059 		eri_phy_mintrans = 0;
5318297a64e7Sgd78059 	}
5319297a64e7Sgd78059 	/*
5320297a64e7Sgd78059 	 * Initialize the mif interrupt mask.
5321297a64e7Sgd78059 	 */
5322297a64e7Sgd78059 	erip->mif_mask = (uint16_t)(~PHY_BMSR_RES1);
5323297a64e7Sgd78059 
5324297a64e7Sgd78059 	/*
5325297a64e7Sgd78059 	 * Establish link speeds and do necessary special stuff based
5326297a64e7Sgd78059 	 * in the speed.
5327297a64e7Sgd78059 	 */
5328297a64e7Sgd78059 	speed_100 = param_anar_100fdx | param_anar_100hdx;
5329297a64e7Sgd78059 	speed_10 = param_anar_10fdx | param_anar_10hdx;
5330297a64e7Sgd78059 
5331297a64e7Sgd78059 	ERI_DEBUG_MSG5(erip, XCVR_MSG, "eri_reset_xcvr: %d %d %d %d",
5332297a64e7Sgd78059 	    param_anar_100fdx, param_anar_100hdx, param_anar_10fdx,
5333297a64e7Sgd78059 	    param_anar_10hdx);
5334297a64e7Sgd78059 
5335297a64e7Sgd78059 	ERI_DEBUG_MSG3(erip, XCVR_MSG,
5336297a64e7Sgd78059 	    "eri_reset_xcvr: speed_100 %d speed_10 %d", speed_100, speed_10);
5337297a64e7Sgd78059 
5338297a64e7Sgd78059 	if ((!speed_100) && (speed_10)) {
5339297a64e7Sgd78059 		erip->mif_mask &= ~PHY_BMSR_JABDET;
5340297a64e7Sgd78059 		if (!(param_anar_10fdx) &&
5341297a64e7Sgd78059 		    (param_anar_10hdx) &&
5342297a64e7Sgd78059 		    (erip->link_pulse_disabled)) {
5343297a64e7Sgd78059 			param_speed = 0;
5344297a64e7Sgd78059 			param_mode = 0;
5345297a64e7Sgd78059 			(void) eri_mii_read(erip, ERI_PHY_NICR, &nicr);
5346297a64e7Sgd78059 			nicr &= ~PHY_NICR_LD;
5347297a64e7Sgd78059 			eri_mii_write(erip, ERI_PHY_NICR, nicr);
5348297a64e7Sgd78059 			param_linkup = 1;
5349297a64e7Sgd78059 			erip->stats.link_up = LINK_STATE_UP;
5350297a64e7Sgd78059 			if (param_mode)
5351297a64e7Sgd78059 				erip->stats.link_duplex = LINK_DUPLEX_FULL;
5352297a64e7Sgd78059 			else
5353297a64e7Sgd78059 				erip->stats.link_duplex = LINK_DUPLEX_HALF;
5354297a64e7Sgd78059 		}
5355297a64e7Sgd78059 	}
5356297a64e7Sgd78059 
5357297a64e7Sgd78059 	/*
5358297a64e7Sgd78059 	 * Clear the autonegotitation before re-starting
5359297a64e7Sgd78059 	 */
5360297a64e7Sgd78059 	control = PHY_BMCR_100M | PHY_BMCR_FDX;
5361297a64e7Sgd78059 /*	eri_mii_write(erip, ERI_PHY_BMCR, control); */
5362297a64e7Sgd78059 	if (param_autoneg) {
5363297a64e7Sgd78059 		/*
5364297a64e7Sgd78059 		 * Setup the transceiver for autonegotiation.
5365297a64e7Sgd78059 		 */
5366297a64e7Sgd78059 		erip->mif_mask &= ~PHY_BMSR_ANC;
5367297a64e7Sgd78059 
5368297a64e7Sgd78059 		/*
5369297a64e7Sgd78059 		 * Clear the Auto-negotiation before re-starting
5370297a64e7Sgd78059 		 */
5371297a64e7Sgd78059 		eri_mii_write(erip, ERI_PHY_BMCR, control & ~PHY_BMCR_ANE);
5372297a64e7Sgd78059 
5373297a64e7Sgd78059 		/*
5374297a64e7Sgd78059 		 * Switch on auto-negotiation.
5375297a64e7Sgd78059 		 */
5376297a64e7Sgd78059 		control |= (PHY_BMCR_ANE | PHY_BMCR_RAN);
5377297a64e7Sgd78059 
5378297a64e7Sgd78059 		eri_mii_write(erip, ERI_PHY_BMCR, control);
5379297a64e7Sgd78059 	} else {
5380297a64e7Sgd78059 		/*
5381297a64e7Sgd78059 		 * Force the transceiver.
5382297a64e7Sgd78059 		 */
5383297a64e7Sgd78059 		erip->mif_mask &= ~PHY_BMSR_LNKSTS;
5384297a64e7Sgd78059 
5385297a64e7Sgd78059 		/*
5386297a64e7Sgd78059 		 * Switch off auto-negotiation.
5387297a64e7Sgd78059 		 */
5388297a64e7Sgd78059 		control &= ~(PHY_BMCR_FDX | PHY_BMCR_ANE | PHY_BMCR_RAN);
5389297a64e7Sgd78059 
5390297a64e7Sgd78059 		if (speed_100) {
5391297a64e7Sgd78059 			control |= PHY_BMCR_100M;
5392297a64e7Sgd78059 			param_aner_lpancap = 0; /* Clear LP nway */
5393297a64e7Sgd78059 			param_anlpar_10fdx = 0;
5394297a64e7Sgd78059 			param_anlpar_10hdx = 0;
5395297a64e7Sgd78059 			param_anlpar_100T4 = param_anar_100T4;
5396297a64e7Sgd78059 			param_anlpar_100fdx = param_anar_100fdx;
5397297a64e7Sgd78059 			param_anlpar_100hdx = param_anar_100hdx;
5398297a64e7Sgd78059 			param_speed = 1;
5399297a64e7Sgd78059 			erip->stats.ifspeed = 100;
5400297a64e7Sgd78059 			param_mode = param_anar_100fdx;
5401297a64e7Sgd78059 			if (param_mode) {
5402297a64e7Sgd78059 				param_anlpar_100hdx = 0;
5403297a64e7Sgd78059 				erip->stats.link_duplex = LINK_DUPLEX_FULL;
5404297a64e7Sgd78059 			} else {
5405297a64e7Sgd78059 				erip->stats.link_duplex = LINK_DUPLEX_HALF;
5406297a64e7Sgd78059 			}
5407297a64e7Sgd78059 		} else if (speed_10) {
5408297a64e7Sgd78059 			control &= ~PHY_BMCR_100M;
5409297a64e7Sgd78059 			param_aner_lpancap = 0; /* Clear LP nway */
5410297a64e7Sgd78059 			param_anlpar_100fdx = 0;
5411297a64e7Sgd78059 			param_anlpar_100hdx = 0;
5412297a64e7Sgd78059 			param_anlpar_100T4 = 0;
5413297a64e7Sgd78059 			param_anlpar_10fdx = param_anar_10fdx;
5414297a64e7Sgd78059 			param_anlpar_10hdx = param_anar_10hdx;
5415297a64e7Sgd78059 			param_speed = 0;
5416297a64e7Sgd78059 			erip->stats.ifspeed = 10;
5417297a64e7Sgd78059 			param_mode = param_anar_10fdx;
5418297a64e7Sgd78059 			if (param_mode) {
5419297a64e7Sgd78059 				param_anlpar_10hdx = 0;
5420297a64e7Sgd78059 				erip->stats.link_duplex = LINK_DUPLEX_FULL;
5421297a64e7Sgd78059 			} else {
5422297a64e7Sgd78059 				erip->stats.link_duplex = LINK_DUPLEX_HALF;
5423297a64e7Sgd78059 			}
5424297a64e7Sgd78059 		} else {
5425297a64e7Sgd78059 			ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
5426297a64e7Sgd78059 			    "Transceiver speed set incorrectly.");
5427297a64e7Sgd78059 		}
5428297a64e7Sgd78059 
5429297a64e7Sgd78059 		if (param_mode) {
5430297a64e7Sgd78059 			control |= PHY_BMCR_FDX;
5431297a64e7Sgd78059 		}
5432297a64e7Sgd78059 
5433297a64e7Sgd78059 		ERI_DEBUG_MSG4(erip, PHY_MSG,
5434297a64e7Sgd78059 		    "control = %x status = %x param_mode %d",
5435297a64e7Sgd78059 		    control, stat, param_mode);
5436297a64e7Sgd78059 
5437297a64e7Sgd78059 		eri_mii_write(erip, ERI_PHY_BMCR, control);
5438297a64e7Sgd78059 /*
5439297a64e7Sgd78059  *		if (param_mode) {
5440297a64e7Sgd78059  *			control |= PHY_BMCR_FDX;
5441297a64e7Sgd78059  *		}
5442297a64e7Sgd78059  *		control &= ~(PHY_BMCR_FDX | PHY_BMCR_ANE | PHY_BMCR_RAN);
5443297a64e7Sgd78059  *		eri_mii_write(erip, ERI_PHY_BMCR, control);
5444297a64e7Sgd78059  */
5445297a64e7Sgd78059 	}
5446297a64e7Sgd78059 
5447297a64e7Sgd78059 #ifdef DEBUG
5448297a64e7Sgd78059 	(void) eri_mii_read(erip, ERI_PHY_BMCR, &control);
5449297a64e7Sgd78059 	(void) eri_mii_read(erip, ERI_PHY_BMSR, &stat);
5450297a64e7Sgd78059 	(void) eri_mii_read(erip, ERI_PHY_ANAR, &anar);
5451297a64e7Sgd78059 #endif
5452297a64e7Sgd78059 	ERI_DEBUG_MSG4(erip, PHY_MSG,
5453297a64e7Sgd78059 	    "control %X status %X anar %X", control, stat, anar);
5454297a64e7Sgd78059 
5455297a64e7Sgd78059 eri_reset_xcvr_exit:
5456297a64e7Sgd78059 	return (0);
5457297a64e7Sgd78059 
5458297a64e7Sgd78059 eri_reset_xcvr_failed:
5459297a64e7Sgd78059 	return (1);
5460297a64e7Sgd78059 }
5461297a64e7Sgd78059 
5462297a64e7Sgd78059 #ifdef	ERI_10_10_FORCE_SPEED_WORKAROUND
5463297a64e7Sgd78059 
5464297a64e7Sgd78059 static void
eri_xcvr_force_mode(struct eri * erip,uint32_t * link_timeout)5465297a64e7Sgd78059 eri_xcvr_force_mode(struct eri *erip, uint32_t *link_timeout)
5466297a64e7Sgd78059 {
5467297a64e7Sgd78059 
5468297a64e7Sgd78059 	if (!param_autoneg && !param_linkup && (erip->stats.ifspeed == 10) &&
5469297a64e7Sgd78059 	    (param_anar_10fdx | param_anar_10hdx)) {
5470297a64e7Sgd78059 		*link_timeout = SECOND(1);
5471297a64e7Sgd78059 		return;
5472297a64e7Sgd78059 	}
5473297a64e7Sgd78059 
5474297a64e7Sgd78059 	if (!param_autoneg && !param_linkup && (erip->ifspeed_old == 10) &&
5475297a64e7Sgd78059 	    (param_anar_100fdx | param_anar_100hdx)) {
5476297a64e7Sgd78059 		/*
5477297a64e7Sgd78059 		 * May have to set link partner's speed and mode.
5478297a64e7Sgd78059 		 */
5479297a64e7Sgd78059 		ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_LOG_MSG,
5480297a64e7Sgd78059 		"May have to set link partner's speed and duplex mode.");
5481297a64e7Sgd78059 	}
5482297a64e7Sgd78059 }
5483297a64e7Sgd78059 #endif
5484297a64e7Sgd78059 
5485297a64e7Sgd78059 static void
eri_mif_poll(struct eri * erip,soft_mif_enable_t enable)5486297a64e7Sgd78059 eri_mif_poll(struct eri *erip, soft_mif_enable_t enable)
5487297a64e7Sgd78059 {
5488297a64e7Sgd78059 	if (enable == MIF_POLL_START) {
5489297a64e7Sgd78059 		if (erip->mifpoll_enable && !erip->openloop_autoneg) {
5490297a64e7Sgd78059 			erip->mif_config |= ERI_MIF_CFGPE;
5491297a64e7Sgd78059 			PUT_MIFREG(mif_cfg, erip->mif_config);
5492297a64e7Sgd78059 			drv_usecwait(ERI_MIF_POLL_DELAY);
5493297a64e7Sgd78059 			PUT_GLOBREG(intmask, GET_GLOBREG(intmask) &
5494297a64e7Sgd78059 			    ~ERI_G_MASK_MIF_INT);
5495297a64e7Sgd78059 			PUT_MIFREG(mif_imask, erip->mif_mask);
5496297a64e7Sgd78059 		}
5497297a64e7Sgd78059 	} else if (enable == MIF_POLL_STOP) {
5498297a64e7Sgd78059 			erip->mif_config &= ~ERI_MIF_CFGPE;
5499297a64e7Sgd78059 			PUT_MIFREG(mif_cfg, erip->mif_config);
5500297a64e7Sgd78059 			drv_usecwait(ERI_MIF_POLL_DELAY);
5501297a64e7Sgd78059 			PUT_GLOBREG(intmask, GET_GLOBREG(intmask) |
5502297a64e7Sgd78059 			    ERI_G_MASK_MIF_INT);
5503297a64e7Sgd78059 			PUT_MIFREG(mif_imask, ERI_MIF_INTMASK);
5504297a64e7Sgd78059 	}
5505297a64e7Sgd78059 	ERI_DEBUG_MSG2(erip, XCVR_MSG, "MIF Config = 0x%X",
5506297a64e7Sgd78059 	    GET_MIFREG(mif_cfg));
5507297a64e7Sgd78059 	ERI_DEBUG_MSG2(erip, XCVR_MSG, "MIF imask = 0x%X",
5508297a64e7Sgd78059 	    GET_MIFREG(mif_imask));
5509297a64e7Sgd78059 	ERI_DEBUG_MSG2(erip, XCVR_MSG, "INT imask = 0x%X",
5510297a64e7Sgd78059 	    GET_GLOBREG(intmask));
5511297a64e7Sgd78059 	ERI_DEBUG_MSG1(erip, XCVR_MSG, "<== mif_poll");
5512297a64e7Sgd78059 }
5513297a64e7Sgd78059 
5514297a64e7Sgd78059 /* Decide if transmitter went dead and reinitialize everything */
5515297a64e7Sgd78059 #ifdef	ERI_TX_HUNG
5516297a64e7Sgd78059 static int eri_txhung_limit = 2;
5517297a64e7Sgd78059 static int
eri_check_txhung(struct eri * erip)5518297a64e7Sgd78059 eri_check_txhung(struct eri *erip)
5519297a64e7Sgd78059 {
5520297a64e7Sgd78059 	boolean_t	macupdate = B_FALSE;
5521297a64e7Sgd78059 
5522297a64e7Sgd78059 	mutex_enter(&erip->xmitlock);
5523297a64e7Sgd78059 	if (erip->flags & ERI_RUNNING)
5524297a64e7Sgd78059 		erip->tx_completion = (uint32_t)(GET_ETXREG(tx_completion) &
5525297a64e7Sgd78059 		    ETX_COMPLETION_MASK);
5526297a64e7Sgd78059 		macupdate |= eri_reclaim(erip, erip->tx_completion);
5527297a64e7Sgd78059 
5528297a64e7Sgd78059 	/* Something needs to be sent out but it is not going out */
5529297a64e7Sgd78059 	if ((erip->tcurp != erip->tnextp) &&
5530297a64e7Sgd78059 	    (erip->stats.opackets64 == erip->erisave.reclaim_opackets) &&
5531297a64e7Sgd78059 	    (erip->stats.collisions == erip->erisave.starts))
5532297a64e7Sgd78059 		erip->txhung++;
5533297a64e7Sgd78059 	else
5534297a64e7Sgd78059 		erip->txhung = 0;
5535297a64e7Sgd78059 
5536297a64e7Sgd78059 	erip->erisave.reclaim_opackets = erip->stats.opackets64;
5537297a64e7Sgd78059 	erip->erisave.starts = erip->stats.collisions;
5538297a64e7Sgd78059 	mutex_exit(&erip->xmitlock);
5539297a64e7Sgd78059 
5540297a64e7Sgd78059 	if (macupdate)
5541297a64e7Sgd78059 		mac_tx_update(erip->mh);
5542297a64e7Sgd78059 
5543297a64e7Sgd78059 	return (erip->txhung >= eri_txhung_limit);
5544297a64e7Sgd78059 }
5545297a64e7Sgd78059 #endif
5546