xref: /illumos-gate/usr/src/uts/sun/io/eri/eri.c (revision 7e996435)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5447e4a63Spetede  * Common Development and Distribution License (the "License").
6447e4a63Spetede  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
220dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate /*
277c478bd9Sstevel@tonic-gate  * SunOS MT STREAMS ERI(PCI) 10/100 Mb Ethernet Device Driver
287c478bd9Sstevel@tonic-gate  */
297c478bd9Sstevel@tonic-gate 
307c478bd9Sstevel@tonic-gate #include	<sys/types.h>
317c478bd9Sstevel@tonic-gate #include	<sys/debug.h>
327c478bd9Sstevel@tonic-gate #include	<sys/stropts.h>
337c478bd9Sstevel@tonic-gate #include	<sys/stream.h>
347c478bd9Sstevel@tonic-gate #include	<sys/strsubr.h>
357c478bd9Sstevel@tonic-gate #include	<sys/kmem.h>
367c478bd9Sstevel@tonic-gate #include	<sys/crc32.h>
377c478bd9Sstevel@tonic-gate #include	<sys/ddi.h>
387c478bd9Sstevel@tonic-gate #include	<sys/sunddi.h>
397c478bd9Sstevel@tonic-gate #include	<sys/strsun.h>
407c478bd9Sstevel@tonic-gate #include	<sys/stat.h>
417c478bd9Sstevel@tonic-gate #include	<sys/cpu.h>
427c478bd9Sstevel@tonic-gate #include	<sys/kstat.h>
437c478bd9Sstevel@tonic-gate #include	<inet/common.h>
447c478bd9Sstevel@tonic-gate #include	<sys/pattr.h>
457c478bd9Sstevel@tonic-gate #include	<inet/mi.h>
467c478bd9Sstevel@tonic-gate #include	<inet/nd.h>
477c478bd9Sstevel@tonic-gate #include	<sys/ethernet.h>
48d62bc4baSyz #include	<sys/vlan.h>
497c478bd9Sstevel@tonic-gate #include	<sys/policy.h>
50da14cebeSEric Cheng #include	<sys/mac_provider.h>
51d64540e3Sgd #include	<sys/mac_ether.h>
52d64540e3Sgd #include	<sys/dlpi.h>
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate #include	<sys/pci.h>
557c478bd9Sstevel@tonic-gate 
56297a64e7Sgd #include	"eri_phy.h"
57297a64e7Sgd #include	"eri_mac.h"
58297a64e7Sgd #include	"eri.h"
59297a64e7Sgd #include	"eri_common.h"
607c478bd9Sstevel@tonic-gate 
61297a64e7Sgd #include	"eri_msg.h"
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate /*
647c478bd9Sstevel@tonic-gate  *  **** Function Prototypes *****
657c478bd9Sstevel@tonic-gate  */
667c478bd9Sstevel@tonic-gate /*
677c478bd9Sstevel@tonic-gate  * Entry points (man9e)
687c478bd9Sstevel@tonic-gate  */
697c478bd9Sstevel@tonic-gate static	int	eri_attach(dev_info_t *, ddi_attach_cmd_t);
707c478bd9Sstevel@tonic-gate static	int	eri_detach(dev_info_t *, ddi_detach_cmd_t);
71d64540e3Sgd static	uint_t	eri_intr(caddr_t);
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * I/O (Input/Output) Functions
757c478bd9Sstevel@tonic-gate  */
76d64540e3Sgd static	boolean_t	eri_send_msg(struct eri *, mblk_t *);
77d64540e3Sgd static  mblk_t		*eri_read_dma(struct eri *, volatile struct rmd *,
78d64540e3Sgd 			    volatile int, uint64_t flags);
797c478bd9Sstevel@tonic-gate 
807c478bd9Sstevel@tonic-gate /*
817c478bd9Sstevel@tonic-gate  * Initialization Functions
827c478bd9Sstevel@tonic-gate  */
83d64540e3Sgd static  boolean_t	eri_init(struct eri *);
847c478bd9Sstevel@tonic-gate static	int	eri_allocthings(struct eri *);
857c478bd9Sstevel@tonic-gate static  int	eri_init_xfer_params(struct eri *);
867c478bd9Sstevel@tonic-gate static  void	eri_statinit(struct eri *);
877c478bd9Sstevel@tonic-gate static	int	eri_burstsize(struct eri *);
887c478bd9Sstevel@tonic-gate 
897c478bd9Sstevel@tonic-gate static	void	eri_setup_mac_address(struct eri *, dev_info_t *);
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate static	uint32_t eri_init_rx_channel(struct eri *);
927c478bd9Sstevel@tonic-gate static	void	eri_init_rx(struct eri *);
937c478bd9Sstevel@tonic-gate static	void	eri_init_txmac(struct eri *);
947c478bd9Sstevel@tonic-gate 
957c478bd9Sstevel@tonic-gate /*
967c478bd9Sstevel@tonic-gate  * Un-init Functions
977c478bd9Sstevel@tonic-gate  */
987c478bd9Sstevel@tonic-gate static	uint32_t eri_txmac_disable(struct eri *);
997c478bd9Sstevel@tonic-gate static	uint32_t eri_rxmac_disable(struct eri *);
1007c478bd9Sstevel@tonic-gate static	int	eri_stop(struct eri *);
1017c478bd9Sstevel@tonic-gate static	void	eri_uninit(struct eri *erip);
1027c478bd9Sstevel@tonic-gate static	int	eri_freebufs(struct eri *);
103d64540e3Sgd static	boolean_t	eri_reclaim(struct eri *, uint32_t);
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate /*
1067c478bd9Sstevel@tonic-gate  * Transceiver (xcvr) Functions
1077c478bd9Sstevel@tonic-gate  */
1087c478bd9Sstevel@tonic-gate static	int	eri_new_xcvr(struct eri *); /* Initializes & detects xcvrs */
1097c478bd9Sstevel@tonic-gate static	int	eri_reset_xcvr(struct eri *);
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate #ifdef	ERI_10_10_FORCE_SPEED_WORKAROUND
1127c478bd9Sstevel@tonic-gate static	void	eri_xcvr_force_mode(struct eri *, uint32_t *);
1137c478bd9Sstevel@tonic-gate #endif
1147c478bd9Sstevel@tonic-gate 
1157c478bd9Sstevel@tonic-gate static	void	eri_mif_poll(struct eri *, soft_mif_enable_t);
1167c478bd9Sstevel@tonic-gate static	void	eri_check_link(struct eri *);
117860c4cd4Scarlsonj static	uint32_t eri_check_link_noind(struct eri *);
118d64540e3Sgd static	link_state_t eri_mif_check(struct eri *, uint16_t, uint16_t);
1197c478bd9Sstevel@tonic-gate static	void    eri_mii_write(struct eri *, uint8_t, uint16_t);
1207c478bd9Sstevel@tonic-gate static	uint32_t eri_mii_read(struct eri *, uint8_t, uint16_t *);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate /*
1237c478bd9Sstevel@tonic-gate  * Reset Functions
1247c478bd9Sstevel@tonic-gate  */
1257c478bd9Sstevel@tonic-gate static	uint32_t eri_etx_reset(struct eri *);
1267c478bd9Sstevel@tonic-gate static	uint32_t eri_erx_reset(struct eri *);
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate /*
1297c478bd9Sstevel@tonic-gate  * Error Functions
1307c478bd9Sstevel@tonic-gate  */
1317c478bd9Sstevel@tonic-gate static	void eri_fatal_err(struct eri *, uint32_t);
1327c478bd9Sstevel@tonic-gate static	void eri_nonfatal_err(struct eri *, uint32_t);
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate #ifdef	ERI_TX_HUNG
1357c478bd9Sstevel@tonic-gate static	int eri_check_txhung(struct eri *);
1367c478bd9Sstevel@tonic-gate #endif
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate /*
1397c478bd9Sstevel@tonic-gate  * Hardening Functions
1407c478bd9Sstevel@tonic-gate  */
141d64540e3Sgd static void eri_fault_msg(struct eri *, uint_t, msg_t, const char *, ...);
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate /*
1447c478bd9Sstevel@tonic-gate  * Misc Functions
1457c478bd9Sstevel@tonic-gate  */
1467c478bd9Sstevel@tonic-gate static void	eri_savecntrs(struct eri *);
1477c478bd9Sstevel@tonic-gate 
1487c478bd9Sstevel@tonic-gate static	void	eri_stop_timer(struct eri *erip);
1497c478bd9Sstevel@tonic-gate static	void	eri_start_timer(struct eri *erip, fptrv_t func, clock_t msec);
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate static	void eri_bb_force_idle(struct eri *);
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate /*
1547c478bd9Sstevel@tonic-gate  * Utility Functions
1557c478bd9Sstevel@tonic-gate  */
1567c478bd9Sstevel@tonic-gate static	mblk_t *eri_allocb(size_t size);
1577c478bd9Sstevel@tonic-gate static	mblk_t *eri_allocb_sp(size_t size);
1587c478bd9Sstevel@tonic-gate static	int	eri_param_get(queue_t *q, mblk_t *mp, caddr_t cp);
1597c478bd9Sstevel@tonic-gate static	int	eri_param_set(queue_t *, mblk_t *, char *, caddr_t);
1607c478bd9Sstevel@tonic-gate 
1617c478bd9Sstevel@tonic-gate /*
1627c478bd9Sstevel@tonic-gate  * Functions to support ndd
1637c478bd9Sstevel@tonic-gate  */
1647c478bd9Sstevel@tonic-gate static	void	eri_nd_free(caddr_t *nd_pparam);
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate static	boolean_t	eri_nd_load(caddr_t *nd_pparam, char *name,
1677c478bd9Sstevel@tonic-gate 				pfi_t get_pfi, pfi_t set_pfi, caddr_t data);
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate static	int	eri_nd_getset(queue_t *q, caddr_t nd_param, MBLKP mp);
1707c478bd9Sstevel@tonic-gate static	void	eri_param_cleanup(struct eri *);
1717c478bd9Sstevel@tonic-gate static	int	eri_param_register(struct eri *, param_t *, int);
172d64540e3Sgd static	void	eri_process_ndd_ioctl(struct eri *, queue_t *, mblk_t *, int);
173d64540e3Sgd static	int	eri_mk_mblk_tail_space(mblk_t *, mblk_t **, size_t);
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate 
176d64540e3Sgd static	void eri_loopback(struct eri *, queue_t *, mblk_t *);
1777c478bd9Sstevel@tonic-gate 
178d64540e3Sgd static uint32_t	eri_ladrf_bit(const uint8_t *);
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 
181d64540e3Sgd /*
182d64540e3Sgd  * Nemo (GLDv3) Functions.
183d64540e3Sgd  */
184d64540e3Sgd static	int		eri_m_stat(void *, uint_t, uint64_t *);
185d64540e3Sgd static	int		eri_m_start(void *);
186d64540e3Sgd static	void		eri_m_stop(void *);
187d64540e3Sgd static	int		eri_m_promisc(void *, boolean_t);
188d64540e3Sgd static	int		eri_m_multicst(void *, boolean_t, const uint8_t *);
189d64540e3Sgd static	int		eri_m_unicst(void *, const uint8_t *);
190d64540e3Sgd static	void		eri_m_ioctl(void *, queue_t *, mblk_t *);
191d64540e3Sgd static	boolean_t	eri_m_getcapab(void *, mac_capab_t, void *);
192d64540e3Sgd static	mblk_t		*eri_m_tx(void *, mblk_t *);
193d64540e3Sgd 
194d64540e3Sgd static mac_callbacks_t eri_m_callbacks = {
195d64540e3Sgd 	MC_IOCTL | MC_GETCAPAB,
196d64540e3Sgd 	eri_m_stat,
197d64540e3Sgd 	eri_m_start,
198d64540e3Sgd 	eri_m_stop,
199d64540e3Sgd 	eri_m_promisc,
200d64540e3Sgd 	eri_m_multicst,
201d64540e3Sgd 	eri_m_unicst,
202d64540e3Sgd 	eri_m_tx,
2030dc2366fSVenugopal Iyer 	NULL,
204d64540e3Sgd 	eri_m_ioctl,
205d64540e3Sgd 	eri_m_getcapab
206d64540e3Sgd };
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate /*
2097c478bd9Sstevel@tonic-gate  * Define PHY Vendors: Matches to IEEE
2107c478bd9Sstevel@tonic-gate  * Organizationally Unique Identifier (OUI)
2117c478bd9Sstevel@tonic-gate  */
2127c478bd9Sstevel@tonic-gate /*
2137c478bd9Sstevel@tonic-gate  * The first two are supported as Internal XCVRs
2147c478bd9Sstevel@tonic-gate  */
2157c478bd9Sstevel@tonic-gate #define	PHY_VENDOR_LUCENT	0x601d
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate #define	PHY_LINK_NONE		0	/* Not attempted yet or retry */
2187c478bd9Sstevel@tonic-gate #define	PHY_LINK_DOWN		1	/* Not being used	*/
2197c478bd9Sstevel@tonic-gate #define	PHY_LINK_UP		2	/* Not being used	*/
2207c478bd9Sstevel@tonic-gate 
2217c478bd9Sstevel@tonic-gate #define	AUTO_SPEED		0
2227c478bd9Sstevel@tonic-gate #define	FORCE_SPEED		1
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate /*
225d64540e3Sgd  * MIB II broadcast/multicast packets
2267c478bd9Sstevel@tonic-gate  */
2277c478bd9Sstevel@tonic-gate 
228d64540e3Sgd #define	IS_BROADCAST(pkt) (bcmp(pkt, &etherbroadcastaddr, ETHERADDRL) == 0)
229d64540e3Sgd #define	IS_MULTICAST(pkt) ((pkt[0] & 01) == 1)
2307c478bd9Sstevel@tonic-gate 
231d64540e3Sgd #define	BUMP_InNUcast(erip, pkt) \
232d64540e3Sgd 		if (IS_BROADCAST(pkt)) { \
2337c478bd9Sstevel@tonic-gate 			HSTAT(erip, brdcstrcv); \
234d64540e3Sgd 		} else if (IS_MULTICAST(pkt)) { \
2357c478bd9Sstevel@tonic-gate 			HSTAT(erip, multircv); \
2367c478bd9Sstevel@tonic-gate 		}
2377c478bd9Sstevel@tonic-gate 
238d64540e3Sgd #define	BUMP_OutNUcast(erip, pkt) \
239d64540e3Sgd 		if (IS_BROADCAST(pkt)) { \
2407c478bd9Sstevel@tonic-gate 			HSTAT(erip, brdcstxmt); \
241d64540e3Sgd 		} else if (IS_MULTICAST(pkt)) { \
2427c478bd9Sstevel@tonic-gate 			HSTAT(erip, multixmt); \
2437c478bd9Sstevel@tonic-gate 		}
2447c478bd9Sstevel@tonic-gate 
2457c478bd9Sstevel@tonic-gate #define	NEXTTMDP(tbasep, tmdlimp, tmdp)	(((tmdp) + 1) == tmdlimp	\
2467c478bd9Sstevel@tonic-gate 	? tbasep : ((tmdp) + 1))
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate #define	ETHERHEADER_SIZE (sizeof (struct ether_header))
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate #ifdef	ERI_RCV_CKSUM
2517c478bd9Sstevel@tonic-gate #define	ERI_PROCESS_READ(erip, bp, sum)				\
2527c478bd9Sstevel@tonic-gate {								\
2537c478bd9Sstevel@tonic-gate 	t_uscalar_t	type;					\
2547c478bd9Sstevel@tonic-gate 	uint_t	start_offset, end_offset;			\
2557c478bd9Sstevel@tonic-gate 								\
2567c478bd9Sstevel@tonic-gate 	*(bp->b_wptr) = 0;	/* pad byte */			\
2577c478bd9Sstevel@tonic-gate 								\
2587c478bd9Sstevel@tonic-gate 	/*							\
2597c478bd9Sstevel@tonic-gate 	 * update MIB II statistics				\
2607c478bd9Sstevel@tonic-gate 	 */							\
2617c478bd9Sstevel@tonic-gate 	HSTAT(erip, ipackets64);				\
2627c478bd9Sstevel@tonic-gate 	HSTATN(erip, rbytes64, len);				\
263d64540e3Sgd 	BUMP_InNUcast(erip, bp->b_rptr);			\
264d64540e3Sgd 	type = get_ether_type(bp->b_rptr);			\
265d64540e3Sgd 	if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6) {	\
2667c478bd9Sstevel@tonic-gate 		start_offset = 0;				\
26722eb7cb5Sgd 		end_offset = MBLKL(bp) - ETHERHEADER_SIZE;	\
2680dc2366fSVenugopal Iyer 		mac_hcksum_set(bp,				\
269*7e996435SToomas Soome 			start_offset, 0, end_offset, sum,	\
2700dc2366fSVenugopal Iyer 			HCK_PARTIALCKSUM);			\
2717c478bd9Sstevel@tonic-gate 	} else {						\
2727c478bd9Sstevel@tonic-gate 		/*						\
2737c478bd9Sstevel@tonic-gate 		 * Strip the PADS for 802.3			\
2747c478bd9Sstevel@tonic-gate 		 */						\
2757c478bd9Sstevel@tonic-gate 		if (type <= ETHERMTU)				\
2767c478bd9Sstevel@tonic-gate 			bp->b_wptr = bp->b_rptr +		\
2777c478bd9Sstevel@tonic-gate 				ETHERHEADER_SIZE + type;	\
2787c478bd9Sstevel@tonic-gate 	}							\
2797c478bd9Sstevel@tonic-gate }
2807c478bd9Sstevel@tonic-gate #else
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate #define	ERI_PROCESS_READ(erip, bp)				\
2837c478bd9Sstevel@tonic-gate {								\
2847c478bd9Sstevel@tonic-gate 	t_uscalar_t	type;					\
285d64540e3Sgd 	type = get_ether_type(bp->b_rptr);			\
286d64540e3Sgd 								\
287d64540e3Sgd 	/*							\
288d64540e3Sgd 	 * update MIB II statistics				\
289d64540e3Sgd 	 */							\
290d64540e3Sgd 	HSTAT(erip, ipackets64);				\
291d64540e3Sgd 	HSTATN(erip, rbytes64, len);				\
292d64540e3Sgd 	BUMP_InNUcast(erip, bp->b_rptr);			\
293d64540e3Sgd 	/*							\
294d64540e3Sgd 	 * Strip the PADS for 802.3				\
295d64540e3Sgd 	 */							\
296d64540e3Sgd 	if (type <= ETHERMTU)					\
297*7e996435SToomas Soome 		bp->b_wptr = bp->b_rptr + ETHERHEADER_SIZE +	\
298*7e996435SToomas Soome 		    type;					\
2997c478bd9Sstevel@tonic-gate }
3007c478bd9Sstevel@tonic-gate #endif  /* ERI_RCV_CKSUM */
3017c478bd9Sstevel@tonic-gate 
3027c478bd9Sstevel@tonic-gate /*
3037c478bd9Sstevel@tonic-gate  * TX Interrupt Rate
3047c478bd9Sstevel@tonic-gate  */
3057c478bd9Sstevel@tonic-gate static	int	tx_interrupt_rate = 16;
3067c478bd9Sstevel@tonic-gate 
3077c478bd9Sstevel@tonic-gate /*
3087c478bd9Sstevel@tonic-gate  * Ethernet broadcast address definition.
3097c478bd9Sstevel@tonic-gate  */
310d64540e3Sgd static uint8_t	etherbroadcastaddr[] = {
3117c478bd9Sstevel@tonic-gate 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
3127c478bd9Sstevel@tonic-gate };
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate /*
3157c478bd9Sstevel@tonic-gate  * The following variables are used for configuring various features
3167c478bd9Sstevel@tonic-gate  */
3177c478bd9Sstevel@tonic-gate #define	ERI_DESC_HANDLE_ALLOC	0x0001
3187c478bd9Sstevel@tonic-gate #define	ERI_DESC_MEM_ALLOC	0x0002
3197c478bd9Sstevel@tonic-gate #define	ERI_DESC_MEM_MAP	0x0004
3207c478bd9Sstevel@tonic-gate #define	ERI_RCV_HANDLE_ALLOC	0x0020
3217c478bd9Sstevel@tonic-gate #define	ERI_RCV_HANDLE_BIND	0x0040
3227c478bd9Sstevel@tonic-gate #define	ERI_XMIT_DVMA_ALLOC	0x0100
3237c478bd9Sstevel@tonic-gate #define	ERI_RCV_DVMA_ALLOC	0x0200
3247c478bd9Sstevel@tonic-gate #define	ERI_XBUFS_HANDLE_ALLOC  0x0400
3257c478bd9Sstevel@tonic-gate #define	ERI_XBUFS_KMEM_ALLOC    0x0800
3267c478bd9Sstevel@tonic-gate #define	ERI_XBUFS_KMEM_DMABIND  0x1000
3277c478bd9Sstevel@tonic-gate 
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate #define	ERI_DONT_STRIP_CRC
3307c478bd9Sstevel@tonic-gate /*
3317c478bd9Sstevel@tonic-gate  * Translate a kernel virtual address to i/o address.
3327c478bd9Sstevel@tonic-gate  */
3337c478bd9Sstevel@tonic-gate #define	ERI_IOPBIOADDR(erip, a) \
3347c478bd9Sstevel@tonic-gate 	((erip)->iopbiobase + ((uintptr_t)a - (erip)->iopbkbase))
3357c478bd9Sstevel@tonic-gate 
3367c478bd9Sstevel@tonic-gate /*
3377c478bd9Sstevel@tonic-gate  * ERI Configuration Register Value
3387c478bd9Sstevel@tonic-gate  * Used to configure parameters that define DMA burst
3397c478bd9Sstevel@tonic-gate  * and internal arbitration behavior.
3407c478bd9Sstevel@tonic-gate  * for equal TX and RX bursts, set the following in global
3417c478bd9Sstevel@tonic-gate  * configuration register.
3427c478bd9Sstevel@tonic-gate  * static	int	global_config = 0x42;
3437c478bd9Sstevel@tonic-gate  */
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate /*
3467c478bd9Sstevel@tonic-gate  * ERI ERX Interrupt Blanking Time
3477c478bd9Sstevel@tonic-gate  * Each count is about 16 us (2048 clocks) for 66 MHz PCI.
3487c478bd9Sstevel@tonic-gate  */
3497c478bd9Sstevel@tonic-gate static	int	intr_blank_time = 6;	/* for about 96 us */
3507c478bd9Sstevel@tonic-gate static	int	intr_blank_packets = 8;	/*  */
3517c478bd9Sstevel@tonic-gate 
3527c478bd9Sstevel@tonic-gate /*
3537c478bd9Sstevel@tonic-gate  * ERX PAUSE Threshold Register value
3547c478bd9Sstevel@tonic-gate  * The following value is for an OFF Threshold of about 15.5 Kbytes
3557c478bd9Sstevel@tonic-gate  * and an ON Threshold of 4K bytes.
3567c478bd9Sstevel@tonic-gate  */
3577c478bd9Sstevel@tonic-gate static	int rx_pause_threshold = 0xf8 | (0x40 << 12);
3587c478bd9Sstevel@tonic-gate static	int eri_reinit_fatal = 0;
3597c478bd9Sstevel@tonic-gate #ifdef	DEBUG
3607c478bd9Sstevel@tonic-gate static	int noteri = 0;
3617c478bd9Sstevel@tonic-gate #endif
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate #ifdef	ERI_TX_HUNG
3647c478bd9Sstevel@tonic-gate static	int eri_reinit_txhung = 0;
3657c478bd9Sstevel@tonic-gate #endif
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate #ifdef ERI_HDX_BUG_WORKAROUND
3687c478bd9Sstevel@tonic-gate /*
3697c478bd9Sstevel@tonic-gate  * By default enable padding in hdx mode to 97 bytes.
3707c478bd9Sstevel@tonic-gate  * To disabled, in /etc/system:
3717c478bd9Sstevel@tonic-gate  * set eri:eri_hdx_pad_enable=0
3727c478bd9Sstevel@tonic-gate  */
3737c478bd9Sstevel@tonic-gate static	uchar_t eri_hdx_pad_enable = 1;
3747c478bd9Sstevel@tonic-gate #endif
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate /*
3777c478bd9Sstevel@tonic-gate  * Default values to initialize the cache line size and latency timer
3787c478bd9Sstevel@tonic-gate  * registers in the PCI configuration space.
3797c478bd9Sstevel@tonic-gate  * ERI_G_CACHE_LINE_SIZE_16 is defined as 16 since RIO expects in units
3807c478bd9Sstevel@tonic-gate  * of 4 bytes.
3817c478bd9Sstevel@tonic-gate  */
3827c478bd9Sstevel@tonic-gate #ifdef ERI_PM_WORKAROUND_PCI
3837c478bd9Sstevel@tonic-gate static int eri_pci_cache_line = ERI_G_CACHE_LINE_SIZE_32; /* 128 bytes */
3847c478bd9Sstevel@tonic-gate static int eri_pci_latency_timer = 0xff;		/* 255 PCI cycles */
3857c478bd9Sstevel@tonic-gate #else
3867c478bd9Sstevel@tonic-gate static int eri_pci_cache_line = ERI_G_CACHE_LINE_SIZE_16; /* 64 bytes */
3877c478bd9Sstevel@tonic-gate static int eri_pci_latency_timer = 0x40;		/* 64 PCI cycles */
3887c478bd9Sstevel@tonic-gate #endif
3897c478bd9Sstevel@tonic-gate #define	ERI_CACHE_LINE_SIZE	(eri_pci_cache_line << ERI_G_CACHE_BIT)
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate /*
3927c478bd9Sstevel@tonic-gate  * Claim the device is ultra-capable of burst in the beginning.  Use
3937c478bd9Sstevel@tonic-gate  * the value returned by ddi_dma_burstsizes() to actually set the ERI
3947c478bd9Sstevel@tonic-gate  * global configuration register later.
3957c478bd9Sstevel@tonic-gate  *
3967c478bd9Sstevel@tonic-gate  * PCI_ERI supports Infinite burst or 64-byte-multiple bursts.
3977c478bd9Sstevel@tonic-gate  */
3987c478bd9Sstevel@tonic-gate #define	ERI_LIMADDRLO	((uint64_t)0x00000000)
3997c478bd9Sstevel@tonic-gate #define	ERI_LIMADDRHI	((uint64_t)0xffffffff)
4007c478bd9Sstevel@tonic-gate 
4017c478bd9Sstevel@tonic-gate static ddi_dma_attr_t dma_attr = {
4027c478bd9Sstevel@tonic-gate 	DMA_ATTR_V0,		/* version number. */
4037c478bd9Sstevel@tonic-gate 	(uint64_t)ERI_LIMADDRLO, /* low address */
4047c478bd9Sstevel@tonic-gate 	(uint64_t)ERI_LIMADDRHI, /* high address */
4057c478bd9Sstevel@tonic-gate 	(uint64_t)0x00ffffff,	/* address counter max */
4067c478bd9Sstevel@tonic-gate 	(uint64_t)1,		/* alignment */
4077c478bd9Sstevel@tonic-gate 	(uint_t)0xe000e0,	/* dlim_burstsizes for 32 4 bit xfers */
4087c478bd9Sstevel@tonic-gate 	(uint32_t)0x1,		/* minimum transfer size */
4097c478bd9Sstevel@tonic-gate 	(uint64_t)0x7fffffff,	/* maximum transfer size */
4107c478bd9Sstevel@tonic-gate 	(uint64_t)0x00ffffff,	/* maximum segment size */
4117c478bd9Sstevel@tonic-gate 	1,			/* scatter/gather list length */
4127c478bd9Sstevel@tonic-gate 	(uint32_t)1,		/* granularity */
4137c478bd9Sstevel@tonic-gate 	(uint_t)0		/* attribute flags */
4147c478bd9Sstevel@tonic-gate };
4157c478bd9Sstevel@tonic-gate 
4167c478bd9Sstevel@tonic-gate static ddi_dma_attr_t desc_dma_attr = {
4177c478bd9Sstevel@tonic-gate 	DMA_ATTR_V0,		/* version number. */
4187c478bd9Sstevel@tonic-gate 	(uint64_t)ERI_LIMADDRLO, /* low address */
4197c478bd9Sstevel@tonic-gate 	(uint64_t)ERI_LIMADDRHI, /* high address */
4207c478bd9Sstevel@tonic-gate 	(uint64_t)0x00ffffff,	/* address counter max */
4217c478bd9Sstevel@tonic-gate 	(uint64_t)8,		/* alignment */
4227c478bd9Sstevel@tonic-gate 	(uint_t)0xe000e0,	/* dlim_burstsizes for 32 4 bit xfers */
4237c478bd9Sstevel@tonic-gate 	(uint32_t)0x1,		/* minimum transfer size */
4247c478bd9Sstevel@tonic-gate 	(uint64_t)0x7fffffff,	/* maximum transfer size */
4257c478bd9Sstevel@tonic-gate 	(uint64_t)0x00ffffff,	/* maximum segment size */
4267c478bd9Sstevel@tonic-gate 	1,			/* scatter/gather list length */
4277c478bd9Sstevel@tonic-gate 	16,			/* granularity */
4287c478bd9Sstevel@tonic-gate 	0			/* attribute flags */
4297c478bd9Sstevel@tonic-gate };
4307c478bd9Sstevel@tonic-gate 
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 
4387c478bd9Sstevel@tonic-gate ddi_dma_lim_t eri_dma_limits = {
4397c478bd9Sstevel@tonic-gate 	(uint64_t)ERI_LIMADDRLO, /* dlim_addr_lo */
4407c478bd9Sstevel@tonic-gate 	(uint64_t)ERI_LIMADDRHI, /* dlim_addr_hi */
4417c478bd9Sstevel@tonic-gate 	(uint64_t)ERI_LIMADDRHI, /* dlim_cntr_max */
4427c478bd9Sstevel@tonic-gate 	(uint_t)0x00e000e0,	/* dlim_burstsizes for 32 and 64 bit xfers */
4437c478bd9Sstevel@tonic-gate 	(uint32_t)0x1,		/* dlim_minxfer */
4447c478bd9Sstevel@tonic-gate 	1024			/* dlim_speed */
4457c478bd9Sstevel@tonic-gate };
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate /*
4487c478bd9Sstevel@tonic-gate  * Link Configuration variables
4497c478bd9Sstevel@tonic-gate  *
4507c478bd9Sstevel@tonic-gate  * On Motherboard implementations, 10/100 Mbps speeds may be supported
4517c478bd9Sstevel@tonic-gate  * by using both the Serial Link and the MII on Non-serial-link interface.
4527c478bd9Sstevel@tonic-gate  * When both links are present, the driver automatically tries to bring up
4537c478bd9Sstevel@tonic-gate  * both. If both are up, the Gigabit Serial Link is selected for use, by
4547c478bd9Sstevel@tonic-gate  * default. The following configuration variable is used to force the selection
4557c478bd9Sstevel@tonic-gate  * of one of the links when both are up.
4567c478bd9Sstevel@tonic-gate  * To change the default selection to the MII link when both the Serial
4577c478bd9Sstevel@tonic-gate  * Link and the MII link are up, change eri_default_link to 1.
4587c478bd9Sstevel@tonic-gate  *
4597c478bd9Sstevel@tonic-gate  * Once a link is in use, the driver will continue to use that link till it
4607c478bd9Sstevel@tonic-gate  * goes down. When it goes down, the driver will look at the status of both the
4617c478bd9Sstevel@tonic-gate  * links again for link selection.
4627c478bd9Sstevel@tonic-gate  *
4637c478bd9Sstevel@tonic-gate  * Currently the standard is not stable w.r.t. gigabit link configuration
4647c478bd9Sstevel@tonic-gate  * using auto-negotiation procedures. Meanwhile, the link may be configured
4657c478bd9Sstevel@tonic-gate  * in "forced" mode using the "autonegotiation enable" bit (bit-12) in the
4667c478bd9Sstevel@tonic-gate  * PCS MII Command Register. In this mode the PCS sends "idles" until sees
4677c478bd9Sstevel@tonic-gate  * "idles" as initialization instead of the Link Configuration protocol
4687c478bd9Sstevel@tonic-gate  * where a Config register is exchanged. In this mode, the ERI is programmed
4697c478bd9Sstevel@tonic-gate  * for full-duplex operation with both pauseTX and pauseRX (for flow control)
4707c478bd9Sstevel@tonic-gate  * enabled.
4717c478bd9Sstevel@tonic-gate  */
4727c478bd9Sstevel@tonic-gate 
4737c478bd9Sstevel@tonic-gate static	int	select_link = 0; /* automatic selection */
4747c478bd9Sstevel@tonic-gate static	int	default_link = 0; /* Select Serial link if both are up */
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate /*
4777c478bd9Sstevel@tonic-gate  * The following variables are used for configuring link-operation
4787c478bd9Sstevel@tonic-gate  * for all the "eri" interfaces in the system.
4797c478bd9Sstevel@tonic-gate  * Later these parameters may be changed per interface using "ndd" command
4807c478bd9Sstevel@tonic-gate  * These parameters may also be specified as properties using the .conf
4817c478bd9Sstevel@tonic-gate  * file mechanism for each interface.
4827c478bd9Sstevel@tonic-gate  */
4837c478bd9Sstevel@tonic-gate 
4847c478bd9Sstevel@tonic-gate /*
4857c478bd9Sstevel@tonic-gate  * The following variable value will be overridden by "link-pulse-disabled"
4867c478bd9Sstevel@tonic-gate  * property which may be created by OBP or eri.conf file. This property is
4877c478bd9Sstevel@tonic-gate  * applicable only for 10 Mbps links.
4887c478bd9Sstevel@tonic-gate  */
4897c478bd9Sstevel@tonic-gate static	int	link_pulse_disabled = 0;	/* link pulse disabled */
4907c478bd9Sstevel@tonic-gate 
4917c478bd9Sstevel@tonic-gate /* For MII-based FastEthernet links */
4927c478bd9Sstevel@tonic-gate static	int	adv_autoneg_cap = 1;
4937c478bd9Sstevel@tonic-gate static	int	adv_100T4_cap = 0;
4947c478bd9Sstevel@tonic-gate static	int	adv_100fdx_cap = 1;
4957c478bd9Sstevel@tonic-gate static	int	adv_100hdx_cap = 1;
4967c478bd9Sstevel@tonic-gate static	int	adv_10fdx_cap = 1;
4977c478bd9Sstevel@tonic-gate static	int	adv_10hdx_cap = 1;
4987c478bd9Sstevel@tonic-gate static	int	adv_pauseTX_cap =  0;
4997c478bd9Sstevel@tonic-gate static	int	adv_pauseRX_cap =  0;
5007c478bd9Sstevel@tonic-gate 
5017c478bd9Sstevel@tonic-gate /*
5027c478bd9Sstevel@tonic-gate  * The following gap parameters are in terms of byte times.
5037c478bd9Sstevel@tonic-gate  */
5047c478bd9Sstevel@tonic-gate static	int	ipg0 = 8;
5057c478bd9Sstevel@tonic-gate static	int	ipg1 = 8;
5067c478bd9Sstevel@tonic-gate static	int	ipg2 = 4;
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate static	int	lance_mode = 1;		/* to enable LANCE mode */
5097c478bd9Sstevel@tonic-gate static	int	mifpoll_enable = 0;	/* to enable mif poll */
5107c478bd9Sstevel@tonic-gate static	int	ngu_enable = 0;		/* to enable Never Give Up mode */
5117c478bd9Sstevel@tonic-gate 
512*7e996435SToomas Soome static	int	eri_force_mlf = 0;	/* to enable mif poll */
5137c478bd9Sstevel@tonic-gate static	int	eri_phy_mintrans = 1;	/* Lu3X31T mintrans algorithm */
5147c478bd9Sstevel@tonic-gate /*
5157c478bd9Sstevel@tonic-gate  * For the MII interface, the External Transceiver is selected when present.
5167c478bd9Sstevel@tonic-gate  * The following variable is used to select the Internal Transceiver even
5177c478bd9Sstevel@tonic-gate  * when the External Transceiver is present.
5187c478bd9Sstevel@tonic-gate  */
5197c478bd9Sstevel@tonic-gate static	int	use_int_xcvr = 0;
5207c478bd9Sstevel@tonic-gate static	int	pace_size = 0;	/* Do not use pacing for now */
5217c478bd9Sstevel@tonic-gate 
5227c478bd9Sstevel@tonic-gate static	int	eri_use_dvma_rx = 0;	/* =1:use dvma */
5237c478bd9Sstevel@tonic-gate static	int	eri_rx_bcopy_max = RX_BCOPY_MAX;	/* =1:use bcopy() */
5247c478bd9Sstevel@tonic-gate static	int	eri_overflow_reset = 1;	/* global reset if rx_fifo_overflow */
5257c478bd9Sstevel@tonic-gate static	int	eri_tx_ring_size = 2048; /* number of entries in tx ring */
5267c478bd9Sstevel@tonic-gate static	int	eri_rx_ring_size = 1024; /* number of entries in rx ring */
5277c478bd9Sstevel@tonic-gate /*
5287c478bd9Sstevel@tonic-gate  * The following parameters may be configured by the user. If they are not
5297c478bd9Sstevel@tonic-gate  * configured by the user, the values will be based on the capabilities of
5307c478bd9Sstevel@tonic-gate  * the transceiver.
5317c478bd9Sstevel@tonic-gate  * The value "ERI_NOTUSR" is ORed with the parameter value to indicate values
5327c478bd9Sstevel@tonic-gate  * which are NOT configured by the user.
5337c478bd9Sstevel@tonic-gate  */
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate #define	ERI_NOTUSR	0x0f000000
5367c478bd9Sstevel@tonic-gate #define	ERI_MASK_1BIT	0x1
5377c478bd9Sstevel@tonic-gate #define	ERI_MASK_2BIT	0x3
5387c478bd9Sstevel@tonic-gate #define	ERI_MASK_8BIT	0xff
5397c478bd9Sstevel@tonic-gate 
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate /*
5427c478bd9Sstevel@tonic-gate  * Note:
5437c478bd9Sstevel@tonic-gate  * ERI has all of the above capabilities.
5447c478bd9Sstevel@tonic-gate  * Only when an External Transceiver is selected for MII-based FastEthernet
5457c478bd9Sstevel@tonic-gate  * link operation, the capabilities depend upon the capabilities of the
5467c478bd9Sstevel@tonic-gate  * External Transceiver.
5477c478bd9Sstevel@tonic-gate  */
5487c478bd9Sstevel@tonic-gate 
5497c478bd9Sstevel@tonic-gate /* ------------------------------------------------------------------------- */
5507c478bd9Sstevel@tonic-gate 
5517c478bd9Sstevel@tonic-gate static  param_t	param_arr[] = {
552d64540e3Sgd 	/* min		max		value	r/w/hidden+name */
553d64540e3Sgd 	{  0,		2,		2,	"-transceiver_inuse"},
554d64540e3Sgd 	{  0,		1,		0,	"-link_status"},
555d64540e3Sgd 	{  0,		1,		0,	"-link_speed"},
556d64540e3Sgd 	{  0,		1,		0,	"-link_mode"},
557d64540e3Sgd 	{  0,		255,		8,	"+ipg1"},
558d64540e3Sgd 	{  0,		255,		4,	"+ipg2"},
559d64540e3Sgd 	{  0,		1,		0,	"+use_int_xcvr"},
560d64540e3Sgd 	{  0,		255,		0,	"+pace_size"},
561d64540e3Sgd 	{  0,		1,		1,	"+adv_autoneg_cap"},
562d64540e3Sgd 	{  0,		1,		1,	"+adv_100T4_cap"},
563d64540e3Sgd 	{  0,		1,		1,	"+adv_100fdx_cap"},
564d64540e3Sgd 	{  0,		1,		1,	"+adv_100hdx_cap"},
565d64540e3Sgd 	{  0,		1,		1,	"+adv_10fdx_cap"},
566d64540e3Sgd 	{  0,		1,		1,	"+adv_10hdx_cap"},
567d64540e3Sgd 	{  0,		1,		1,	"-autoneg_cap"},
568d64540e3Sgd 	{  0,		1,		1,	"-100T4_cap"},
569d64540e3Sgd 	{  0,		1,		1,	"-100fdx_cap"},
570d64540e3Sgd 	{  0,		1,		1,	"-100hdx_cap"},
571d64540e3Sgd 	{  0,		1,		1,	"-10fdx_cap"},
572d64540e3Sgd 	{  0,		1,		1,	"-10hdx_cap"},
573d64540e3Sgd 	{  0,		1,		0,	"-lp_autoneg_cap"},
574d64540e3Sgd 	{  0,		1,		0,	"-lp_100T4_cap"},
575d64540e3Sgd 	{  0,		1,		0,	"-lp_100fdx_cap"},
576d64540e3Sgd 	{  0,		1,		0,	"-lp_100hdx_cap"},
577d64540e3Sgd 	{  0,		1,		0,	"-lp_10fdx_cap"},
578d64540e3Sgd 	{  0,		1,		0,	"-lp_10hdx_cap"},
579d64540e3Sgd 	{  0,		1,		1,	"+lance_mode"},
580d64540e3Sgd 	{  0,		31,		8,	"+ipg0"},
581d64540e3Sgd 	{  0,		127,		6,	"+intr_blank_time"},
582d64540e3Sgd 	{  0,		255,		8,	"+intr_blank_packets"},
583d64540e3Sgd 	{  0,		1,		1,	"!serial-link"},
584d64540e3Sgd 	{  0,		2,		1,	"!non-serial-link"},
585d64540e3Sgd 	{  0,		1,		0,	"%select-link"},
586d64540e3Sgd 	{  0,		1,		0,	"%default-link"},
587d64540e3Sgd 	{  0,		2,		0,	"!link-in-use"},
588d64540e3Sgd 	{  0,		1,		1,	"%adv_asm_dir_cap"},
589d64540e3Sgd 	{  0,		1,		1,	"%adv_pause_cap"},
590d64540e3Sgd 	{  0,		1,		0,	"!asm_dir_cap"},
591d64540e3Sgd 	{  0,		1,		0,	"!pause_cap"},
592d64540e3Sgd 	{  0,		1,		0,	"!lp_asm_dir_cap"},
593d64540e3Sgd 	{  0,		1,		0,	"!lp_pause_cap"},
5947c478bd9Sstevel@tonic-gate };
5957c478bd9Sstevel@tonic-gate 
596d64540e3Sgd DDI_DEFINE_STREAM_OPS(eri_dev_ops, nulldev, nulldev, eri_attach, eri_detach,
597*7e996435SToomas Soome     nodev, NULL, D_MP, NULL, ddi_quiesce_not_supported);
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate /*
6007c478bd9Sstevel@tonic-gate  * This is the loadable module wrapper.
6017c478bd9Sstevel@tonic-gate  */
6027c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
6037c478bd9Sstevel@tonic-gate 
6047c478bd9Sstevel@tonic-gate /*
6057c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
6067c478bd9Sstevel@tonic-gate  */
6077c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
6087c478bd9Sstevel@tonic-gate 	&mod_driverops,	/* Type of module.  This one is a driver */
609d64540e3Sgd 	"Sun RIO 10/100 Mb Ethernet",
610d64540e3Sgd 	&eri_dev_ops,	/* driver ops */
6117c478bd9Sstevel@tonic-gate };
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
6147c478bd9Sstevel@tonic-gate 	MODREV_1, &modldrv, NULL
6157c478bd9Sstevel@tonic-gate };
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate /*
6187c478bd9Sstevel@tonic-gate  * Hardware Independent Functions
6197c478bd9Sstevel@tonic-gate  * New Section
6207c478bd9Sstevel@tonic-gate  */
6217c478bd9Sstevel@tonic-gate 
6227c478bd9Sstevel@tonic-gate int
_init(void)6237c478bd9Sstevel@tonic-gate _init(void)
6247c478bd9Sstevel@tonic-gate {
6257c478bd9Sstevel@tonic-gate 	int	status;
6267c478bd9Sstevel@tonic-gate 
627d64540e3Sgd 	mac_init_ops(&eri_dev_ops, "eri");
628d64540e3Sgd 	if ((status = mod_install(&modlinkage)) != 0) {
629d64540e3Sgd 		mac_fini_ops(&eri_dev_ops);
630d64540e3Sgd 	}
6317c478bd9Sstevel@tonic-gate 	return (status);
6327c478bd9Sstevel@tonic-gate }
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate int
_fini(void)6357c478bd9Sstevel@tonic-gate _fini(void)
6367c478bd9Sstevel@tonic-gate {
637d64540e3Sgd 	int status;
6387c478bd9Sstevel@tonic-gate 
6397c478bd9Sstevel@tonic-gate 	status = mod_remove(&modlinkage);
640d64540e3Sgd 	if (status == 0) {
641d64540e3Sgd 		mac_fini_ops(&eri_dev_ops);
642d64540e3Sgd 	}
6437c478bd9Sstevel@tonic-gate 	return (status);
6447c478bd9Sstevel@tonic-gate }
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)6477c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
6487c478bd9Sstevel@tonic-gate {
649d64540e3Sgd 	return (mod_info(&modlinkage, modinfop));
6507c478bd9Sstevel@tonic-gate }
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate /*
6547c478bd9Sstevel@tonic-gate  * Interface exists: make available by filling in network interface
6557c478bd9Sstevel@tonic-gate  * record.  System will initialize the interface when it is ready
6567c478bd9Sstevel@tonic-gate  * to accept packets.
6577c478bd9Sstevel@tonic-gate  */
6587c478bd9Sstevel@tonic-gate static int
eri_attach(dev_info_t * dip,ddi_attach_cmd_t cmd)6597c478bd9Sstevel@tonic-gate eri_attach(dev_info_t *dip, ddi_attach_cmd_t cmd)
6607c478bd9Sstevel@tonic-gate {
661d64540e3Sgd 	struct eri *erip = NULL;
662d64540e3Sgd 	mac_register_t *macp = NULL;
6637c478bd9Sstevel@tonic-gate 	int	regno;
664d64540e3Sgd 	boolean_t	doinit;
665d64540e3Sgd 	boolean_t	mutex_inited = B_FALSE;
666d64540e3Sgd 	boolean_t	intr_add = B_FALSE;
6677c478bd9Sstevel@tonic-gate 
6687c478bd9Sstevel@tonic-gate 	switch (cmd) {
6697c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
6707c478bd9Sstevel@tonic-gate 		break;
6717c478bd9Sstevel@tonic-gate 
6727c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
6737c478bd9Sstevel@tonic-gate 		if ((erip = ddi_get_driver_private(dip)) == NULL)
6747c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
6757c478bd9Sstevel@tonic-gate 
676d64540e3Sgd 		mutex_enter(&erip->intrlock);
6777c478bd9Sstevel@tonic-gate 		erip->flags &= ~ERI_SUSPENDED;
6787c478bd9Sstevel@tonic-gate 		erip->init_macregs = 1;
6797c478bd9Sstevel@tonic-gate 		param_linkup = 0;
680d64540e3Sgd 		erip->stats.link_up = LINK_STATE_DOWN;
6817c478bd9Sstevel@tonic-gate 		erip->linkcheck = 0;
6827c478bd9Sstevel@tonic-gate 
683d64540e3Sgd 		doinit =  (erip->flags & ERI_STARTED) ? B_TRUE : B_FALSE;
684d64540e3Sgd 		mutex_exit(&erip->intrlock);
685d64540e3Sgd 
686d64540e3Sgd 		if (doinit && !eri_init(erip)) {
687d64540e3Sgd 			return (DDI_FAILURE);
6887c478bd9Sstevel@tonic-gate 		}
6897c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	default:
6927c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6937c478bd9Sstevel@tonic-gate 	}
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	/*
6967c478bd9Sstevel@tonic-gate 	 * Allocate soft device data structure
6977c478bd9Sstevel@tonic-gate 	 */
698d64540e3Sgd 	erip = kmem_zalloc(sizeof (struct eri), KM_SLEEP);
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	/*
7017c478bd9Sstevel@tonic-gate 	 * Initialize as many elements as possible.
7027c478bd9Sstevel@tonic-gate 	 */
7037c478bd9Sstevel@tonic-gate 	ddi_set_driver_private(dip, erip);
7047c478bd9Sstevel@tonic-gate 	erip->dip = dip;			/* dip	*/
7057c478bd9Sstevel@tonic-gate 	erip->instance = ddi_get_instance(dip);	/* instance */
7067c478bd9Sstevel@tonic-gate 	erip->flags = 0;
707d64540e3Sgd 	erip->multi_refcnt = 0;
708d64540e3Sgd 	erip->promisc = B_FALSE;
709d64540e3Sgd 
710d64540e3Sgd 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
711d64540e3Sgd 		ERI_FAULT_MSG1(erip, SEVERITY_HIGH, ERI_VERB_MSG,
712d64540e3Sgd 		    "mac_alloc failed");
713d64540e3Sgd 		goto attach_fail;
714d64540e3Sgd 	}
715d64540e3Sgd 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
716d64540e3Sgd 	macp->m_driver = erip;
717d64540e3Sgd 	macp->m_dip = dip;
718d64540e3Sgd 	macp->m_src_addr = erip->ouraddr;
719d64540e3Sgd 	macp->m_callbacks = &eri_m_callbacks;
720d64540e3Sgd 	macp->m_min_sdu = 0;
721d64540e3Sgd 	macp->m_max_sdu = ETHERMTU;
722d62bc4baSyz 	macp->m_margin = VLAN_TAGSZ;
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	/*
7257c478bd9Sstevel@tonic-gate 	 * Map in the device registers.
7267c478bd9Sstevel@tonic-gate 	 * Separate pointers will be set up for the following
7277c478bd9Sstevel@tonic-gate 	 * register groups within the GEM Register Space:
728*7e996435SToomas Soome 	 *	Global register set
729*7e996435SToomas Soome 	 *	ETX register set
730*7e996435SToomas Soome 	 *	ERX register set
731*7e996435SToomas Soome 	 *	BigMAC register set.
732*7e996435SToomas Soome 	 *	MIF register set
7337c478bd9Sstevel@tonic-gate 	 */
7347c478bd9Sstevel@tonic-gate 
7357c478bd9Sstevel@tonic-gate 	if (ddi_dev_nregs(dip, &regno) != (DDI_SUCCESS)) {
7367c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG2(erip, SEVERITY_HIGH, ERI_VERB_MSG,
737d64540e3Sgd 		    "ddi_dev_nregs failed, returned %d", regno);
7387c478bd9Sstevel@tonic-gate 		goto attach_fail;
7397c478bd9Sstevel@tonic-gate 	}
7407c478bd9Sstevel@tonic-gate 
7417c478bd9Sstevel@tonic-gate 	/*
7427c478bd9Sstevel@tonic-gate 	 * Map the PCI config space
7437c478bd9Sstevel@tonic-gate 	 */
744d64540e3Sgd 	if (pci_config_setup(dip, &erip->pci_config_handle) != DDI_SUCCESS) {
7457c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG2(erip, SEVERITY_HIGH, ERI_VERB_MSG,
746d64540e3Sgd 		    "%s pci_config_setup()", config_space_fatal_msg);
7477c478bd9Sstevel@tonic-gate 		goto attach_fail;
7487c478bd9Sstevel@tonic-gate 	}
7497c478bd9Sstevel@tonic-gate 
7507c478bd9Sstevel@tonic-gate 	/*
7517c478bd9Sstevel@tonic-gate 	 * Initialize device attributes structure
7527c478bd9Sstevel@tonic-gate 	 */
7537c478bd9Sstevel@tonic-gate 	erip->dev_attr.devacc_attr_version =	DDI_DEVICE_ATTR_V0;
7547c478bd9Sstevel@tonic-gate 	erip->dev_attr.devacc_attr_dataorder =	DDI_STRICTORDER_ACC;
7557c478bd9Sstevel@tonic-gate 	erip->dev_attr.devacc_attr_endian_flags =	DDI_STRUCTURE_LE_ACC;
7567c478bd9Sstevel@tonic-gate 
757d64540e3Sgd 	if (ddi_regs_map_setup(dip, 1, (caddr_t *)&(erip->globregp), 0, 0,
758d64540e3Sgd 	    &erip->dev_attr, &erip->globregh)) {
759d64540e3Sgd 		goto attach_fail;
7607c478bd9Sstevel@tonic-gate 	}
7617c478bd9Sstevel@tonic-gate 	erip->etxregh =		erip->globregh;
7627c478bd9Sstevel@tonic-gate 	erip->erxregh =		erip->globregh;
7637c478bd9Sstevel@tonic-gate 	erip->bmacregh =	erip->globregh;
7647c478bd9Sstevel@tonic-gate 	erip->mifregh =		erip->globregh;
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	erip->etxregp =  (void *)(((caddr_t)erip->globregp) + 0x2000);
7677c478bd9Sstevel@tonic-gate 	erip->erxregp =  (void *)(((caddr_t)erip->globregp) + 0x4000);
7687c478bd9Sstevel@tonic-gate 	erip->bmacregp = (void *)(((caddr_t)erip->globregp) + 0x6000);
7697c478bd9Sstevel@tonic-gate 	erip->mifregp =  (void *)(((caddr_t)erip->globregp) + 0x6200);
7707c478bd9Sstevel@tonic-gate 
7717c478bd9Sstevel@tonic-gate 	/*
7727c478bd9Sstevel@tonic-gate 	 * Map the software reset register.
7737c478bd9Sstevel@tonic-gate 	 */
774d64540e3Sgd 	if (ddi_regs_map_setup(dip, 1, (caddr_t *)&(erip->sw_reset_reg),
775d64540e3Sgd 	    0x1010, 4, &erip->dev_attr, &erip->sw_reset_regh)) {
7767c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG1(erip, SEVERITY_MID, ERI_VERB_MSG,
777d64540e3Sgd 		    mregs_4soft_reset_fail_msg);
778d64540e3Sgd 		goto attach_fail;
7797c478bd9Sstevel@tonic-gate 	}
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	/*
7827c478bd9Sstevel@tonic-gate 	 * Try and stop the device.
7837c478bd9Sstevel@tonic-gate 	 * This is done until we want to handle interrupts.
7847c478bd9Sstevel@tonic-gate 	 */
7857c478bd9Sstevel@tonic-gate 	if (eri_stop(erip))
7867c478bd9Sstevel@tonic-gate 		goto attach_fail;
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	/*
7897c478bd9Sstevel@tonic-gate 	 * set PCI latency timer register.
7907c478bd9Sstevel@tonic-gate 	 */
7917c478bd9Sstevel@tonic-gate 	pci_config_put8(erip->pci_config_handle, PCI_CONF_LATENCY_TIMER,
792d64540e3Sgd 	    (uchar_t)eri_pci_latency_timer);
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	if (ddi_intr_hilevel(dip, 0)) {
7957c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
7967c478bd9Sstevel@tonic-gate 		    " high-level interrupts are not supported");
7977c478bd9Sstevel@tonic-gate 		goto attach_fail;
7987c478bd9Sstevel@tonic-gate 	}
7997c478bd9Sstevel@tonic-gate 
8007c478bd9Sstevel@tonic-gate 	/*
8017c478bd9Sstevel@tonic-gate 	 * Get the interrupt cookie so the mutexes can be
8027c478bd9Sstevel@tonic-gate 	 * Initialized.
8037c478bd9Sstevel@tonic-gate 	 */
8047c478bd9Sstevel@tonic-gate 	if (ddi_get_iblock_cookie(dip, 0, &erip->cookie) != DDI_SUCCESS)
8057c478bd9Sstevel@tonic-gate 		goto attach_fail;
8067c478bd9Sstevel@tonic-gate 
8077c478bd9Sstevel@tonic-gate 	/*
8087c478bd9Sstevel@tonic-gate 	 * Initialize mutex's for this device.
8097c478bd9Sstevel@tonic-gate 	 */
8107c478bd9Sstevel@tonic-gate 	mutex_init(&erip->xmitlock, NULL, MUTEX_DRIVER, (void *)erip->cookie);
8117c478bd9Sstevel@tonic-gate 	mutex_init(&erip->intrlock, NULL, MUTEX_DRIVER, (void *)erip->cookie);
8127c478bd9Sstevel@tonic-gate 	mutex_init(&erip->linklock, NULL, MUTEX_DRIVER, (void *)erip->cookie);
8137c478bd9Sstevel@tonic-gate 	mutex_init(&erip->xcvrlock, NULL, MUTEX_DRIVER, (void *)erip->cookie);
8147c478bd9Sstevel@tonic-gate 
815d64540e3Sgd 	mutex_inited = B_TRUE;
8167c478bd9Sstevel@tonic-gate 
8177c478bd9Sstevel@tonic-gate 	/*
8187c478bd9Sstevel@tonic-gate 	 * Add interrupt to system
8197c478bd9Sstevel@tonic-gate 	 */
820d64540e3Sgd 	if (ddi_add_intr(dip, 0, &erip->cookie, 0, eri_intr, (caddr_t)erip) ==
821d64540e3Sgd 	    DDI_SUCCESS)
822d64540e3Sgd 		intr_add = B_TRUE;
8237c478bd9Sstevel@tonic-gate 	else {
8247c478bd9Sstevel@tonic-gate 		goto attach_fail;
8257c478bd9Sstevel@tonic-gate 	}
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	/*
8287c478bd9Sstevel@tonic-gate 	 * Set up the ethernet mac address.
8297c478bd9Sstevel@tonic-gate 	 */
8307c478bd9Sstevel@tonic-gate 	(void) eri_setup_mac_address(erip, dip);
8317c478bd9Sstevel@tonic-gate 
8327c478bd9Sstevel@tonic-gate 	if (eri_init_xfer_params(erip))
8337c478bd9Sstevel@tonic-gate 		goto attach_fail;
8347c478bd9Sstevel@tonic-gate 
8357c478bd9Sstevel@tonic-gate 	if (eri_burstsize(erip) == DDI_FAILURE) {
8367c478bd9Sstevel@tonic-gate 		goto attach_fail;
8377c478bd9Sstevel@tonic-gate 	}
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 	/*
8407c478bd9Sstevel@tonic-gate 	 * Setup fewer receive bufers.
8417c478bd9Sstevel@tonic-gate 	 */
8427c478bd9Sstevel@tonic-gate 	ERI_RPENDING = eri_rx_ring_size;
8437c478bd9Sstevel@tonic-gate 	ERI_TPENDING = eri_tx_ring_size;
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 	erip->rpending_mask = ERI_RPENDING - 1;
8467c478bd9Sstevel@tonic-gate 	erip->rmdmax_mask = ERI_RPENDING - 1;
8477c478bd9Sstevel@tonic-gate 	erip->mif_config = (ERI_PHY_BMSR << ERI_MIF_CFGPR_SHIFT);
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	erip->stats.pmcap = ERI_PMCAP_NONE;
8507c478bd9Sstevel@tonic-gate 	if (pci_report_pmcap(dip, PCI_PM_IDLESPEED, (void *)4000) ==
851d64540e3Sgd 	    DDI_SUCCESS)
8527c478bd9Sstevel@tonic-gate 		erip->stats.pmcap = ERI_PMCAP_4MHZ;
8537c478bd9Sstevel@tonic-gate 
854d64540e3Sgd 	if (mac_register(macp, &erip->mh) != 0)
855d64540e3Sgd 		goto attach_fail;
8567c478bd9Sstevel@tonic-gate 
857d64540e3Sgd 	mac_free(macp);
8587c478bd9Sstevel@tonic-gate 
8597c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate attach_fail:
8627c478bd9Sstevel@tonic-gate 	if (erip->pci_config_handle)
8637c478bd9Sstevel@tonic-gate 		(void) pci_config_teardown(&erip->pci_config_handle);
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	if (mutex_inited) {
8667c478bd9Sstevel@tonic-gate 		mutex_destroy(&erip->xmitlock);
8677c478bd9Sstevel@tonic-gate 		mutex_destroy(&erip->intrlock);
8687c478bd9Sstevel@tonic-gate 		mutex_destroy(&erip->linklock);
8697c478bd9Sstevel@tonic-gate 		mutex_destroy(&erip->xcvrlock);
8707c478bd9Sstevel@tonic-gate 	}
8717c478bd9Sstevel@tonic-gate 
872d64540e3Sgd 	ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG, attach_fail_msg);
8737c478bd9Sstevel@tonic-gate 
8747c478bd9Sstevel@tonic-gate 	if (intr_add)
8757c478bd9Sstevel@tonic-gate 		ddi_remove_intr(dip, 0, erip->cookie);
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	if (erip->globregh)
8787c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&erip->globregh);
8797c478bd9Sstevel@tonic-gate 
880d64540e3Sgd 	if (macp != NULL)
881d64540e3Sgd 		mac_free(macp);
882d64540e3Sgd 	if (erip != NULL)
883d64540e3Sgd 		kmem_free(erip, sizeof (*erip));
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
8867c478bd9Sstevel@tonic-gate }
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate static int
eri_detach(dev_info_t * dip,ddi_detach_cmd_t cmd)8897c478bd9Sstevel@tonic-gate eri_detach(dev_info_t *dip, ddi_detach_cmd_t cmd)
8907c478bd9Sstevel@tonic-gate {
891*7e996435SToomas Soome 	struct eri	*erip;
8927c478bd9Sstevel@tonic-gate 	int i;
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	if ((erip = ddi_get_driver_private(dip)) == NULL) {
8957c478bd9Sstevel@tonic-gate 		/*
8967c478bd9Sstevel@tonic-gate 		 * No resources allocated.
8977c478bd9Sstevel@tonic-gate 		 */
8987c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8997c478bd9Sstevel@tonic-gate 	}
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	switch (cmd) {
9027c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
9037c478bd9Sstevel@tonic-gate 		break;
9047c478bd9Sstevel@tonic-gate 
9057c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
9067c478bd9Sstevel@tonic-gate 		erip->flags |= ERI_SUSPENDED;
9077c478bd9Sstevel@tonic-gate 		eri_uninit(erip);
9087c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
9097c478bd9Sstevel@tonic-gate 
9107c478bd9Sstevel@tonic-gate 	default:
9117c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9127c478bd9Sstevel@tonic-gate 	}
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	if (erip->flags & (ERI_RUNNING | ERI_SUSPENDED)) {
9157c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG, busy_msg);
9167c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9177c478bd9Sstevel@tonic-gate 	}
9187c478bd9Sstevel@tonic-gate 
919d64540e3Sgd 	if (mac_unregister(erip->mh) != 0) {
920d64540e3Sgd 		return (DDI_FAILURE);
921d64540e3Sgd 	}
922d64540e3Sgd 
9237c478bd9Sstevel@tonic-gate 	/*
9247c478bd9Sstevel@tonic-gate 	 * Make the device quiescent
9257c478bd9Sstevel@tonic-gate 	 */
9267c478bd9Sstevel@tonic-gate 	(void) eri_stop(erip);
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 	/*
9297c478bd9Sstevel@tonic-gate 	 * Remove instance of the intr
9307c478bd9Sstevel@tonic-gate 	 */
9317c478bd9Sstevel@tonic-gate 	ddi_remove_intr(dip, 0, erip->cookie);
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate 	if (erip->pci_config_handle)
9347c478bd9Sstevel@tonic-gate 		(void) pci_config_teardown(&erip->pci_config_handle);
9357c478bd9Sstevel@tonic-gate 
9367c478bd9Sstevel@tonic-gate 	/*
9377c478bd9Sstevel@tonic-gate 	 * Destroy all mutexes and data structures allocated during
9387c478bd9Sstevel@tonic-gate 	 * attach time.
9397c478bd9Sstevel@tonic-gate 	 */
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate 	if (erip->globregh)
9427c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&erip->globregh);
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 	erip->etxregh =		NULL;
9457c478bd9Sstevel@tonic-gate 	erip->erxregh =		NULL;
9467c478bd9Sstevel@tonic-gate 	erip->bmacregh =	NULL;
9477c478bd9Sstevel@tonic-gate 	erip->mifregh =		NULL;
9487c478bd9Sstevel@tonic-gate 	erip->globregh =	NULL;
9497c478bd9Sstevel@tonic-gate 
9507c478bd9Sstevel@tonic-gate 	if (erip->sw_reset_regh)
9517c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&erip->sw_reset_regh);
9527c478bd9Sstevel@tonic-gate 
9537c478bd9Sstevel@tonic-gate 	if (erip->ksp)
9547c478bd9Sstevel@tonic-gate 		kstat_delete(erip->ksp);
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 	eri_stop_timer(erip); /* acquire linklock */
9577c478bd9Sstevel@tonic-gate 	eri_start_timer(erip, eri_check_link, 0);
9587c478bd9Sstevel@tonic-gate 	mutex_destroy(&erip->xmitlock);
9597c478bd9Sstevel@tonic-gate 	mutex_destroy(&erip->intrlock);
9607c478bd9Sstevel@tonic-gate 	mutex_destroy(&erip->linklock);
9617c478bd9Sstevel@tonic-gate 	mutex_destroy(&erip->xcvrlock);
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 	if (erip->md_h) {
9647c478bd9Sstevel@tonic-gate 		if (ddi_dma_unbind_handle(erip->md_h) ==
9657c478bd9Sstevel@tonic-gate 		    DDI_FAILURE)
9667c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
9677c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&erip->mdm_h);
9687c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&erip->md_h);
9697c478bd9Sstevel@tonic-gate 	}
9707c478bd9Sstevel@tonic-gate 
9717c478bd9Sstevel@tonic-gate 	if (eri_freebufs(erip))
9727c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 	/* dvma handle case */
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	if (erip->eri_dvmarh) {
9777c478bd9Sstevel@tonic-gate 		(void) dvma_release(erip->eri_dvmarh);
9787c478bd9Sstevel@tonic-gate 		erip->eri_dvmarh = NULL;
9797c478bd9Sstevel@tonic-gate 	}
9807c478bd9Sstevel@tonic-gate /*
9817c478bd9Sstevel@tonic-gate  *	xmit_dma_mode, erip->ndmaxh[i]=NULL for dvma
9827c478bd9Sstevel@tonic-gate  */
9837c478bd9Sstevel@tonic-gate 	else {
9847c478bd9Sstevel@tonic-gate 		for (i = 0; i < ERI_RPENDING; i++)
9857c478bd9Sstevel@tonic-gate 			if (erip->ndmarh[i])
9867c478bd9Sstevel@tonic-gate 				ddi_dma_free_handle(&erip->ndmarh[i]);
9877c478bd9Sstevel@tonic-gate 	}
9887c478bd9Sstevel@tonic-gate /*
989bd78278bSGarrett D'Amore  *	Release TX buffer
9907c478bd9Sstevel@tonic-gate  */
9917c478bd9Sstevel@tonic-gate 	if (erip->tbuf_ioaddr != 0) {
9927c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(erip->tbuf_handle);
9937c478bd9Sstevel@tonic-gate 		erip->tbuf_ioaddr = 0;
9947c478bd9Sstevel@tonic-gate 	}
9957c478bd9Sstevel@tonic-gate 	if (erip->tbuf_kaddr != NULL) {
996bd78278bSGarrett D'Amore 		ddi_dma_mem_free(&erip->tbuf_acch);
9977c478bd9Sstevel@tonic-gate 		erip->tbuf_kaddr = NULL;
9987c478bd9Sstevel@tonic-gate 	}
9997c478bd9Sstevel@tonic-gate 	if (erip->tbuf_handle != NULL) {
10007c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&erip->tbuf_handle);
10017c478bd9Sstevel@tonic-gate 		erip->tbuf_handle = NULL;
10027c478bd9Sstevel@tonic-gate 	}
10037c478bd9Sstevel@tonic-gate 
10047c478bd9Sstevel@tonic-gate 	eri_param_cleanup(erip);
10057c478bd9Sstevel@tonic-gate 
10067c478bd9Sstevel@tonic-gate 	ddi_set_driver_private(dip, NULL);
10077c478bd9Sstevel@tonic-gate 	kmem_free((caddr_t)erip, sizeof (struct eri));
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
10107c478bd9Sstevel@tonic-gate }
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate /*
10137c478bd9Sstevel@tonic-gate  * To set up the mac address for the network interface:
10147c478bd9Sstevel@tonic-gate  * The adapter card may support a local mac address which is published
10157c478bd9Sstevel@tonic-gate  * in a device node property "local-mac-address". This mac address is
10167c478bd9Sstevel@tonic-gate  * treated as the factory-installed mac address for DLPI interface.
10177c478bd9Sstevel@tonic-gate  * If the adapter firmware has used the device for diskless boot
10187c478bd9Sstevel@tonic-gate  * operation it publishes a property called "mac-address" for use by
10197c478bd9Sstevel@tonic-gate  * inetboot and the device driver.
10207c478bd9Sstevel@tonic-gate  * If "mac-address" is not found, the system options property
10217c478bd9Sstevel@tonic-gate  * "local-mac-address" is used to select the mac-address. If this option
10227c478bd9Sstevel@tonic-gate  * is set to "true", and "local-mac-address" has been found, then
10237c478bd9Sstevel@tonic-gate  * local-mac-address is used; otherwise the system mac address is used
10247c478bd9Sstevel@tonic-gate  * by calling the "localetheraddr()" function.
10257c478bd9Sstevel@tonic-gate  */
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate static void
eri_setup_mac_address(struct eri * erip,dev_info_t * dip)10287c478bd9Sstevel@tonic-gate eri_setup_mac_address(struct eri *erip, dev_info_t *dip)
10297c478bd9Sstevel@tonic-gate {
1030d64540e3Sgd 	uchar_t			*prop;
1031d64540e3Sgd 	char			*uselocal;
1032d64540e3Sgd 	unsigned		prop_len;
1033d64540e3Sgd 	uint32_t		addrflags = 0;
1034d64540e3Sgd 	struct ether_addr	factaddr;
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	/*
10377c478bd9Sstevel@tonic-gate 	 * Check if it is an adapter with its own local mac address
10387c478bd9Sstevel@tonic-gate 	 * If it is present, save it as the "factory-address"
10397c478bd9Sstevel@tonic-gate 	 * for this adapter.
10407c478bd9Sstevel@tonic-gate 	 */
1041d64540e3Sgd 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1042d64540e3Sgd 	    "local-mac-address", &prop, &prop_len) == DDI_PROP_SUCCESS) {
10437c478bd9Sstevel@tonic-gate 		if (prop_len == ETHERADDRL) {
1044d64540e3Sgd 			addrflags = ERI_FACTADDR_PRESENT;
1045d64540e3Sgd 			bcopy(prop, &factaddr, ETHERADDRL);
10467c478bd9Sstevel@tonic-gate 			ERI_FAULT_MSG2(erip, SEVERITY_NONE, ERI_VERB_MSG,
1047d64540e3Sgd 			    lether_addr_msg, ether_sprintf(&factaddr));
10487c478bd9Sstevel@tonic-gate 		}
1049d64540e3Sgd 		ddi_prop_free(prop);
10507c478bd9Sstevel@tonic-gate 	}
10517c478bd9Sstevel@tonic-gate 	/*
10527c478bd9Sstevel@tonic-gate 	 * Check if the adapter has published "mac-address" property.
10537c478bd9Sstevel@tonic-gate 	 * If it is present, use it as the mac address for this device.
10547c478bd9Sstevel@tonic-gate 	 */
1055d64540e3Sgd 	if (ddi_prop_lookup_byte_array(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
1056d64540e3Sgd 	    "mac-address", &prop, &prop_len) == DDI_PROP_SUCCESS) {
10577c478bd9Sstevel@tonic-gate 		if (prop_len >= ETHERADDRL) {
1058d64540e3Sgd 			bcopy(prop, erip->ouraddr, ETHERADDRL);
10594c27844fSgd 			ddi_prop_free(prop);
10607c478bd9Sstevel@tonic-gate 			return;
10617c478bd9Sstevel@tonic-gate 		}
1062d64540e3Sgd 		ddi_prop_free(prop);
10637c478bd9Sstevel@tonic-gate 	}
10647c478bd9Sstevel@tonic-gate 
1065d64540e3Sgd 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, "local-mac-address?",
1066d64540e3Sgd 	    &uselocal) == DDI_PROP_SUCCESS) {
1067d64540e3Sgd 		if ((strcmp("true", uselocal) == 0) &&
1068d64540e3Sgd 		    (addrflags & ERI_FACTADDR_PRESENT)) {
1069d64540e3Sgd 			addrflags |= ERI_FACTADDR_USE;
1070d64540e3Sgd 			bcopy(&factaddr, erip->ouraddr, ETHERADDRL);
1071d64540e3Sgd 			ddi_prop_free(uselocal);
10727c478bd9Sstevel@tonic-gate 			ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
1073d64540e3Sgd 			    lmac_addr_msg);
10747c478bd9Sstevel@tonic-gate 			return;
10757c478bd9Sstevel@tonic-gate 		}
1076d64540e3Sgd 		ddi_prop_free(uselocal);
10777c478bd9Sstevel@tonic-gate 	}
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 	/*
10807c478bd9Sstevel@tonic-gate 	 * Get the system ethernet address.
10817c478bd9Sstevel@tonic-gate 	 */
1082d64540e3Sgd 	(void) localetheraddr(NULL, &factaddr);
1083d64540e3Sgd 	bcopy(&factaddr, erip->ouraddr, ETHERADDRL);
10847c478bd9Sstevel@tonic-gate }
10857c478bd9Sstevel@tonic-gate 
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate /*
10887c478bd9Sstevel@tonic-gate  * Calculate the bit in the multicast address filter that selects the given
10897c478bd9Sstevel@tonic-gate  * address.
10907c478bd9Sstevel@tonic-gate  * Note: For ERI, the last 8-bits are used.
10917c478bd9Sstevel@tonic-gate  */
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate static uint32_t
eri_ladrf_bit(const uint8_t * addr)1094d64540e3Sgd eri_ladrf_bit(const uint8_t *addr)
10957c478bd9Sstevel@tonic-gate {
10967c478bd9Sstevel@tonic-gate 	uint32_t crc;
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	CRC32(crc, addr, ETHERADDRL, -1U, crc32_table);
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	/*
11017c478bd9Sstevel@tonic-gate 	 * Just want the 8 most significant bits.
11027c478bd9Sstevel@tonic-gate 	 */
11037c478bd9Sstevel@tonic-gate 	return ((~crc) >> 24);
11047c478bd9Sstevel@tonic-gate }
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate static void
eri_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)1107d64540e3Sgd eri_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
11087c478bd9Sstevel@tonic-gate {
1109d64540e3Sgd 	struct	eri	*erip = arg;
1110d64540e3Sgd 	struct	iocblk	*iocp = (void *)mp->b_rptr;
1111d64540e3Sgd 	int	err;
11127c478bd9Sstevel@tonic-gate 
1113d64540e3Sgd 	ASSERT(erip != NULL);
11147c478bd9Sstevel@tonic-gate 
1115d64540e3Sgd 	/*
1116d64540e3Sgd 	 * Privilege checks.
1117d64540e3Sgd 	 */
1118d64540e3Sgd 	switch (iocp->ioc_cmd) {
1119d64540e3Sgd 	case ERI_SET_LOOP_MODE:
1120d64540e3Sgd 	case ERI_ND_SET:
1121d64540e3Sgd 		err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
1122d64540e3Sgd 		if (err != 0) {
1123d64540e3Sgd 			miocnak(wq, mp, 0, err);
1124d64540e3Sgd 			return;
1125d64540e3Sgd 		}
11267c478bd9Sstevel@tonic-gate 		break;
1127d64540e3Sgd 	default:
11287c478bd9Sstevel@tonic-gate 		break;
1129d64540e3Sgd 	}
11307c478bd9Sstevel@tonic-gate 
1131d64540e3Sgd 	switch (iocp->ioc_cmd) {
1132d64540e3Sgd 	case ERI_ND_GET:
1133d64540e3Sgd 	case ERI_ND_SET:
1134d64540e3Sgd 		eri_process_ndd_ioctl(erip, wq, mp, iocp->ioc_cmd);
11357c478bd9Sstevel@tonic-gate 		break;
11367c478bd9Sstevel@tonic-gate 
1137d64540e3Sgd 	case ERI_SET_LOOP_MODE:
1138d64540e3Sgd 	case ERI_GET_LOOP_MODE:
1139d64540e3Sgd 		/*
1140d64540e3Sgd 		 * XXX: Consider updating this to the new netlb ioctls.
1141d64540e3Sgd 		 */
1142d64540e3Sgd 		eri_loopback(erip, wq, mp);
11437c478bd9Sstevel@tonic-gate 		break;
11447c478bd9Sstevel@tonic-gate 
1145d64540e3Sgd 	default:
1146d64540e3Sgd 		miocnak(wq, mp, 0, EINVAL);
11477c478bd9Sstevel@tonic-gate 		break;
1148d64540e3Sgd 	}
11497c478bd9Sstevel@tonic-gate 
1150d64540e3Sgd 	ASSERT(!MUTEX_HELD(&erip->linklock));
1151d64540e3Sgd }
11527c478bd9Sstevel@tonic-gate 
1153d64540e3Sgd static void
eri_loopback(struct eri * erip,queue_t * wq,mblk_t * mp)1154d64540e3Sgd eri_loopback(struct eri *erip, queue_t *wq, mblk_t *mp)
1155d64540e3Sgd {
1156d64540e3Sgd 	struct	iocblk	*iocp = (void *)mp->b_rptr;
1157d64540e3Sgd 	loopback_t	*al;
11587c478bd9Sstevel@tonic-gate 
1159d64540e3Sgd 	if (mp->b_cont == NULL || MBLKL(mp->b_cont) < sizeof (loopback_t)) {
1160d64540e3Sgd 		miocnak(wq, mp, 0, EINVAL);
1161d64540e3Sgd 		return;
1162d64540e3Sgd 	}
11637c478bd9Sstevel@tonic-gate 
1164d64540e3Sgd 	al = (void *)mp->b_cont->b_rptr;
11657c478bd9Sstevel@tonic-gate 
1166d64540e3Sgd 	switch (iocp->ioc_cmd) {
1167d64540e3Sgd 	case ERI_SET_LOOP_MODE:
1168d64540e3Sgd 		switch (al->loopback) {
1169d64540e3Sgd 		case ERI_LOOPBACK_OFF:
1170d64540e3Sgd 			erip->flags &= (~ERI_MACLOOPBACK & ~ERI_SERLOOPBACK);
1171d64540e3Sgd 			/* force link status to go down */
1172d64540e3Sgd 			param_linkup = 0;
1173d64540e3Sgd 			erip->stats.link_up = LINK_STATE_DOWN;
1174d64540e3Sgd 			erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
1175d64540e3Sgd 			(void) eri_init(erip);
1176d64540e3Sgd 			break;
11777c478bd9Sstevel@tonic-gate 
1178d64540e3Sgd 		case ERI_MAC_LOOPBACK_ON:
1179d64540e3Sgd 			erip->flags |= ERI_MACLOOPBACK;
1180d64540e3Sgd 			erip->flags &= ~ERI_SERLOOPBACK;
1181d64540e3Sgd 			param_linkup = 0;
1182d64540e3Sgd 			erip->stats.link_up = LINK_STATE_DOWN;
1183d64540e3Sgd 			erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
1184d64540e3Sgd 			(void) eri_init(erip);
1185d64540e3Sgd 			break;
11867c478bd9Sstevel@tonic-gate 
1187d64540e3Sgd 		case ERI_PCS_LOOPBACK_ON:
1188d64540e3Sgd 			break;
1189d64540e3Sgd 
1190d64540e3Sgd 		case ERI_SER_LOOPBACK_ON:
1191d64540e3Sgd 			erip->flags |= ERI_SERLOOPBACK;
1192d64540e3Sgd 			erip->flags &= ~ERI_MACLOOPBACK;
1193d64540e3Sgd 			/* force link status to go down */
1194d64540e3Sgd 			param_linkup = 0;
1195d64540e3Sgd 			erip->stats.link_up = LINK_STATE_DOWN;
1196d64540e3Sgd 			erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
1197d64540e3Sgd 			(void) eri_init(erip);
1198d64540e3Sgd 			break;
11997c478bd9Sstevel@tonic-gate 
1200d64540e3Sgd 		default:
1201d64540e3Sgd 			ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
1202d64540e3Sgd 			    loopback_val_default);
1203d64540e3Sgd 			miocnak(wq, mp, 0, EINVAL);
1204d64540e3Sgd 			return;
1205d64540e3Sgd 		}
1206d64540e3Sgd 		miocnak(wq, mp, 0, 0);
12077c478bd9Sstevel@tonic-gate 		break;
12087c478bd9Sstevel@tonic-gate 
1209d64540e3Sgd 	case ERI_GET_LOOP_MODE:
1210d64540e3Sgd 		al->loopback =	ERI_MAC_LOOPBACK_ON | ERI_PCS_LOOPBACK_ON |
1211d64540e3Sgd 		    ERI_SER_LOOPBACK_ON;
1212d64540e3Sgd 		miocack(wq, mp, sizeof (loopback_t), 0);
12137c478bd9Sstevel@tonic-gate 		break;
12147c478bd9Sstevel@tonic-gate 
12157c478bd9Sstevel@tonic-gate 	default:
1216d64540e3Sgd 		ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
1217d64540e3Sgd 		    loopback_cmd_default);
12187c478bd9Sstevel@tonic-gate 	}
12197c478bd9Sstevel@tonic-gate }
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate static int
eri_m_promisc(void * arg,boolean_t on)1222d64540e3Sgd eri_m_promisc(void *arg, boolean_t on)
12237c478bd9Sstevel@tonic-gate {
1224d64540e3Sgd 	struct	eri	*erip = arg;
12257c478bd9Sstevel@tonic-gate 
1226d64540e3Sgd 	mutex_enter(&erip->intrlock);
1227d64540e3Sgd 	erip->promisc = on;
1228d64540e3Sgd 	eri_init_rx(erip);
1229d64540e3Sgd 	mutex_exit(&erip->intrlock);
1230d64540e3Sgd 	return (0);
1231d64540e3Sgd }
12327c478bd9Sstevel@tonic-gate 
1233d64540e3Sgd /*
1234d64540e3Sgd  * This is to support unlimited number of members
1235d64540e3Sgd  * in Multicast.
1236d64540e3Sgd  */
1237d64540e3Sgd static int
eri_m_multicst(void * arg,boolean_t add,const uint8_t * mca)1238d64540e3Sgd eri_m_multicst(void *arg, boolean_t add, const uint8_t *mca)
1239d64540e3Sgd {
1240d64540e3Sgd 	struct eri		*erip = arg;
1241*7e996435SToomas Soome 	uint32_t		ladrf_bit;
12427c478bd9Sstevel@tonic-gate 
12437c478bd9Sstevel@tonic-gate 	/*
1244d64540e3Sgd 	 * If this address's bit was not already set in the local address
1245d64540e3Sgd 	 * filter, add it and re-initialize the Hardware.
12467c478bd9Sstevel@tonic-gate 	 */
1247d64540e3Sgd 	ladrf_bit = eri_ladrf_bit(mca);
12487c478bd9Sstevel@tonic-gate 
1249d64540e3Sgd 	mutex_enter(&erip->intrlock);
1250d64540e3Sgd 	if (add) {
1251d64540e3Sgd 		erip->ladrf_refcnt[ladrf_bit]++;
1252d64540e3Sgd 		if (erip->ladrf_refcnt[ladrf_bit] == 1) {
1253d64540e3Sgd 			LADRF_SET(erip, ladrf_bit);
1254d64540e3Sgd 			erip->multi_refcnt++;
1255d64540e3Sgd 			eri_init_rx(erip);
1256d64540e3Sgd 		}
1257d64540e3Sgd 	} else {
1258d64540e3Sgd 		erip->ladrf_refcnt[ladrf_bit]--;
1259d64540e3Sgd 		if (erip->ladrf_refcnt[ladrf_bit] == 0) {
1260d64540e3Sgd 			LADRF_CLR(erip, ladrf_bit);
1261d64540e3Sgd 			erip->multi_refcnt--;
12627c478bd9Sstevel@tonic-gate 			eri_init_rx(erip);
12637c478bd9Sstevel@tonic-gate 		}
12647c478bd9Sstevel@tonic-gate 	}
1265d64540e3Sgd 	mutex_exit(&erip->intrlock);
1266d64540e3Sgd 	return (0);
1267d64540e3Sgd }
1268d64540e3Sgd 
1269d64540e3Sgd static int
eri_m_unicst(void * arg,const uint8_t * macaddr)1270d64540e3Sgd eri_m_unicst(void *arg, const uint8_t *macaddr)
1271d64540e3Sgd {
1272d64540e3Sgd 	struct	eri	*erip = arg;
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 	/*
12757c478bd9Sstevel@tonic-gate 	 * Set new interface local address and re-init device.
12767c478bd9Sstevel@tonic-gate 	 * This is destructive to any other streams attached
12777c478bd9Sstevel@tonic-gate 	 * to this device.
12787c478bd9Sstevel@tonic-gate 	 */
12797c478bd9Sstevel@tonic-gate 	mutex_enter(&erip->intrlock);
1280d64540e3Sgd 	bcopy(macaddr, &erip->ouraddr, ETHERADDRL);
1281d64540e3Sgd 	eri_init_rx(erip);
12827c478bd9Sstevel@tonic-gate 	mutex_exit(&erip->intrlock);
1283d64540e3Sgd 	return (0);
12847c478bd9Sstevel@tonic-gate }
12857c478bd9Sstevel@tonic-gate 
1286d64540e3Sgd /*ARGSUSED*/
1287d64540e3Sgd static boolean_t
eri_m_getcapab(void * arg,mac_capab_t cap,void * cap_data)1288d64540e3Sgd eri_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
12897c478bd9Sstevel@tonic-gate {
1290d64540e3Sgd 	switch (cap) {
1291d64540e3Sgd 	case MAC_CAPAB_HCKSUM: {
1292d64540e3Sgd 		uint32_t *hcksum_txflags = cap_data;
1293d64540e3Sgd 		*hcksum_txflags = HCKSUM_INET_PARTIAL;
1294d64540e3Sgd 		return (B_TRUE);
12957c478bd9Sstevel@tonic-gate 	}
1296d64540e3Sgd 	default:
1297d64540e3Sgd 		return (B_FALSE);
12987c478bd9Sstevel@tonic-gate 	}
12997c478bd9Sstevel@tonic-gate }
13007c478bd9Sstevel@tonic-gate 
1301d64540e3Sgd static int
eri_m_start(void * arg)1302d64540e3Sgd eri_m_start(void *arg)
13037c478bd9Sstevel@tonic-gate {
1304d64540e3Sgd 	struct eri	*erip = arg;
13057c478bd9Sstevel@tonic-gate 
1306d64540e3Sgd 	mutex_enter(&erip->intrlock);
1307d64540e3Sgd 	erip->flags |= ERI_STARTED;
1308d64540e3Sgd 	mutex_exit(&erip->intrlock);
13097c478bd9Sstevel@tonic-gate 
1310d64540e3Sgd 	if (!eri_init(erip)) {
1311d64540e3Sgd 		mutex_enter(&erip->intrlock);
1312d64540e3Sgd 		erip->flags &= ~ERI_STARTED;
1313d64540e3Sgd 		mutex_exit(&erip->intrlock);
1314d64540e3Sgd 		return (EIO);
13157c478bd9Sstevel@tonic-gate 	}
1316d64540e3Sgd 	return (0);
13177c478bd9Sstevel@tonic-gate }
13187c478bd9Sstevel@tonic-gate 
13197c478bd9Sstevel@tonic-gate static void
eri_m_stop(void * arg)1320d64540e3Sgd eri_m_stop(void *arg)
13217c478bd9Sstevel@tonic-gate {
1322d64540e3Sgd 	struct eri	*erip = arg;
13237c478bd9Sstevel@tonic-gate 
1324d64540e3Sgd 	mutex_enter(&erip->intrlock);
1325d64540e3Sgd 	erip->flags &= ~ERI_STARTED;
1326d64540e3Sgd 	mutex_exit(&erip->intrlock);
1327d64540e3Sgd 	eri_uninit(erip);
13287c478bd9Sstevel@tonic-gate }
13297c478bd9Sstevel@tonic-gate 
1330d64540e3Sgd static int
eri_m_stat(void * arg,uint_t stat,uint64_t * val)1331d64540e3Sgd eri_m_stat(void *arg, uint_t stat, uint64_t *val)
1332860c4cd4Scarlsonj {
1333d64540e3Sgd 	struct eri	*erip = arg;
1334d64540e3Sgd 	struct stats	*esp;
1335d64540e3Sgd 	boolean_t	macupdate = B_FALSE;
1336860c4cd4Scarlsonj 
1337d64540e3Sgd 	esp = &erip->stats;
1338d64540e3Sgd 
1339d64540e3Sgd 	mutex_enter(&erip->xmitlock);
1340d64540e3Sgd 	if ((erip->flags & ERI_RUNNING) && (erip->flags & ERI_TXINIT)) {
1341d64540e3Sgd 		erip->tx_completion =
1342d64540e3Sgd 		    GET_ETXREG(tx_completion) & ETX_COMPLETION_MASK;
1343d64540e3Sgd 		macupdate |= eri_reclaim(erip, erip->tx_completion);
13447c478bd9Sstevel@tonic-gate 	}
1345d64540e3Sgd 	mutex_exit(&erip->xmitlock);
1346d64540e3Sgd 	if (macupdate)
1347d64540e3Sgd 		mac_tx_update(erip->mh);
13487c478bd9Sstevel@tonic-gate 
1349d64540e3Sgd 	eri_savecntrs(erip);
13507c478bd9Sstevel@tonic-gate 
1351d64540e3Sgd 	switch (stat) {
1352d64540e3Sgd 	case MAC_STAT_IFSPEED:
1353d64540e3Sgd 		*val = esp->ifspeed * 1000000ULL;
1354d64540e3Sgd 		break;
1355d64540e3Sgd 	case MAC_STAT_MULTIRCV:
1356d64540e3Sgd 		*val = esp->multircv;
1357d64540e3Sgd 		break;
1358d64540e3Sgd 	case MAC_STAT_BRDCSTRCV:
1359d64540e3Sgd 		*val = esp->brdcstrcv;
1360d64540e3Sgd 		break;
1361d64540e3Sgd 	case MAC_STAT_IPACKETS:
1362d64540e3Sgd 		*val = esp->ipackets64;
1363d64540e3Sgd 		break;
1364d64540e3Sgd 	case MAC_STAT_RBYTES:
1365d64540e3Sgd 		*val = esp->rbytes64;
1366d64540e3Sgd 		break;
1367d64540e3Sgd 	case MAC_STAT_OBYTES:
1368d64540e3Sgd 		*val = esp->obytes64;
1369d64540e3Sgd 		break;
1370d64540e3Sgd 	case MAC_STAT_OPACKETS:
1371d64540e3Sgd 		*val = esp->opackets64;
1372d64540e3Sgd 		break;
1373d64540e3Sgd 	case MAC_STAT_IERRORS:
1374d64540e3Sgd 		*val = esp->ierrors;
1375d64540e3Sgd 		break;
1376d64540e3Sgd 	case MAC_STAT_OERRORS:
1377d64540e3Sgd 		*val = esp->oerrors;
1378d64540e3Sgd 		break;
1379d64540e3Sgd 	case MAC_STAT_MULTIXMT:
1380d64540e3Sgd 		*val = esp->multixmt;
1381d64540e3Sgd 		break;
1382d64540e3Sgd 	case MAC_STAT_BRDCSTXMT:
1383d64540e3Sgd 		*val = esp->brdcstxmt;
1384d64540e3Sgd 		break;
1385d64540e3Sgd 	case MAC_STAT_NORCVBUF:
1386d64540e3Sgd 		*val = esp->norcvbuf;
1387d64540e3Sgd 		break;
1388d64540e3Sgd 	case MAC_STAT_NOXMTBUF:
1389d64540e3Sgd 		*val = esp->noxmtbuf;
1390d64540e3Sgd 		break;
1391d64540e3Sgd 	case MAC_STAT_UNDERFLOWS:
1392d64540e3Sgd 		*val = esp->txmac_urun;
1393d64540e3Sgd 		break;
1394d64540e3Sgd 	case MAC_STAT_OVERFLOWS:
1395d64540e3Sgd 		*val = esp->rx_overflow;
1396d64540e3Sgd 		break;
1397d64540e3Sgd 	case MAC_STAT_COLLISIONS:
1398d64540e3Sgd 		*val = esp->collisions;
1399d64540e3Sgd 		break;
1400d64540e3Sgd 	case ETHER_STAT_ALIGN_ERRORS:
1401d64540e3Sgd 		*val = esp->rx_align_err;
1402d64540e3Sgd 		break;
1403d64540e3Sgd 	case ETHER_STAT_FCS_ERRORS:
1404d64540e3Sgd 		*val = esp->rx_crc_err;
1405d64540e3Sgd 		break;
1406d64540e3Sgd 	case ETHER_STAT_EX_COLLISIONS:
1407d64540e3Sgd 		*val = esp->excessive_coll;
1408d64540e3Sgd 		break;
1409d64540e3Sgd 	case ETHER_STAT_TX_LATE_COLLISIONS:
1410d64540e3Sgd 		*val = esp->late_coll;
1411d64540e3Sgd 		break;
1412d64540e3Sgd 	case ETHER_STAT_FIRST_COLLISIONS:
1413d64540e3Sgd 		*val = esp->first_coll;
1414d64540e3Sgd 		break;
1415d64540e3Sgd 	case ETHER_STAT_LINK_DUPLEX:
1416d64540e3Sgd 		*val = esp->link_duplex;
1417d64540e3Sgd 		break;
1418d64540e3Sgd 	case ETHER_STAT_TOOLONG_ERRORS:
1419d64540e3Sgd 		*val = esp->rx_toolong_pkts;
1420d64540e3Sgd 		break;
1421d64540e3Sgd 	case ETHER_STAT_TOOSHORT_ERRORS:
1422d64540e3Sgd 		*val = esp->rx_runt;
1423d64540e3Sgd 		break;
14247c478bd9Sstevel@tonic-gate 
1425d64540e3Sgd 	case ETHER_STAT_XCVR_ADDR:
1426d64540e3Sgd 		*val = erip->phyad;
1427d64540e3Sgd 		break;
1428d64540e3Sgd 
1429d64540e3Sgd 	case ETHER_STAT_XCVR_INUSE:
1430d64540e3Sgd 		*val = XCVR_100X;	/* should always be 100X for now */
1431d64540e3Sgd 		break;
14327c478bd9Sstevel@tonic-gate 
1433d64540e3Sgd 	case ETHER_STAT_CAP_100FDX:
1434d64540e3Sgd 		*val = param_bmsr_100fdx;
1435d64540e3Sgd 		break;
1436d64540e3Sgd 	case ETHER_STAT_CAP_100HDX:
1437d64540e3Sgd 		*val = param_bmsr_100hdx;
1438d64540e3Sgd 		break;
1439d64540e3Sgd 	case ETHER_STAT_CAP_10FDX:
1440d64540e3Sgd 		*val = param_bmsr_10fdx;
1441d64540e3Sgd 		break;
1442d64540e3Sgd 	case ETHER_STAT_CAP_10HDX:
1443d64540e3Sgd 		*val = param_bmsr_10hdx;
1444d64540e3Sgd 		break;
1445d64540e3Sgd 	case ETHER_STAT_CAP_AUTONEG:
1446d64540e3Sgd 		*val = param_bmsr_ancap;
1447d64540e3Sgd 		break;
1448d64540e3Sgd 	case ETHER_STAT_CAP_ASMPAUSE:
1449d64540e3Sgd 		*val = param_bmsr_asm_dir;
1450d64540e3Sgd 		break;
1451d64540e3Sgd 	case ETHER_STAT_CAP_PAUSE:
1452d64540e3Sgd 		*val = param_bmsr_pause;
1453d64540e3Sgd 		break;
1454d64540e3Sgd 	case ETHER_STAT_ADV_CAP_100FDX:
1455d64540e3Sgd 		*val = param_anar_100fdx;
1456d64540e3Sgd 		break;
1457d64540e3Sgd 	case ETHER_STAT_ADV_CAP_100HDX:
1458d64540e3Sgd 		*val = param_anar_100hdx;
1459d64540e3Sgd 		break;
1460d64540e3Sgd 	case ETHER_STAT_ADV_CAP_10FDX:
1461d64540e3Sgd 		*val = param_anar_10fdx;
1462d64540e3Sgd 		break;
1463d64540e3Sgd 	case ETHER_STAT_ADV_CAP_10HDX:
1464d64540e3Sgd 		*val = param_anar_10hdx;
1465d64540e3Sgd 		break;
1466d64540e3Sgd 	case ETHER_STAT_ADV_CAP_AUTONEG:
1467d64540e3Sgd 		*val = param_autoneg;
1468d64540e3Sgd 		break;
1469d64540e3Sgd 	case ETHER_STAT_ADV_CAP_ASMPAUSE:
1470d64540e3Sgd 		*val = param_anar_asm_dir;
1471d64540e3Sgd 		break;
1472d64540e3Sgd 	case ETHER_STAT_ADV_CAP_PAUSE:
1473d64540e3Sgd 		*val = param_anar_pause;
1474d64540e3Sgd 		break;
1475d64540e3Sgd 	case ETHER_STAT_LP_CAP_100FDX:
1476d64540e3Sgd 		*val = param_anlpar_100fdx;
1477d64540e3Sgd 		break;
1478d64540e3Sgd 	case ETHER_STAT_LP_CAP_100HDX:
1479d64540e3Sgd 		*val = param_anlpar_100hdx;
1480d64540e3Sgd 		break;
1481d64540e3Sgd 	case ETHER_STAT_LP_CAP_10FDX:
1482d64540e3Sgd 		*val = param_anlpar_10fdx;
1483d64540e3Sgd 		break;
1484d64540e3Sgd 	case ETHER_STAT_LP_CAP_10HDX:
1485d64540e3Sgd 		*val = param_anlpar_10hdx;
1486d64540e3Sgd 		break;
1487d64540e3Sgd 	case ETHER_STAT_LP_CAP_AUTONEG:
1488d64540e3Sgd 		*val = param_aner_lpancap;
1489d64540e3Sgd 		break;
1490d64540e3Sgd 	case ETHER_STAT_LP_CAP_ASMPAUSE:
1491d64540e3Sgd 		*val = param_anlpar_pauseTX;
1492d64540e3Sgd 		break;
1493d64540e3Sgd 	case ETHER_STAT_LP_CAP_PAUSE:
1494d64540e3Sgd 		*val = param_anlpar_pauseRX;
1495d64540e3Sgd 		break;
1496d64540e3Sgd 	case ETHER_STAT_LINK_PAUSE:
1497d64540e3Sgd 		*val = esp->pausing;
1498d64540e3Sgd 		break;
1499d64540e3Sgd 	case ETHER_STAT_LINK_ASMPAUSE:
1500d64540e3Sgd 		*val = param_anar_asm_dir &&
1501d64540e3Sgd 		    param_anlpar_pauseTX &&
1502d64540e3Sgd 		    (param_anar_pause != param_anlpar_pauseRX);
1503d64540e3Sgd 		break;
1504d64540e3Sgd 	case ETHER_STAT_LINK_AUTONEG:
1505d64540e3Sgd 		*val = param_autoneg && param_aner_lpancap;
1506d64540e3Sgd 		break;
1507d64540e3Sgd 	}
1508d64540e3Sgd 	return (0);
1509d64540e3Sgd }
15107c478bd9Sstevel@tonic-gate 
15117c478bd9Sstevel@tonic-gate /*
15127c478bd9Sstevel@tonic-gate  * Hardware Functions
15137c478bd9Sstevel@tonic-gate  * New Section
15147c478bd9Sstevel@tonic-gate  */
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate /*
15177c478bd9Sstevel@tonic-gate  * Initialize the MAC registers. Some of of the MAC  registers are initialized
15187c478bd9Sstevel@tonic-gate  * just once since  Global Reset or MAC reset doesn't clear them. Others (like
15197c478bd9Sstevel@tonic-gate  * Host MAC Address Registers) are cleared on every reset and have to be
15207c478bd9Sstevel@tonic-gate  * reinitialized.
15217c478bd9Sstevel@tonic-gate  */
15227c478bd9Sstevel@tonic-gate static void
eri_init_macregs_generic(struct eri * erip)15237c478bd9Sstevel@tonic-gate eri_init_macregs_generic(struct eri *erip)
15247c478bd9Sstevel@tonic-gate {
15257c478bd9Sstevel@tonic-gate 	/*
15267c478bd9Sstevel@tonic-gate 	 * set up the MAC parameter registers once
15277c478bd9Sstevel@tonic-gate 	 * after power cycle. SUSPEND/RESUME also requires
15287c478bd9Sstevel@tonic-gate 	 * setting these registers.
15297c478bd9Sstevel@tonic-gate 	 */
15307c478bd9Sstevel@tonic-gate 	if ((erip->stats.inits == 1) || (erip->init_macregs)) {
15317c478bd9Sstevel@tonic-gate 		erip->init_macregs = 0;
15327c478bd9Sstevel@tonic-gate 		PUT_MACREG(ipg0, param_ipg0);
15337c478bd9Sstevel@tonic-gate 		PUT_MACREG(ipg1, param_ipg1);
15347c478bd9Sstevel@tonic-gate 		PUT_MACREG(ipg2, param_ipg2);
15357c478bd9Sstevel@tonic-gate 		PUT_MACREG(macmin, BMAC_MIN_FRAME_SIZE);
15367c478bd9Sstevel@tonic-gate #ifdef	ERI_RX_TAG_ERROR_WORKAROUND
15377c478bd9Sstevel@tonic-gate 		PUT_MACREG(macmax, BMAC_MAX_FRAME_SIZE_TAG | BMAC_MAX_BURST);
15387c478bd9Sstevel@tonic-gate #else
15397c478bd9Sstevel@tonic-gate 		PUT_MACREG(macmax, BMAC_MAX_FRAME_SIZE | BMAC_MAX_BURST);
15407c478bd9Sstevel@tonic-gate #endif
15417c478bd9Sstevel@tonic-gate 		PUT_MACREG(palen, BMAC_PREAMBLE_SIZE);
15427c478bd9Sstevel@tonic-gate 		PUT_MACREG(jam, BMAC_JAM_SIZE);
15437c478bd9Sstevel@tonic-gate 		PUT_MACREG(alimit, BMAC_ATTEMPT_LIMIT);
15447c478bd9Sstevel@tonic-gate 		PUT_MACREG(macctl_type, BMAC_CONTROL_TYPE);
15457c478bd9Sstevel@tonic-gate 		PUT_MACREG(rseed,
1546d64540e3Sgd 		    ((erip->ouraddr[0] & 0x3) << 8) | erip->ouraddr[1]);
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 		PUT_MACREG(madd3, BMAC_ADDRESS_3);
15497c478bd9Sstevel@tonic-gate 		PUT_MACREG(madd4, BMAC_ADDRESS_4);
15507c478bd9Sstevel@tonic-gate 		PUT_MACREG(madd5, BMAC_ADDRESS_5);
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate 		/* Program MAC Control address */
15537c478bd9Sstevel@tonic-gate 		PUT_MACREG(madd6, BMAC_ADDRESS_6);
15547c478bd9Sstevel@tonic-gate 		PUT_MACREG(madd7, BMAC_ADDRESS_7);
15557c478bd9Sstevel@tonic-gate 		PUT_MACREG(madd8, BMAC_ADDRESS_8);
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate 		PUT_MACREG(afr0, BMAC_AF_0);
15587c478bd9Sstevel@tonic-gate 		PUT_MACREG(afr1, BMAC_AF_1);
15597c478bd9Sstevel@tonic-gate 		PUT_MACREG(afr2, BMAC_AF_2);
15607c478bd9Sstevel@tonic-gate 		PUT_MACREG(afmr1_2, BMAC_AF21_MASK);
15617c478bd9Sstevel@tonic-gate 		PUT_MACREG(afmr0, BMAC_AF0_MASK);
15627c478bd9Sstevel@tonic-gate 	}
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate 	/* The counters need to be zeroed */
15657c478bd9Sstevel@tonic-gate 	PUT_MACREG(nccnt, 0);
15667c478bd9Sstevel@tonic-gate 	PUT_MACREG(fccnt, 0);
15677c478bd9Sstevel@tonic-gate 	PUT_MACREG(excnt, 0);
15687c478bd9Sstevel@tonic-gate 	PUT_MACREG(ltcnt, 0);
15697c478bd9Sstevel@tonic-gate 	PUT_MACREG(dcnt,  0);
15707c478bd9Sstevel@tonic-gate 	PUT_MACREG(frcnt, 0);
15717c478bd9Sstevel@tonic-gate 	PUT_MACREG(lecnt, 0);
15727c478bd9Sstevel@tonic-gate 	PUT_MACREG(aecnt, 0);
15737c478bd9Sstevel@tonic-gate 	PUT_MACREG(fecnt, 0);
15747c478bd9Sstevel@tonic-gate 	PUT_MACREG(rxcv,  0);
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate 	if (erip->pauseTX)
15777c478bd9Sstevel@tonic-gate 		PUT_MACREG(spcmd, BMAC_SEND_PAUSE_CMD);
15787c478bd9Sstevel@tonic-gate 	else
15797c478bd9Sstevel@tonic-gate 		PUT_MACREG(spcmd, 0);
1580fd8be74fSgd 
1581fd8be74fSgd 	/*
1582fd8be74fSgd 	 * Program BigMAC with local individual ethernet address.
1583fd8be74fSgd 	 */
1584fd8be74fSgd 
1585fd8be74fSgd 	PUT_MACREG(madd0, (erip->ouraddr[4] << 8) | erip->ouraddr[5]);
1586fd8be74fSgd 	PUT_MACREG(madd1, (erip->ouraddr[2] << 8) | erip->ouraddr[3]);
1587fd8be74fSgd 	PUT_MACREG(madd2, (erip->ouraddr[0] << 8) | erip->ouraddr[1]);
1588fd8be74fSgd 
1589fd8be74fSgd 	/*
1590fd8be74fSgd 	 * Install multicast address filter.
1591fd8be74fSgd 	 */
1592fd8be74fSgd 
1593fd8be74fSgd 	PUT_MACREG(hash0, erip->ladrf[0]);
1594fd8be74fSgd 	PUT_MACREG(hash1, erip->ladrf[1]);
1595fd8be74fSgd 	PUT_MACREG(hash2, erip->ladrf[2]);
1596fd8be74fSgd 	PUT_MACREG(hash3, erip->ladrf[3]);
1597fd8be74fSgd 	PUT_MACREG(hash4, erip->ladrf[4]);
1598fd8be74fSgd 	PUT_MACREG(hash5, erip->ladrf[5]);
1599fd8be74fSgd 	PUT_MACREG(hash6, erip->ladrf[6]);
1600fd8be74fSgd 	PUT_MACREG(hash7, erip->ladrf[7]);
1601fd8be74fSgd 	PUT_MACREG(hash8, erip->ladrf[8]);
1602fd8be74fSgd 	PUT_MACREG(hash9, erip->ladrf[9]);
1603fd8be74fSgd 	PUT_MACREG(hash10, erip->ladrf[10]);
1604fd8be74fSgd 	PUT_MACREG(hash11, erip->ladrf[11]);
1605fd8be74fSgd 	PUT_MACREG(hash12, erip->ladrf[12]);
1606fd8be74fSgd 	PUT_MACREG(hash13, erip->ladrf[13]);
1607fd8be74fSgd 	PUT_MACREG(hash14, erip->ladrf[14]);
16087c478bd9Sstevel@tonic-gate }
16097c478bd9Sstevel@tonic-gate 
16107c478bd9Sstevel@tonic-gate static int
eri_flush_rxbufs(struct eri * erip)16117c478bd9Sstevel@tonic-gate eri_flush_rxbufs(struct eri *erip)
16127c478bd9Sstevel@tonic-gate {
16137c478bd9Sstevel@tonic-gate 	uint_t	i;
16147c478bd9Sstevel@tonic-gate 	int	status = 0;
16157c478bd9Sstevel@tonic-gate 	/*
16167c478bd9Sstevel@tonic-gate 	 * Free and dvma_unload pending recv buffers.
16177c478bd9Sstevel@tonic-gate 	 * Maintaining the 1-to-1 ordered sequence of
16187c478bd9Sstevel@tonic-gate 	 * dvma_load() followed by dvma_unload() is critical.
16197c478bd9Sstevel@tonic-gate 	 * Always unload anything before loading it again.
16207c478bd9Sstevel@tonic-gate 	 * Never unload anything twice.  Always unload
16217c478bd9Sstevel@tonic-gate 	 * before freeing the buffer.  We satisfy these
16227c478bd9Sstevel@tonic-gate 	 * requirements by unloading only those descriptors
16237c478bd9Sstevel@tonic-gate 	 * which currently have an mblk associated with them.
16247c478bd9Sstevel@tonic-gate 	 */
16257c478bd9Sstevel@tonic-gate 	for (i = 0; i < ERI_RPENDING; i++) {
16267c478bd9Sstevel@tonic-gate 		if (erip->rmblkp[i]) {
16277c478bd9Sstevel@tonic-gate 			if (erip->eri_dvmarh)
16287c478bd9Sstevel@tonic-gate 				dvma_unload(erip->eri_dvmarh, 2 * i,
1629d64540e3Sgd 				    DDI_DMA_SYNC_FORCPU);
16307c478bd9Sstevel@tonic-gate 			else if ((ddi_dma_unbind_handle(erip->ndmarh[i]) ==
16317c478bd9Sstevel@tonic-gate 			    DDI_FAILURE))
16327c478bd9Sstevel@tonic-gate 				status = -1;
16337c478bd9Sstevel@tonic-gate 			freeb(erip->rmblkp[i]);
16347c478bd9Sstevel@tonic-gate 			erip->rmblkp[i] = NULL;
16357c478bd9Sstevel@tonic-gate 		}
16367c478bd9Sstevel@tonic-gate 	}
16377c478bd9Sstevel@tonic-gate 	return (status);
16387c478bd9Sstevel@tonic-gate }
16397c478bd9Sstevel@tonic-gate 
16407c478bd9Sstevel@tonic-gate static void
eri_init_txbufs(struct eri * erip)16417c478bd9Sstevel@tonic-gate eri_init_txbufs(struct eri *erip)
16427c478bd9Sstevel@tonic-gate {
16437c478bd9Sstevel@tonic-gate 	/*
16447c478bd9Sstevel@tonic-gate 	 * Clear TX descriptors.
16457c478bd9Sstevel@tonic-gate 	 */
16467c478bd9Sstevel@tonic-gate 	bzero((caddr_t)erip->eri_tmdp, ERI_TPENDING * sizeof (struct eri_tmd));
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate 	/*
16497c478bd9Sstevel@tonic-gate 	 * sync TXDMA descriptors.
16507c478bd9Sstevel@tonic-gate 	 */
16517c478bd9Sstevel@tonic-gate 	ERI_SYNCIOPB(erip, erip->eri_tmdp,
16527c478bd9Sstevel@tonic-gate 	    (ERI_TPENDING * sizeof (struct eri_tmd)), DDI_DMA_SYNC_FORDEV);
16537c478bd9Sstevel@tonic-gate 	/*
16547c478bd9Sstevel@tonic-gate 	 * Reset TMD 'walking' pointers.
16557c478bd9Sstevel@tonic-gate 	 */
16567c478bd9Sstevel@tonic-gate 	erip->tcurp = erip->eri_tmdp;
16577c478bd9Sstevel@tonic-gate 	erip->tnextp = erip->eri_tmdp;
16587c478bd9Sstevel@tonic-gate 	erip->tx_cur_cnt = 0;
16597c478bd9Sstevel@tonic-gate 	erip->tx_kick = 0;
16607c478bd9Sstevel@tonic-gate 	erip->tx_completion = 0;
16617c478bd9Sstevel@tonic-gate }
16627c478bd9Sstevel@tonic-gate 
16637c478bd9Sstevel@tonic-gate static int
eri_init_rxbufs(struct eri * erip)16647c478bd9Sstevel@tonic-gate eri_init_rxbufs(struct eri *erip)
16657c478bd9Sstevel@tonic-gate {
16667c478bd9Sstevel@tonic-gate 
16677c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t	dma_cookie;
16687c478bd9Sstevel@tonic-gate 	mblk_t			*bp;
16697c478bd9Sstevel@tonic-gate 	int			i, status = 0;
16707c478bd9Sstevel@tonic-gate 	uint32_t		ccnt;
16717c478bd9Sstevel@tonic-gate 
16727c478bd9Sstevel@tonic-gate 	/*
16737c478bd9Sstevel@tonic-gate 	 * clear rcv descriptors
16747c478bd9Sstevel@tonic-gate 	 */
16757c478bd9Sstevel@tonic-gate 	bzero((caddr_t)erip->rmdp, ERI_RPENDING * sizeof (struct rmd));
16767c478bd9Sstevel@tonic-gate 
16777c478bd9Sstevel@tonic-gate 	for (i = 0; i < ERI_RPENDING; i++) {
16787c478bd9Sstevel@tonic-gate 		if ((bp = eri_allocb(ERI_BUFSIZE)) == NULL) {
16797c478bd9Sstevel@tonic-gate 			status = -1;
16807c478bd9Sstevel@tonic-gate 			continue;
16817c478bd9Sstevel@tonic-gate 		}
16827c478bd9Sstevel@tonic-gate 		/* Load data buffer to DVMA space */
16837c478bd9Sstevel@tonic-gate 		if (erip->eri_dvmarh)
1684d64540e3Sgd 			dvma_kaddr_load(erip->eri_dvmarh,
1685d64540e3Sgd 			    (caddr_t)bp->b_rptr, ERI_BUFSIZE,
1686d64540e3Sgd 			    2 * i, &dma_cookie);
16877c478bd9Sstevel@tonic-gate /*
16887c478bd9Sstevel@tonic-gate  *		Bind data buffer to DMA handle
16897c478bd9Sstevel@tonic-gate  */
16907c478bd9Sstevel@tonic-gate 		else if (ddi_dma_addr_bind_handle(erip->ndmarh[i], NULL,
1691d64540e3Sgd 		    (caddr_t)bp->b_rptr, ERI_BUFSIZE,
1692d64540e3Sgd 		    DDI_DMA_READ | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, 0,
1693d64540e3Sgd 		    &dma_cookie, &ccnt) != DDI_DMA_MAPPED)
1694d64540e3Sgd 			status = -1;
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate 		PUT_RMD((&erip->rmdp[i]), dma_cookie);
16977c478bd9Sstevel@tonic-gate 		erip->rmblkp[i] = bp;	/* save for later use */
16987c478bd9Sstevel@tonic-gate 	}
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate 	/*
17017c478bd9Sstevel@tonic-gate 	 * sync RXDMA descriptors.
17027c478bd9Sstevel@tonic-gate 	 */
1703d64540e3Sgd 	ERI_SYNCIOPB(erip, erip->rmdp, (ERI_RPENDING * sizeof (struct rmd)),
1704d64540e3Sgd 	    DDI_DMA_SYNC_FORDEV);
17057c478bd9Sstevel@tonic-gate 	/*
17067c478bd9Sstevel@tonic-gate 	 * Reset RMD 'walking' pointers.
17077c478bd9Sstevel@tonic-gate 	 */
17087c478bd9Sstevel@tonic-gate 	erip->rnextp = erip->rmdp;
17097c478bd9Sstevel@tonic-gate 	erip->rx_completion = 0;
17107c478bd9Sstevel@tonic-gate 	erip->rx_kick = ERI_RPENDING - 4;
17117c478bd9Sstevel@tonic-gate 	return (status);
17127c478bd9Sstevel@tonic-gate }
17137c478bd9Sstevel@tonic-gate 
17147c478bd9Sstevel@tonic-gate static uint32_t
eri_txmac_disable(struct eri * erip)17157c478bd9Sstevel@tonic-gate eri_txmac_disable(struct eri *erip)
17167c478bd9Sstevel@tonic-gate {
17177c478bd9Sstevel@tonic-gate 	int	n;
17187c478bd9Sstevel@tonic-gate 
17197c478bd9Sstevel@tonic-gate 	PUT_MACREG(txcfg, GET_MACREG(txcfg) & ~BMAC_TXCFG_ENAB);
17207c478bd9Sstevel@tonic-gate 	n = (BMACTXRSTDELAY * 10) / ERI_WAITPERIOD;
17217c478bd9Sstevel@tonic-gate 
17227c478bd9Sstevel@tonic-gate 	while (--n > 0) {
17237c478bd9Sstevel@tonic-gate 		drv_usecwait(ERI_WAITPERIOD);
17247c478bd9Sstevel@tonic-gate 		if ((GET_MACREG(txcfg) & 1) == 0)
17257c478bd9Sstevel@tonic-gate 			return (0);
17267c478bd9Sstevel@tonic-gate 	}
17277c478bd9Sstevel@tonic-gate 	return (1);
17287c478bd9Sstevel@tonic-gate }
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate static uint32_t
eri_rxmac_disable(struct eri * erip)17317c478bd9Sstevel@tonic-gate eri_rxmac_disable(struct eri *erip)
17327c478bd9Sstevel@tonic-gate {
17337c478bd9Sstevel@tonic-gate 	int	n;
17347c478bd9Sstevel@tonic-gate 	PUT_MACREG(rxcfg, GET_MACREG(rxcfg) & ~BMAC_RXCFG_ENAB);
17357c478bd9Sstevel@tonic-gate 	n = BMACRXRSTDELAY / ERI_WAITPERIOD;
17367c478bd9Sstevel@tonic-gate 
17377c478bd9Sstevel@tonic-gate 	while (--n > 0) {
17387c478bd9Sstevel@tonic-gate 		drv_usecwait(ERI_WAITPERIOD);
17397c478bd9Sstevel@tonic-gate 		if ((GET_MACREG(rxcfg) & 1) == 0)
17407c478bd9Sstevel@tonic-gate 			return (0);
17417c478bd9Sstevel@tonic-gate 	}
17427c478bd9Sstevel@tonic-gate 	return (1);
17437c478bd9Sstevel@tonic-gate }
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate /*
17467c478bd9Sstevel@tonic-gate  * Return 0 upon success, 1 on failure.
17477c478bd9Sstevel@tonic-gate  */
17487c478bd9Sstevel@tonic-gate static int
eri_stop(struct eri * erip)17497c478bd9Sstevel@tonic-gate eri_stop(struct eri *erip)
17507c478bd9Sstevel@tonic-gate {
17517c478bd9Sstevel@tonic-gate 	(void) eri_erx_reset(erip);
17527c478bd9Sstevel@tonic-gate 	(void) eri_etx_reset(erip);
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate 	/*
17557c478bd9Sstevel@tonic-gate 	 * set up cache line to 16 for 64 bytes of pci burst size
17567c478bd9Sstevel@tonic-gate 	 */
17577c478bd9Sstevel@tonic-gate 	PUT_SWRSTREG(reset, ERI_G_RESET_GLOBAL | ERI_CACHE_LINE_SIZE);
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate 	if (erip->linkcheck) {
17607c478bd9Sstevel@tonic-gate 		erip->linkcheck = 0;
17617c478bd9Sstevel@tonic-gate 		erip->global_reset_issued = 2;
17627c478bd9Sstevel@tonic-gate 	} else {
17637c478bd9Sstevel@tonic-gate 		param_linkup = 0;
1764d64540e3Sgd 		erip->stats.link_up = LINK_STATE_DOWN;
1765d64540e3Sgd 		erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
17667c478bd9Sstevel@tonic-gate 		erip->global_reset_issued = -1;
17677c478bd9Sstevel@tonic-gate 	}
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 	ERI_DELAY((GET_SWRSTREG(reset) == ERI_CACHE_LINE_SIZE),
1770d64540e3Sgd 	    ERI_MAX_RST_DELAY);
17717c478bd9Sstevel@tonic-gate 	erip->rx_reset_issued = -1;
17727c478bd9Sstevel@tonic-gate 	erip->tx_reset_issued = -1;
17737c478bd9Sstevel@tonic-gate 
17747c478bd9Sstevel@tonic-gate 	/*
17757c478bd9Sstevel@tonic-gate 	 * workaround for RIO not resetting the interrupt mask
17767c478bd9Sstevel@tonic-gate 	 * register to default value 0xffffffff.
17777c478bd9Sstevel@tonic-gate 	 */
17787c478bd9Sstevel@tonic-gate 	PUT_GLOBREG(intmask, ERI_G_MASK_ALL);
17797c478bd9Sstevel@tonic-gate 
17807c478bd9Sstevel@tonic-gate 	if (GET_SWRSTREG(reset) == ERI_CACHE_LINE_SIZE) {
17817c478bd9Sstevel@tonic-gate 		return (0);
17827c478bd9Sstevel@tonic-gate 	} else {
17837c478bd9Sstevel@tonic-gate 		return (1);
17847c478bd9Sstevel@tonic-gate 	}
17857c478bd9Sstevel@tonic-gate }
17867c478bd9Sstevel@tonic-gate 
17877c478bd9Sstevel@tonic-gate /*
17887c478bd9Sstevel@tonic-gate  * Reset Just the RX Portion
17897c478bd9Sstevel@tonic-gate  * Return 0 upon success, 1 on failure.
17907c478bd9Sstevel@tonic-gate  *
17917c478bd9Sstevel@tonic-gate  * Resetting the rxdma while there is a rx dma transaction going on the
17927c478bd9Sstevel@tonic-gate  * bus, will cause bus hang or parity errors. To avoid this, we would first
17937c478bd9Sstevel@tonic-gate  * disable the rxdma by clearing the ENABLE bit (bit 0). To make sure it is
17947c478bd9Sstevel@tonic-gate  * disabled, we will poll it until it realy clears. Furthermore, to verify
17957c478bd9Sstevel@tonic-gate  * any RX DMA activity is subsided, we delay for 5 msec.
17967c478bd9Sstevel@tonic-gate  */
17977c478bd9Sstevel@tonic-gate static uint32_t
eri_erx_reset(struct eri * erip)17987c478bd9Sstevel@tonic-gate eri_erx_reset(struct eri *erip)
17997c478bd9Sstevel@tonic-gate {
18007c478bd9Sstevel@tonic-gate 	(void) eri_rxmac_disable(erip); /* Disable the RX MAC */
18017c478bd9Sstevel@tonic-gate 
18021ac4c836Sjoycey 	/* Disable the RX DMA */
18031ac4c836Sjoycey 	PUT_ERXREG(config, GET_ERXREG(config) & ~GET_CONFIG_RXDMA_EN);
18047c478bd9Sstevel@tonic-gate 	ERI_DELAY(((GET_ERXREG(config) &  1) == 0), ERI_MAX_RST_DELAY);
18057c478bd9Sstevel@tonic-gate 	if ((GET_ERXREG(config) & 1) != 0)
18067c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
1807d64540e3Sgd 		    disable_erx_msg);
18087c478bd9Sstevel@tonic-gate 
18097c478bd9Sstevel@tonic-gate 	drv_usecwait(5000); /* Delay to insure no RX DMA activity */
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate 	PUT_SWRSTREG(reset, ERI_G_RESET_ERX | ERI_CACHE_LINE_SIZE);
18127c478bd9Sstevel@tonic-gate 	/*
18137c478bd9Sstevel@tonic-gate 	 * Wait until the reset is completed which is indicated by
18147c478bd9Sstevel@tonic-gate 	 * the reset bit cleared or time out..
18157c478bd9Sstevel@tonic-gate 	 */
1816d64540e3Sgd 	ERI_DELAY(((GET_SWRSTREG(reset) & (ERI_G_RESET_ERX)) ==
1817d64540e3Sgd 	    ERI_CACHE_LINE_SIZE), ERI_MAX_RST_DELAY);
18187c478bd9Sstevel@tonic-gate 	erip->rx_reset_issued = -1;
18197c478bd9Sstevel@tonic-gate 
1820d64540e3Sgd 	return ((GET_SWRSTREG(reset) & (ERI_G_RESET_ERX)) ? 1 : 0);
18217c478bd9Sstevel@tonic-gate }
18227c478bd9Sstevel@tonic-gate 
18237c478bd9Sstevel@tonic-gate /*
18247c478bd9Sstevel@tonic-gate  * Reset Just the TX Portion
18257c478bd9Sstevel@tonic-gate  * Return 0 upon success, 1 on failure.
18267c478bd9Sstevel@tonic-gate  * Resetting the txdma while there is a tx dma transaction on the bus, may cause
18277c478bd9Sstevel@tonic-gate  * bus hang or parity errors. To avoid this we would first disable the txdma by
18287c478bd9Sstevel@tonic-gate  * clearing the ENABLE bit (bit 0). To make sure it is disabled, we will poll
18297c478bd9Sstevel@tonic-gate  * it until it realy clears. Furthermore, to any TX DMA activity is subsided,
18307c478bd9Sstevel@tonic-gate  * we delay for 1 msec.
18317c478bd9Sstevel@tonic-gate  */
18327c478bd9Sstevel@tonic-gate static uint32_t
eri_etx_reset(struct eri * erip)18337c478bd9Sstevel@tonic-gate eri_etx_reset(struct eri *erip)
18347c478bd9Sstevel@tonic-gate {
18357c478bd9Sstevel@tonic-gate 	(void) eri_txmac_disable(erip);
18361ac4c836Sjoycey 
18371ac4c836Sjoycey 	/* Disable the TX DMA */
18381ac4c836Sjoycey 	PUT_ETXREG(config, GET_ETXREG(config) & ~GET_CONFIG_TXDMA_EN);
18397c478bd9Sstevel@tonic-gate #ifdef ORIG
18407c478bd9Sstevel@tonic-gate 	ERI_DELAY(((GET_ETXREG(config) &  1) == 0), ERI_MAX_RST_DELAY);
18417c478bd9Sstevel@tonic-gate 	if ((GET_ETXREG(config) &  1) != 0)
18427c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
1843d64540e3Sgd 		    disable_etx_msg);
18447c478bd9Sstevel@tonic-gate 	drv_usecwait(5000); /* Delay  to ensure DMA completed (if any). */
18457c478bd9Sstevel@tonic-gate #endif
18467c478bd9Sstevel@tonic-gate 	drv_usecwait(5000); /* Delay  to ensure DMA completed (if any). */
18477c478bd9Sstevel@tonic-gate 	ERI_DELAY(((GET_ETXREG(config) &  1) == 0), ERI_MAX_RST_DELAY);
18487c478bd9Sstevel@tonic-gate 	if ((GET_ETXREG(config) &  1) != 0)
18497c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
1850d64540e3Sgd 		    disable_etx_msg);
18517c478bd9Sstevel@tonic-gate 
18527c478bd9Sstevel@tonic-gate 	PUT_SWRSTREG(reset, ERI_G_RESET_ETX | ERI_CACHE_LINE_SIZE);
18537c478bd9Sstevel@tonic-gate 
18547c478bd9Sstevel@tonic-gate 	/*
18557c478bd9Sstevel@tonic-gate 	 * Wait until the reset is completed which is indicated by the reset bit
18567c478bd9Sstevel@tonic-gate 	 * cleared or time out..
18577c478bd9Sstevel@tonic-gate 	 */
18587c478bd9Sstevel@tonic-gate 	ERI_DELAY(((GET_SWRSTREG(reset) & (ERI_G_RESET_ETX)) ==
1859d64540e3Sgd 	    ERI_CACHE_LINE_SIZE), ERI_MAX_RST_DELAY);
18607c478bd9Sstevel@tonic-gate 	erip->tx_reset_issued = -1;
18617c478bd9Sstevel@tonic-gate 
18627c478bd9Sstevel@tonic-gate 	if (GET_SWRSTREG(reset) &  (ERI_G_RESET_ETX)) {
18637c478bd9Sstevel@tonic-gate 		return (1);
18647c478bd9Sstevel@tonic-gate 	} else
18657c478bd9Sstevel@tonic-gate 		return (0);
18667c478bd9Sstevel@tonic-gate }
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 
18697c478bd9Sstevel@tonic-gate /*
18707c478bd9Sstevel@tonic-gate  * Initialize the TX DMA registers and Enable the TX DMA.
18717c478bd9Sstevel@tonic-gate  */
18727c478bd9Sstevel@tonic-gate static uint32_t
eri_init_txregs(struct eri * erip)18737c478bd9Sstevel@tonic-gate eri_init_txregs(struct eri *erip)
18747c478bd9Sstevel@tonic-gate {
18757c478bd9Sstevel@tonic-gate 
18767c478bd9Sstevel@tonic-gate 	uint32_t	i;
18777c478bd9Sstevel@tonic-gate 	uint64_t	tx_ring;
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate 	/*
18807c478bd9Sstevel@tonic-gate 	 * Initialize ETX Registers:
18817c478bd9Sstevel@tonic-gate 	 * config, txring_lo, txring_hi
18827c478bd9Sstevel@tonic-gate 	 */
18837c478bd9Sstevel@tonic-gate 	tx_ring = ERI_IOPBIOADDR(erip, erip->eri_tmdp);
18847c478bd9Sstevel@tonic-gate 	PUT_ETXREG(txring_lo, (uint32_t)(tx_ring));
18857c478bd9Sstevel@tonic-gate 	PUT_ETXREG(txring_hi, (uint32_t)(tx_ring >> 32));
18867c478bd9Sstevel@tonic-gate 
18877c478bd9Sstevel@tonic-gate 	/*
18887c478bd9Sstevel@tonic-gate 	 * Get TX Ring Size Masks.
18897c478bd9Sstevel@tonic-gate 	 * The ring size ERI_TPENDING is defined in eri_mac.h.
18907c478bd9Sstevel@tonic-gate 	 */
18917c478bd9Sstevel@tonic-gate 	switch (ERI_TPENDING) {
18927c478bd9Sstevel@tonic-gate 	case 32: i = ETX_RINGSZ_32;
18937c478bd9Sstevel@tonic-gate 		break;
18947c478bd9Sstevel@tonic-gate 	case 64: i = ETX_RINGSZ_64;
18957c478bd9Sstevel@tonic-gate 		break;
18967c478bd9Sstevel@tonic-gate 	case 128: i = ETX_RINGSZ_128;
18977c478bd9Sstevel@tonic-gate 		break;
18987c478bd9Sstevel@tonic-gate 	case 256: i = ETX_RINGSZ_256;
18997c478bd9Sstevel@tonic-gate 		break;
19007c478bd9Sstevel@tonic-gate 	case 512: i = ETX_RINGSZ_512;
19017c478bd9Sstevel@tonic-gate 		break;
19027c478bd9Sstevel@tonic-gate 	case 1024: i = ETX_RINGSZ_1024;
19037c478bd9Sstevel@tonic-gate 		break;
19047c478bd9Sstevel@tonic-gate 	case 2048: i = ETX_RINGSZ_2048;
19057c478bd9Sstevel@tonic-gate 		break;
19067c478bd9Sstevel@tonic-gate 	case 4096: i = ETX_RINGSZ_4096;
19077c478bd9Sstevel@tonic-gate 		break;
19087c478bd9Sstevel@tonic-gate 	default:
19097c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG2(erip, SEVERITY_HIGH, ERI_VERB_MSG,
1910d64540e3Sgd 		    unk_tx_descr_sze_msg, ERI_TPENDING);
19117c478bd9Sstevel@tonic-gate 		return (1);
19127c478bd9Sstevel@tonic-gate 	}
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate 	i <<= ERI_TX_RINGSZ_SHIFT;
19157c478bd9Sstevel@tonic-gate 	PUT_ETXREG(config, ETX_CONFIG_THRESHOLD | i);
19167c478bd9Sstevel@tonic-gate 	ENABLE_TXDMA(erip);
19177c478bd9Sstevel@tonic-gate 	ENABLE_MAC(erip);
19187c478bd9Sstevel@tonic-gate 	return (0);
19197c478bd9Sstevel@tonic-gate }
19207c478bd9Sstevel@tonic-gate 
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate /*
19237c478bd9Sstevel@tonic-gate  * Initialize the RX DMA registers and Enable the RX DMA.
19247c478bd9Sstevel@tonic-gate  */
19257c478bd9Sstevel@tonic-gate static uint32_t
eri_init_rxregs(struct eri * erip)19267c478bd9Sstevel@tonic-gate eri_init_rxregs(struct eri *erip)
19277c478bd9Sstevel@tonic-gate {
19287c478bd9Sstevel@tonic-gate 	int i;
19297c478bd9Sstevel@tonic-gate 	uint64_t	rx_ring;
19307c478bd9Sstevel@tonic-gate 
19317c478bd9Sstevel@tonic-gate 	/*
19327c478bd9Sstevel@tonic-gate 	 * Initialize ERX Registers:
19337c478bd9Sstevel@tonic-gate 	 * rxring_lo, rxring_hi, config, rx_blanking, rx_pause_threshold.
19347c478bd9Sstevel@tonic-gate 	 * Also, rx_kick
19357c478bd9Sstevel@tonic-gate 	 * Read and save rxfifo_size.
19367c478bd9Sstevel@tonic-gate 	 * XXX: Use this to properly configure PAUSE threshold values.
19377c478bd9Sstevel@tonic-gate 	 */
19387c478bd9Sstevel@tonic-gate 	rx_ring = ERI_IOPBIOADDR(erip, erip->rmdp);
19397c478bd9Sstevel@tonic-gate 	PUT_ERXREG(rxring_lo, (uint32_t)(rx_ring));
19407c478bd9Sstevel@tonic-gate 	PUT_ERXREG(rxring_hi, (uint32_t)(rx_ring >> 32));
19417c478bd9Sstevel@tonic-gate 	PUT_ERXREG(rx_kick, erip->rx_kick);
19427c478bd9Sstevel@tonic-gate 
19437c478bd9Sstevel@tonic-gate 	/*
19447c478bd9Sstevel@tonic-gate 	 * The Max ring size, ERI_RMDMAX is defined in eri_mac.h.
19457c478bd9Sstevel@tonic-gate 	 * More ERI_RPENDING will provide better performance but requires more
19467c478bd9Sstevel@tonic-gate 	 * system DVMA memory.
19477c478bd9Sstevel@tonic-gate 	 * eri_rx_ring_size can be used to tune this value from /etc/system
19487c478bd9Sstevel@tonic-gate 	 * eri_rx_ring_size cannot be NDD'able due to non-recoverable errors
19497c478bd9Sstevel@tonic-gate 	 * which cannot be detected from NDD operations
19507c478bd9Sstevel@tonic-gate 	 */
19517c478bd9Sstevel@tonic-gate 
19527c478bd9Sstevel@tonic-gate 	/*
19537c478bd9Sstevel@tonic-gate 	 * get the rxring size bits
19547c478bd9Sstevel@tonic-gate 	 */
19557c478bd9Sstevel@tonic-gate 	switch (ERI_RPENDING) {
19567c478bd9Sstevel@tonic-gate 	case 32: i = ERX_RINGSZ_32;
19577c478bd9Sstevel@tonic-gate 		break;
19587c478bd9Sstevel@tonic-gate 	case 64: i = ERX_RINGSZ_64;
19597c478bd9Sstevel@tonic-gate 		break;
19607c478bd9Sstevel@tonic-gate 	case 128: i = ERX_RINGSZ_128;
19617c478bd9Sstevel@tonic-gate 		break;
19627c478bd9Sstevel@tonic-gate 	case 256: i = ERX_RINGSZ_256;
19637c478bd9Sstevel@tonic-gate 		break;
19647c478bd9Sstevel@tonic-gate 	case 512: i = ERX_RINGSZ_512;
19657c478bd9Sstevel@tonic-gate 		break;
19667c478bd9Sstevel@tonic-gate 	case 1024: i = ERX_RINGSZ_1024;
19677c478bd9Sstevel@tonic-gate 		break;
19687c478bd9Sstevel@tonic-gate 	case 2048: i = ERX_RINGSZ_2048;
19697c478bd9Sstevel@tonic-gate 		break;
19707c478bd9Sstevel@tonic-gate 	case 4096: i = ERX_RINGSZ_4096;
19717c478bd9Sstevel@tonic-gate 		break;
19727c478bd9Sstevel@tonic-gate 	default:
19737c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG2(erip, SEVERITY_HIGH, ERI_VERB_MSG,
1974d64540e3Sgd 		    unk_rx_descr_sze_msg, ERI_RPENDING);
19757c478bd9Sstevel@tonic-gate 		return (1);
19767c478bd9Sstevel@tonic-gate 	}
19777c478bd9Sstevel@tonic-gate 
19787c478bd9Sstevel@tonic-gate 	i <<= ERI_RX_RINGSZ_SHIFT;
19797c478bd9Sstevel@tonic-gate 	i |=  (ERI_FSTBYTE_OFFSET << ERI_RX_CONFIG_FBO_SHIFT) |
1980d64540e3Sgd 	    (ETHERHEADER_SIZE << ERI_RX_CONFIG_RX_CSSTART_SHIFT) |
1981d64540e3Sgd 	    (ERI_RX_FIFOTH_1024 << ERI_RX_CONFIG_RXFIFOTH_SHIFT);
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate 	PUT_ERXREG(config, i);
19847c478bd9Sstevel@tonic-gate 	PUT_ERXREG(rx_blanking,
1985d64540e3Sgd 	    (param_intr_blank_time << ERI_RX_BLNK_INTR_TIME_SHIFT) |
1986d64540e3Sgd 	    param_intr_blank_packets);
19877c478bd9Sstevel@tonic-gate 
19887c478bd9Sstevel@tonic-gate 	PUT_ERXREG(rx_pause_threshold, rx_pause_threshold);
19897c478bd9Sstevel@tonic-gate 	erip->rxfifo_size = GET_ERXREG(rxfifo_size);
19907c478bd9Sstevel@tonic-gate 	ENABLE_RXDMA(erip);
19917c478bd9Sstevel@tonic-gate 	return (0);
19927c478bd9Sstevel@tonic-gate }
19937c478bd9Sstevel@tonic-gate 
19947c478bd9Sstevel@tonic-gate static int
eri_freebufs(struct eri * erip)19957c478bd9Sstevel@tonic-gate eri_freebufs(struct eri *erip)
19967c478bd9Sstevel@tonic-gate {
19977c478bd9Sstevel@tonic-gate 	int status = 0;
19987c478bd9Sstevel@tonic-gate 
1999bd78278bSGarrett D'Amore 	status = eri_flush_rxbufs(erip);
20007c478bd9Sstevel@tonic-gate 	return (status);
20017c478bd9Sstevel@tonic-gate }
20027c478bd9Sstevel@tonic-gate 
20037c478bd9Sstevel@tonic-gate static void
eri_update_rxbufs(struct eri * erip)20047c478bd9Sstevel@tonic-gate eri_update_rxbufs(struct eri *erip)
20057c478bd9Sstevel@tonic-gate {
20067c478bd9Sstevel@tonic-gate 	int		i;
20077c478bd9Sstevel@tonic-gate 	volatile struct rmd  *rmdp, *rmdpbase;
20087c478bd9Sstevel@tonic-gate 
20097c478bd9Sstevel@tonic-gate 	/*
20107c478bd9Sstevel@tonic-gate 	 * Hang out receive buffers.
20117c478bd9Sstevel@tonic-gate 	 */
20127c478bd9Sstevel@tonic-gate 	rmdpbase = erip->rmdp;
20137c478bd9Sstevel@tonic-gate 	for (i = 0; i < ERI_RPENDING; i++) {
20147c478bd9Sstevel@tonic-gate 		rmdp = rmdpbase + i;
20157c478bd9Sstevel@tonic-gate 		UPDATE_RMD(rmdp);
20167c478bd9Sstevel@tonic-gate 	}
20177c478bd9Sstevel@tonic-gate 
20187c478bd9Sstevel@tonic-gate 	/*
20197c478bd9Sstevel@tonic-gate 	 * sync RXDMA descriptors.
20207c478bd9Sstevel@tonic-gate 	 */
2021d64540e3Sgd 	ERI_SYNCIOPB(erip, erip->rmdp, (ERI_RPENDING * sizeof (struct rmd)),
2022d64540e3Sgd 	    DDI_DMA_SYNC_FORDEV);
20237c478bd9Sstevel@tonic-gate 	/*
20247c478bd9Sstevel@tonic-gate 	 * Reset RMD 'walking' pointers.
20257c478bd9Sstevel@tonic-gate 	 */
20267c478bd9Sstevel@tonic-gate 	erip->rnextp =	erip->rmdp;
20277c478bd9Sstevel@tonic-gate 	erip->rx_completion = 0;
20287c478bd9Sstevel@tonic-gate 	erip->rx_kick =	ERI_RPENDING - 4;
20297c478bd9Sstevel@tonic-gate }
20307c478bd9Sstevel@tonic-gate 
20317c478bd9Sstevel@tonic-gate /*
20327c478bd9Sstevel@tonic-gate  * This routine is used to reset the RX DMA only. In the case of RX
20337c478bd9Sstevel@tonic-gate  * failures such as RX Tag Error, RX hang etc... we don't want to
20347c478bd9Sstevel@tonic-gate  * do global reset which takes down the link and clears the FIFO's
20357c478bd9Sstevel@tonic-gate  * By doing RX only reset, we leave the TX and the link intact.
20367c478bd9Sstevel@tonic-gate  */
20377c478bd9Sstevel@tonic-gate static uint32_t
eri_init_rx_channel(struct eri * erip)20387c478bd9Sstevel@tonic-gate eri_init_rx_channel(struct eri *erip)
20397c478bd9Sstevel@tonic-gate {
20407c478bd9Sstevel@tonic-gate 	erip->flags &= ~ERI_RXINIT;
20417c478bd9Sstevel@tonic-gate 	(void) eri_erx_reset(erip);
20427c478bd9Sstevel@tonic-gate 	eri_update_rxbufs(erip);
20437c478bd9Sstevel@tonic-gate 	if (eri_init_rxregs(erip))
20447c478bd9Sstevel@tonic-gate 		return (1);
20457c478bd9Sstevel@tonic-gate 	PUT_MACREG(rxmask, BMAC_RXINTR_MASK);
20467c478bd9Sstevel@tonic-gate 	PUT_MACREG(rxcfg, GET_MACREG(rxcfg) | BMAC_RXCFG_ENAB);
20477c478bd9Sstevel@tonic-gate 	erip->rx_reset_issued = 0;
20487c478bd9Sstevel@tonic-gate 	HSTAT(erip, rx_inits);
20497c478bd9Sstevel@tonic-gate 	erip->flags |= ERI_RXINIT;
20507c478bd9Sstevel@tonic-gate 	return (0);
20517c478bd9Sstevel@tonic-gate }
20527c478bd9Sstevel@tonic-gate 
20537c478bd9Sstevel@tonic-gate static void
eri_init_rx(struct eri * erip)20547c478bd9Sstevel@tonic-gate eri_init_rx(struct eri *erip)
20557c478bd9Sstevel@tonic-gate {
2056d64540e3Sgd 	uint16_t	*ladrf;
20577c478bd9Sstevel@tonic-gate 
20587c478bd9Sstevel@tonic-gate 	/*
20597c478bd9Sstevel@tonic-gate 	 * First of all make sure the Receive MAC is stop.
20607c478bd9Sstevel@tonic-gate 	 */
20617c478bd9Sstevel@tonic-gate 	(void) eri_rxmac_disable(erip); /* Disable the RX MAC */
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate 	/*
20647c478bd9Sstevel@tonic-gate 	 * Program BigMAC with local individual ethernet address.
20657c478bd9Sstevel@tonic-gate 	 */
20667c478bd9Sstevel@tonic-gate 
2067d64540e3Sgd 	PUT_MACREG(madd0, (erip->ouraddr[4] << 8) | erip->ouraddr[5]);
2068d64540e3Sgd 	PUT_MACREG(madd1, (erip->ouraddr[2] << 8) | erip->ouraddr[3]);
2069d64540e3Sgd 	PUT_MACREG(madd2, (erip->ouraddr[0] << 8) | erip->ouraddr[1]);
20707c478bd9Sstevel@tonic-gate 
20717c478bd9Sstevel@tonic-gate 	/*
20727c478bd9Sstevel@tonic-gate 	 * Set up multicast address filter by passing all multicast
20737c478bd9Sstevel@tonic-gate 	 * addresses through a crc generator, and then using the
20747c478bd9Sstevel@tonic-gate 	 * low order 8 bits as a index into the 256 bit logical
20757c478bd9Sstevel@tonic-gate 	 * address filter. The high order four bits select the word,
20767c478bd9Sstevel@tonic-gate 	 * while the rest of the bits select the bit within the word.
20777c478bd9Sstevel@tonic-gate 	 */
20787c478bd9Sstevel@tonic-gate 
2079d64540e3Sgd 	ladrf = erip->ladrf;
20807c478bd9Sstevel@tonic-gate 
20817c478bd9Sstevel@tonic-gate 	PUT_MACREG(hash0, ladrf[0]);
20827c478bd9Sstevel@tonic-gate 	PUT_MACREG(hash1, ladrf[1]);
20837c478bd9Sstevel@tonic-gate 	PUT_MACREG(hash2, ladrf[2]);
20847c478bd9Sstevel@tonic-gate 	PUT_MACREG(hash3, ladrf[3]);
20857c478bd9Sstevel@tonic-gate 	PUT_MACREG(hash4, ladrf[4]);
20867c478bd9Sstevel@tonic-gate 	PUT_MACREG(hash5, ladrf[5]);
20877c478bd9Sstevel@tonic-gate 	PUT_MACREG(hash6, ladrf[6]);
20887c478bd9Sstevel@tonic-gate 	PUT_MACREG(hash7, ladrf[7]);
20897c478bd9Sstevel@tonic-gate 	PUT_MACREG(hash8, ladrf[8]);
20907c478bd9Sstevel@tonic-gate 	PUT_MACREG(hash9, ladrf[9]);
20917c478bd9Sstevel@tonic-gate 	PUT_MACREG(hash10, ladrf[10]);
20927c478bd9Sstevel@tonic-gate 	PUT_MACREG(hash11, ladrf[11]);
20937c478bd9Sstevel@tonic-gate 	PUT_MACREG(hash12, ladrf[12]);
20947c478bd9Sstevel@tonic-gate 	PUT_MACREG(hash13, ladrf[13]);
20957c478bd9Sstevel@tonic-gate 	PUT_MACREG(hash14, ladrf[14]);
20967c478bd9Sstevel@tonic-gate 	PUT_MACREG(hash15, ladrf[15]);
20977c478bd9Sstevel@tonic-gate 
20987c478bd9Sstevel@tonic-gate #ifdef ERI_DONT_STRIP_CRC
20997c478bd9Sstevel@tonic-gate 	PUT_MACREG(rxcfg,
2100d64540e3Sgd 	    ((erip->promisc ? BMAC_RXCFG_PROMIS : 0) |
2101d64540e3Sgd 	    (erip->multi_refcnt ? BMAC_RXCFG_HASH : 0) |
21027c478bd9Sstevel@tonic-gate 	    BMAC_RXCFG_ENAB));
21037c478bd9Sstevel@tonic-gate #else
21047c478bd9Sstevel@tonic-gate 	PUT_MACREG(rxcfg,
2105d64540e3Sgd 	    ((erip->promisc ? BMAC_RXCFG_PROMIS : 0) |
2106d64540e3Sgd 	    (erip->multi_refcnt ? BMAC_RXCFG_HASH : 0) |
21077c478bd9Sstevel@tonic-gate 	    BMAC_RXCFG_ENAB | BMAC_RXCFG_STRIP_CRC));
21087c478bd9Sstevel@tonic-gate #endif
21097c478bd9Sstevel@tonic-gate 	/* wait after setting Hash Enable bit */
21107c478bd9Sstevel@tonic-gate 	/* drv_usecwait(10); */
21117c478bd9Sstevel@tonic-gate 
21127c478bd9Sstevel@tonic-gate 	HSTAT(erip, rx_inits);
21137c478bd9Sstevel@tonic-gate }
21147c478bd9Sstevel@tonic-gate 
21157c478bd9Sstevel@tonic-gate /*
21167c478bd9Sstevel@tonic-gate  * This routine is used to init the TX MAC only.
21177c478bd9Sstevel@tonic-gate  *	&erip->xmitlock is held before calling this routine.
21187c478bd9Sstevel@tonic-gate  */
21197c478bd9Sstevel@tonic-gate void
eri_init_txmac(struct eri * erip)21207c478bd9Sstevel@tonic-gate eri_init_txmac(struct eri *erip)
21217c478bd9Sstevel@tonic-gate {
21227c478bd9Sstevel@tonic-gate 	uint32_t carrier_ext = 0;
21237c478bd9Sstevel@tonic-gate 
21247c478bd9Sstevel@tonic-gate 	erip->flags &= ~ERI_TXINIT;
21257c478bd9Sstevel@tonic-gate 	/*
21267c478bd9Sstevel@tonic-gate 	 * Stop the Transmit MAC.
21277c478bd9Sstevel@tonic-gate 	 */
21287c478bd9Sstevel@tonic-gate 	(void) eri_txmac_disable(erip);
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate 	/*
21317c478bd9Sstevel@tonic-gate 	 * Must be Internal Transceiver
21327c478bd9Sstevel@tonic-gate 	 */
21337c478bd9Sstevel@tonic-gate 	if (param_mode)
21347c478bd9Sstevel@tonic-gate 		PUT_MACREG(xifc, ((param_transceiver == EXTERNAL_XCVR ?
21357c478bd9Sstevel@tonic-gate 		    BMAC_XIFC_MIIBUF_OE : 0) | BMAC_XIFC_TX_MII_OE));
21367c478bd9Sstevel@tonic-gate 	else
21377c478bd9Sstevel@tonic-gate 		PUT_MACREG(xifc, ((param_transceiver == EXTERNAL_XCVR ?
21387c478bd9Sstevel@tonic-gate 		    BMAC_XIFC_MIIBUF_OE : 0) | BMAC_XIFC_TX_MII_OE |
21397c478bd9Sstevel@tonic-gate 		    BMAC_XIFC_DIS_ECHO));
21407c478bd9Sstevel@tonic-gate 
21417c478bd9Sstevel@tonic-gate 	/*
21427c478bd9Sstevel@tonic-gate 	 * Initialize the interpacket gap registers
21437c478bd9Sstevel@tonic-gate 	 */
21447c478bd9Sstevel@tonic-gate 	PUT_MACREG(ipg1, param_ipg1);
21457c478bd9Sstevel@tonic-gate 	PUT_MACREG(ipg2, param_ipg2);
21467c478bd9Sstevel@tonic-gate 
21477c478bd9Sstevel@tonic-gate 	if (erip->ngu_enable)
2148d64540e3Sgd 		PUT_MACREG(txcfg, ((param_mode ? BMAC_TXCFG_FDX: 0) |
2149d64540e3Sgd 		    ((param_lance_mode && (erip->lance_mode_enable)) ?
2150d64540e3Sgd 		    BMAC_TXCFG_ENIPG0 : 0) |
2151d64540e3Sgd 		    (carrier_ext ? BMAC_TXCFG_CARR_EXT : 0) |
2152d64540e3Sgd 		    BMAC_TXCFG_NGU));
21537c478bd9Sstevel@tonic-gate 	else
2154d64540e3Sgd 		PUT_MACREG(txcfg, ((param_mode ? BMAC_TXCFG_FDX: 0) |
2155d64540e3Sgd 		    ((param_lance_mode && (erip->lance_mode_enable)) ?
2156d64540e3Sgd 		    BMAC_TXCFG_ENIPG0 : 0) |
2157d64540e3Sgd 		    (carrier_ext ? BMAC_TXCFG_CARR_EXT : 0)));
21587c478bd9Sstevel@tonic-gate 
21597c478bd9Sstevel@tonic-gate 	ENABLE_TXDMA(erip);
21607c478bd9Sstevel@tonic-gate 	ENABLE_TXMAC(erip);
21617c478bd9Sstevel@tonic-gate 
21627c478bd9Sstevel@tonic-gate 	HSTAT(erip, tx_inits);
21637c478bd9Sstevel@tonic-gate 	erip->flags |= ERI_TXINIT;
21647c478bd9Sstevel@tonic-gate }
21657c478bd9Sstevel@tonic-gate 
21667c478bd9Sstevel@tonic-gate static void
eri_unallocthings(struct eri * erip)21677c478bd9Sstevel@tonic-gate eri_unallocthings(struct eri *erip)
21687c478bd9Sstevel@tonic-gate {
21697c478bd9Sstevel@tonic-gate 	uint32_t	flag;
21707c478bd9Sstevel@tonic-gate 	uint32_t	i;
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate 	flag = erip->alloc_flag;
21737c478bd9Sstevel@tonic-gate 
21747c478bd9Sstevel@tonic-gate 	if (flag & ERI_DESC_MEM_MAP)
21757c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(erip->md_h);
21767c478bd9Sstevel@tonic-gate 
21777c478bd9Sstevel@tonic-gate 	if (flag & ERI_DESC_MEM_ALLOC) {
21787c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&erip->mdm_h);
21797c478bd9Sstevel@tonic-gate 		erip->rmdp = NULL;
21807c478bd9Sstevel@tonic-gate 		erip->eri_tmdp = NULL;
21817c478bd9Sstevel@tonic-gate 	}
21827c478bd9Sstevel@tonic-gate 
21837c478bd9Sstevel@tonic-gate 	if (flag & ERI_DESC_HANDLE_ALLOC)
21847c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&erip->md_h);
21857c478bd9Sstevel@tonic-gate 
21867c478bd9Sstevel@tonic-gate 	(void) eri_freebufs(erip);
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate 	if (flag & ERI_RCV_HANDLE_ALLOC)
21897c478bd9Sstevel@tonic-gate 		for (i = 0; i < erip->rcv_handle_cnt; i++)
21907c478bd9Sstevel@tonic-gate 			ddi_dma_free_handle(&erip->ndmarh[i]);
21917c478bd9Sstevel@tonic-gate 
21927c478bd9Sstevel@tonic-gate 	if (flag & ERI_RCV_DVMA_ALLOC) {
21937c478bd9Sstevel@tonic-gate 		(void) dvma_release(erip->eri_dvmarh);
21947c478bd9Sstevel@tonic-gate 		erip->eri_dvmarh = NULL;
21957c478bd9Sstevel@tonic-gate 	}
21967c478bd9Sstevel@tonic-gate 
21977c478bd9Sstevel@tonic-gate 	if (flag & ERI_XBUFS_KMEM_DMABIND) {
21987c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(erip->tbuf_handle);
21997c478bd9Sstevel@tonic-gate 		erip->tbuf_ioaddr = 0;
22007c478bd9Sstevel@tonic-gate 	}
22017c478bd9Sstevel@tonic-gate 
22027c478bd9Sstevel@tonic-gate 	if (flag & ERI_XBUFS_KMEM_ALLOC) {
2203bd78278bSGarrett D'Amore 		ddi_dma_mem_free(&erip->tbuf_acch);
22047c478bd9Sstevel@tonic-gate 		erip->tbuf_kaddr = NULL;
22057c478bd9Sstevel@tonic-gate 	}
22067c478bd9Sstevel@tonic-gate 
22077c478bd9Sstevel@tonic-gate 	if (flag & ERI_XBUFS_HANDLE_ALLOC) {
22087c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&erip->tbuf_handle);
22097c478bd9Sstevel@tonic-gate 		erip->tbuf_handle = NULL;
22107c478bd9Sstevel@tonic-gate 	}
22117c478bd9Sstevel@tonic-gate 
22127c478bd9Sstevel@tonic-gate }
22137c478bd9Sstevel@tonic-gate 
22147c478bd9Sstevel@tonic-gate /*
22157c478bd9Sstevel@tonic-gate  * Initialize channel.
2216d64540e3Sgd  * Return true on success, false on error.
22177c478bd9Sstevel@tonic-gate  *
22187c478bd9Sstevel@tonic-gate  * The recommended sequence for initialization is:
22197c478bd9Sstevel@tonic-gate  * 1. Issue a Global Reset command to the Ethernet Channel.
22207c478bd9Sstevel@tonic-gate  * 2. Poll the Global_Reset bits until the execution of the reset has been
22217c478bd9Sstevel@tonic-gate  *    completed.
22227c478bd9Sstevel@tonic-gate  * 2(a). Use the MIF Frame/Output register to reset the transceiver.
22237c478bd9Sstevel@tonic-gate  *	 Poll Register 0 to till the Resetbit is 0.
22247c478bd9Sstevel@tonic-gate  * 2(b). Use the MIF Frame/Output register to set the PHY in in Normal-Op,
22257c478bd9Sstevel@tonic-gate  *	 100Mbps and Non-Isolated mode. The main point here is to bring the
22267c478bd9Sstevel@tonic-gate  *	 PHY out of Isolate mode so that it can generate the rx_clk and tx_clk
22277c478bd9Sstevel@tonic-gate  *	 to the MII interface so that the Bigmac core can correctly reset
22287c478bd9Sstevel@tonic-gate  *	 upon a software reset.
22297c478bd9Sstevel@tonic-gate  * 2(c).  Issue another Global Reset command to the Ethernet Channel and poll
22307c478bd9Sstevel@tonic-gate  *	  the Global_Reset bits till completion.
22317c478bd9Sstevel@tonic-gate  * 3. Set up all the data structures in the host memory.
22327c478bd9Sstevel@tonic-gate  * 4. Program the TX_MAC registers/counters (excluding the TX_MAC Configuration
22337c478bd9Sstevel@tonic-gate  *    Register).
22347c478bd9Sstevel@tonic-gate  * 5. Program the RX_MAC registers/counters (excluding the RX_MAC Configuration
22357c478bd9Sstevel@tonic-gate  *    Register).
22367c478bd9Sstevel@tonic-gate  * 6. Program the Transmit Descriptor Ring Base Address in the ETX.
22377c478bd9Sstevel@tonic-gate  * 7. Program the Receive Descriptor Ring Base Address in the ERX.
22387c478bd9Sstevel@tonic-gate  * 8. Program the Global Configuration and the Global Interrupt Mask Registers.
22397c478bd9Sstevel@tonic-gate  * 9. Program the ETX Configuration register (enable the Transmit DMA channel).
22407c478bd9Sstevel@tonic-gate  * 10. Program the ERX Configuration register (enable the Receive DMA channel).
22417c478bd9Sstevel@tonic-gate  * 11. Program the XIF Configuration Register (enable the XIF).
22427c478bd9Sstevel@tonic-gate  * 12. Program the RX_MAC Configuration Register (Enable the RX_MAC).
22437c478bd9Sstevel@tonic-gate  * 13. Program the TX_MAC Configuration Register (Enable the TX_MAC).
22447c478bd9Sstevel@tonic-gate  */
22457c478bd9Sstevel@tonic-gate /*
22467c478bd9Sstevel@tonic-gate  * lock order:
2247d64540e3Sgd  *	intrlock->linklock->xmitlock->xcvrlock
22487c478bd9Sstevel@tonic-gate  */
2249d64540e3Sgd static boolean_t
eri_init(struct eri * erip)22507c478bd9Sstevel@tonic-gate eri_init(struct eri *erip)
22517c478bd9Sstevel@tonic-gate {
22527c478bd9Sstevel@tonic-gate 	uint32_t	init_stat = 0;
22537c478bd9Sstevel@tonic-gate 	uint32_t	partial_init = 0;
22547c478bd9Sstevel@tonic-gate 	uint32_t	carrier_ext = 0;
22557c478bd9Sstevel@tonic-gate 	uint32_t	mac_ctl = 0;
2256d64540e3Sgd 	boolean_t	ret;
2257*7e996435SToomas Soome 	uint32_t	link_timeout = ERI_LINKCHECK_TIMER;
2258d64540e3Sgd 	link_state_t	linkupdate = LINK_STATE_UNKNOWN;
22597c478bd9Sstevel@tonic-gate 
22607c478bd9Sstevel@tonic-gate 	/*
2261d64540e3Sgd 	 * Just return successfully if device is suspended.
22627c478bd9Sstevel@tonic-gate 	 * eri_init() will be called again from resume.
22637c478bd9Sstevel@tonic-gate 	 */
2264d64540e3Sgd 	ASSERT(erip != NULL);
2265d64540e3Sgd 
2266d64540e3Sgd 	if (erip->flags & ERI_SUSPENDED) {
2267d64540e3Sgd 		ret = B_TRUE;
22687c478bd9Sstevel@tonic-gate 		goto init_exit;
22697c478bd9Sstevel@tonic-gate 	}
22707c478bd9Sstevel@tonic-gate 
22717c478bd9Sstevel@tonic-gate 	mutex_enter(&erip->intrlock);
22727c478bd9Sstevel@tonic-gate 	eri_stop_timer(erip);	/* acquire linklock */
22737c478bd9Sstevel@tonic-gate 	mutex_enter(&erip->xmitlock);
2274d64540e3Sgd 	erip->flags &= (ERI_DLPI_LINKUP | ERI_STARTED);
2275d64540e3Sgd 	erip->wantw = B_FALSE;
22767c478bd9Sstevel@tonic-gate 	HSTAT(erip, inits);
22777c478bd9Sstevel@tonic-gate 	erip->txhung = 0;
22787c478bd9Sstevel@tonic-gate 
2279fd8be74fSgd 	if ((erip->stats.inits > 1) && (erip->init_macregs == 0))
22807c478bd9Sstevel@tonic-gate 		eri_savecntrs(erip);
22817c478bd9Sstevel@tonic-gate 
22827c478bd9Sstevel@tonic-gate 	mutex_enter(&erip->xcvrlock);
22837c478bd9Sstevel@tonic-gate 	if (!param_linkup || erip->linkcheck) {
2284860c4cd4Scarlsonj 		if (!erip->linkcheck)
2285d64540e3Sgd 			linkupdate = LINK_STATE_DOWN;
22867c478bd9Sstevel@tonic-gate 		(void) eri_stop(erip);
22877c478bd9Sstevel@tonic-gate 	}
22887c478bd9Sstevel@tonic-gate 	if (!(erip->flags & ERI_DLPI_LINKUP) || !param_linkup) {
22897c478bd9Sstevel@tonic-gate 		erip->flags |= ERI_DLPI_LINKUP;
22907c478bd9Sstevel@tonic-gate 		eri_mif_poll(erip, MIF_POLL_STOP);
22917c478bd9Sstevel@tonic-gate 		(void) eri_new_xcvr(erip);
2292d64540e3Sgd 		ERI_DEBUG_MSG1(erip, XCVR_MSG, "New transceiver detected.");
22937c478bd9Sstevel@tonic-gate 		if (param_transceiver != NO_XCVR) {
22947c478bd9Sstevel@tonic-gate 			/*
22957c478bd9Sstevel@tonic-gate 			 * Reset the new PHY and bring up the
22967c478bd9Sstevel@tonic-gate 			 * link
22977c478bd9Sstevel@tonic-gate 			 */
22987c478bd9Sstevel@tonic-gate 			if (eri_reset_xcvr(erip)) {
22997c478bd9Sstevel@tonic-gate 				ERI_FAULT_MSG1(erip, SEVERITY_NONE,
23007c478bd9Sstevel@tonic-gate 				    ERI_VERB_MSG, "In Init after reset");
23017c478bd9Sstevel@tonic-gate 				mutex_exit(&erip->xcvrlock);
23027c478bd9Sstevel@tonic-gate 				link_timeout = 0;
23037c478bd9Sstevel@tonic-gate 				goto done;
23047c478bd9Sstevel@tonic-gate 			}
2305d64540e3Sgd 			if (erip->stats.link_up == LINK_STATE_UP)
2306d64540e3Sgd 				linkupdate = LINK_STATE_UP;
23077c478bd9Sstevel@tonic-gate 		} else {
23087c478bd9Sstevel@tonic-gate 			erip->flags |= (ERI_RUNNING | ERI_INITIALIZED);
23097c478bd9Sstevel@tonic-gate 			param_linkup = 0;
2310d64540e3Sgd 			erip->stats.link_up = LINK_STATE_DOWN;
2311d64540e3Sgd 			erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
2312d64540e3Sgd 			linkupdate = LINK_STATE_DOWN;
23137c478bd9Sstevel@tonic-gate 			/*
23147c478bd9Sstevel@tonic-gate 			 * Still go on and complete the MAC initialization as
23157c478bd9Sstevel@tonic-gate 			 * xcvr might show up later.
23167c478bd9Sstevel@tonic-gate 			 * you must return to their mutex ordering.
23177c478bd9Sstevel@tonic-gate 			 */
23187c478bd9Sstevel@tonic-gate 		}
23197c478bd9Sstevel@tonic-gate 		eri_mif_poll(erip, MIF_POLL_START);
23207c478bd9Sstevel@tonic-gate 	}
23217c478bd9Sstevel@tonic-gate 
23227c478bd9Sstevel@tonic-gate 	mutex_exit(&erip->xcvrlock);
23237c478bd9Sstevel@tonic-gate 
23247c478bd9Sstevel@tonic-gate 	/*
23257c478bd9Sstevel@tonic-gate 	 * Allocate data structures.
23267c478bd9Sstevel@tonic-gate 	 */
23277c478bd9Sstevel@tonic-gate 	if (erip->global_reset_issued) {
23287c478bd9Sstevel@tonic-gate 		if (erip->global_reset_issued == 2) { /* fast path */
2329bd78278bSGarrett D'Amore 
23307c478bd9Sstevel@tonic-gate 			/*
23317c478bd9Sstevel@tonic-gate 			 * Hang out/Initialize descriptors and buffers.
23327c478bd9Sstevel@tonic-gate 			 */
23337c478bd9Sstevel@tonic-gate 			eri_init_txbufs(erip);
23347c478bd9Sstevel@tonic-gate 
23357c478bd9Sstevel@tonic-gate 			eri_update_rxbufs(erip);
23367c478bd9Sstevel@tonic-gate 		} else {
23377c478bd9Sstevel@tonic-gate 			init_stat = eri_allocthings(erip);
23387c478bd9Sstevel@tonic-gate 			if (init_stat)
23397c478bd9Sstevel@tonic-gate 				goto done;
23407c478bd9Sstevel@tonic-gate 
23417c478bd9Sstevel@tonic-gate 			if (eri_freebufs(erip))
23427c478bd9Sstevel@tonic-gate 				goto done;
23437c478bd9Sstevel@tonic-gate 			/*
23447c478bd9Sstevel@tonic-gate 			 * Hang out/Initialize descriptors and buffers.
23457c478bd9Sstevel@tonic-gate 			 */
23467c478bd9Sstevel@tonic-gate 			eri_init_txbufs(erip);
23477c478bd9Sstevel@tonic-gate 			if (eri_init_rxbufs(erip))
23487c478bd9Sstevel@tonic-gate 				goto done;
23497c478bd9Sstevel@tonic-gate 		}
23507c478bd9Sstevel@tonic-gate 	}
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate 	/*
23537c478bd9Sstevel@tonic-gate 	 * BigMAC requires that we confirm that tx, rx and hash are in
23547c478bd9Sstevel@tonic-gate 	 * quiescent state.
23557c478bd9Sstevel@tonic-gate 	 * MAC will not reset successfully if the transceiver is not reset and
23567c478bd9Sstevel@tonic-gate 	 * brought out of Isolate mode correctly. TXMAC reset may fail if the
23577c478bd9Sstevel@tonic-gate 	 * ext. transceiver is just disconnected. If it fails, try again by
23587c478bd9Sstevel@tonic-gate 	 * checking the transceiver.
23597c478bd9Sstevel@tonic-gate 	 */
23607c478bd9Sstevel@tonic-gate 	if (eri_txmac_disable(erip)) {
23617c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
2362d64540e3Sgd 		    disable_txmac_msg);
23637c478bd9Sstevel@tonic-gate 		param_linkup = 0;	/* force init again */
2364d64540e3Sgd 		erip->stats.link_up = LINK_STATE_DOWN;
2365d64540e3Sgd 		erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
2366d64540e3Sgd 		linkupdate = LINK_STATE_DOWN;
23677c478bd9Sstevel@tonic-gate 		goto done;
23687c478bd9Sstevel@tonic-gate 	}
23697c478bd9Sstevel@tonic-gate 
23707c478bd9Sstevel@tonic-gate 	if (eri_rxmac_disable(erip)) {
23717c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
2372d64540e3Sgd 		    disable_rxmac_msg);
23737c478bd9Sstevel@tonic-gate 		param_linkup = 0;	/* force init again */
2374d64540e3Sgd 		erip->stats.link_up = LINK_STATE_DOWN;
2375d64540e3Sgd 		erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
2376d64540e3Sgd 		linkupdate = LINK_STATE_DOWN;
23777c478bd9Sstevel@tonic-gate 		goto done;
23787c478bd9Sstevel@tonic-gate 	}
23797c478bd9Sstevel@tonic-gate 
23807c478bd9Sstevel@tonic-gate 	eri_init_macregs_generic(erip);
23817c478bd9Sstevel@tonic-gate 
23827c478bd9Sstevel@tonic-gate 	/*
23837c478bd9Sstevel@tonic-gate 	 * Initialize ERI Global registers :
23847c478bd9Sstevel@tonic-gate 	 * config
23857c478bd9Sstevel@tonic-gate 	 * For PCI :  err_mask, bif_cfg
23867c478bd9Sstevel@tonic-gate 	 *
23877c478bd9Sstevel@tonic-gate 	 * Use user-configurable parameter for enabling 64-bit transfers.
23887c478bd9Sstevel@tonic-gate 	 * Note:For PCI, burst sizes are in multiples of 64-bytes.
23897c478bd9Sstevel@tonic-gate 	 */
23907c478bd9Sstevel@tonic-gate 
23917c478bd9Sstevel@tonic-gate 	/*
23927c478bd9Sstevel@tonic-gate 	 * Significant performance improvements can be achieved by
23937c478bd9Sstevel@tonic-gate 	 * disabling transmit interrupt. Thus TMD's are reclaimed
23947c478bd9Sstevel@tonic-gate 	 * only very infrequently.
23957c478bd9Sstevel@tonic-gate 	 * The PCS Interrupt is masked here. It is enabled only when
23967c478bd9Sstevel@tonic-gate 	 * a PCS link is brought up because there is no second level
23977c478bd9Sstevel@tonic-gate 	 * mask for this interrupt..
23987c478bd9Sstevel@tonic-gate 	 * Init GLOBAL, TXMAC, RXMAC and MACCTL interrupt masks here.
23997c478bd9Sstevel@tonic-gate 	 */
24007c478bd9Sstevel@tonic-gate 	if (! partial_init) {
24017c478bd9Sstevel@tonic-gate 		PUT_GLOBREG(intmask, ERI_G_MASK_INTR);
24027c478bd9Sstevel@tonic-gate 		erip->tx_int_me = 0;
24037c478bd9Sstevel@tonic-gate 		PUT_MACREG(txmask, BMAC_TXINTR_MASK);
24047c478bd9Sstevel@tonic-gate 		PUT_MACREG(rxmask, BMAC_RXINTR_MASK);
24057c478bd9Sstevel@tonic-gate 		PUT_MACREG(macctl_mask, ERI_MACCTL_INTR_MASK);
24067c478bd9Sstevel@tonic-gate 	}
24077c478bd9Sstevel@tonic-gate 
24087c478bd9Sstevel@tonic-gate 	if (erip->global_reset_issued) {
24097c478bd9Sstevel@tonic-gate 		/*
24107c478bd9Sstevel@tonic-gate 		 * Initialize ETX Registers:
24117c478bd9Sstevel@tonic-gate 		 * config, txring_lo, txring_hi
24127c478bd9Sstevel@tonic-gate 		 */
24137c478bd9Sstevel@tonic-gate 		if (eri_init_txregs(erip))
2414d64540e3Sgd 			goto done;
24157c478bd9Sstevel@tonic-gate 		/*
24167c478bd9Sstevel@tonic-gate 		 * Initialize ERX Registers:
24177c478bd9Sstevel@tonic-gate 		 * rxring_lo, rxring_hi, config, rx_blanking,
24187c478bd9Sstevel@tonic-gate 		 * rx_pause_threshold.  Also, rx_kick
24197c478bd9Sstevel@tonic-gate 		 * Read and save rxfifo_size.
24207c478bd9Sstevel@tonic-gate 		 */
24217c478bd9Sstevel@tonic-gate 		if (eri_init_rxregs(erip))
24227c478bd9Sstevel@tonic-gate 			goto done;
24237c478bd9Sstevel@tonic-gate 	}
24247c478bd9Sstevel@tonic-gate 
24257c478bd9Sstevel@tonic-gate 	PUT_MACREG(macctl_mask, ERI_MACCTL_INTR_MASK);
24267c478bd9Sstevel@tonic-gate 
24277c478bd9Sstevel@tonic-gate 	/*
24287c478bd9Sstevel@tonic-gate 	 * Set up the slottime,and  rxconfig, txconfig without enabling
24297c478bd9Sstevel@tonic-gate 	 * the latter two at this time
24307c478bd9Sstevel@tonic-gate 	 */
24317c478bd9Sstevel@tonic-gate 	PUT_MACREG(slot, BMAC_SLOT_TIME);
24327c478bd9Sstevel@tonic-gate 	carrier_ext = 0;
24337c478bd9Sstevel@tonic-gate 
24347c478bd9Sstevel@tonic-gate #ifdef ERI_DONT_STRIP_CRC
24357c478bd9Sstevel@tonic-gate 	PUT_MACREG(rxcfg,
2436d64540e3Sgd 	    ((erip->promisc ? BMAC_RXCFG_PROMIS : 0) |
2437d64540e3Sgd 	    (erip->multi_refcnt ? BMAC_RXCFG_HASH : 0) |
24387c478bd9Sstevel@tonic-gate 	    (carrier_ext ? BMAC_RXCFG_CARR_EXT : 0)));
24397c478bd9Sstevel@tonic-gate #else
24407c478bd9Sstevel@tonic-gate 	PUT_MACREG(rxcfg,
2441d64540e3Sgd 	    ((erip->promisc ? BMAC_RXCFG_PROMIS : 0) |
2442d64540e3Sgd 	    (erip->multi_refcnt ? BMAC_RXCFG_HASH : 0) |
24437c478bd9Sstevel@tonic-gate 	    BMAC_RXCFG_STRIP_CRC |
24447c478bd9Sstevel@tonic-gate 	    (carrier_ext ? BMAC_RXCFG_CARR_EXT : 0)));
24457c478bd9Sstevel@tonic-gate #endif
24467c478bd9Sstevel@tonic-gate 	drv_usecwait(10);	/* wait after setting Hash Enable bit */
24477c478bd9Sstevel@tonic-gate 
24487c478bd9Sstevel@tonic-gate 	if (erip->ngu_enable)
24497c478bd9Sstevel@tonic-gate 		PUT_MACREG(txcfg,
24507c478bd9Sstevel@tonic-gate 		    ((param_mode ? BMAC_TXCFG_FDX: 0) |
24517c478bd9Sstevel@tonic-gate 		    ((param_lance_mode && (erip->lance_mode_enable)) ?
24527c478bd9Sstevel@tonic-gate 		    BMAC_TXCFG_ENIPG0 : 0) |
24537c478bd9Sstevel@tonic-gate 		    (carrier_ext ? BMAC_TXCFG_CARR_EXT : 0) |
24547c478bd9Sstevel@tonic-gate 		    BMAC_TXCFG_NGU));
24557c478bd9Sstevel@tonic-gate 	else
24567c478bd9Sstevel@tonic-gate 		PUT_MACREG(txcfg,
24577c478bd9Sstevel@tonic-gate 		    ((param_mode ? BMAC_TXCFG_FDX: 0) |
24587c478bd9Sstevel@tonic-gate 		    ((param_lance_mode && (erip->lance_mode_enable)) ?
24597c478bd9Sstevel@tonic-gate 		    BMAC_TXCFG_ENIPG0 : 0) |
24607c478bd9Sstevel@tonic-gate 		    (carrier_ext ? BMAC_TXCFG_CARR_EXT : 0)));
24617c478bd9Sstevel@tonic-gate 
24627c478bd9Sstevel@tonic-gate 	if (erip->pauseRX)
24637c478bd9Sstevel@tonic-gate 		mac_ctl = ERI_MCTLCFG_RXPAUSE;
24647c478bd9Sstevel@tonic-gate 	if (erip->pauseTX)
24657c478bd9Sstevel@tonic-gate 		mac_ctl |= ERI_MCTLCFG_TXPAUSE;
24667c478bd9Sstevel@tonic-gate 
24677c478bd9Sstevel@tonic-gate 	PUT_MACREG(macctl_cfg, mac_ctl);
24687c478bd9Sstevel@tonic-gate 
24697c478bd9Sstevel@tonic-gate 	/*
24707c478bd9Sstevel@tonic-gate 	 * Must be Internal Transceiver
24717c478bd9Sstevel@tonic-gate 	 */
24727c478bd9Sstevel@tonic-gate 	if (param_mode)
24737c478bd9Sstevel@tonic-gate 		PUT_MACREG(xifc, ((param_transceiver == EXTERNAL_XCVR ?
24747c478bd9Sstevel@tonic-gate 		    BMAC_XIFC_MIIBUF_OE : 0) | BMAC_XIFC_TX_MII_OE));
24757c478bd9Sstevel@tonic-gate 	else {
24767c478bd9Sstevel@tonic-gate 		PUT_MACREG(xifc, ((param_transceiver == EXTERNAL_XCVR ?
24777c478bd9Sstevel@tonic-gate 		    BMAC_XIFC_MIIBUF_OE : 0) | BMAC_XIFC_TX_MII_OE |
24787c478bd9Sstevel@tonic-gate 		    BMAC_XIFC_DIS_ECHO));
24797c478bd9Sstevel@tonic-gate 
24807c478bd9Sstevel@tonic-gate 		link_timeout = ERI_CHECK_HANG_TIMER;
24817c478bd9Sstevel@tonic-gate 	}
24827c478bd9Sstevel@tonic-gate 
24837c478bd9Sstevel@tonic-gate 	/*
24847c478bd9Sstevel@tonic-gate 	 * if MAC int loopback flag is set, put xifc reg in mii loopback
24857c478bd9Sstevel@tonic-gate 	 * mode {DIAG}
24867c478bd9Sstevel@tonic-gate 	 */
24877c478bd9Sstevel@tonic-gate 	if (erip->flags & ERI_MACLOOPBACK) {
24887c478bd9Sstevel@tonic-gate 		PUT_MACREG(xifc, GET_MACREG(xifc) | BMAC_XIFC_MIILPBK);
24897c478bd9Sstevel@tonic-gate 	}
24907c478bd9Sstevel@tonic-gate 
24917c478bd9Sstevel@tonic-gate 	/*
24927c478bd9Sstevel@tonic-gate 	 * Enable TX and RX MACs.
24937c478bd9Sstevel@tonic-gate 	 */
24947c478bd9Sstevel@tonic-gate 	ENABLE_MAC(erip);
24957c478bd9Sstevel@tonic-gate 	erip->flags |= (ERI_RUNNING | ERI_INITIALIZED |
2496d64540e3Sgd 	    ERI_TXINIT | ERI_RXINIT);
2497d64540e3Sgd 	mac_tx_update(erip->mh);
24987c478bd9Sstevel@tonic-gate 	erip->global_reset_issued = 0;
24997c478bd9Sstevel@tonic-gate 
25007c478bd9Sstevel@tonic-gate #ifdef	ERI_10_10_FORCE_SPEED_WORKAROUND
25017c478bd9Sstevel@tonic-gate 	eri_xcvr_force_mode(erip, &link_timeout);
25027c478bd9Sstevel@tonic-gate #endif
25037c478bd9Sstevel@tonic-gate 
25047c478bd9Sstevel@tonic-gate done:
25057c478bd9Sstevel@tonic-gate 	if (init_stat)
25067c478bd9Sstevel@tonic-gate 		eri_unallocthings(erip);
25077c478bd9Sstevel@tonic-gate 
25087c478bd9Sstevel@tonic-gate 	mutex_exit(&erip->xmitlock);
25097c478bd9Sstevel@tonic-gate 	eri_start_timer(erip, eri_check_link, link_timeout);
25107c478bd9Sstevel@tonic-gate 	mutex_exit(&erip->intrlock);
25117c478bd9Sstevel@tonic-gate 
2512d64540e3Sgd 	if (linkupdate != LINK_STATE_UNKNOWN)
2513d64540e3Sgd 		mac_link_update(erip->mh, linkupdate);
2514860c4cd4Scarlsonj 
2515d64540e3Sgd 	ret = (erip->flags & ERI_RUNNING) ? B_TRUE : B_FALSE;
2516d64540e3Sgd 	if (!ret) {
25177c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
2518d64540e3Sgd 		    "eri_init failed");
25197c478bd9Sstevel@tonic-gate 	}
25207c478bd9Sstevel@tonic-gate 
25217c478bd9Sstevel@tonic-gate init_exit:
25227c478bd9Sstevel@tonic-gate 	ASSERT(!MUTEX_HELD(&erip->linklock));
25237c478bd9Sstevel@tonic-gate 	return (ret);
25247c478bd9Sstevel@tonic-gate }
25257c478bd9Sstevel@tonic-gate 
25267c478bd9Sstevel@tonic-gate /*
25277c478bd9Sstevel@tonic-gate  * 0 as burstsize upon failure as it signifies no burst size.
25287c478bd9Sstevel@tonic-gate  */
25297c478bd9Sstevel@tonic-gate static int
eri_burstsize(struct eri * erip)25307c478bd9Sstevel@tonic-gate eri_burstsize(struct eri *erip)
25317c478bd9Sstevel@tonic-gate {
25327c478bd9Sstevel@tonic-gate 	ddi_dma_handle_t handle;
25337c478bd9Sstevel@tonic-gate 
2534d64540e3Sgd 	if (ddi_dma_alloc_handle(erip->dip, &dma_attr, DDI_DMA_DONTWAIT,
2535d64540e3Sgd 	    NULL, &handle))
25367c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
25377c478bd9Sstevel@tonic-gate 
25387c478bd9Sstevel@tonic-gate 	erip->burstsizes = ddi_dma_burstsizes(handle);
25397c478bd9Sstevel@tonic-gate 	ddi_dma_free_handle(&handle);
25407c478bd9Sstevel@tonic-gate 
25417c478bd9Sstevel@tonic-gate 	if (erip->burstsizes)
25427c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
25437c478bd9Sstevel@tonic-gate 
25447c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
25457c478bd9Sstevel@tonic-gate }
25467c478bd9Sstevel@tonic-gate 
25477c478bd9Sstevel@tonic-gate /*
25487c478bd9Sstevel@tonic-gate  * Un-initialize (STOP) ERI channel.
25497c478bd9Sstevel@tonic-gate  */
25507c478bd9Sstevel@tonic-gate static void
eri_uninit(struct eri * erip)25517c478bd9Sstevel@tonic-gate eri_uninit(struct eri *erip)
25527c478bd9Sstevel@tonic-gate {
2553860c4cd4Scarlsonj 	boolean_t needind;
2554860c4cd4Scarlsonj 
25557c478bd9Sstevel@tonic-gate 	/*
25567c478bd9Sstevel@tonic-gate 	 * Allow up to 'ERI_DRAINTIME' for pending xmit's to complete.
25577c478bd9Sstevel@tonic-gate 	 */
25587c478bd9Sstevel@tonic-gate 	ERI_DELAY((erip->tcurp == erip->tnextp), ERI_DRAINTIME);
25597c478bd9Sstevel@tonic-gate 
25607c478bd9Sstevel@tonic-gate 	mutex_enter(&erip->intrlock);
25617c478bd9Sstevel@tonic-gate 	eri_stop_timer(erip);   /* acquire linklock */
25627c478bd9Sstevel@tonic-gate 	mutex_enter(&erip->xmitlock);
25637c478bd9Sstevel@tonic-gate 	mutex_enter(&erip->xcvrlock);
25647c478bd9Sstevel@tonic-gate 	eri_mif_poll(erip, MIF_POLL_STOP);
25657c478bd9Sstevel@tonic-gate 	erip->flags &= ~ERI_DLPI_LINKUP;
25667c478bd9Sstevel@tonic-gate 	mutex_exit(&erip->xcvrlock);
25677c478bd9Sstevel@tonic-gate 
2568860c4cd4Scarlsonj 	needind = !erip->linkcheck;
25697c478bd9Sstevel@tonic-gate 	(void) eri_stop(erip);
25707c478bd9Sstevel@tonic-gate 	erip->flags &= ~ERI_RUNNING;
25717c478bd9Sstevel@tonic-gate 
25727c478bd9Sstevel@tonic-gate 	mutex_exit(&erip->xmitlock);
25737c478bd9Sstevel@tonic-gate 	eri_start_timer(erip, eri_check_link, 0);
25747c478bd9Sstevel@tonic-gate 	mutex_exit(&erip->intrlock);
2575860c4cd4Scarlsonj 
2576860c4cd4Scarlsonj 	if (needind)
2577d64540e3Sgd 		mac_link_update(erip->mh, LINK_STATE_DOWN);
25787c478bd9Sstevel@tonic-gate }
25797c478bd9Sstevel@tonic-gate 
25807c478bd9Sstevel@tonic-gate /*
25817c478bd9Sstevel@tonic-gate  * Allocate CONSISTENT memory for rmds and tmds with appropriate alignment and
25827c478bd9Sstevel@tonic-gate  * map it in IO space.
25837c478bd9Sstevel@tonic-gate  *
25847c478bd9Sstevel@tonic-gate  * The driver allocates STREAMS buffers which will be mapped in DVMA
25857c478bd9Sstevel@tonic-gate  * space using DDI DMA resources.
25867c478bd9Sstevel@tonic-gate  *
25877c478bd9Sstevel@tonic-gate  */
25887c478bd9Sstevel@tonic-gate static int
eri_allocthings(struct eri * erip)25897c478bd9Sstevel@tonic-gate eri_allocthings(struct eri *erip)
25907c478bd9Sstevel@tonic-gate {
25917c478bd9Sstevel@tonic-gate 
25927c478bd9Sstevel@tonic-gate 	uintptr_t	a;
25937c478bd9Sstevel@tonic-gate 	int		size;
25947c478bd9Sstevel@tonic-gate 	uint32_t	rval;
25957c478bd9Sstevel@tonic-gate 	int		i;
25967c478bd9Sstevel@tonic-gate 	size_t		real_len;
25977c478bd9Sstevel@tonic-gate 	uint32_t	cookiec;
25987c478bd9Sstevel@tonic-gate 	int		alloc_stat = 0;
25997c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t dma_cookie;
26007c478bd9Sstevel@tonic-gate 
26017c478bd9Sstevel@tonic-gate 	/*
26027c478bd9Sstevel@tonic-gate 	 * Return if resources are already allocated.
26037c478bd9Sstevel@tonic-gate 	 */
26047c478bd9Sstevel@tonic-gate 	if (erip->rmdp)
26057c478bd9Sstevel@tonic-gate 		return (alloc_stat);
26067c478bd9Sstevel@tonic-gate 
26077c478bd9Sstevel@tonic-gate 	erip->alloc_flag = 0;
26087c478bd9Sstevel@tonic-gate 
26097c478bd9Sstevel@tonic-gate 	/*
26107c478bd9Sstevel@tonic-gate 	 * Allocate the TMD and RMD descriptors and extra for alignments.
26117c478bd9Sstevel@tonic-gate 	 */
2612d64540e3Sgd 	size = (ERI_RPENDING * sizeof (struct rmd) +
2613d64540e3Sgd 	    ERI_TPENDING * sizeof (struct eri_tmd)) + ERI_GMDALIGN;
26147c478bd9Sstevel@tonic-gate 
26157c478bd9Sstevel@tonic-gate 	rval = ddi_dma_alloc_handle(erip->dip, &desc_dma_attr,
2616d64540e3Sgd 	    DDI_DMA_DONTWAIT, 0, &erip->md_h);
26177c478bd9Sstevel@tonic-gate 	if (rval != DDI_SUCCESS) {
26187c478bd9Sstevel@tonic-gate 		return (++alloc_stat);
26197c478bd9Sstevel@tonic-gate 	}
26207c478bd9Sstevel@tonic-gate 	erip->alloc_flag |= ERI_DESC_HANDLE_ALLOC;
26217c478bd9Sstevel@tonic-gate 
26227c478bd9Sstevel@tonic-gate 	rval = ddi_dma_mem_alloc(erip->md_h, size, &erip->dev_attr,
2623d64540e3Sgd 	    DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, 0,
2624d64540e3Sgd 	    (caddr_t *)&erip->iopbkbase, &real_len, &erip->mdm_h);
26257c478bd9Sstevel@tonic-gate 	if (rval != DDI_SUCCESS) {
26267c478bd9Sstevel@tonic-gate 		return (++alloc_stat);
26277c478bd9Sstevel@tonic-gate 	}
26287c478bd9Sstevel@tonic-gate 	erip->alloc_flag |= ERI_DESC_MEM_ALLOC;
26297c478bd9Sstevel@tonic-gate 
26307c478bd9Sstevel@tonic-gate 	rval = ddi_dma_addr_bind_handle(erip->md_h, NULL,
2631d64540e3Sgd 	    (caddr_t)erip->iopbkbase, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
2632d64540e3Sgd 	    DDI_DMA_DONTWAIT, 0, &erip->md_c, &cookiec);
26337c478bd9Sstevel@tonic-gate 
26347c478bd9Sstevel@tonic-gate 	if (rval != DDI_DMA_MAPPED)
26357c478bd9Sstevel@tonic-gate 		return (++alloc_stat);
26367c478bd9Sstevel@tonic-gate 
26377c478bd9Sstevel@tonic-gate 	erip->alloc_flag |= ERI_DESC_MEM_MAP;
26387c478bd9Sstevel@tonic-gate 
26397c478bd9Sstevel@tonic-gate 	if (cookiec != 1)
26407c478bd9Sstevel@tonic-gate 		return (++alloc_stat);
26417c478bd9Sstevel@tonic-gate 
26427c478bd9Sstevel@tonic-gate 	erip->iopbiobase = erip->md_c.dmac_address;
26437c478bd9Sstevel@tonic-gate 
26447c478bd9Sstevel@tonic-gate 	a = erip->iopbkbase;
26457c478bd9Sstevel@tonic-gate 	a = ROUNDUP(a, ERI_GMDALIGN);
26467c478bd9Sstevel@tonic-gate 	erip->rmdp = (struct rmd *)a;
26477c478bd9Sstevel@tonic-gate 	a += ERI_RPENDING * sizeof (struct rmd);
26487c478bd9Sstevel@tonic-gate 	erip->eri_tmdp = (struct eri_tmd *)a;
2649*7e996435SToomas Soome 	/*
2650*7e996435SToomas Soome 	 * Specifically we reserve n (ERI_TPENDING + ERI_RPENDING)
2651*7e996435SToomas Soome 	 * pagetable entries. Therefore we have 2 ptes for each
2652*7e996435SToomas Soome 	 * descriptor. Since the ethernet buffers are 1518 bytes
2653*7e996435SToomas Soome 	 * so they can at most use 2 ptes.
2654*7e996435SToomas Soome 	 * Will do a ddi_dma_addr_setup for each bufer
2655*7e996435SToomas Soome 	 */
26567c478bd9Sstevel@tonic-gate 	/*
26577c478bd9Sstevel@tonic-gate 	 * 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.
26617c478bd9Sstevel@tonic-gate 	 * Dma resources are deallocated by calling ddi_dma_unbind_handle
26627c478bd9Sstevel@tonic-gate 	 * in eri_reclaim() for transmit and eri_read_dma(), for receive io.
26637c478bd9Sstevel@tonic-gate 	 */
26647c478bd9Sstevel@tonic-gate 
26657c478bd9Sstevel@tonic-gate 	if (eri_use_dvma_rx &&
26667c478bd9Sstevel@tonic-gate 	    (dvma_reserve(erip->dip, &eri_dma_limits, (ERI_RPENDING * 2),
26677c478bd9Sstevel@tonic-gate 	    &erip->eri_dvmarh)) == DDI_SUCCESS) {
26687c478bd9Sstevel@tonic-gate 		erip->alloc_flag |= ERI_RCV_DVMA_ALLOC;
26697c478bd9Sstevel@tonic-gate 	} else {
26707c478bd9Sstevel@tonic-gate 		erip->eri_dvmarh = NULL;
26717c478bd9Sstevel@tonic-gate 
26727c478bd9Sstevel@tonic-gate 		for (i = 0; i < ERI_RPENDING; i++) {
26737c478bd9Sstevel@tonic-gate 			rval = ddi_dma_alloc_handle(erip->dip,
26747c478bd9Sstevel@tonic-gate 			    &dma_attr, DDI_DMA_DONTWAIT,
26757c478bd9Sstevel@tonic-gate 			    0, &erip->ndmarh[i]);
26767c478bd9Sstevel@tonic-gate 
26777c478bd9Sstevel@tonic-gate 			if (rval != DDI_SUCCESS) {
26787c478bd9Sstevel@tonic-gate 				ERI_FAULT_MSG1(erip, SEVERITY_HIGH,
26797c478bd9Sstevel@tonic-gate 				    ERI_VERB_MSG, alloc_rx_dmah_msg);
26807c478bd9Sstevel@tonic-gate 				alloc_stat++;
26817c478bd9Sstevel@tonic-gate 				break;
26827c478bd9Sstevel@tonic-gate 			}
26837c478bd9Sstevel@tonic-gate 		}
26847c478bd9Sstevel@tonic-gate 
26857c478bd9Sstevel@tonic-gate 		erip->rcv_handle_cnt = i;
26867c478bd9Sstevel@tonic-gate 
26877c478bd9Sstevel@tonic-gate 		if (i)
26887c478bd9Sstevel@tonic-gate 			erip->alloc_flag |= ERI_RCV_HANDLE_ALLOC;
26897c478bd9Sstevel@tonic-gate 
26907c478bd9Sstevel@tonic-gate 		if (alloc_stat)
26917c478bd9Sstevel@tonic-gate 			return (alloc_stat);
26927c478bd9Sstevel@tonic-gate 
26937c478bd9Sstevel@tonic-gate 	}
26947c478bd9Sstevel@tonic-gate 
26957c478bd9Sstevel@tonic-gate /*
2696bd78278bSGarrett D'Amore  *	Allocate TX buffer
2697bd78278bSGarrett D'Amore  *	Note: buffers must always be allocated in the native
26987c478bd9Sstevel@tonic-gate  *	ordering of the CPU (always big-endian for Sparc).
26997c478bd9Sstevel@tonic-gate  *	ddi_dma_mem_alloc returns memory in the native ordering
27007c478bd9Sstevel@tonic-gate  *	of the bus (big endian for SBus, little endian for PCI).
27017c478bd9Sstevel@tonic-gate  *	So we cannot use ddi_dma_mem_alloc(, &erip->ge_dev_attr)
27027c478bd9Sstevel@tonic-gate  *	because we'll get little endian memory on PCI.
27037c478bd9Sstevel@tonic-gate  */
2704d64540e3Sgd 	if (ddi_dma_alloc_handle(erip->dip, &desc_dma_attr, DDI_DMA_DONTWAIT,
2705d64540e3Sgd 	    0, &erip->tbuf_handle) != DDI_SUCCESS) {
2706d64540e3Sgd 		ERI_FAULT_MSG1(erip, SEVERITY_HIGH, ERI_VERB_MSG,
2707d64540e3Sgd 		    alloc_tx_dmah_msg);
2708d64540e3Sgd 		return (++alloc_stat);
27097c478bd9Sstevel@tonic-gate 	}
27107c478bd9Sstevel@tonic-gate 	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) {
27157c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG1(erip, SEVERITY_HIGH, ERI_VERB_MSG,
2716d64540e3Sgd 		    alloc_tx_dmah_msg);
27177c478bd9Sstevel@tonic-gate 		return (++alloc_stat);
27187c478bd9Sstevel@tonic-gate 	}
27197c478bd9Sstevel@tonic-gate 	erip->alloc_flag |= ERI_XBUFS_KMEM_ALLOC;
27207c478bd9Sstevel@tonic-gate 	if (ddi_dma_addr_bind_handle(erip->tbuf_handle, NULL,
2721d64540e3Sgd 	    erip->tbuf_kaddr, size, DDI_DMA_WRITE | DDI_DMA_CONSISTENT,
2722d64540e3Sgd 	    DDI_DMA_DONTWAIT, 0, &dma_cookie, &cookiec) != DDI_DMA_MAPPED) {
27237c478bd9Sstevel@tonic-gate 			return (++alloc_stat);
27247c478bd9Sstevel@tonic-gate 	}
27257c478bd9Sstevel@tonic-gate 	erip->tbuf_ioaddr = dma_cookie.dmac_address;
27267c478bd9Sstevel@tonic-gate 	erip->alloc_flag |= ERI_XBUFS_KMEM_DMABIND;
27277c478bd9Sstevel@tonic-gate 	if (cookiec != 1)
27287c478bd9Sstevel@tonic-gate 		return (++alloc_stat);
27297c478bd9Sstevel@tonic-gate 
27307c478bd9Sstevel@tonic-gate 	/*
27317c478bd9Sstevel@tonic-gate 	 * Keep handy limit values for RMD, TMD, and Buffers.
27327c478bd9Sstevel@tonic-gate 	 */
27337c478bd9Sstevel@tonic-gate 	erip->rmdlimp = &((erip->rmdp)[ERI_RPENDING]);
27347c478bd9Sstevel@tonic-gate 	erip->eri_tmdlimp = &((erip->eri_tmdp)[ERI_TPENDING]);
27357c478bd9Sstevel@tonic-gate 
27367c478bd9Sstevel@tonic-gate 	/*
2737bd78278bSGarrett D'Amore 	 * Zero out RCV holders.
27387c478bd9Sstevel@tonic-gate 	 */
27397c478bd9Sstevel@tonic-gate 	bzero((caddr_t)erip->rmblkp, sizeof (erip->rmblkp));
27407c478bd9Sstevel@tonic-gate 	return (alloc_stat);
27417c478bd9Sstevel@tonic-gate }
27427c478bd9Sstevel@tonic-gate 
27437c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<	INTERRUPT HANDLING FUNCTION	>>>>>>>>>>>>>>>>>>>> */
27447c478bd9Sstevel@tonic-gate /*
27457c478bd9Sstevel@tonic-gate  *	First check to see if it is our device interrupting.
27467c478bd9Sstevel@tonic-gate  */
27477c478bd9Sstevel@tonic-gate static uint_t
eri_intr(caddr_t arg)2748d64540e3Sgd eri_intr(caddr_t arg)
27497c478bd9Sstevel@tonic-gate {
2750d64540e3Sgd 	struct eri *erip = (void *)arg;
27517c478bd9Sstevel@tonic-gate 	uint32_t erisbits;
27527c478bd9Sstevel@tonic-gate 	uint32_t mif_status;
27537c478bd9Sstevel@tonic-gate 	uint32_t serviced = DDI_INTR_UNCLAIMED;
2754d64540e3Sgd 	link_state_t linkupdate = LINK_STATE_UNKNOWN;
2755d64540e3Sgd 	boolean_t macupdate = B_FALSE;
2756d64540e3Sgd 	mblk_t *mp;
2757d64540e3Sgd 	mblk_t *head;
2758d64540e3Sgd 	mblk_t **tail;
2759d64540e3Sgd 
2760d64540e3Sgd 	head = NULL;
2761d64540e3Sgd 	tail = &head;
2762860c4cd4Scarlsonj 
27637c478bd9Sstevel@tonic-gate 	mutex_enter(&erip->intrlock);
27647c478bd9Sstevel@tonic-gate 
27657c478bd9Sstevel@tonic-gate 	erisbits = GET_GLOBREG(status);
27667c478bd9Sstevel@tonic-gate 
27677c478bd9Sstevel@tonic-gate 	/*
27687c478bd9Sstevel@tonic-gate 	 * Check if it is only the RX_DONE interrupt, which is
27697c478bd9Sstevel@tonic-gate 	 * the most frequent one.
27707c478bd9Sstevel@tonic-gate 	 */
27717c478bd9Sstevel@tonic-gate 	if (((erisbits & ERI_G_STATUS_RX_INT) == ERI_G_STATUS_RX_DONE) &&
2772d64540e3Sgd 	    (erip->flags & ERI_RUNNING)) {
27737c478bd9Sstevel@tonic-gate 		serviced = DDI_INTR_CLAIMED;
27747c478bd9Sstevel@tonic-gate 		goto rx_done_int;
27757c478bd9Sstevel@tonic-gate 	}
27767c478bd9Sstevel@tonic-gate 
27777c478bd9Sstevel@tonic-gate 	/* Claim the first interrupt after initialization */
27787c478bd9Sstevel@tonic-gate 	if (erip->flags & ERI_INITIALIZED) {
27797c478bd9Sstevel@tonic-gate 		erip->flags &= ~ERI_INITIALIZED;
27807c478bd9Sstevel@tonic-gate 		serviced = DDI_INTR_CLAIMED;
27817c478bd9Sstevel@tonic-gate 	}
27827c478bd9Sstevel@tonic-gate 
27837c478bd9Sstevel@tonic-gate 	/* Check for interesting events */
27847c478bd9Sstevel@tonic-gate 	if ((erisbits & ERI_G_STATUS_INTR) == 0) {
2785860c4cd4Scarlsonj #ifdef	ESTAR_WORKAROUND
2786d64540e3Sgd 		uint32_t linkupdate;
2787860c4cd4Scarlsonj #endif
2788860c4cd4Scarlsonj 
27897c478bd9Sstevel@tonic-gate 		ERI_DEBUG_MSG2(erip, DIAG_MSG,
2790d64540e3Sgd 		    "eri_intr: Interrupt Not Claimed gsbits  %X", erisbits);
27917c478bd9Sstevel@tonic-gate #ifdef	DEBUG
27927c478bd9Sstevel@tonic-gate 		noteri++;
27937c478bd9Sstevel@tonic-gate #endif
2794d64540e3Sgd 		ERI_DEBUG_MSG2(erip, DIAG_MSG, "eri_intr:MIF Config = 0x%X",
2795d64540e3Sgd 		    GET_MIFREG(mif_cfg));
2796d64540e3Sgd 		ERI_DEBUG_MSG2(erip, DIAG_MSG, "eri_intr:MIF imask = 0x%X",
2797d64540e3Sgd 		    GET_MIFREG(mif_imask));
2798d64540e3Sgd 		ERI_DEBUG_MSG2(erip, DIAG_MSG, "eri_intr:INT imask = 0x%X",
2799d64540e3Sgd 		    GET_GLOBREG(intmask));
2800d64540e3Sgd 		ERI_DEBUG_MSG2(erip, DIAG_MSG, "eri_intr:alias %X",
2801d64540e3Sgd 		    GET_GLOBREG(status_alias));
28027c478bd9Sstevel@tonic-gate #ifdef	ESTAR_WORKAROUND
2803d64540e3Sgd 		linkupdate = eri_check_link_noind(erip);
28047c478bd9Sstevel@tonic-gate #endif
28057c478bd9Sstevel@tonic-gate 		mutex_exit(&erip->intrlock);
2806860c4cd4Scarlsonj #ifdef	ESTAR_WORKAROUND
2807d64540e3Sgd 		if (linkupdate != LINK_STATE_UNKNOWN)
2808d64540e3Sgd 			mac_link_update(erip->mh, linkupdate);
2809860c4cd4Scarlsonj #endif
28107c478bd9Sstevel@tonic-gate 		return (serviced);
28117c478bd9Sstevel@tonic-gate 	}
28127c478bd9Sstevel@tonic-gate 	serviced = DDI_INTR_CLAIMED;
28137c478bd9Sstevel@tonic-gate 
28147c478bd9Sstevel@tonic-gate 	if (!(erip->flags & ERI_RUNNING)) {
28157c478bd9Sstevel@tonic-gate 		mutex_exit(&erip->intrlock);
28167c478bd9Sstevel@tonic-gate 		eri_uninit(erip);
28177c478bd9Sstevel@tonic-gate 		return (serviced);
28187c478bd9Sstevel@tonic-gate 	}
28197c478bd9Sstevel@tonic-gate 
28207c478bd9Sstevel@tonic-gate 	if (erisbits & ERI_G_STATUS_FATAL_ERR) {
28217c478bd9Sstevel@tonic-gate 		ERI_DEBUG_MSG2(erip, INTR_MSG,
2822d64540e3Sgd 		    "eri_intr: fatal error: erisbits = %X", erisbits);
28237c478bd9Sstevel@tonic-gate 		(void) eri_fatal_err(erip, erisbits);
28247c478bd9Sstevel@tonic-gate 		eri_reinit_fatal++;
28257c478bd9Sstevel@tonic-gate 
28267c478bd9Sstevel@tonic-gate 		if (erip->rx_reset_issued) {
28277c478bd9Sstevel@tonic-gate 			erip->rx_reset_issued = 0;
28287c478bd9Sstevel@tonic-gate 			(void) eri_init_rx_channel(erip);
28297c478bd9Sstevel@tonic-gate 			mutex_exit(&erip->intrlock);
28307c478bd9Sstevel@tonic-gate 		} else {
28317c478bd9Sstevel@tonic-gate 			param_linkup = 0;
2832d64540e3Sgd 			erip->stats.link_up = LINK_STATE_DOWN;
2833d64540e3Sgd 			erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
28347c478bd9Sstevel@tonic-gate 			DISABLE_MAC(erip);
28357c478bd9Sstevel@tonic-gate 			mutex_exit(&erip->intrlock);
28367c478bd9Sstevel@tonic-gate 			(void) eri_init(erip);
28377c478bd9Sstevel@tonic-gate 		}
28387c478bd9Sstevel@tonic-gate 		return (serviced);
28397c478bd9Sstevel@tonic-gate 	}
28407c478bd9Sstevel@tonic-gate 
28417c478bd9Sstevel@tonic-gate 	if (erisbits & ERI_G_STATUS_NONFATAL_ERR) {
28427c478bd9Sstevel@tonic-gate 		ERI_DEBUG_MSG2(erip, INTR_MSG,
2843d64540e3Sgd 		    "eri_intr: non-fatal error: erisbits = %X", erisbits);
28447c478bd9Sstevel@tonic-gate 		(void) eri_nonfatal_err(erip, erisbits);
28457c478bd9Sstevel@tonic-gate 		if (erip->linkcheck) {
28467c478bd9Sstevel@tonic-gate 			mutex_exit(&erip->intrlock);
28477c478bd9Sstevel@tonic-gate 			(void) eri_init(erip);
28487c478bd9Sstevel@tonic-gate 			return (serviced);
28497c478bd9Sstevel@tonic-gate 		}
28507c478bd9Sstevel@tonic-gate 	}
28517c478bd9Sstevel@tonic-gate 
28527c478bd9Sstevel@tonic-gate 	if (erisbits & ERI_G_STATUS_MIF_INT) {
28537c478bd9Sstevel@tonic-gate 		uint16_t stat;
28547c478bd9Sstevel@tonic-gate 		ERI_DEBUG_MSG2(erip, XCVR_MSG,
2855d64540e3Sgd 		    "eri_intr:MIF Interrupt:mii_status %X", erip->mii_status);
28567c478bd9Sstevel@tonic-gate 		eri_stop_timer(erip);   /* acquire linklock */
28577c478bd9Sstevel@tonic-gate 
28587c478bd9Sstevel@tonic-gate 		mutex_enter(&erip->xmitlock);
28597c478bd9Sstevel@tonic-gate 		mutex_enter(&erip->xcvrlock);
28607c478bd9Sstevel@tonic-gate #ifdef	ERI_MIF_POLL_STATUS_WORKAROUND
28617c478bd9Sstevel@tonic-gate 		mif_status = GET_MIFREG(mif_bsts);
28627c478bd9Sstevel@tonic-gate 		eri_mif_poll(erip, MIF_POLL_STOP);
28637c478bd9Sstevel@tonic-gate 		ERI_DEBUG_MSG3(erip, XCVR_MSG,
2864d64540e3Sgd 		    "eri_intr: new MIF interrupt status %X XCVR status %X",
2865d64540e3Sgd 		    mif_status, erip->mii_status);
28667c478bd9Sstevel@tonic-gate 		(void) eri_mii_read(erip, ERI_PHY_BMSR, &stat);
2867d64540e3Sgd 		linkupdate = eri_mif_check(erip, stat, stat);
28687c478bd9Sstevel@tonic-gate 
28697c478bd9Sstevel@tonic-gate #else
28707c478bd9Sstevel@tonic-gate 		mif_status = GET_MIFREG(mif_bsts);
28717c478bd9Sstevel@tonic-gate 		eri_mif_poll(erip, MIF_POLL_STOP);
2872d64540e3Sgd 		linkupdate = eri_mif_check(erip, (uint16_t)mif_status,
2873d64540e3Sgd 		    (uint16_t)(mif_status >> 16));
28747c478bd9Sstevel@tonic-gate #endif
28757c478bd9Sstevel@tonic-gate 		eri_mif_poll(erip, MIF_POLL_START);
28767c478bd9Sstevel@tonic-gate 		mutex_exit(&erip->xcvrlock);
28777c478bd9Sstevel@tonic-gate 		mutex_exit(&erip->xmitlock);
28787c478bd9Sstevel@tonic-gate 
28797c478bd9Sstevel@tonic-gate 		if (!erip->openloop_autoneg)
28807c478bd9Sstevel@tonic-gate 			eri_start_timer(erip, eri_check_link,
2881d64540e3Sgd 			    ERI_LINKCHECK_TIMER);
28827c478bd9Sstevel@tonic-gate 		else
28837c478bd9Sstevel@tonic-gate 			eri_start_timer(erip, eri_check_link,
2884d64540e3Sgd 			    ERI_P_FAULT_TIMER);
28857c478bd9Sstevel@tonic-gate 	}
28867c478bd9Sstevel@tonic-gate 
28877c478bd9Sstevel@tonic-gate 	ERI_DEBUG_MSG2(erip, INTR_MSG,
2888d64540e3Sgd 	    "eri_intr:May have Read Interrupt status:status %X", erisbits);
28897c478bd9Sstevel@tonic-gate 
28907c478bd9Sstevel@tonic-gate rx_done_int:
28917c478bd9Sstevel@tonic-gate 	if ((erisbits & (ERI_G_STATUS_TX_INT_ME)) ||
28927c478bd9Sstevel@tonic-gate 	    (erip->tx_cur_cnt >= tx_interrupt_rate)) {
28937c478bd9Sstevel@tonic-gate 		mutex_enter(&erip->xmitlock);
28947c478bd9Sstevel@tonic-gate 		erip->tx_completion = (uint32_t)(GET_ETXREG(tx_completion) &
28957c478bd9Sstevel@tonic-gate 		    ETX_COMPLETION_MASK);
28967c478bd9Sstevel@tonic-gate 
2897d64540e3Sgd 		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 
29017c478bd9Sstevel@tonic-gate 		mutex_exit(&erip->xmitlock);
29027c478bd9Sstevel@tonic-gate 	}
29037c478bd9Sstevel@tonic-gate 
29047c478bd9Sstevel@tonic-gate 	if (erisbits & ERI_G_STATUS_RX_DONE) {
29057c478bd9Sstevel@tonic-gate 		volatile struct	rmd	*rmdp, *rmdpbase;
29067c478bd9Sstevel@tonic-gate 		volatile uint32_t rmdi;
29077c478bd9Sstevel@tonic-gate 		uint8_t loop_limit = 0x20;
29087c478bd9Sstevel@tonic-gate 		uint64_t flags;
29097c478bd9Sstevel@tonic-gate 		uint32_t rmdmax_mask = erip->rmdmax_mask;
29107c478bd9Sstevel@tonic-gate 
29117c478bd9Sstevel@tonic-gate 		rmdpbase = erip->rmdp;
29127c478bd9Sstevel@tonic-gate 		rmdi = erip->rx_completion;
29137c478bd9Sstevel@tonic-gate 		rmdp = rmdpbase + rmdi;
29147c478bd9Sstevel@tonic-gate 
29157c478bd9Sstevel@tonic-gate 		/*
29167c478bd9Sstevel@tonic-gate 		 * Sync RMD before looking at it.
29177c478bd9Sstevel@tonic-gate 		 */
29187c478bd9Sstevel@tonic-gate 		ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
2919d64540e3Sgd 		    DDI_DMA_SYNC_FORCPU);
29207c478bd9Sstevel@tonic-gate 		/*
29217c478bd9Sstevel@tonic-gate 		 * Loop through each RMD.
29227c478bd9Sstevel@tonic-gate 		 */
29237c478bd9Sstevel@tonic-gate 
29247c478bd9Sstevel@tonic-gate 		flags = GET_RMD_FLAGS(rmdp);
29257c478bd9Sstevel@tonic-gate 		while (((flags & ERI_RMD_OWN) == 0) && (loop_limit)) {
29267c478bd9Sstevel@tonic-gate 			/* process one packet */
2927d64540e3Sgd 			mp = eri_read_dma(erip, rmdp, rmdi, flags);
29287c478bd9Sstevel@tonic-gate 			rmdi =  (rmdi + 1) & rmdmax_mask;
29297c478bd9Sstevel@tonic-gate 			rmdp = rmdpbase + rmdi;
29307c478bd9Sstevel@tonic-gate 
2931d64540e3Sgd 			if (mp != NULL) {
2932d64540e3Sgd 				*tail = mp;
2933d64540e3Sgd 				tail = &mp->b_next;
2934d64540e3Sgd 			}
2935d64540e3Sgd 
29367c478bd9Sstevel@tonic-gate 			/*
29377c478bd9Sstevel@tonic-gate 			 * ERI RCV DMA fetches or updates four descriptors
29387c478bd9Sstevel@tonic-gate 			 * a time. Also we don't want to update the desc.
29397c478bd9Sstevel@tonic-gate 			 * batch we just received packet on. So we update
29407c478bd9Sstevel@tonic-gate 			 * descriptors for every 4 packets and we update
29417c478bd9Sstevel@tonic-gate 			 * the group of 4 after the current batch.
29427c478bd9Sstevel@tonic-gate 			 */
29437c478bd9Sstevel@tonic-gate 
29447c478bd9Sstevel@tonic-gate 			if (!(rmdi % 4)) {
29457c478bd9Sstevel@tonic-gate 				if (eri_overflow_reset &&
29467c478bd9Sstevel@tonic-gate 				    (GET_GLOBREG(status_alias) &
29477c478bd9Sstevel@tonic-gate 				    ERI_G_STATUS_NONFATAL_ERR)) {
29487c478bd9Sstevel@tonic-gate 					loop_limit = 1;
29497c478bd9Sstevel@tonic-gate 				} else {
29507c478bd9Sstevel@tonic-gate 					erip->rx_kick =
2951d64540e3Sgd 					    (rmdi + ERI_RPENDING - 4) &
2952d64540e3Sgd 					    rmdmax_mask;
29537c478bd9Sstevel@tonic-gate 					PUT_ERXREG(rx_kick, erip->rx_kick);
29547c478bd9Sstevel@tonic-gate 				}
29557c478bd9Sstevel@tonic-gate 			}
29567c478bd9Sstevel@tonic-gate 
29577c478bd9Sstevel@tonic-gate 			/*
29587c478bd9Sstevel@tonic-gate 			 * Sync the next RMD before looking at it.
29597c478bd9Sstevel@tonic-gate 			 */
29607c478bd9Sstevel@tonic-gate 			ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
2961d64540e3Sgd 			    DDI_DMA_SYNC_FORCPU);
29627c478bd9Sstevel@tonic-gate 			flags = GET_RMD_FLAGS(rmdp);
29637c478bd9Sstevel@tonic-gate 			loop_limit--;
29647c478bd9Sstevel@tonic-gate 		}
29657c478bd9Sstevel@tonic-gate 		erip->rx_completion = rmdi;
29667c478bd9Sstevel@tonic-gate 	}
2967d64540e3Sgd 
29687c478bd9Sstevel@tonic-gate 	mutex_exit(&erip->intrlock);
29697c478bd9Sstevel@tonic-gate 
2970d64540e3Sgd 	if (head)
2971d64540e3Sgd 		mac_rx(erip->mh, NULL, head);
2972d64540e3Sgd 
2973d64540e3Sgd 	if (macupdate)
2974d64540e3Sgd 		mac_tx_update(erip->mh);
2975d64540e3Sgd 
2976d64540e3Sgd 	if (linkupdate != LINK_STATE_UNKNOWN)
2977d64540e3Sgd 		mac_link_update(erip->mh, linkupdate);
2978860c4cd4Scarlsonj 
29797c478bd9Sstevel@tonic-gate 	return (serviced);
29807c478bd9Sstevel@tonic-gate }
29817c478bd9Sstevel@tonic-gate 
29827c478bd9Sstevel@tonic-gate /*
29837c478bd9Sstevel@tonic-gate  * Handle interrupts for fatal errors
29847c478bd9Sstevel@tonic-gate  * Need reinitialization.
29857c478bd9Sstevel@tonic-gate  */
29867c478bd9Sstevel@tonic-gate #define	PCI_DATA_PARITY_REP	(1 << 8)
29877c478bd9Sstevel@tonic-gate #define	PCI_SING_TARGET_ABORT	(1 << 11)
29887c478bd9Sstevel@tonic-gate #define	PCI_RCV_TARGET_ABORT	(1 << 12)
29897c478bd9Sstevel@tonic-gate #define	PCI_RCV_MASTER_ABORT	(1 << 13)
29907c478bd9Sstevel@tonic-gate #define	PCI_SING_SYSTEM_ERR	(1 << 14)
29917c478bd9Sstevel@tonic-gate #define	PCI_DATA_PARITY_ERR	(1 << 15)
29927c478bd9Sstevel@tonic-gate 
29937c478bd9Sstevel@tonic-gate /* called with intrlock held */
29947c478bd9Sstevel@tonic-gate static void
eri_fatal_err(struct eri * erip,uint32_t erisbits)29957c478bd9Sstevel@tonic-gate eri_fatal_err(struct eri *erip, uint32_t erisbits)
29967c478bd9Sstevel@tonic-gate {
29977c478bd9Sstevel@tonic-gate 	uint16_t	pci_status;
29987c478bd9Sstevel@tonic-gate 	uint32_t	pci_error_int = 0;
29997c478bd9Sstevel@tonic-gate 
30007c478bd9Sstevel@tonic-gate 	if (erisbits & ERI_G_STATUS_RX_TAG_ERR) {
30017c478bd9Sstevel@tonic-gate 		erip->rx_reset_issued = 1;
30027c478bd9Sstevel@tonic-gate 		HSTAT(erip, rxtag_err);
30037c478bd9Sstevel@tonic-gate 	} else {
30047c478bd9Sstevel@tonic-gate 		erip->global_reset_issued = 1;
30057c478bd9Sstevel@tonic-gate 		if (erisbits & ERI_G_STATUS_BUS_ERR_INT) {
30067c478bd9Sstevel@tonic-gate 			pci_error_int = 1;
30077c478bd9Sstevel@tonic-gate 			HSTAT(erip, pci_error_int);
30087c478bd9Sstevel@tonic-gate 		} else if (erisbits & ERI_G_STATUS_PERR_INT) {
30097c478bd9Sstevel@tonic-gate 			HSTAT(erip, parity_error);
30107c478bd9Sstevel@tonic-gate 		} else {
30117c478bd9Sstevel@tonic-gate 			HSTAT(erip, unknown_fatal);
30127c478bd9Sstevel@tonic-gate 		}
30137c478bd9Sstevel@tonic-gate 	}
30147c478bd9Sstevel@tonic-gate 
30157c478bd9Sstevel@tonic-gate 	/*
30167c478bd9Sstevel@tonic-gate 	 * PCI bus error
30177c478bd9Sstevel@tonic-gate 	 */
30187c478bd9Sstevel@tonic-gate 	if (pci_error_int && erip->pci_config_handle) {
30197c478bd9Sstevel@tonic-gate 		pci_status = pci_config_get16(erip->pci_config_handle,
3020d64540e3Sgd 		    PCI_CONF_STAT);
3021d64540e3Sgd 		ERI_DEBUG_MSG2(erip, FATAL_ERR_MSG, "Bus Error Status %x",
3022d64540e3Sgd 		    pci_status);
30237c478bd9Sstevel@tonic-gate 		if (pci_status & PCI_DATA_PARITY_REP)
30247c478bd9Sstevel@tonic-gate 			HSTAT(erip, pci_data_parity_err);
30257c478bd9Sstevel@tonic-gate 		if (pci_status & PCI_SING_TARGET_ABORT)
30267c478bd9Sstevel@tonic-gate 			HSTAT(erip, pci_signal_target_abort);
30277c478bd9Sstevel@tonic-gate 		if (pci_status & PCI_RCV_TARGET_ABORT)
30287c478bd9Sstevel@tonic-gate 			HSTAT(erip, pci_rcvd_target_abort);
30297c478bd9Sstevel@tonic-gate 		if (pci_status & PCI_RCV_MASTER_ABORT)
30307c478bd9Sstevel@tonic-gate 			HSTAT(erip, pci_rcvd_master_abort);
30317c478bd9Sstevel@tonic-gate 		if (pci_status & PCI_SING_SYSTEM_ERR)
30327c478bd9Sstevel@tonic-gate 			HSTAT(erip, pci_signal_system_err);
30337c478bd9Sstevel@tonic-gate 		if (pci_status & PCI_DATA_PARITY_ERR)
30347c478bd9Sstevel@tonic-gate 			HSTAT(erip, pci_signal_system_err);
30357c478bd9Sstevel@tonic-gate 		/*
30367c478bd9Sstevel@tonic-gate 		 * clear it by writing the value that was read back.
30377c478bd9Sstevel@tonic-gate 		 */
3038d64540e3Sgd 		pci_config_put16(erip->pci_config_handle, PCI_CONF_STAT,
3039d64540e3Sgd 		    pci_status);
30407c478bd9Sstevel@tonic-gate 	}
30417c478bd9Sstevel@tonic-gate }
30427c478bd9Sstevel@tonic-gate 
30437c478bd9Sstevel@tonic-gate /*
30447c478bd9Sstevel@tonic-gate  * Handle interrupts regarding non-fatal events.
30457c478bd9Sstevel@tonic-gate  * TXMAC, RXMAC and MACCTL events
30467c478bd9Sstevel@tonic-gate  */
30477c478bd9Sstevel@tonic-gate static void
eri_nonfatal_err(struct eri * erip,uint32_t erisbits)30487c478bd9Sstevel@tonic-gate eri_nonfatal_err(struct eri *erip, uint32_t erisbits)
30497c478bd9Sstevel@tonic-gate {
30507c478bd9Sstevel@tonic-gate 
30517c478bd9Sstevel@tonic-gate 	uint32_t	txmac_sts, rxmac_sts, macctl_sts, pause_time;
30527c478bd9Sstevel@tonic-gate 
30537c478bd9Sstevel@tonic-gate #ifdef ERI_PM_WORKAROUND
30547c478bd9Sstevel@tonic-gate 	if (pci_report_pmcap(erip->dip, PCI_PM_IDLESPEED,
30557c478bd9Sstevel@tonic-gate 	    PCI_PM_IDLESPEED_NONE) == DDI_SUCCESS)
30567c478bd9Sstevel@tonic-gate 		erip->stats.pmcap = ERI_PMCAP_NONE;
30577c478bd9Sstevel@tonic-gate #endif
30587c478bd9Sstevel@tonic-gate 
30597c478bd9Sstevel@tonic-gate 	if (erisbits & ERI_G_STATUS_TX_MAC_INT) {
30607c478bd9Sstevel@tonic-gate 		txmac_sts = GET_MACREG(txsts);
30617c478bd9Sstevel@tonic-gate 		if (txmac_sts & BMAC_TXSTS_TX_URUN) {
30627c478bd9Sstevel@tonic-gate 			erip->linkcheck = 1;
30637c478bd9Sstevel@tonic-gate 			HSTAT(erip, txmac_urun);
30647c478bd9Sstevel@tonic-gate 			HSTAT(erip, oerrors);
30657c478bd9Sstevel@tonic-gate 		}
30667c478bd9Sstevel@tonic-gate 
30677c478bd9Sstevel@tonic-gate 		if (txmac_sts & BMAC_TXSTS_MAXPKT_ERR) {
30687c478bd9Sstevel@tonic-gate 			erip->linkcheck = 1;
30697c478bd9Sstevel@tonic-gate 			HSTAT(erip, txmac_maxpkt_err);
30707c478bd9Sstevel@tonic-gate 			HSTAT(erip, oerrors);
30717c478bd9Sstevel@tonic-gate 		}
30727c478bd9Sstevel@tonic-gate 		if (txmac_sts & BMAC_TXSTS_NCC_EXP) {
30737c478bd9Sstevel@tonic-gate 			erip->stats.collisions += 0x10000;
30747c478bd9Sstevel@tonic-gate 		}
30757c478bd9Sstevel@tonic-gate 
30767c478bd9Sstevel@tonic-gate 		if (txmac_sts & BMAC_TXSTS_ECC_EXP) {
30777c478bd9Sstevel@tonic-gate 			erip->stats.excessive_coll += 0x10000;
30787c478bd9Sstevel@tonic-gate 		}
30797c478bd9Sstevel@tonic-gate 
30807c478bd9Sstevel@tonic-gate 		if (txmac_sts & BMAC_TXSTS_LCC_EXP) {
30817c478bd9Sstevel@tonic-gate 			erip->stats.late_coll += 0x10000;
30827c478bd9Sstevel@tonic-gate 		}
30837c478bd9Sstevel@tonic-gate 
30847c478bd9Sstevel@tonic-gate 		if (txmac_sts & BMAC_TXSTS_FCC_EXP) {
30857c478bd9Sstevel@tonic-gate 			erip->stats.first_coll += 0x10000;
30867c478bd9Sstevel@tonic-gate 		}
30877c478bd9Sstevel@tonic-gate 
30887c478bd9Sstevel@tonic-gate 		if (txmac_sts & BMAC_TXSTS_DEFER_EXP) {
30897c478bd9Sstevel@tonic-gate 			HSTAT(erip, defer_timer_exp);
30907c478bd9Sstevel@tonic-gate 		}
30917c478bd9Sstevel@tonic-gate 
30927c478bd9Sstevel@tonic-gate 		if (txmac_sts & BMAC_TXSTS_PEAK_EXP) {
30937c478bd9Sstevel@tonic-gate 			erip->stats.peak_attempt_cnt += 0x100;
30947c478bd9Sstevel@tonic-gate 		}
30957c478bd9Sstevel@tonic-gate 	}
30967c478bd9Sstevel@tonic-gate 
30977c478bd9Sstevel@tonic-gate 	if (erisbits & ERI_G_STATUS_RX_NO_BUF) {
3098d64540e3Sgd 		ERI_DEBUG_MSG1(erip, NONFATAL_MSG, "rx dropped/no free desc");
30997c478bd9Sstevel@tonic-gate 
31007c478bd9Sstevel@tonic-gate 		if (eri_overflow_reset)
31017c478bd9Sstevel@tonic-gate 			erip->linkcheck = 1;
31027c478bd9Sstevel@tonic-gate 
31037c478bd9Sstevel@tonic-gate 		HSTAT(erip, no_free_rx_desc);
31047c478bd9Sstevel@tonic-gate 		HSTAT(erip, ierrors);
31057c478bd9Sstevel@tonic-gate 	}
31067c478bd9Sstevel@tonic-gate 	if (erisbits & ERI_G_STATUS_RX_MAC_INT) {
31077c478bd9Sstevel@tonic-gate 		rxmac_sts = GET_MACREG(rxsts);
31087c478bd9Sstevel@tonic-gate 		if (rxmac_sts & BMAC_RXSTS_RX_OVF) {
31097c478bd9Sstevel@tonic-gate #ifndef ERI_RMAC_HANG_WORKAROUND
31107c478bd9Sstevel@tonic-gate 			eri_stop_timer(erip);   /* acquire linklock */
31117c478bd9Sstevel@tonic-gate 			erip->check_rmac_hang ++;
31127c478bd9Sstevel@tonic-gate 			erip->check2_rmac_hang = 0;
31137c478bd9Sstevel@tonic-gate 			erip->rxfifo_wr_ptr = GET_ERXREG(rxfifo_wr_ptr);
31147c478bd9Sstevel@tonic-gate 			erip->rxfifo_rd_ptr = GET_ERXREG(rxfifo_rd_ptr);
31157c478bd9Sstevel@tonic-gate 
3116d64540e3Sgd 			ERI_DEBUG_MSG5(erip, NONFATAL_MSG,
31177c478bd9Sstevel@tonic-gate 			    "overflow intr %d: %8x wr:%2x rd:%2x",
31187c478bd9Sstevel@tonic-gate 			    erip->check_rmac_hang,
31197c478bd9Sstevel@tonic-gate 			    GET_MACREG(macsm),
31207c478bd9Sstevel@tonic-gate 			    GET_ERXREG(rxfifo_wr_ptr),
31217c478bd9Sstevel@tonic-gate 			    GET_ERXREG(rxfifo_rd_ptr));
31227c478bd9Sstevel@tonic-gate 
31237c478bd9Sstevel@tonic-gate 			eri_start_timer(erip, eri_check_link,
3124d64540e3Sgd 			    ERI_CHECK_HANG_TIMER);
31257c478bd9Sstevel@tonic-gate #endif
31267c478bd9Sstevel@tonic-gate 			if (eri_overflow_reset)
31277c478bd9Sstevel@tonic-gate 				erip->linkcheck = 1;
31287c478bd9Sstevel@tonic-gate 
31297c478bd9Sstevel@tonic-gate 			HSTAT(erip, rx_overflow);
31307c478bd9Sstevel@tonic-gate 			HSTAT(erip, ierrors);
31317c478bd9Sstevel@tonic-gate 		}
31327c478bd9Sstevel@tonic-gate 
31337c478bd9Sstevel@tonic-gate 		if (rxmac_sts & BMAC_RXSTS_ALE_EXP) {
31347c478bd9Sstevel@tonic-gate 			erip->stats.rx_align_err += 0x10000;
31357c478bd9Sstevel@tonic-gate 			erip->stats.ierrors += 0x10000;
31367c478bd9Sstevel@tonic-gate 		}
31377c478bd9Sstevel@tonic-gate 
31387c478bd9Sstevel@tonic-gate 		if (rxmac_sts & BMAC_RXSTS_CRC_EXP) {
31397c478bd9Sstevel@tonic-gate 			erip->stats.rx_crc_err += 0x10000;
31407c478bd9Sstevel@tonic-gate 			erip->stats.ierrors += 0x10000;
31417c478bd9Sstevel@tonic-gate 		}
31427c478bd9Sstevel@tonic-gate 
31437c478bd9Sstevel@tonic-gate 		if (rxmac_sts & BMAC_RXSTS_LEN_EXP) {
31447c478bd9Sstevel@tonic-gate 			erip->stats.rx_length_err += 0x10000;
31457c478bd9Sstevel@tonic-gate 			erip->stats.ierrors += 0x10000;
31467c478bd9Sstevel@tonic-gate 		}
31477c478bd9Sstevel@tonic-gate 
31487c478bd9Sstevel@tonic-gate 		if (rxmac_sts & BMAC_RXSTS_CVI_EXP) {
31497c478bd9Sstevel@tonic-gate 			erip->stats.rx_code_viol_err += 0x10000;
31507c478bd9Sstevel@tonic-gate 			erip->stats.ierrors += 0x10000;
31517c478bd9Sstevel@tonic-gate 		}
31527c478bd9Sstevel@tonic-gate 	}
31537c478bd9Sstevel@tonic-gate 
31547c478bd9Sstevel@tonic-gate 	if (erisbits & ERI_G_STATUS_MAC_CTRL_INT) {
31557c478bd9Sstevel@tonic-gate 
31567c478bd9Sstevel@tonic-gate 		macctl_sts = GET_MACREG(macctl_sts);
31577c478bd9Sstevel@tonic-gate 		if (macctl_sts & ERI_MCTLSTS_PAUSE_RCVD) {
31587c478bd9Sstevel@tonic-gate 			pause_time = ((macctl_sts &
3159d64540e3Sgd 			    ERI_MCTLSTS_PAUSE_TIME) >> 16);
31607c478bd9Sstevel@tonic-gate 			ERI_DEBUG_MSG2(erip, NONFATAL_MSG,
3161d64540e3Sgd 			    "PAUSE Received. pause time = %X slot_times",
3162d64540e3Sgd 			    pause_time);
31637c478bd9Sstevel@tonic-gate 			HSTAT(erip, pause_rxcount);
31647c478bd9Sstevel@tonic-gate 			erip->stats.pause_time_count += pause_time;
31657c478bd9Sstevel@tonic-gate 		}
31667c478bd9Sstevel@tonic-gate 
31677c478bd9Sstevel@tonic-gate 		if (macctl_sts & ERI_MCTLSTS_PAUSE_STATE) {
31687c478bd9Sstevel@tonic-gate 			HSTAT(erip, pause_oncount);
3169d64540e3Sgd 			erip->stats.pausing = 1;
31707c478bd9Sstevel@tonic-gate 		}
31717c478bd9Sstevel@tonic-gate 
31727c478bd9Sstevel@tonic-gate 		if (macctl_sts & ERI_MCTLSTS_NONPAUSE) {
31737c478bd9Sstevel@tonic-gate 			HSTAT(erip, pause_offcount);
3174d64540e3Sgd 			erip->stats.pausing = 0;
31757c478bd9Sstevel@tonic-gate 		}
31767c478bd9Sstevel@tonic-gate 	}
31777c478bd9Sstevel@tonic-gate 
31787c478bd9Sstevel@tonic-gate }
31797c478bd9Sstevel@tonic-gate 
31807c478bd9Sstevel@tonic-gate /*
31817c478bd9Sstevel@tonic-gate  * if this is the first init do not bother to save the
31827c478bd9Sstevel@tonic-gate  * counters.
31837c478bd9Sstevel@tonic-gate  */
31847c478bd9Sstevel@tonic-gate static void
eri_savecntrs(struct eri * erip)31857c478bd9Sstevel@tonic-gate eri_savecntrs(struct eri *erip)
31867c478bd9Sstevel@tonic-gate {
31877c478bd9Sstevel@tonic-gate 	uint32_t	fecnt, aecnt, lecnt, rxcv;
31887c478bd9Sstevel@tonic-gate 	uint32_t	ltcnt, excnt, fccnt;
31897c478bd9Sstevel@tonic-gate 
31907c478bd9Sstevel@tonic-gate 	/* XXX What all gets added in ierrors and oerrors? */
31917c478bd9Sstevel@tonic-gate 	fecnt = GET_MACREG(fecnt);
31927c478bd9Sstevel@tonic-gate 	HSTATN(erip, rx_crc_err, fecnt);
31937c478bd9Sstevel@tonic-gate 	PUT_MACREG(fecnt, 0);
31947c478bd9Sstevel@tonic-gate 
31957c478bd9Sstevel@tonic-gate 	aecnt = GET_MACREG(aecnt);
31967c478bd9Sstevel@tonic-gate 	HSTATN(erip, rx_align_err, aecnt);
31977c478bd9Sstevel@tonic-gate 	PUT_MACREG(aecnt, 0);
31987c478bd9Sstevel@tonic-gate 
31997c478bd9Sstevel@tonic-gate 	lecnt = GET_MACREG(lecnt);
32007c478bd9Sstevel@tonic-gate 	HSTATN(erip, rx_length_err, lecnt);
32017c478bd9Sstevel@tonic-gate 	PUT_MACREG(lecnt, 0);
32027c478bd9Sstevel@tonic-gate 
32037c478bd9Sstevel@tonic-gate 	rxcv = GET_MACREG(rxcv);
32047c478bd9Sstevel@tonic-gate 	HSTATN(erip, rx_code_viol_err, rxcv);
32057c478bd9Sstevel@tonic-gate 	PUT_MACREG(rxcv, 0);
32067c478bd9Sstevel@tonic-gate 
32077c478bd9Sstevel@tonic-gate 	ltcnt = GET_MACREG(ltcnt);
32087c478bd9Sstevel@tonic-gate 	HSTATN(erip, late_coll, ltcnt);
32097c478bd9Sstevel@tonic-gate 	PUT_MACREG(ltcnt, 0);
32107c478bd9Sstevel@tonic-gate 
32117c478bd9Sstevel@tonic-gate 	erip->stats.collisions += (GET_MACREG(nccnt) + ltcnt);
32127c478bd9Sstevel@tonic-gate 	PUT_MACREG(nccnt, 0);
32137c478bd9Sstevel@tonic-gate 
32147c478bd9Sstevel@tonic-gate 	excnt = GET_MACREG(excnt);
32157c478bd9Sstevel@tonic-gate 	HSTATN(erip, excessive_coll, excnt);
32167c478bd9Sstevel@tonic-gate 	PUT_MACREG(excnt, 0);
32177c478bd9Sstevel@tonic-gate 
32187c478bd9Sstevel@tonic-gate 	fccnt = GET_MACREG(fccnt);
32197c478bd9Sstevel@tonic-gate 	HSTATN(erip, first_coll, fccnt);
32207c478bd9Sstevel@tonic-gate 	PUT_MACREG(fccnt, 0);
32217c478bd9Sstevel@tonic-gate 
32227c478bd9Sstevel@tonic-gate 	/*
32237c478bd9Sstevel@tonic-gate 	 * Do not add code violations to input errors.
32247c478bd9Sstevel@tonic-gate 	 * They are already counted in CRC errors
32257c478bd9Sstevel@tonic-gate 	 */
32267c478bd9Sstevel@tonic-gate 	HSTATN(erip, ierrors, (fecnt + aecnt + lecnt));
32277c478bd9Sstevel@tonic-gate 	HSTATN(erip, oerrors, (ltcnt + excnt));
32287c478bd9Sstevel@tonic-gate }
32297c478bd9Sstevel@tonic-gate 
32307c478bd9Sstevel@tonic-gate mblk_t *
eri_allocb_sp(size_t size)32317c478bd9Sstevel@tonic-gate eri_allocb_sp(size_t size)
32327c478bd9Sstevel@tonic-gate {
32337c478bd9Sstevel@tonic-gate 	mblk_t  *mp;
32347c478bd9Sstevel@tonic-gate 
32357c478bd9Sstevel@tonic-gate 	size += 128;
32367c478bd9Sstevel@tonic-gate 	if ((mp = allocb(size + 3 * ERI_BURSTSIZE, BPRI_HI)) == NULL) {
32377c478bd9Sstevel@tonic-gate 		return (NULL);
32387c478bd9Sstevel@tonic-gate 	}
32397c478bd9Sstevel@tonic-gate 	mp->b_wptr += 128;
32407c478bd9Sstevel@tonic-gate 	mp->b_wptr = (uint8_t *)ROUNDUP2(mp->b_wptr, ERI_BURSTSIZE);
32417c478bd9Sstevel@tonic-gate 	mp->b_rptr = mp->b_wptr;
32427c478bd9Sstevel@tonic-gate 
32437c478bd9Sstevel@tonic-gate 	return (mp);
32447c478bd9Sstevel@tonic-gate }
32457c478bd9Sstevel@tonic-gate 
32467c478bd9Sstevel@tonic-gate mblk_t *
eri_allocb(size_t size)32477c478bd9Sstevel@tonic-gate eri_allocb(size_t size)
32487c478bd9Sstevel@tonic-gate {
32497c478bd9Sstevel@tonic-gate 	mblk_t  *mp;
32507c478bd9Sstevel@tonic-gate 
32517c478bd9Sstevel@tonic-gate 	if ((mp = allocb(size + 3 * ERI_BURSTSIZE, BPRI_HI)) == NULL) {
32527c478bd9Sstevel@tonic-gate 		return (NULL);
32537c478bd9Sstevel@tonic-gate 	}
32547c478bd9Sstevel@tonic-gate 	mp->b_wptr = (uint8_t *)ROUNDUP2(mp->b_wptr, ERI_BURSTSIZE);
32557c478bd9Sstevel@tonic-gate 	mp->b_rptr = mp->b_wptr;
32567c478bd9Sstevel@tonic-gate 
32577c478bd9Sstevel@tonic-gate 	return (mp);
32587c478bd9Sstevel@tonic-gate }
32597c478bd9Sstevel@tonic-gate 
32607c478bd9Sstevel@tonic-gate /*
32617c478bd9Sstevel@tonic-gate  * Hardware Dependent Functions
32627c478bd9Sstevel@tonic-gate  * New Section.
32637c478bd9Sstevel@tonic-gate  */
32647c478bd9Sstevel@tonic-gate 
32657c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<< Fast Ethernet PHY Bit Bang Operations >>>>>>>>>>>>>>>>>> */
32667c478bd9Sstevel@tonic-gate 
32677c478bd9Sstevel@tonic-gate static void
send_bit(struct eri * erip,uint32_t x)32687c478bd9Sstevel@tonic-gate send_bit(struct eri *erip, uint32_t x)
32697c478bd9Sstevel@tonic-gate {
32707c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbdata, x);
32717c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbclk, ERI_BBCLK_LOW);
32727c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbclk, ERI_BBCLK_HIGH);
32737c478bd9Sstevel@tonic-gate }
32747c478bd9Sstevel@tonic-gate 
32757c478bd9Sstevel@tonic-gate /*
32767c478bd9Sstevel@tonic-gate  * To read the MII register bits according to the IEEE Standard
32777c478bd9Sstevel@tonic-gate  */
32787c478bd9Sstevel@tonic-gate static uint32_t
get_bit_std(struct eri * erip)32797c478bd9Sstevel@tonic-gate get_bit_std(struct eri *erip)
32807c478bd9Sstevel@tonic-gate {
32817c478bd9Sstevel@tonic-gate 	uint32_t	x;
32827c478bd9Sstevel@tonic-gate 
32837c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbclk, ERI_BBCLK_LOW);
32847c478bd9Sstevel@tonic-gate 	drv_usecwait(1);	/* wait for  >330 ns for stable data */
32857c478bd9Sstevel@tonic-gate 	if (param_transceiver == INTERNAL_XCVR)
32867c478bd9Sstevel@tonic-gate 		x = (GET_MIFREG(mif_cfg) & ERI_MIF_CFGM0) ? 1 : 0;
32877c478bd9Sstevel@tonic-gate 	else
32887c478bd9Sstevel@tonic-gate 		x = (GET_MIFREG(mif_cfg) & ERI_MIF_CFGM1) ? 1 : 0;
32897c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbclk, ERI_BBCLK_HIGH);
32907c478bd9Sstevel@tonic-gate 	return (x);
32917c478bd9Sstevel@tonic-gate }
32927c478bd9Sstevel@tonic-gate 
32937c478bd9Sstevel@tonic-gate #define	SEND_BIT(x)		send_bit(erip, x)
32947c478bd9Sstevel@tonic-gate #define	GET_BIT_STD(x)		x = get_bit_std(erip)
32957c478bd9Sstevel@tonic-gate 
32967c478bd9Sstevel@tonic-gate 
32977c478bd9Sstevel@tonic-gate static void
eri_bb_mii_write(struct eri * erip,uint8_t regad,uint16_t data)32987c478bd9Sstevel@tonic-gate eri_bb_mii_write(struct eri *erip, uint8_t regad, uint16_t data)
32997c478bd9Sstevel@tonic-gate {
33007c478bd9Sstevel@tonic-gate 	uint8_t	phyad;
33017c478bd9Sstevel@tonic-gate 	int		i;
33027c478bd9Sstevel@tonic-gate 
33037c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbopenb, 1);	/* Enable the MII driver */
33047c478bd9Sstevel@tonic-gate 	phyad = erip->phyad;
33057c478bd9Sstevel@tonic-gate 	(void) eri_bb_force_idle(erip);
33067c478bd9Sstevel@tonic-gate 	SEND_BIT(0); SEND_BIT(1);	/* <ST> */
33077c478bd9Sstevel@tonic-gate 	SEND_BIT(0); SEND_BIT(1);	/* <OP> */
33087c478bd9Sstevel@tonic-gate 	for (i = 4; i >= 0; i--) {		/* <AAAAA> */
33097c478bd9Sstevel@tonic-gate 		SEND_BIT((phyad >> i) & 1);
33107c478bd9Sstevel@tonic-gate 	}
33117c478bd9Sstevel@tonic-gate 	for (i = 4; i >= 0; i--) {		/* <RRRRR> */
33127c478bd9Sstevel@tonic-gate 		SEND_BIT((regad >> i) & 1);
33137c478bd9Sstevel@tonic-gate 	}
33147c478bd9Sstevel@tonic-gate 	SEND_BIT(1); SEND_BIT(0);	/* <TA> */
33157c478bd9Sstevel@tonic-gate 	for (i = 0xf; i >= 0; i--) {	/* <DDDDDDDDDDDDDDDD> */
33167c478bd9Sstevel@tonic-gate 		SEND_BIT((data >> i) & 1);
33177c478bd9Sstevel@tonic-gate 	}
33187c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbopenb, 0);	/* Disable the MII driver */
33197c478bd9Sstevel@tonic-gate }
33207c478bd9Sstevel@tonic-gate 
33217c478bd9Sstevel@tonic-gate /* Return 0 if OK, 1 if error (Transceiver does not talk management) */
33227c478bd9Sstevel@tonic-gate static uint32_t
eri_bb_mii_read(struct eri * erip,uint8_t regad,uint16_t * datap)33237c478bd9Sstevel@tonic-gate eri_bb_mii_read(struct eri *erip, uint8_t regad, uint16_t *datap)
33247c478bd9Sstevel@tonic-gate {
33257c478bd9Sstevel@tonic-gate 	uint8_t	phyad;
33267c478bd9Sstevel@tonic-gate 	int	i;
33277c478bd9Sstevel@tonic-gate 	uint32_t	x;
33287c478bd9Sstevel@tonic-gate 	uint32_t	y;
33297c478bd9Sstevel@tonic-gate 
33307c478bd9Sstevel@tonic-gate 	*datap = 0;
33317c478bd9Sstevel@tonic-gate 
33327c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbopenb, 1);	/* Enable the MII driver */
33337c478bd9Sstevel@tonic-gate 	phyad = erip->phyad;
33347c478bd9Sstevel@tonic-gate 	(void) eri_bb_force_idle(erip);
33357c478bd9Sstevel@tonic-gate 	SEND_BIT(0); SEND_BIT(1);	/* <ST> */
33367c478bd9Sstevel@tonic-gate 	SEND_BIT(1); SEND_BIT(0);	/* <OP> */
33377c478bd9Sstevel@tonic-gate 	for (i = 4; i >= 0; i--) {		/* <AAAAA> */
33387c478bd9Sstevel@tonic-gate 		SEND_BIT((phyad >> i) & 1);
33397c478bd9Sstevel@tonic-gate 	}
33407c478bd9Sstevel@tonic-gate 	for (i = 4; i >= 0; i--) {		/* <RRRRR> */
33417c478bd9Sstevel@tonic-gate 		SEND_BIT((regad >> i) & 1);
33427c478bd9Sstevel@tonic-gate 	}
33437c478bd9Sstevel@tonic-gate 
33447c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbopenb, 0);	/* Disable the MII driver */
33457c478bd9Sstevel@tonic-gate 
33467c478bd9Sstevel@tonic-gate 	GET_BIT_STD(x);
33477c478bd9Sstevel@tonic-gate 	GET_BIT_STD(y);		/* <TA> */
33487c478bd9Sstevel@tonic-gate 	for (i = 0xf; i >= 0; i--) {	/* <DDDDDDDDDDDDDDDD> */
33497c478bd9Sstevel@tonic-gate 		GET_BIT_STD(x);
33507c478bd9Sstevel@tonic-gate 		*datap += (x << i);
33517c478bd9Sstevel@tonic-gate 	}
33527c478bd9Sstevel@tonic-gate 	/* Kludge to get the Transceiver out of hung mode */
33537c478bd9Sstevel@tonic-gate 	/* XXX: Test if this is still needed */
33547c478bd9Sstevel@tonic-gate 	GET_BIT_STD(x);
33557c478bd9Sstevel@tonic-gate 	GET_BIT_STD(x);
33567c478bd9Sstevel@tonic-gate 	GET_BIT_STD(x);
33577c478bd9Sstevel@tonic-gate 
33587c478bd9Sstevel@tonic-gate 	return (y);
33597c478bd9Sstevel@tonic-gate }
33607c478bd9Sstevel@tonic-gate 
33617c478bd9Sstevel@tonic-gate static void
eri_bb_force_idle(struct eri * erip)33627c478bd9Sstevel@tonic-gate eri_bb_force_idle(struct eri *erip)
33637c478bd9Sstevel@tonic-gate {
33647c478bd9Sstevel@tonic-gate 	int		i;
33657c478bd9Sstevel@tonic-gate 
33667c478bd9Sstevel@tonic-gate 	for (i = 0; i < 33; i++) {
33677c478bd9Sstevel@tonic-gate 		SEND_BIT(1);
33687c478bd9Sstevel@tonic-gate 	}
33697c478bd9Sstevel@tonic-gate }
33707c478bd9Sstevel@tonic-gate 
33717c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<End of Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */
33727c478bd9Sstevel@tonic-gate 
33737c478bd9Sstevel@tonic-gate 
33747c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<< Frame Register used for MII operations >>>>>>>>>>>>>>>>>>>> */
33757c478bd9Sstevel@tonic-gate 
33767c478bd9Sstevel@tonic-gate #ifdef ERI_FRM_DEBUG
33777c478bd9Sstevel@tonic-gate int frame_flag = 0;
33787c478bd9Sstevel@tonic-gate #endif
33797c478bd9Sstevel@tonic-gate 
33807c478bd9Sstevel@tonic-gate /* Return 0 if OK, 1 if error (Transceiver does not talk management) */
33817c478bd9Sstevel@tonic-gate static uint32_t
eri_mii_read(struct eri * erip,uint8_t regad,uint16_t * datap)33827c478bd9Sstevel@tonic-gate eri_mii_read(struct eri	*erip, uint8_t regad, uint16_t *datap)
33837c478bd9Sstevel@tonic-gate {
33847c478bd9Sstevel@tonic-gate 	uint32_t frame;
33857c478bd9Sstevel@tonic-gate 	uint8_t phyad;
33867c478bd9Sstevel@tonic-gate 
33877c478bd9Sstevel@tonic-gate 	if (param_transceiver == NO_XCVR)
33887c478bd9Sstevel@tonic-gate 		return (1);	/* No xcvr present */
33897c478bd9Sstevel@tonic-gate 
33907c478bd9Sstevel@tonic-gate 	if (!erip->frame_enable)
33917c478bd9Sstevel@tonic-gate 		return (eri_bb_mii_read(erip, regad, datap));
33927c478bd9Sstevel@tonic-gate 
33937c478bd9Sstevel@tonic-gate 	phyad = erip->phyad;
33947c478bd9Sstevel@tonic-gate #ifdef ERI_FRM_DEBUG
33957c478bd9Sstevel@tonic-gate 	if (!frame_flag) {
33967c478bd9Sstevel@tonic-gate 		eri_errror(erip->dip, "Frame Register used for MII");
33977c478bd9Sstevel@tonic-gate 		frame_flag = 1;
33987c478bd9Sstevel@tonic-gate 	}
33997c478bd9Sstevel@tonic-gate #endif
34007c478bd9Sstevel@tonic-gate 	ERI_DEBUG_MSG3(erip, FRM_MSG,
3401d64540e3Sgd 	    "Frame Reg :mii_read: phyad = %X reg = %X ", phyad, regad);
34027c478bd9Sstevel@tonic-gate 
34037c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_frame, ERI_MIF_FRREAD |
3404d64540e3Sgd 	    (phyad << ERI_MIF_FRPHYAD_SHIFT) |
3405d64540e3Sgd 	    (regad << ERI_MIF_FRREGAD_SHIFT));
34067c478bd9Sstevel@tonic-gate 	MIF_ERIDELAY(300,  phyad, regad);
34077c478bd9Sstevel@tonic-gate 	frame = GET_MIFREG(mif_frame);
34087c478bd9Sstevel@tonic-gate 	if ((frame & ERI_MIF_FRTA0) == 0) {
34097c478bd9Sstevel@tonic-gate 		return (1);
34107c478bd9Sstevel@tonic-gate 	} else {
34117c478bd9Sstevel@tonic-gate 		*datap = (uint16_t)(frame & ERI_MIF_FRDATA);
34127c478bd9Sstevel@tonic-gate 		return (0);
34137c478bd9Sstevel@tonic-gate 	}
34147c478bd9Sstevel@tonic-gate 
34157c478bd9Sstevel@tonic-gate }
34167c478bd9Sstevel@tonic-gate 
34177c478bd9Sstevel@tonic-gate static void
eri_mii_write(struct eri * erip,uint8_t regad,uint16_t data)34187c478bd9Sstevel@tonic-gate eri_mii_write(struct eri *erip, uint8_t regad, uint16_t data)
34197c478bd9Sstevel@tonic-gate {
34207c478bd9Sstevel@tonic-gate 	uint8_t	phyad;
34217c478bd9Sstevel@tonic-gate 
34227c478bd9Sstevel@tonic-gate 	if (!erip->frame_enable) {
34237c478bd9Sstevel@tonic-gate 		eri_bb_mii_write(erip, regad, data);
34247c478bd9Sstevel@tonic-gate 		return;
34257c478bd9Sstevel@tonic-gate 	}
34267c478bd9Sstevel@tonic-gate 
34277c478bd9Sstevel@tonic-gate 	phyad = erip->phyad;
34287c478bd9Sstevel@tonic-gate 
34297c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_frame, (ERI_MIF_FRWRITE |
3430d64540e3Sgd 	    (phyad << ERI_MIF_FRPHYAD_SHIFT) |
3431d64540e3Sgd 	    (regad << ERI_MIF_FRREGAD_SHIFT) | data));
34327c478bd9Sstevel@tonic-gate 	MIF_ERIDELAY(300,  phyad, regad);
3433d64540e3Sgd 	(void) GET_MIFREG(mif_frame);
34347c478bd9Sstevel@tonic-gate }
34357c478bd9Sstevel@tonic-gate 
34367c478bd9Sstevel@tonic-gate 
34377c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<	PACKET TRANSMIT FUNCTIONS	>>>>>>>>>>>>>>>>>>>> */
34387c478bd9Sstevel@tonic-gate 
34397c478bd9Sstevel@tonic-gate #define	ERI_CROSS_PAGE_BOUNDRY(i, size, pagesize) \
34407c478bd9Sstevel@tonic-gate 	((i & pagesize) != ((i + size) & pagesize))
34417c478bd9Sstevel@tonic-gate 
3442d64540e3Sgd /*
3443d64540e3Sgd  * Send a single mblk.  Returns B_TRUE if the packet is sent, or disposed of
3444d64540e3Sgd  * by freemsg.  Returns B_FALSE if the packet was not sent or queued, and
3445d64540e3Sgd  * should be retried later (due to tx resource exhaustion.)
3446d64540e3Sgd  */
3447d64540e3Sgd static boolean_t
eri_send_msg(struct eri * erip,mblk_t * mp)3448d64540e3Sgd eri_send_msg(struct eri *erip, mblk_t *mp)
34497c478bd9Sstevel@tonic-gate {
34507c478bd9Sstevel@tonic-gate 	volatile struct	eri_tmd	*tmdp = NULL;
34517c478bd9Sstevel@tonic-gate 	volatile struct	eri_tmd	*tbasep = NULL;
3452bd78278bSGarrett D'Amore 	uint32_t	len_msg = 0;
3453bd78278bSGarrett D'Amore 	uint32_t	i;
34547c478bd9Sstevel@tonic-gate 	uint64_t	int_me = 0;
34557c478bd9Sstevel@tonic-gate 	uint_t		tmdcsum = 0;
34567c478bd9Sstevel@tonic-gate 	uint_t		start_offset = 0;
34577c478bd9Sstevel@tonic-gate 	uint_t		stuff_offset = 0;
34587c478bd9Sstevel@tonic-gate 	uint_t		flags = 0;
34597c478bd9Sstevel@tonic-gate 
34607c478bd9Sstevel@tonic-gate 	caddr_t	ptr;
34617c478bd9Sstevel@tonic-gate 	uint32_t	offset;
34627c478bd9Sstevel@tonic-gate 	uint64_t	ctrl;
34637c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t	c;
34647c478bd9Sstevel@tonic-gate 
34657c478bd9Sstevel@tonic-gate 	if (!param_linkup) {
34667c478bd9Sstevel@tonic-gate 		freemsg(mp);
3467d64540e3Sgd 		HSTAT(erip, tnocar);
34687c478bd9Sstevel@tonic-gate 		HSTAT(erip, oerrors);
3469d64540e3Sgd 		return (B_TRUE);
34707c478bd9Sstevel@tonic-gate 	}
34717c478bd9Sstevel@tonic-gate 
34727c478bd9Sstevel@tonic-gate #ifdef ERI_HWCSUM
34730dc2366fSVenugopal Iyer 	mac_hcksum_get(mp, &start_offset, &stuff_offset, NULL, NULL, &flags);
3474d64540e3Sgd 
3475d64540e3Sgd 	if (flags & HCK_PARTIALCKSUM) {
3476fd8be74fSgd 		if (get_ether_type(mp->b_rptr) == ETHERTYPE_VLAN) {
3477fd8be74fSgd 			start_offset += ETHERHEADER_SIZE + 4;
3478fd8be74fSgd 			stuff_offset += ETHERHEADER_SIZE + 4;
3479fd8be74fSgd 		} else {
3480fd8be74fSgd 			start_offset += ETHERHEADER_SIZE;
3481fd8be74fSgd 			stuff_offset += ETHERHEADER_SIZE;
3482fd8be74fSgd 		}
3483d64540e3Sgd 		tmdcsum = ERI_TMD_CSENABL;
34847c478bd9Sstevel@tonic-gate 	}
34857c478bd9Sstevel@tonic-gate #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);
34957c478bd9Sstevel@tonic-gate 	}
34967c478bd9Sstevel@tonic-gate 
34977c478bd9Sstevel@tonic-gate 	/*
34987c478bd9Sstevel@tonic-gate 	 * update MIB II statistics
34997c478bd9Sstevel@tonic-gate 	 */
3500d64540e3Sgd 	BUMP_OutNUcast(erip, mp->b_rptr);
35017c478bd9Sstevel@tonic-gate 
35027c478bd9Sstevel@tonic-gate 	mutex_enter(&erip->xmitlock);
35037c478bd9Sstevel@tonic-gate 
35047c478bd9Sstevel@tonic-gate 	tbasep = erip->eri_tmdp;
35057c478bd9Sstevel@tonic-gate 
35067c478bd9Sstevel@tonic-gate 	/* Check if there are enough descriptors for this packet */
35077c478bd9Sstevel@tonic-gate 	tmdp = erip->tnextp;
35087c478bd9Sstevel@tonic-gate 
35097c478bd9Sstevel@tonic-gate 	if (tmdp >=  erip->tcurp) /* check notmds */
35107c478bd9Sstevel@tonic-gate 		i = tmdp - erip->tcurp;
35117c478bd9Sstevel@tonic-gate 	else
35127c478bd9Sstevel@tonic-gate 		i = tmdp + ERI_TPENDING - erip->tcurp;
35137c478bd9Sstevel@tonic-gate 
35147c478bd9Sstevel@tonic-gate 	if (i > (ERI_TPENDING - 4))
35157c478bd9Sstevel@tonic-gate 		goto notmds;
35167c478bd9Sstevel@tonic-gate 
35176213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic 	if (i >= (ERI_TPENDING >> 1) && !(erip->starts & 0x7)) {
35187c478bd9Sstevel@tonic-gate 		int_me = ERI_TMD_INTME;
35197c478bd9Sstevel@tonic-gate 
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 
3527bd78278bSGarrett D'Amore 	i = tmdp - tbasep; /* index */
35287c478bd9Sstevel@tonic-gate 
3529bd78278bSGarrett D'Amore 	offset = (i * ERI_BUFSIZE);
3530bd78278bSGarrett D'Amore 	ptr = erip->tbuf_kaddr + offset;
35317c478bd9Sstevel@tonic-gate 
3532bd78278bSGarrett D'Amore 	mcopymsg(mp, ptr);
35337c478bd9Sstevel@tonic-gate 
35347c478bd9Sstevel@tonic-gate #ifdef	ERI_HDX_BUG_WORKAROUND
3535bd78278bSGarrett D'Amore 	if ((param_mode) || (eri_hdx_pad_enable == 0)) {
3536bd78278bSGarrett D'Amore 		if (len_msg < ETHERMIN) {
3537bd78278bSGarrett D'Amore 			bzero((ptr + len_msg), (ETHERMIN - len_msg));
3538bd78278bSGarrett D'Amore 			len_msg = ETHERMIN;
35397c478bd9Sstevel@tonic-gate 		}
3540bd78278bSGarrett D'Amore 	} else {
3541bd78278bSGarrett D'Amore 		if (len_msg < 97) {
3542bd78278bSGarrett D'Amore 			bzero((ptr + len_msg), (97 - len_msg));
3543bd78278bSGarrett D'Amore 			len_msg = 97;
35447c478bd9Sstevel@tonic-gate 		}
3545bd78278bSGarrett D'Amore 	}
3546bd78278bSGarrett D'Amore #endif
3547bd78278bSGarrett D'Amore 	c.dmac_address = erip->tbuf_ioaddr + offset;
3548bd78278bSGarrett D'Amore 	(void) ddi_dma_sync(erip->tbuf_handle,
3549bd78278bSGarrett D'Amore 	    (off_t)offset, len_msg, DDI_DMA_SYNC_FORDEV);
35507c478bd9Sstevel@tonic-gate 
3551bd78278bSGarrett D'Amore 		/* first and last (and only!) descr of packet */
3552bd78278bSGarrett D'Amore 	ctrl = ERI_TMD_SOP | ERI_TMD_EOP | int_me | tmdcsum |
3553bd78278bSGarrett D'Amore 	    (start_offset << ERI_TMD_CSSTART_SHIFT) |
3554bd78278bSGarrett D'Amore 	    (stuff_offset << ERI_TMD_CSSTUFF_SHIFT);
35557c478bd9Sstevel@tonic-gate 
3556bd78278bSGarrett D'Amore 	PUT_TMD(tmdp, c, len_msg, ctrl);
3557bd78278bSGarrett D'Amore 	ERI_SYNCIOPB(erip, tmdp, sizeof (struct eri_tmd),
3558bd78278bSGarrett D'Amore 	    DDI_DMA_SYNC_FORDEV);
35597c478bd9Sstevel@tonic-gate 
3560bd78278bSGarrett D'Amore 	tmdp = NEXTTMD(erip, tmdp);
3561bd78278bSGarrett D'Amore 	erip->tx_cur_cnt++;
35627c478bd9Sstevel@tonic-gate 
35637c478bd9Sstevel@tonic-gate 	erip->tx_kick = tmdp - tbasep;
35647c478bd9Sstevel@tonic-gate 	PUT_ETXREG(tx_kick, erip->tx_kick);
35657c478bd9Sstevel@tonic-gate 	erip->tnextp = tmdp;
35667c478bd9Sstevel@tonic-gate 
35677c478bd9Sstevel@tonic-gate 	erip->starts++;
35687c478bd9Sstevel@tonic-gate 
35697c478bd9Sstevel@tonic-gate 	if (erip->tx_cur_cnt >= tx_interrupt_rate) {
35707c478bd9Sstevel@tonic-gate 		erip->tx_completion = (uint32_t)(GET_ETXREG(tx_completion) &
35717c478bd9Sstevel@tonic-gate 		    ETX_COMPLETION_MASK);
35726213860bSvitezslav batrla - Sun Microsystems - Prague Czech Republic 		(void) eri_reclaim(erip, erip->tx_completion);
35737c478bd9Sstevel@tonic-gate 	}
35747c478bd9Sstevel@tonic-gate 	mutex_exit(&erip->xmitlock);
35757c478bd9Sstevel@tonic-gate 
3576d64540e3Sgd 	return (B_TRUE);
35777c478bd9Sstevel@tonic-gate 
35787c478bd9Sstevel@tonic-gate notmds:
35797c478bd9Sstevel@tonic-gate 	HSTAT(erip, notmds);
3580d64540e3Sgd 	erip->wantw = B_TRUE;
35817c478bd9Sstevel@tonic-gate 
35827c478bd9Sstevel@tonic-gate 	mutex_exit(&erip->xmitlock);
35837c478bd9Sstevel@tonic-gate 
3584d64540e3Sgd 	return (B_FALSE);
3585d64540e3Sgd }
3586d64540e3Sgd 
3587d64540e3Sgd static mblk_t *
eri_m_tx(void * arg,mblk_t * mp)3588d64540e3Sgd eri_m_tx(void *arg, mblk_t *mp)
3589d64540e3Sgd {
3590d64540e3Sgd 	struct eri *erip = arg;
3591d64540e3Sgd 	mblk_t *next;
3592d64540e3Sgd 
3593d64540e3Sgd 	while (mp != NULL) {
3594d64540e3Sgd 		next = mp->b_next;
3595d64540e3Sgd 		mp->b_next = NULL;
3596d64540e3Sgd 		if (!eri_send_msg(erip, mp)) {
3597d64540e3Sgd 			mp->b_next = next;
3598d64540e3Sgd 			break;
3599d64540e3Sgd 		}
3600d64540e3Sgd 		mp = next;
3601d64540e3Sgd 	}
3602d64540e3Sgd 
3603d64540e3Sgd 	return (mp);
36047c478bd9Sstevel@tonic-gate }
36057c478bd9Sstevel@tonic-gate 
36067c478bd9Sstevel@tonic-gate /*
36077c478bd9Sstevel@tonic-gate  * Transmit completion reclaiming.
36087c478bd9Sstevel@tonic-gate  */
3609d64540e3Sgd static boolean_t
eri_reclaim(struct eri * erip,uint32_t tx_completion)36107c478bd9Sstevel@tonic-gate eri_reclaim(struct eri *erip, uint32_t tx_completion)
36117c478bd9Sstevel@tonic-gate {
36127c478bd9Sstevel@tonic-gate 	volatile struct	eri_tmd	*tmdp;
36137c478bd9Sstevel@tonic-gate 	struct	eri_tmd	*tcomp;
36147c478bd9Sstevel@tonic-gate 	struct	eri_tmd	*tbasep;
36157c478bd9Sstevel@tonic-gate 	struct	eri_tmd	*tlimp;
36167c478bd9Sstevel@tonic-gate 	uint64_t	flags;
36177c478bd9Sstevel@tonic-gate 	uint_t reclaimed = 0;
36187c478bd9Sstevel@tonic-gate 
36197c478bd9Sstevel@tonic-gate 	tbasep = erip->eri_tmdp;
36207c478bd9Sstevel@tonic-gate 	tlimp = erip->eri_tmdlimp;
36217c478bd9Sstevel@tonic-gate 
36227c478bd9Sstevel@tonic-gate 	tmdp = erip->tcurp;
36237c478bd9Sstevel@tonic-gate 	tcomp = tbasep + tx_completion; /* pointer to completion tmd */
36247c478bd9Sstevel@tonic-gate 
36257c478bd9Sstevel@tonic-gate 	/*
36267c478bd9Sstevel@tonic-gate 	 * Loop through each TMD starting from tcurp and upto tcomp.
36277c478bd9Sstevel@tonic-gate 	 */
36287c478bd9Sstevel@tonic-gate 	while (tmdp != tcomp) {
36297c478bd9Sstevel@tonic-gate 		flags = GET_TMD_FLAGS(tmdp);
36307c478bd9Sstevel@tonic-gate 		if (flags & (ERI_TMD_SOP))
36317c478bd9Sstevel@tonic-gate 			HSTAT(erip, opackets64);
36327c478bd9Sstevel@tonic-gate 
36337c478bd9Sstevel@tonic-gate 		HSTATN(erip, obytes64, (flags & ERI_TMD_BUFSIZE));
36347c478bd9Sstevel@tonic-gate 
36357c478bd9Sstevel@tonic-gate 		tmdp = NEXTTMDP(tbasep, tlimp, tmdp);
36367c478bd9Sstevel@tonic-gate 		reclaimed++;
36377c478bd9Sstevel@tonic-gate 	}
36387c478bd9Sstevel@tonic-gate 
36397c478bd9Sstevel@tonic-gate 	erip->tcurp = tmdp;
36407c478bd9Sstevel@tonic-gate 	erip->tx_cur_cnt -= reclaimed;
36417c478bd9Sstevel@tonic-gate 
3642d64540e3Sgd 	return (erip->wantw && reclaimed ? B_TRUE : B_FALSE);
36437c478bd9Sstevel@tonic-gate }
36447c478bd9Sstevel@tonic-gate 
36457c478bd9Sstevel@tonic-gate 
36467c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<	PACKET RECEIVE FUNCTIONS	>>>>>>>>>>>>>>>>>>> */
3647d64540e3Sgd static mblk_t *
eri_read_dma(struct eri * erip,volatile struct rmd * rmdp,int rmdi,uint64_t flags)36487c478bd9Sstevel@tonic-gate eri_read_dma(struct eri *erip, volatile struct rmd *rmdp,
3649*7e996435SToomas Soome     int rmdi, uint64_t flags)
36507c478bd9Sstevel@tonic-gate {
36517c478bd9Sstevel@tonic-gate 	mblk_t	*bp, *nbp;
36527c478bd9Sstevel@tonic-gate 	int	len;
36537c478bd9Sstevel@tonic-gate 	uint_t ccnt;
36547c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t	c;
36557c478bd9Sstevel@tonic-gate #ifdef ERI_RCV_CKSUM
36567c478bd9Sstevel@tonic-gate 	ushort_t sum;
36577c478bd9Sstevel@tonic-gate #endif /* ERI_RCV_CKSUM */
3658d64540e3Sgd 	mblk_t *retmp = NULL;
36597c478bd9Sstevel@tonic-gate 
36607c478bd9Sstevel@tonic-gate 	bp = erip->rmblkp[rmdi];
36617c478bd9Sstevel@tonic-gate 	len = (flags & ERI_RMD_BUFSIZE) >> ERI_RMD_BUFSIZE_SHIFT;
36627c478bd9Sstevel@tonic-gate #ifdef	ERI_DONT_STRIP_CRC
36637c478bd9Sstevel@tonic-gate 	len -= 4;
36647c478bd9Sstevel@tonic-gate #endif
36657c478bd9Sstevel@tonic-gate 	/*
36667c478bd9Sstevel@tonic-gate 	 * In the event of RX FIFO overflow error, ERI REV 1.0 ASIC can
36677c478bd9Sstevel@tonic-gate 	 * corrupt packets following the descriptor corresponding the
36687c478bd9Sstevel@tonic-gate 	 * overflow. To detect the corrupted packets, we disable the
36697c478bd9Sstevel@tonic-gate 	 * dropping of the "bad" packets at the MAC. The descriptor
36707c478bd9Sstevel@tonic-gate 	 * then would have the "BAD" bit set. We drop the overflowing
36717c478bd9Sstevel@tonic-gate 	 * packet and the packet following it. We could have done some sort
36727c478bd9Sstevel@tonic-gate 	 * of checking to determine if the second packet was indeed bad
36737c478bd9Sstevel@tonic-gate 	 * (using CRC or checksum) but it would be expensive in this
36747c478bd9Sstevel@tonic-gate 	 * routine, since it is run in interrupt context.
36757c478bd9Sstevel@tonic-gate 	 */
3676d64540e3Sgd 	if ((flags & ERI_RMD_BAD) || (len  < ETHERMIN) || (len > ETHERMAX+4)) {
36777c478bd9Sstevel@tonic-gate 
36787c478bd9Sstevel@tonic-gate 		HSTAT(erip, rx_bad_pkts);
36797c478bd9Sstevel@tonic-gate 		if ((flags & ERI_RMD_BAD) == 0)
36807c478bd9Sstevel@tonic-gate 			HSTAT(erip, ierrors);
36817c478bd9Sstevel@tonic-gate 		if (len < ETHERMIN) {
36827c478bd9Sstevel@tonic-gate 			HSTAT(erip, rx_runt);
3683d64540e3Sgd 		} else if (len > ETHERMAX+4) {
36847c478bd9Sstevel@tonic-gate 			HSTAT(erip, rx_toolong_pkts);
36857c478bd9Sstevel@tonic-gate 		}
36867c478bd9Sstevel@tonic-gate 		HSTAT(erip, drop);
36877c478bd9Sstevel@tonic-gate 		UPDATE_RMD(rmdp);
36887c478bd9Sstevel@tonic-gate 
36897c478bd9Sstevel@tonic-gate 		ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
3690d64540e3Sgd 		    DDI_DMA_SYNC_FORDEV);
3691d64540e3Sgd 		return (NULL);
36927c478bd9Sstevel@tonic-gate 	}
36937c478bd9Sstevel@tonic-gate #ifdef  ERI_DONT_STRIP_CRC
36947c478bd9Sstevel@tonic-gate 	{
36957c478bd9Sstevel@tonic-gate 		uint32_t hw_fcs, tail_fcs;
36967c478bd9Sstevel@tonic-gate 		/*
369783fcdc8cSyc 		 * since we don't let the hardware strip the CRC in hdx
36987c478bd9Sstevel@tonic-gate 		 * then the driver needs to do it.
36997c478bd9Sstevel@tonic-gate 		 * this is to workaround a hardware bug
37007c478bd9Sstevel@tonic-gate 		 */
37017c478bd9Sstevel@tonic-gate 		bp->b_wptr = bp->b_rptr + ERI_FSTBYTE_OFFSET + len;
37027c478bd9Sstevel@tonic-gate 		/*
37037c478bd9Sstevel@tonic-gate 		 * Get the Checksum calculated by the hardware.
37047c478bd9Sstevel@tonic-gate 		 */
37057c478bd9Sstevel@tonic-gate 		hw_fcs = flags & ERI_RMD_CKSUM;
37067c478bd9Sstevel@tonic-gate 		/*
37077c478bd9Sstevel@tonic-gate 		 * Catch the case when the CRC starts on an odd
37087c478bd9Sstevel@tonic-gate 		 * boundary.
37097c478bd9Sstevel@tonic-gate 		 */
37107c478bd9Sstevel@tonic-gate 		tail_fcs = bp->b_wptr[0] << 8 | bp->b_wptr[1];
37117c478bd9Sstevel@tonic-gate 		tail_fcs += bp->b_wptr[2] << 8 | bp->b_wptr[3];
37127c478bd9Sstevel@tonic-gate 		tail_fcs = (tail_fcs & 0xffff) + (tail_fcs >> 16);
371383fcdc8cSyc 		if ((uintptr_t)(bp->b_wptr) & 1) {
37147c478bd9Sstevel@tonic-gate 			tail_fcs = (tail_fcs << 8) & 0xffff  | (tail_fcs >> 8);
37157c478bd9Sstevel@tonic-gate 		}
37167c478bd9Sstevel@tonic-gate 		hw_fcs += tail_fcs;
37177c478bd9Sstevel@tonic-gate 		hw_fcs = (hw_fcs & 0xffff) + (hw_fcs >> 16);
37187c478bd9Sstevel@tonic-gate 		hw_fcs &= 0xffff;
37197c478bd9Sstevel@tonic-gate 		/*
37207c478bd9Sstevel@tonic-gate 		 * Now we can replace what the hardware wrote, make believe
37217c478bd9Sstevel@tonic-gate 		 * it got it right in the first place.
37227c478bd9Sstevel@tonic-gate 		 */
37237c478bd9Sstevel@tonic-gate 		flags = (flags & ~(uint64_t)ERI_RMD_CKSUM) | hw_fcs;
37247c478bd9Sstevel@tonic-gate 	}
37257c478bd9Sstevel@tonic-gate #endif
37267c478bd9Sstevel@tonic-gate 	/*
37277c478bd9Sstevel@tonic-gate 	 * Packet Processing
37287c478bd9Sstevel@tonic-gate 	 * Once we get a packet bp, we try allocate a new mblk, nbp
37297c478bd9Sstevel@tonic-gate 	 * to replace this one. If we succeed, we map it to the current
37307c478bd9Sstevel@tonic-gate 	 * dma handle and update the descriptor with the new cookie. We
37317c478bd9Sstevel@tonic-gate 	 * then put bp in our read service queue erip->ipq, if it exists
37327c478bd9Sstevel@tonic-gate 	 * or we just bp to the streams expecting it.
37337c478bd9Sstevel@tonic-gate 	 * If allocation of the new mblk fails, we implicitly drop the
37347c478bd9Sstevel@tonic-gate 	 * current packet, i.e do not pass up the mblk and re-use it.
37357c478bd9Sstevel@tonic-gate 	 * Re-mapping is not required.
37367c478bd9Sstevel@tonic-gate 	 */
37377c478bd9Sstevel@tonic-gate 
37387c478bd9Sstevel@tonic-gate 	if (len < eri_rx_bcopy_max) {
37397c478bd9Sstevel@tonic-gate 		if ((nbp = eri_allocb_sp(len + ERI_FSTBYTE_OFFSET))) {
37407c478bd9Sstevel@tonic-gate 			(void) ddi_dma_sync(erip->ndmarh[rmdi], 0,
3741d64540e3Sgd 			    len + ERI_FSTBYTE_OFFSET, DDI_DMA_SYNC_FORCPU);
37427c478bd9Sstevel@tonic-gate 			DB_TYPE(nbp) = M_DATA;
37437c478bd9Sstevel@tonic-gate 			bcopy(bp->b_rptr, nbp->b_rptr,
3744d64540e3Sgd 			    len + ERI_FSTBYTE_OFFSET);
37457c478bd9Sstevel@tonic-gate 			UPDATE_RMD(rmdp);
37467c478bd9Sstevel@tonic-gate 			ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
3747d64540e3Sgd 			    DDI_DMA_SYNC_FORDEV);
37487c478bd9Sstevel@tonic-gate 
37497c478bd9Sstevel@tonic-gate 			/* Add the First Byte offset to the b_rptr */
37507c478bd9Sstevel@tonic-gate 			nbp->b_rptr += ERI_FSTBYTE_OFFSET;
37517c478bd9Sstevel@tonic-gate 			nbp->b_wptr = nbp->b_rptr + len;
37527c478bd9Sstevel@tonic-gate 
37537c478bd9Sstevel@tonic-gate #ifdef ERI_RCV_CKSUM
37547c478bd9Sstevel@tonic-gate 			sum = ~(uint16_t)(flags & ERI_RMD_CKSUM);
37557c478bd9Sstevel@tonic-gate 			ERI_PROCESS_READ(erip, nbp, sum);
37567c478bd9Sstevel@tonic-gate #else
37577c478bd9Sstevel@tonic-gate 			ERI_PROCESS_READ(erip, nbp);
37587c478bd9Sstevel@tonic-gate #endif
3759d64540e3Sgd 			retmp = nbp;
37607c478bd9Sstevel@tonic-gate 		} else {
37617c478bd9Sstevel@tonic-gate 
37627c478bd9Sstevel@tonic-gate 			/*
37637c478bd9Sstevel@tonic-gate 			 * mblk allocation has failed. Re-use the old mblk for
37647c478bd9Sstevel@tonic-gate 			 * the next packet. Re-mapping is not required since
37657c478bd9Sstevel@tonic-gate 			 * the same mblk and dma cookie is to be used again.
37667c478bd9Sstevel@tonic-gate 			 */
37677c478bd9Sstevel@tonic-gate 			HSTAT(erip, ierrors);
37687c478bd9Sstevel@tonic-gate 			HSTAT(erip, allocbfail);
37697c478bd9Sstevel@tonic-gate 			HSTAT(erip, norcvbuf);
37707c478bd9Sstevel@tonic-gate 
37717c478bd9Sstevel@tonic-gate 			UPDATE_RMD(rmdp);
37727c478bd9Sstevel@tonic-gate 			ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
3773d64540e3Sgd 			    DDI_DMA_SYNC_FORDEV);
3774d64540e3Sgd 			ERI_DEBUG_MSG1(erip, RESOURCE_MSG, "allocb fail");
37757c478bd9Sstevel@tonic-gate 		}
37767c478bd9Sstevel@tonic-gate 	} else {
37777c478bd9Sstevel@tonic-gate 		/* Use dma unmap/map */
37787c478bd9Sstevel@tonic-gate 		if ((nbp = eri_allocb_sp(ERI_BUFSIZE))) {
37797c478bd9Sstevel@tonic-gate 			/*
37807c478bd9Sstevel@tonic-gate 			 * How do we harden this, specially if unbind
37817c478bd9Sstevel@tonic-gate 			 * succeeds and then bind fails?
37827c478bd9Sstevel@tonic-gate 			 *  If Unbind fails, we can leave without updating
37837c478bd9Sstevel@tonic-gate 			 * the descriptor but would it continue to work on
37847c478bd9Sstevel@tonic-gate 			 * next round?
37857c478bd9Sstevel@tonic-gate 			 */
37867c478bd9Sstevel@tonic-gate 			(void) ddi_dma_unbind_handle(erip->ndmarh[rmdi]);
37877c478bd9Sstevel@tonic-gate 			(void) ddi_dma_addr_bind_handle(erip->ndmarh[rmdi],
3788d64540e3Sgd 			    NULL, (caddr_t)nbp->b_rptr, ERI_BUFSIZE,
3789d64540e3Sgd 			    DDI_DMA_READ | DDI_DMA_CONSISTENT,
3790d64540e3Sgd 			    DDI_DMA_DONTWAIT, 0, &c, &ccnt);
37917c478bd9Sstevel@tonic-gate 
3792d64540e3Sgd 			erip->rmblkp[rmdi] = nbp;
3793d64540e3Sgd 			PUT_RMD(rmdp, c);
3794d64540e3Sgd 			ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
3795d64540e3Sgd 			    DDI_DMA_SYNC_FORDEV);
37967c478bd9Sstevel@tonic-gate 
3797d64540e3Sgd 			/* Add the First Byte offset to the b_rptr */
37987c478bd9Sstevel@tonic-gate 
3799d64540e3Sgd 			bp->b_rptr += ERI_FSTBYTE_OFFSET;
3800d64540e3Sgd 			bp->b_wptr = bp->b_rptr + len;
38017c478bd9Sstevel@tonic-gate 
38027c478bd9Sstevel@tonic-gate #ifdef ERI_RCV_CKSUM
3803d64540e3Sgd 			sum = ~(uint16_t)(flags & ERI_RMD_CKSUM);
3804d64540e3Sgd 			ERI_PROCESS_READ(erip, bp, sum);
38057c478bd9Sstevel@tonic-gate #else
3806d64540e3Sgd 			ERI_PROCESS_READ(erip, bp);
38077c478bd9Sstevel@tonic-gate #endif
3808d64540e3Sgd 			retmp = bp;
38097c478bd9Sstevel@tonic-gate 		} else {
38107c478bd9Sstevel@tonic-gate 
38117c478bd9Sstevel@tonic-gate 			/*
38127c478bd9Sstevel@tonic-gate 			 * mblk allocation has failed. Re-use the old mblk for
38137c478bd9Sstevel@tonic-gate 			 * the next packet. Re-mapping is not required since
38147c478bd9Sstevel@tonic-gate 			 * the same mblk and dma cookie is to be used again.
38157c478bd9Sstevel@tonic-gate 			 */
38167c478bd9Sstevel@tonic-gate 			HSTAT(erip, ierrors);
3817d64540e3Sgd 			HSTAT(erip, allocbfail);
3818d64540e3Sgd 			HSTAT(erip, norcvbuf);
38197c478bd9Sstevel@tonic-gate 
3820d64540e3Sgd 			UPDATE_RMD(rmdp);
3821d64540e3Sgd 			ERI_SYNCIOPB(erip, rmdp, sizeof (struct rmd),
3822d64540e3Sgd 			    DDI_DMA_SYNC_FORDEV);
3823d64540e3Sgd 			ERI_DEBUG_MSG1(erip, RESOURCE_MSG, "allocb fail");
38247c478bd9Sstevel@tonic-gate 		}
38257c478bd9Sstevel@tonic-gate 	}
38267c478bd9Sstevel@tonic-gate 
3827d64540e3Sgd 	return (retmp);
3828d64540e3Sgd }
38297c478bd9Sstevel@tonic-gate 
38307c478bd9Sstevel@tonic-gate #define	LINK_STAT_DISPLAY_TIME	20
38317c478bd9Sstevel@tonic-gate 
38327c478bd9Sstevel@tonic-gate static int
eri_init_xfer_params(struct eri * erip)38337c478bd9Sstevel@tonic-gate eri_init_xfer_params(struct eri *erip)
38347c478bd9Sstevel@tonic-gate {
38357c478bd9Sstevel@tonic-gate 	int	i;
38367c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
38377c478bd9Sstevel@tonic-gate 
38387c478bd9Sstevel@tonic-gate 	dip = erip->dip;
38397c478bd9Sstevel@tonic-gate 
38407c478bd9Sstevel@tonic-gate 	for (i = 0; i < A_CNT(param_arr); i++)
38417c478bd9Sstevel@tonic-gate 		erip->param_arr[i] = param_arr[i];
38427c478bd9Sstevel@tonic-gate 
38437c478bd9Sstevel@tonic-gate 	erip->xmit_dma_mode = 0;
38447c478bd9Sstevel@tonic-gate 	erip->rcv_dma_mode = 0;
38457c478bd9Sstevel@tonic-gate 	erip->mifpoll_enable = mifpoll_enable;
38467c478bd9Sstevel@tonic-gate 	erip->lance_mode_enable = lance_mode;
38477c478bd9Sstevel@tonic-gate 	erip->frame_enable = 1;
38487c478bd9Sstevel@tonic-gate 	erip->ngu_enable = ngu_enable;
38497c478bd9Sstevel@tonic-gate 
38507c478bd9Sstevel@tonic-gate 	if (!erip->g_nd && !eri_param_register(erip,
38517c478bd9Sstevel@tonic-gate 	    erip->param_arr, A_CNT(param_arr))) {
38527c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
3853d64540e3Sgd 		    param_reg_fail_msg);
38547c478bd9Sstevel@tonic-gate 			return (-1);
38557c478bd9Sstevel@tonic-gate 		}
38567c478bd9Sstevel@tonic-gate 
38577c478bd9Sstevel@tonic-gate 	/*
38587c478bd9Sstevel@tonic-gate 	 * Set up the start-up values for user-configurable parameters
38597c478bd9Sstevel@tonic-gate 	 * Get the values from the global variables first.
38607c478bd9Sstevel@tonic-gate 	 * Use the MASK to limit the value to allowed maximum.
38617c478bd9Sstevel@tonic-gate 	 */
3862d64540e3Sgd 
38637c478bd9Sstevel@tonic-gate 	param_transceiver = NO_XCVR;
38647c478bd9Sstevel@tonic-gate 
38657c478bd9Sstevel@tonic-gate /*
38667c478bd9Sstevel@tonic-gate  * The link speed may be forced to either 10 Mbps or 100 Mbps using the
38677c478bd9Sstevel@tonic-gate  * property "transfer-speed". This may be done in OBP by using the command
38687c478bd9Sstevel@tonic-gate  * "apply transfer-speed=<speed> <device>". The speed may be either 10 or 100.
38697c478bd9Sstevel@tonic-gate  */
3870d64540e3Sgd 	i = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "transfer-speed", 0);
3871d64540e3Sgd 	if (i != 0) {
38727c478bd9Sstevel@tonic-gate 		param_autoneg = 0;	/* force speed */
38737c478bd9Sstevel@tonic-gate 		param_anar_100T4 = 0;
38747c478bd9Sstevel@tonic-gate 		param_anar_10fdx = 0;
38757c478bd9Sstevel@tonic-gate 		param_anar_10hdx = 0;
38767c478bd9Sstevel@tonic-gate 		param_anar_100fdx = 0;
38777c478bd9Sstevel@tonic-gate 		param_anar_100hdx = 0;
38787c478bd9Sstevel@tonic-gate 		param_anar_asm_dir = 0;
38797c478bd9Sstevel@tonic-gate 		param_anar_pause = 0;
38807c478bd9Sstevel@tonic-gate 
38817c478bd9Sstevel@tonic-gate 		if (i == 10)
38827c478bd9Sstevel@tonic-gate 			param_anar_10hdx = 1;
38837c478bd9Sstevel@tonic-gate 		else if (i == 100)
38847c478bd9Sstevel@tonic-gate 			param_anar_100hdx = 1;
38857c478bd9Sstevel@tonic-gate 	}
38867c478bd9Sstevel@tonic-gate 
38877c478bd9Sstevel@tonic-gate 	/*
38887c478bd9Sstevel@tonic-gate 	 * Get the parameter values configured in .conf file.
38897c478bd9Sstevel@tonic-gate 	 */
3890d64540e3Sgd 	param_ipg1 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "ipg1", ipg1) &
3891d64540e3Sgd 	    ERI_MASK_8BIT;
38927c478bd9Sstevel@tonic-gate 
3893d64540e3Sgd 	param_ipg2 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "ipg2", ipg2) &
3894d64540e3Sgd 	    ERI_MASK_8BIT;
38957c478bd9Sstevel@tonic-gate 
3896d64540e3Sgd 	param_use_intphy = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3897d64540e3Sgd 	    "use_int_xcvr", use_int_xcvr) & ERI_MASK_1BIT;
38987c478bd9Sstevel@tonic-gate 
3899d64540e3Sgd 	param_use_intphy = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3900d64540e3Sgd 	    "pace_size", pace_size) & ERI_MASK_8BIT;
39017c478bd9Sstevel@tonic-gate 
3902d64540e3Sgd 	param_autoneg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3903d64540e3Sgd 	    "adv_autoneg_cap", adv_autoneg_cap) & ERI_MASK_1BIT;
39047c478bd9Sstevel@tonic-gate 
3905d64540e3Sgd 	param_autoneg = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3906d64540e3Sgd 	    "adv_autoneg_cap", adv_autoneg_cap) & ERI_MASK_1BIT;
39077c478bd9Sstevel@tonic-gate 
3908d64540e3Sgd 	param_anar_100T4 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3909d64540e3Sgd 	    "adv_100T4_cap", adv_100T4_cap) & ERI_MASK_1BIT;
3910d64540e3Sgd 
3911d64540e3Sgd 	param_anar_100fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3912d64540e3Sgd 	    "adv_100fdx_cap", adv_100fdx_cap) & ERI_MASK_1BIT;
3913d64540e3Sgd 
3914d64540e3Sgd 	param_anar_100hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3915d64540e3Sgd 	    "adv_100hdx_cap", adv_100hdx_cap) & ERI_MASK_1BIT;
3916d64540e3Sgd 
3917d64540e3Sgd 	param_anar_10fdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3918d64540e3Sgd 	    "adv_10fdx_cap", adv_10fdx_cap) & ERI_MASK_1BIT;
3919d64540e3Sgd 
3920d64540e3Sgd 	param_anar_10hdx = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3921d64540e3Sgd 	    "adv_10hdx_cap", adv_10hdx_cap) & ERI_MASK_1BIT;
3922d64540e3Sgd 
3923d64540e3Sgd 	param_ipg0 = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0, "ipg0", ipg0) &
3924d64540e3Sgd 	    ERI_MASK_8BIT;
3925d64540e3Sgd 
3926d64540e3Sgd 	param_intr_blank_time = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3927d64540e3Sgd 	    "intr_blank_time", intr_blank_time) & ERI_MASK_8BIT;
3928d64540e3Sgd 
3929d64540e3Sgd 	param_intr_blank_packets = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3930d64540e3Sgd 	    "intr_blank_packets", intr_blank_packets) & ERI_MASK_8BIT;
3931d64540e3Sgd 
3932d64540e3Sgd 	param_lance_mode = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3933d64540e3Sgd 	    "lance_mode", lance_mode) & ERI_MASK_1BIT;
3934d64540e3Sgd 
3935d64540e3Sgd 	param_select_link = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3936d64540e3Sgd 	    "select_link", select_link) & ERI_MASK_1BIT;
3937d64540e3Sgd 
3938d64540e3Sgd 	param_default_link = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3939d64540e3Sgd 	    "default_link", default_link) & ERI_MASK_1BIT;
3940d64540e3Sgd 
3941d64540e3Sgd 	param_anar_asm_dir = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3942d64540e3Sgd 	    "adv_asm_dir_cap", adv_pauseTX_cap) & ERI_MASK_1BIT;
3943d64540e3Sgd 
3944d64540e3Sgd 	param_anar_pause = ddi_prop_get_int(DDI_DEV_T_ANY, dip, 0,
3945d64540e3Sgd 	    "adv_pause_cap", adv_pauseRX_cap) & ERI_MASK_1BIT;
3946d64540e3Sgd 
3947d64540e3Sgd 	if (link_pulse_disabled)
3948d64540e3Sgd 		erip->link_pulse_disabled = 1;
3949d64540e3Sgd 	if (ddi_prop_exists(DDI_DEV_T_ANY, dip, 0, "link-pulse-disabled"))
3950d64540e3Sgd 		erip->link_pulse_disabled = 1;
3951d64540e3Sgd 
3952d64540e3Sgd 	eri_statinit(erip);
3953d64540e3Sgd 	return (0);
39547c478bd9Sstevel@tonic-gate 
39557c478bd9Sstevel@tonic-gate }
39567c478bd9Sstevel@tonic-gate 
39577c478bd9Sstevel@tonic-gate static void
eri_process_ndd_ioctl(struct eri * erip,queue_t * wq,mblk_t * mp,int cmd)3958d64540e3Sgd eri_process_ndd_ioctl(struct eri *erip, queue_t *wq, mblk_t *mp, int cmd)
39597c478bd9Sstevel@tonic-gate {
39607c478bd9Sstevel@tonic-gate 
39617c478bd9Sstevel@tonic-gate 	uint32_t old_ipg1, old_ipg2, old_use_int_xcvr, old_autoneg;
39627c478bd9Sstevel@tonic-gate 	uint32_t old_100T4;
39637c478bd9Sstevel@tonic-gate 	uint32_t old_100fdx, old_100hdx, old_10fdx, old_10hdx;
39647c478bd9Sstevel@tonic-gate 	uint32_t old_ipg0, old_lance_mode;
39657c478bd9Sstevel@tonic-gate 	uint32_t old_intr_blank_time, old_intr_blank_packets;
39667c478bd9Sstevel@tonic-gate 	uint32_t old_asm_dir, old_pause;
39677c478bd9Sstevel@tonic-gate 	uint32_t old_select_link, old_default_link;
39687c478bd9Sstevel@tonic-gate 
39697c478bd9Sstevel@tonic-gate 	switch (cmd) {
39707c478bd9Sstevel@tonic-gate 	case ERI_ND_GET:
39717c478bd9Sstevel@tonic-gate 
39727c478bd9Sstevel@tonic-gate 		old_autoneg =	param_autoneg;
39737c478bd9Sstevel@tonic-gate 		old_100T4 =	param_anar_100T4;
39747c478bd9Sstevel@tonic-gate 		old_100fdx =	param_anar_100fdx;
39757c478bd9Sstevel@tonic-gate 		old_100hdx =	param_anar_100hdx;
39767c478bd9Sstevel@tonic-gate 		old_10fdx =	param_anar_10fdx;
39777c478bd9Sstevel@tonic-gate 		old_10hdx =	param_anar_10hdx;
39787c478bd9Sstevel@tonic-gate 		old_asm_dir =	param_anar_asm_dir;
39797c478bd9Sstevel@tonic-gate 		old_pause =	param_anar_pause;
39807c478bd9Sstevel@tonic-gate 
39817c478bd9Sstevel@tonic-gate 		param_autoneg = old_autoneg & ~ERI_NOTUSR;
39827c478bd9Sstevel@tonic-gate 		param_anar_100T4 = old_100T4 & ~ERI_NOTUSR;
39837c478bd9Sstevel@tonic-gate 		param_anar_100fdx = old_100fdx & ~ERI_NOTUSR;
39847c478bd9Sstevel@tonic-gate 		param_anar_100hdx = old_100hdx & ~ERI_NOTUSR;
39857c478bd9Sstevel@tonic-gate 		param_anar_10fdx = old_10fdx & ~ERI_NOTUSR;
39867c478bd9Sstevel@tonic-gate 		param_anar_10hdx = old_10hdx & ~ERI_NOTUSR;
39877c478bd9Sstevel@tonic-gate 		param_anar_asm_dir = old_asm_dir & ~ERI_NOTUSR;
39887c478bd9Sstevel@tonic-gate 		param_anar_pause = old_pause & ~ERI_NOTUSR;
39897c478bd9Sstevel@tonic-gate 
39907c478bd9Sstevel@tonic-gate 		if (!eri_nd_getset(wq, erip->g_nd, mp)) {
39917c478bd9Sstevel@tonic-gate 			param_autoneg = old_autoneg;
39927c478bd9Sstevel@tonic-gate 			param_anar_100T4 = old_100T4;
39937c478bd9Sstevel@tonic-gate 			param_anar_100fdx = old_100fdx;
39947c478bd9Sstevel@tonic-gate 			param_anar_100hdx = old_100hdx;
39957c478bd9Sstevel@tonic-gate 			param_anar_10fdx = old_10fdx;
39967c478bd9Sstevel@tonic-gate 			param_anar_10hdx = old_10hdx;
39977c478bd9Sstevel@tonic-gate 			param_anar_asm_dir = old_asm_dir;
39987c478bd9Sstevel@tonic-gate 			param_anar_pause = old_pause;
39997c478bd9Sstevel@tonic-gate 			miocnak(wq, mp, 0, EINVAL);
40007c478bd9Sstevel@tonic-gate 			return;
40017c478bd9Sstevel@tonic-gate 		}
40027c478bd9Sstevel@tonic-gate 		param_autoneg = old_autoneg;
40037c478bd9Sstevel@tonic-gate 		param_anar_100T4 = old_100T4;
40047c478bd9Sstevel@tonic-gate 		param_anar_100fdx = old_100fdx;
40057c478bd9Sstevel@tonic-gate 		param_anar_100hdx = old_100hdx;
40067c478bd9Sstevel@tonic-gate 		param_anar_10fdx = old_10fdx;
40077c478bd9Sstevel@tonic-gate 		param_anar_10hdx = old_10hdx;
40087c478bd9Sstevel@tonic-gate 		param_anar_asm_dir = old_asm_dir;
40097c478bd9Sstevel@tonic-gate 		param_anar_pause = old_pause;
40107c478bd9Sstevel@tonic-gate 
40117c478bd9Sstevel@tonic-gate 		qreply(wq, mp);
40127c478bd9Sstevel@tonic-gate 		break;
40137c478bd9Sstevel@tonic-gate 
40147c478bd9Sstevel@tonic-gate 	case ERI_ND_SET:
40157c478bd9Sstevel@tonic-gate 		old_ipg0 = param_ipg0;
40167c478bd9Sstevel@tonic-gate 		old_intr_blank_time = param_intr_blank_time;
40177c478bd9Sstevel@tonic-gate 		old_intr_blank_packets = param_intr_blank_packets;
40187c478bd9Sstevel@tonic-gate 		old_lance_mode = param_lance_mode;
40197c478bd9Sstevel@tonic-gate 		old_ipg1 = param_ipg1;
40207c478bd9Sstevel@tonic-gate 		old_ipg2 = param_ipg2;
40217c478bd9Sstevel@tonic-gate 		old_use_int_xcvr = param_use_intphy;
40227c478bd9Sstevel@tonic-gate 		old_autoneg = param_autoneg;
40237c478bd9Sstevel@tonic-gate 		old_100T4 =	param_anar_100T4;
40247c478bd9Sstevel@tonic-gate 		old_100fdx =	param_anar_100fdx;
40257c478bd9Sstevel@tonic-gate 		old_100hdx =	param_anar_100hdx;
40267c478bd9Sstevel@tonic-gate 		old_10fdx =	param_anar_10fdx;
40277c478bd9Sstevel@tonic-gate 		old_10hdx =	param_anar_10hdx;
40287c478bd9Sstevel@tonic-gate 		param_autoneg = 0xff;
40297c478bd9Sstevel@tonic-gate 		old_asm_dir = param_anar_asm_dir;
40307c478bd9Sstevel@tonic-gate 		param_anar_asm_dir = 0xff;
40317c478bd9Sstevel@tonic-gate 		old_pause = param_anar_pause;
40327c478bd9Sstevel@tonic-gate 		param_anar_pause = 0xff;
40337c478bd9Sstevel@tonic-gate 		old_select_link = param_select_link;
40347c478bd9Sstevel@tonic-gate 		old_default_link = param_default_link;
40357c478bd9Sstevel@tonic-gate 
40367c478bd9Sstevel@tonic-gate 		if (!eri_nd_getset(wq, erip->g_nd, mp)) {
40377c478bd9Sstevel@tonic-gate 			param_autoneg = old_autoneg;
40387c478bd9Sstevel@tonic-gate 			miocnak(wq, mp, 0, EINVAL);
40397c478bd9Sstevel@tonic-gate 			return;
40407c478bd9Sstevel@tonic-gate 		}
40417c478bd9Sstevel@tonic-gate 
40427c478bd9Sstevel@tonic-gate 		qreply(wq, mp);
40437c478bd9Sstevel@tonic-gate 
40447c478bd9Sstevel@tonic-gate 		if (param_autoneg != 0xff) {
40457c478bd9Sstevel@tonic-gate 			ERI_DEBUG_MSG2(erip, NDD_MSG,
4046d64540e3Sgd 			    "ndd_ioctl: new param_autoneg %d", param_autoneg);
40477c478bd9Sstevel@tonic-gate 			param_linkup = 0;
4048d64540e3Sgd 			erip->stats.link_up = LINK_STATE_DOWN;
4049d64540e3Sgd 			erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
40507c478bd9Sstevel@tonic-gate 			(void) eri_init(erip);
40517c478bd9Sstevel@tonic-gate 		} else {
40527c478bd9Sstevel@tonic-gate 			param_autoneg = old_autoneg;
40537c478bd9Sstevel@tonic-gate 			if ((old_use_int_xcvr != param_use_intphy) ||
4054d64540e3Sgd 			    (old_default_link != param_default_link) ||
4055d64540e3Sgd 			    (old_select_link != param_select_link)) {
40567c478bd9Sstevel@tonic-gate 				param_linkup = 0;
4057d64540e3Sgd 				erip->stats.link_up = LINK_STATE_DOWN;
4058d64540e3Sgd 				erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
40597c478bd9Sstevel@tonic-gate 				(void) eri_init(erip);
40607c478bd9Sstevel@tonic-gate 			} else if ((old_ipg1 != param_ipg1) ||
40617c478bd9Sstevel@tonic-gate 			    (old_ipg2 != param_ipg2) ||
40627c478bd9Sstevel@tonic-gate 			    (old_ipg0 != param_ipg0) ||
40637c478bd9Sstevel@tonic-gate 			    (old_intr_blank_time != param_intr_blank_time) ||
40647c478bd9Sstevel@tonic-gate 			    (old_intr_blank_packets !=
40657c478bd9Sstevel@tonic-gate 			    param_intr_blank_packets) ||
4066d64540e3Sgd 			    (old_lance_mode != param_lance_mode)) {
40677c478bd9Sstevel@tonic-gate 				param_linkup = 0;
4068d64540e3Sgd 				erip->stats.link_up = LINK_STATE_DOWN;
4069d64540e3Sgd 				erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
40707c478bd9Sstevel@tonic-gate 				(void) eri_init(erip);
40717c478bd9Sstevel@tonic-gate 			}
40727c478bd9Sstevel@tonic-gate 		}
40737c478bd9Sstevel@tonic-gate 		break;
40747c478bd9Sstevel@tonic-gate 	}
40757c478bd9Sstevel@tonic-gate }
40767c478bd9Sstevel@tonic-gate 
40777c478bd9Sstevel@tonic-gate 
40787c478bd9Sstevel@tonic-gate static int
eri_stat_kstat_update(kstat_t * ksp,int rw)40797c478bd9Sstevel@tonic-gate eri_stat_kstat_update(kstat_t *ksp, int rw)
40807c478bd9Sstevel@tonic-gate {
40817c478bd9Sstevel@tonic-gate 	struct eri *erip;
40827c478bd9Sstevel@tonic-gate 	struct erikstat *erikp;
40837c478bd9Sstevel@tonic-gate 	struct stats *esp;
4084d64540e3Sgd 	boolean_t macupdate = B_FALSE;
40857c478bd9Sstevel@tonic-gate 
40867c478bd9Sstevel@tonic-gate 	erip = (struct eri *)ksp->ks_private;
40877c478bd9Sstevel@tonic-gate 	erikp = (struct erikstat *)ksp->ks_data;
40887c478bd9Sstevel@tonic-gate 
4089d64540e3Sgd 	if (rw != KSTAT_READ)
4090d64540e3Sgd 		return (EACCES);
40917c478bd9Sstevel@tonic-gate 	/*
40927c478bd9Sstevel@tonic-gate 	 * Update all the stats by reading all the counter registers.
40937c478bd9Sstevel@tonic-gate 	 * Counter register stats are not updated till they overflow
40947c478bd9Sstevel@tonic-gate 	 * and interrupt.
40957c478bd9Sstevel@tonic-gate 	 */
40967c478bd9Sstevel@tonic-gate 
40977c478bd9Sstevel@tonic-gate 	mutex_enter(&erip->xmitlock);
40987c478bd9Sstevel@tonic-gate 	if ((erip->flags & ERI_RUNNING) && (erip->flags & ERI_TXINIT)) {
40997c478bd9Sstevel@tonic-gate 		erip->tx_completion =
4100d64540e3Sgd 		    GET_ETXREG(tx_completion) & ETX_COMPLETION_MASK;
4101d64540e3Sgd 		macupdate |= eri_reclaim(erip, erip->tx_completion);
41027c478bd9Sstevel@tonic-gate 	}
41037c478bd9Sstevel@tonic-gate 	mutex_exit(&erip->xmitlock);
4104d64540e3Sgd 	if (macupdate)
4105d64540e3Sgd 		mac_tx_update(erip->mh);
41067c478bd9Sstevel@tonic-gate 
41077c478bd9Sstevel@tonic-gate 	eri_savecntrs(erip);
41087c478bd9Sstevel@tonic-gate 
41097c478bd9Sstevel@tonic-gate 	esp = &erip->stats;
41107c478bd9Sstevel@tonic-gate 
4111d64540e3Sgd 	erikp->erik_txmac_maxpkt_err.value.ul = esp->txmac_maxpkt_err;
4112d64540e3Sgd 	erikp->erik_defer_timer_exp.value.ul = esp->defer_timer_exp;
4113d64540e3Sgd 	erikp->erik_peak_attempt_cnt.value.ul = esp->peak_attempt_cnt;
4114d64540e3Sgd 	erikp->erik_tx_hang.value.ul	= esp->tx_hang;
4115d64540e3Sgd 
4116d64540e3Sgd 	erikp->erik_no_free_rx_desc.value.ul	= esp->no_free_rx_desc;
4117d64540e3Sgd 
4118d64540e3Sgd 	erikp->erik_rx_hang.value.ul		= esp->rx_hang;
4119d64540e3Sgd 	erikp->erik_rx_length_err.value.ul	= esp->rx_length_err;
4120d64540e3Sgd 	erikp->erik_rx_code_viol_err.value.ul	= esp->rx_code_viol_err;
4121d64540e3Sgd 	erikp->erik_pause_rxcount.value.ul	= esp->pause_rxcount;
4122d64540e3Sgd 	erikp->erik_pause_oncount.value.ul	= esp->pause_oncount;
4123d64540e3Sgd 	erikp->erik_pause_offcount.value.ul	= esp->pause_offcount;
4124d64540e3Sgd 	erikp->erik_pause_time_count.value.ul	= esp->pause_time_count;
4125d64540e3Sgd 
4126d64540e3Sgd 	erikp->erik_inits.value.ul		= esp->inits;
4127d64540e3Sgd 	erikp->erik_jab.value.ul		= esp->jab;
4128d64540e3Sgd 	erikp->erik_notmds.value.ul		= esp->notmds;
4129d64540e3Sgd 	erikp->erik_allocbfail.value.ul		= esp->allocbfail;
4130d64540e3Sgd 	erikp->erik_drop.value.ul		= esp->drop;
4131d64540e3Sgd 	erikp->erik_rx_bad_pkts.value.ul	= esp->rx_bad_pkts;
4132d64540e3Sgd 	erikp->erik_rx_inits.value.ul		= esp->rx_inits;
4133d64540e3Sgd 	erikp->erik_tx_inits.value.ul		= esp->tx_inits;
4134d64540e3Sgd 	erikp->erik_rxtag_err.value.ul		= esp->rxtag_err;
4135d64540e3Sgd 	erikp->erik_parity_error.value.ul	= esp->parity_error;
4136d64540e3Sgd 	erikp->erik_pci_error_int.value.ul	= esp->pci_error_int;
4137d64540e3Sgd 	erikp->erik_unknown_fatal.value.ul	= esp->unknown_fatal;
4138d64540e3Sgd 	erikp->erik_pci_data_parity_err.value.ul = esp->pci_data_parity_err;
4139d64540e3Sgd 	erikp->erik_pci_signal_target_abort.value.ul =
4140d64540e3Sgd 	    esp->pci_signal_target_abort;
4141d64540e3Sgd 	erikp->erik_pci_rcvd_target_abort.value.ul =
4142d64540e3Sgd 	    esp->pci_rcvd_target_abort;
4143d64540e3Sgd 	erikp->erik_pci_rcvd_master_abort.value.ul =
4144d64540e3Sgd 	    esp->pci_rcvd_master_abort;
4145d64540e3Sgd 	erikp->erik_pci_signal_system_err.value.ul =
4146d64540e3Sgd 	    esp->pci_signal_system_err;
4147d64540e3Sgd 	erikp->erik_pci_det_parity_err.value.ul = esp->pci_det_parity_err;
4148d64540e3Sgd 
4149d64540e3Sgd 	erikp->erik_pmcap.value.ul = esp->pmcap;
41507c478bd9Sstevel@tonic-gate 
41517c478bd9Sstevel@tonic-gate 	return (0);
41527c478bd9Sstevel@tonic-gate }
41537c478bd9Sstevel@tonic-gate 
41547c478bd9Sstevel@tonic-gate static void
eri_statinit(struct eri * erip)41557c478bd9Sstevel@tonic-gate eri_statinit(struct eri *erip)
41567c478bd9Sstevel@tonic-gate {
41577c478bd9Sstevel@tonic-gate 	struct	kstat	*ksp;
41587c478bd9Sstevel@tonic-gate 	struct	erikstat	*erikp;
41597c478bd9Sstevel@tonic-gate 
4160d64540e3Sgd 	if ((ksp = kstat_create("eri", erip->instance, "driver_info", "net",
4161d64540e3Sgd 	    KSTAT_TYPE_NAMED,
41627c478bd9Sstevel@tonic-gate 	    sizeof (struct erikstat) / sizeof (kstat_named_t), 0)) == NULL) {
41637c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG1(erip, SEVERITY_LOW, ERI_VERB_MSG,
4164d64540e3Sgd 		    kstat_create_fail_msg);
41657c478bd9Sstevel@tonic-gate 		return;
41667c478bd9Sstevel@tonic-gate 	}
41677c478bd9Sstevel@tonic-gate 
41687c478bd9Sstevel@tonic-gate 	erip->ksp = ksp;
41697c478bd9Sstevel@tonic-gate 	erikp = (struct erikstat *)(ksp->ks_data);
41707c478bd9Sstevel@tonic-gate 	/*
41717c478bd9Sstevel@tonic-gate 	 * MIB II kstat variables
41727c478bd9Sstevel@tonic-gate 	 */
4173d64540e3Sgd 
4174d64540e3Sgd 	kstat_named_init(&erikp->erik_inits, "inits", KSTAT_DATA_ULONG);
4175d64540e3Sgd 
41767c478bd9Sstevel@tonic-gate 	kstat_named_init(&erikp->erik_txmac_maxpkt_err,	"txmac_maxpkt_err",
4177d64540e3Sgd 	    KSTAT_DATA_ULONG);
4178d64540e3Sgd 	kstat_named_init(&erikp->erik_defer_timer_exp, "defer_timer_exp",
4179d64540e3Sgd 	    KSTAT_DATA_ULONG);
41807c478bd9Sstevel@tonic-gate 	kstat_named_init(&erikp->erik_peak_attempt_cnt,	"peak_attempt_cnt",
4181d64540e3Sgd 	    KSTAT_DATA_ULONG);
4182d64540e3Sgd 	kstat_named_init(&erikp->erik_tx_hang, "tx_hang", KSTAT_DATA_ULONG);
4183d64540e3Sgd 
4184d64540e3Sgd 	kstat_named_init(&erikp->erik_no_free_rx_desc, "no_free_rx_desc",
4185d64540e3Sgd 	    KSTAT_DATA_ULONG);
4186d64540e3Sgd 	kstat_named_init(&erikp->erik_rx_hang, "rx_hang", KSTAT_DATA_ULONG);
4187d64540e3Sgd 	kstat_named_init(&erikp->erik_rx_length_err, "rx_length_err",
4188d64540e3Sgd 	    KSTAT_DATA_ULONG);
41897c478bd9Sstevel@tonic-gate 	kstat_named_init(&erikp->erik_rx_code_viol_err,	"rx_code_viol_err",
4190d64540e3Sgd 	    KSTAT_DATA_ULONG);
41917c478bd9Sstevel@tonic-gate 
4192d64540e3Sgd 	kstat_named_init(&erikp->erik_pause_rxcount, "pause_rcv_cnt",
4193d64540e3Sgd 	    KSTAT_DATA_ULONG);
41947c478bd9Sstevel@tonic-gate 
4195d64540e3Sgd 	kstat_named_init(&erikp->erik_pause_oncount, "pause_on_cnt",
4196d64540e3Sgd 	    KSTAT_DATA_ULONG);
41977c478bd9Sstevel@tonic-gate 
4198d64540e3Sgd 	kstat_named_init(&erikp->erik_pause_offcount, "pause_off_cnt",
4199d64540e3Sgd 	    KSTAT_DATA_ULONG);
42007c478bd9Sstevel@tonic-gate 	kstat_named_init(&erikp->erik_pause_time_count,	"pause_time_cnt",
4201d64540e3Sgd 	    KSTAT_DATA_ULONG);
4202d64540e3Sgd 
4203d64540e3Sgd 	kstat_named_init(&erikp->erik_jab, "jabber", KSTAT_DATA_ULONG);
4204d64540e3Sgd 	kstat_named_init(&erikp->erik_notmds, "no_tmds", KSTAT_DATA_ULONG);
42057c478bd9Sstevel@tonic-gate 	kstat_named_init(&erikp->erik_allocbfail, "allocbfail",
4206d64540e3Sgd 	    KSTAT_DATA_ULONG);
42077c478bd9Sstevel@tonic-gate 
4208d64540e3Sgd 	kstat_named_init(&erikp->erik_drop, "drop", KSTAT_DATA_ULONG);
42097c478bd9Sstevel@tonic-gate 
42107c478bd9Sstevel@tonic-gate 	kstat_named_init(&erikp->erik_rx_bad_pkts, "bad_pkts",
4211d64540e3Sgd 	    KSTAT_DATA_ULONG);
42127c478bd9Sstevel@tonic-gate 
4213d64540e3Sgd 	kstat_named_init(&erikp->erik_rx_inits, "rx_inits", KSTAT_DATA_ULONG);
42147c478bd9Sstevel@tonic-gate 
4215d64540e3Sgd 	kstat_named_init(&erikp->erik_tx_inits, "tx_inits", KSTAT_DATA_ULONG);
42167c478bd9Sstevel@tonic-gate 
42177c478bd9Sstevel@tonic-gate 	kstat_named_init(&erikp->erik_rxtag_err, "rxtag_error",
4218d64540e3Sgd 	    KSTAT_DATA_ULONG);
42197c478bd9Sstevel@tonic-gate 
4220d64540e3Sgd 	kstat_named_init(&erikp->erik_parity_error, "parity_error",
4221d64540e3Sgd 	    KSTAT_DATA_ULONG);
42227c478bd9Sstevel@tonic-gate 
4223d64540e3Sgd 	kstat_named_init(&erikp->erik_pci_error_int, "pci_error_interrupt",
4224d64540e3Sgd 	    KSTAT_DATA_ULONG);
42257c478bd9Sstevel@tonic-gate 	kstat_named_init(&erikp->erik_unknown_fatal, "unknown_fatal",
4226d64540e3Sgd 	    KSTAT_DATA_ULONG);
42277c478bd9Sstevel@tonic-gate 	kstat_named_init(&erikp->erik_pci_data_parity_err,
4228d64540e3Sgd 	    "pci_data_parity_err", KSTAT_DATA_ULONG);
42297c478bd9Sstevel@tonic-gate 	kstat_named_init(&erikp->erik_pci_signal_target_abort,
4230d64540e3Sgd 	    "pci_signal_target_abort", KSTAT_DATA_ULONG);
42317c478bd9Sstevel@tonic-gate 	kstat_named_init(&erikp->erik_pci_rcvd_target_abort,
4232d64540e3Sgd 	    "pci_rcvd_target_abort", KSTAT_DATA_ULONG);
42337c478bd9Sstevel@tonic-gate 	kstat_named_init(&erikp->erik_pci_rcvd_master_abort,
4234d64540e3Sgd 	    "pci_rcvd_master_abort", KSTAT_DATA_ULONG);
42357c478bd9Sstevel@tonic-gate 	kstat_named_init(&erikp->erik_pci_signal_system_err,
4236d64540e3Sgd 	    "pci_signal_system_err", KSTAT_DATA_ULONG);
42377c478bd9Sstevel@tonic-gate 	kstat_named_init(&erikp->erik_pci_det_parity_err,
4238d64540e3Sgd 	    "pci_det_parity_err", KSTAT_DATA_ULONG);
42397c478bd9Sstevel@tonic-gate 
4240d64540e3Sgd 	kstat_named_init(&erikp->erik_pmcap, "pmcap", KSTAT_DATA_ULONG);
42417c478bd9Sstevel@tonic-gate 
42427c478bd9Sstevel@tonic-gate 
42437c478bd9Sstevel@tonic-gate 	ksp->ks_update = eri_stat_kstat_update;
42447c478bd9Sstevel@tonic-gate 	ksp->ks_private = (void *) erip;
42457c478bd9Sstevel@tonic-gate 	kstat_install(ksp);
42467c478bd9Sstevel@tonic-gate }
42477c478bd9Sstevel@tonic-gate 
42487c478bd9Sstevel@tonic-gate 
42497c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<< NDD SUPPORT FUNCTIONS	>>>>>>>>>>>>>>>>>>> */
42507c478bd9Sstevel@tonic-gate /*
42517c478bd9Sstevel@tonic-gate  * ndd support functions to get/set parameters
42527c478bd9Sstevel@tonic-gate  */
42537c478bd9Sstevel@tonic-gate /* Free the Named Dispatch Table by calling eri_nd_free */
42547c478bd9Sstevel@tonic-gate static void
eri_param_cleanup(struct eri * erip)42557c478bd9Sstevel@tonic-gate eri_param_cleanup(struct eri *erip)
42567c478bd9Sstevel@tonic-gate {
42577c478bd9Sstevel@tonic-gate 	if (erip->g_nd)
42587c478bd9Sstevel@tonic-gate 		(void) eri_nd_free(&erip->g_nd);
42597c478bd9Sstevel@tonic-gate }
42607c478bd9Sstevel@tonic-gate 
42617c478bd9Sstevel@tonic-gate /*
42627c478bd9Sstevel@tonic-gate  * Extracts the value from the eri parameter array and prints the
42637c478bd9Sstevel@tonic-gate  * parameter value. cp points to the required parameter.
42647c478bd9Sstevel@tonic-gate  */
42657c478bd9Sstevel@tonic-gate /* ARGSUSED */
42667c478bd9Sstevel@tonic-gate static int
eri_param_get(queue_t * q,mblk_t * mp,caddr_t cp)42677c478bd9Sstevel@tonic-gate eri_param_get(queue_t *q, mblk_t *mp, caddr_t cp)
42687c478bd9Sstevel@tonic-gate {
4269d64540e3Sgd 	param_t		*eripa = (void *)cp;
42707c478bd9Sstevel@tonic-gate 	int		param_len = 1;
42717c478bd9Sstevel@tonic-gate 	uint32_t	param_val;
42727c478bd9Sstevel@tonic-gate 	mblk_t		*nmp;
42737c478bd9Sstevel@tonic-gate 	int		ok;
42747c478bd9Sstevel@tonic-gate 
42757c478bd9Sstevel@tonic-gate 	param_val = eripa->param_val;
42767c478bd9Sstevel@tonic-gate 	/*
42777c478bd9Sstevel@tonic-gate 	 * Calculate space required in mblk.
42787c478bd9Sstevel@tonic-gate 	 * Remember to include NULL terminator.
42797c478bd9Sstevel@tonic-gate 	 */
42807c478bd9Sstevel@tonic-gate 	do {
42817c478bd9Sstevel@tonic-gate 		param_len++;
42827c478bd9Sstevel@tonic-gate 		param_val /= 10;
42837c478bd9Sstevel@tonic-gate 	} while (param_val);
42847c478bd9Sstevel@tonic-gate 
42857c478bd9Sstevel@tonic-gate 	ok = eri_mk_mblk_tail_space(mp, &nmp, param_len);
42867c478bd9Sstevel@tonic-gate 	if (ok == 0) {
42877c478bd9Sstevel@tonic-gate 		(void) sprintf((char *)nmp->b_wptr, "%d", eripa->param_val);
42887c478bd9Sstevel@tonic-gate 		nmp->b_wptr += param_len;
42897c478bd9Sstevel@tonic-gate 	}
42907c478bd9Sstevel@tonic-gate 
42917c478bd9Sstevel@tonic-gate 	return (ok);
42927c478bd9Sstevel@tonic-gate }
42937c478bd9Sstevel@tonic-gate 
42947c478bd9Sstevel@tonic-gate /*
42957c478bd9Sstevel@tonic-gate  * Check if there is space for p_val at the end if mblk.
42967c478bd9Sstevel@tonic-gate  * If not, allocate new 1k mblk.
42977c478bd9Sstevel@tonic-gate  */
42987c478bd9Sstevel@tonic-gate static int
eri_mk_mblk_tail_space(mblk_t * mp,mblk_t ** nmp,size_t sz)42997c478bd9Sstevel@tonic-gate eri_mk_mblk_tail_space(mblk_t *mp, mblk_t **nmp, size_t sz)
43007c478bd9Sstevel@tonic-gate {
43017c478bd9Sstevel@tonic-gate 	mblk_t *tmp = mp;
43027c478bd9Sstevel@tonic-gate 
43037c478bd9Sstevel@tonic-gate 	while (tmp->b_cont)
43047c478bd9Sstevel@tonic-gate 		tmp = tmp->b_cont;
43057c478bd9Sstevel@tonic-gate 
43067c478bd9Sstevel@tonic-gate 	if (MBLKTAIL(tmp) < sz) {
43077c478bd9Sstevel@tonic-gate 		if ((tmp->b_cont = allocb(1024, BPRI_HI)) == NULL)
43087c478bd9Sstevel@tonic-gate 			return (ENOMEM);
43097c478bd9Sstevel@tonic-gate 		tmp = tmp->b_cont;
43107c478bd9Sstevel@tonic-gate 	}
43117c478bd9Sstevel@tonic-gate 	*nmp = tmp;
43127c478bd9Sstevel@tonic-gate 	return (0);
43137c478bd9Sstevel@tonic-gate }
43147c478bd9Sstevel@tonic-gate 
43157c478bd9Sstevel@tonic-gate /*
43167c478bd9Sstevel@tonic-gate  * Register each element of the parameter array with the
43177c478bd9Sstevel@tonic-gate  * named dispatch handler. Each element is loaded using
43187c478bd9Sstevel@tonic-gate  * eri_nd_load()
43197c478bd9Sstevel@tonic-gate  */
43207c478bd9Sstevel@tonic-gate static int
eri_param_register(struct eri * erip,param_t * eripa,int cnt)43217c478bd9Sstevel@tonic-gate eri_param_register(struct eri *erip, param_t *eripa, int cnt)
4322d64540e3Sgd {
43237c478bd9Sstevel@tonic-gate 	/* cnt gives the count of the number of */
43247c478bd9Sstevel@tonic-gate 	/* elements present in the parameter array */
43257c478bd9Sstevel@tonic-gate 
4326d64540e3Sgd 	int i;
43277c478bd9Sstevel@tonic-gate 
4328fd8be74fSgd 	for (i = 0; i < cnt; i++, eripa++) {
4329d64540e3Sgd 		pfi_t	setter = (pfi_t)eri_param_set;
43307c478bd9Sstevel@tonic-gate 
4331d64540e3Sgd 		switch (eripa->param_name[0]) {
4332d64540e3Sgd 		case '+':	/* read-write */
4333d64540e3Sgd 			setter = (pfi_t)eri_param_set;
4334d64540e3Sgd 			break;
4335d64540e3Sgd 
4336d64540e3Sgd 		case '-':	/* read-only */
4337d64540e3Sgd 			setter = NULL;
4338d64540e3Sgd 			break;
4339d64540e3Sgd 
4340d64540e3Sgd 		case '!':	/* read-only, not displayed */
4341d64540e3Sgd 		case '%':	/* read-write, not displayed */
4342d64540e3Sgd 			continue;
43437c478bd9Sstevel@tonic-gate 		}
4344d64540e3Sgd 
4345d64540e3Sgd 		if (!eri_nd_load(&erip->g_nd, eripa->param_name + 1,
4346fd8be74fSgd 		    (pfi_t)eri_param_get, setter, (caddr_t)eripa)) {
4347d64540e3Sgd 			(void) eri_nd_free(&erip->g_nd);
4348d64540e3Sgd 			return (B_FALSE);
43497c478bd9Sstevel@tonic-gate 		}
4350d64540e3Sgd 	}
43517c478bd9Sstevel@tonic-gate 
43527c478bd9Sstevel@tonic-gate 	return (B_TRUE);
43537c478bd9Sstevel@tonic-gate }
43547c478bd9Sstevel@tonic-gate 
43557c478bd9Sstevel@tonic-gate /*
43567c478bd9Sstevel@tonic-gate  * Sets the eri parameter to the value in the param_register using
43577c478bd9Sstevel@tonic-gate  * eri_nd_load().
43587c478bd9Sstevel@tonic-gate  */
43597c478bd9Sstevel@tonic-gate /* ARGSUSED */
43607c478bd9Sstevel@tonic-gate static int
eri_param_set(queue_t * q,mblk_t * mp,char * value,caddr_t cp)43617c478bd9Sstevel@tonic-gate eri_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp)
43627c478bd9Sstevel@tonic-gate {
43637c478bd9Sstevel@tonic-gate 	char *end;
4364d64540e3Sgd 	long new_value;
4365d64540e3Sgd 	param_t	*eripa = (void *)cp;
43667c478bd9Sstevel@tonic-gate 
4367d64540e3Sgd 	if (ddi_strtol(value, &end, 10, &new_value) != 0)
4368d64540e3Sgd 		return (EINVAL);
43697c478bd9Sstevel@tonic-gate 	if (end == value || new_value < eripa->param_min ||
43707c478bd9Sstevel@tonic-gate 	    new_value > eripa->param_max) {
43717c478bd9Sstevel@tonic-gate 			return (EINVAL);
43727c478bd9Sstevel@tonic-gate 	}
4373d64540e3Sgd 	eripa->param_val = (uint32_t)new_value;
43747c478bd9Sstevel@tonic-gate 	return (0);
43757c478bd9Sstevel@tonic-gate 
43767c478bd9Sstevel@tonic-gate }
43777c478bd9Sstevel@tonic-gate 
43787c478bd9Sstevel@tonic-gate /* Free the table pointed to by 'ndp' */
43797c478bd9Sstevel@tonic-gate static void
eri_nd_free(caddr_t * nd_pparam)43807c478bd9Sstevel@tonic-gate eri_nd_free(caddr_t *nd_pparam)
43817c478bd9Sstevel@tonic-gate {
43827c478bd9Sstevel@tonic-gate 	ND	*nd;
43837c478bd9Sstevel@tonic-gate 
4384d64540e3Sgd 	if ((nd = (void *)(*nd_pparam)) != NULL) {
43857c478bd9Sstevel@tonic-gate 		if (nd->nd_tbl)
4386d64540e3Sgd 			kmem_free(nd->nd_tbl, nd->nd_size);
4387d64540e3Sgd 		kmem_free(nd, sizeof (ND));
43887c478bd9Sstevel@tonic-gate 		*nd_pparam = NULL;
43897c478bd9Sstevel@tonic-gate 	}
43907c478bd9Sstevel@tonic-gate }
43917c478bd9Sstevel@tonic-gate 
43927c478bd9Sstevel@tonic-gate static int
eri_nd_getset(queue_t * q,caddr_t nd_param,MBLKP mp)43937c478bd9Sstevel@tonic-gate eri_nd_getset(queue_t *q, caddr_t nd_param, MBLKP mp)
43947c478bd9Sstevel@tonic-gate {
43957c478bd9Sstevel@tonic-gate 	int	err;
43967c478bd9Sstevel@tonic-gate 	IOCP	iocp;
43977c478bd9Sstevel@tonic-gate 	MBLKP	mp1;
43987c478bd9Sstevel@tonic-gate 	ND	*nd;
43997c478bd9Sstevel@tonic-gate 	NDE	*nde;
44007c478bd9Sstevel@tonic-gate 	char	*valp;
44017c478bd9Sstevel@tonic-gate 	size_t	avail;
44027c478bd9Sstevel@tonic-gate 	mblk_t	*nmp;
44037c478bd9Sstevel@tonic-gate 
44047c478bd9Sstevel@tonic-gate 	if (!nd_param)
44057c478bd9Sstevel@tonic-gate 		return (B_FALSE);
44067c478bd9Sstevel@tonic-gate 
4407d64540e3Sgd 	nd = (void *)nd_param;
4408d64540e3Sgd 	iocp = (void *)mp->b_rptr;
44097c478bd9Sstevel@tonic-gate 	if ((iocp->ioc_count == 0) || !(mp1 = mp->b_cont)) {
44107c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
44117c478bd9Sstevel@tonic-gate 		iocp->ioc_count = 0;
44127c478bd9Sstevel@tonic-gate 		iocp->ioc_error = EINVAL;
44137c478bd9Sstevel@tonic-gate 		return (B_TRUE);
44147c478bd9Sstevel@tonic-gate 	}
44157c478bd9Sstevel@tonic-gate 	/*
44167c478bd9Sstevel@tonic-gate 	 * NOTE - logic throughout nd_xxx assumes single data block for ioctl.
44177c478bd9Sstevel@tonic-gate 	 *	However, existing code sends in some big buffers.
44187c478bd9Sstevel@tonic-gate 	 */
44197c478bd9Sstevel@tonic-gate 	avail = iocp->ioc_count;
44207c478bd9Sstevel@tonic-gate 	if (mp1->b_cont) {
44217c478bd9Sstevel@tonic-gate 		freemsg(mp1->b_cont);
44227c478bd9Sstevel@tonic-gate 		mp1->b_cont = NULL;
44237c478bd9Sstevel@tonic-gate 	}
44247c478bd9Sstevel@tonic-gate 
44257c478bd9Sstevel@tonic-gate 	mp1->b_datap->db_lim[-1] = '\0';	/* Force null termination */
44267c478bd9Sstevel@tonic-gate 	valp = (char *)mp1->b_rptr;
44277c478bd9Sstevel@tonic-gate 
44287c478bd9Sstevel@tonic-gate 	for (nde = nd->nd_tbl; /* */; nde++) {
44297c478bd9Sstevel@tonic-gate 		if (!nde->nde_name)
44307c478bd9Sstevel@tonic-gate 			return (B_FALSE);
44317c478bd9Sstevel@tonic-gate 		if (strcmp(nde->nde_name, valp) == 0)
44327c478bd9Sstevel@tonic-gate 			break;
44337c478bd9Sstevel@tonic-gate 	}
44347c478bd9Sstevel@tonic-gate 	err = EINVAL;
44357c478bd9Sstevel@tonic-gate 
44367c478bd9Sstevel@tonic-gate 	while (*valp++)
44377c478bd9Sstevel@tonic-gate 		;
44387c478bd9Sstevel@tonic-gate 
44397c478bd9Sstevel@tonic-gate 	if (!*valp || valp >= (char *)mp1->b_wptr)
44407c478bd9Sstevel@tonic-gate 		valp = NULL;
44417c478bd9Sstevel@tonic-gate 
44427c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
44437c478bd9Sstevel@tonic-gate 	case ND_GET:
44447c478bd9Sstevel@tonic-gate 	/*
44457c478bd9Sstevel@tonic-gate 	 * (XXX) hack: "*valp" is size of user buffer for copyout. If result
44467c478bd9Sstevel@tonic-gate 	 * of action routine is too big, free excess and return ioc_rval as buf
44477c478bd9Sstevel@tonic-gate 	 * size needed.  Return as many mblocks as will fit, free the rest.  For
44487c478bd9Sstevel@tonic-gate 	 * backward compatibility, assume size of orig ioctl buffer if "*valp"
44497c478bd9Sstevel@tonic-gate 	 * bad or not given.
44507c478bd9Sstevel@tonic-gate 	 */
44517c478bd9Sstevel@tonic-gate 		if (valp)
4452d64540e3Sgd 			(void) ddi_strtol(valp, NULL, 10, (long *)&avail);
44537c478bd9Sstevel@tonic-gate 		/* We overwrite the name/value with the reply data */
44547c478bd9Sstevel@tonic-gate 		{
44557c478bd9Sstevel@tonic-gate 			mblk_t *mp2 = mp1;
44567c478bd9Sstevel@tonic-gate 
44577c478bd9Sstevel@tonic-gate 			while (mp2) {
44587c478bd9Sstevel@tonic-gate 				mp2->b_wptr = mp2->b_rptr;
44597c478bd9Sstevel@tonic-gate 				mp2 = mp2->b_cont;
44607c478bd9Sstevel@tonic-gate 			}
44617c478bd9Sstevel@tonic-gate 		}
44627c478bd9Sstevel@tonic-gate 		err = (*nde->nde_get_pfi)(q, mp1, nde->nde_data, iocp->ioc_cr);
44637c478bd9Sstevel@tonic-gate 		if (!err) {
44647c478bd9Sstevel@tonic-gate 			size_t	size_out;
44657c478bd9Sstevel@tonic-gate 			ssize_t	excess;
44667c478bd9Sstevel@tonic-gate 
44677c478bd9Sstevel@tonic-gate 			iocp->ioc_rval = 0;
44687c478bd9Sstevel@tonic-gate 
44697c478bd9Sstevel@tonic-gate 			/* Tack on the null */
44707c478bd9Sstevel@tonic-gate 			err = eri_mk_mblk_tail_space(mp1, &nmp, 1);
44717c478bd9Sstevel@tonic-gate 			if (!err) {
44727c478bd9Sstevel@tonic-gate 				*nmp->b_wptr++ = '\0';
44737c478bd9Sstevel@tonic-gate 				size_out = msgdsize(mp1);
44747c478bd9Sstevel@tonic-gate 				excess = size_out - avail;
44757c478bd9Sstevel@tonic-gate 				if (excess > 0) {
4476d64540e3Sgd 					iocp->ioc_rval = (unsigned)size_out;
44777c478bd9Sstevel@tonic-gate 					size_out -= excess;
44787c478bd9Sstevel@tonic-gate 					(void) adjmsg(mp1, -(excess + 1));
44797c478bd9Sstevel@tonic-gate 					err = eri_mk_mblk_tail_space(mp1,
4480d64540e3Sgd 					    &nmp, 1);
44817c478bd9Sstevel@tonic-gate 					if (!err)
44827c478bd9Sstevel@tonic-gate 						*nmp->b_wptr++ = '\0';
44837c478bd9Sstevel@tonic-gate 					else
44847c478bd9Sstevel@tonic-gate 						size_out = 0;
44857c478bd9Sstevel@tonic-gate 				}
44867c478bd9Sstevel@tonic-gate 
44877c478bd9Sstevel@tonic-gate 			} else
44887c478bd9Sstevel@tonic-gate 				size_out = 0;
44897c478bd9Sstevel@tonic-gate 
44907c478bd9Sstevel@tonic-gate 			iocp->ioc_count = size_out;
44917c478bd9Sstevel@tonic-gate 		}
44927c478bd9Sstevel@tonic-gate 		break;
44937c478bd9Sstevel@tonic-gate 
44947c478bd9Sstevel@tonic-gate 	case ND_SET:
44957c478bd9Sstevel@tonic-gate 		if (valp) {
4496d64540e3Sgd 			err = (*nde->nde_set_pfi)(q, mp1, valp,
4497d64540e3Sgd 			    nde->nde_data, iocp->ioc_cr);
44987c478bd9Sstevel@tonic-gate 			iocp->ioc_count = 0;
44997c478bd9Sstevel@tonic-gate 			freemsg(mp1);
45007c478bd9Sstevel@tonic-gate 			mp->b_cont = NULL;
45017c478bd9Sstevel@tonic-gate 		}
45027c478bd9Sstevel@tonic-gate 		break;
45037c478bd9Sstevel@tonic-gate 	}
4504d64540e3Sgd 
45057c478bd9Sstevel@tonic-gate 	iocp->ioc_error = err;
45067c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_IOCACK;
45077c478bd9Sstevel@tonic-gate 	return (B_TRUE);
45087c478bd9Sstevel@tonic-gate }
45097c478bd9Sstevel@tonic-gate 
45107c478bd9Sstevel@tonic-gate /*
45117c478bd9Sstevel@tonic-gate  * Load 'name' into the named dispatch table pointed to by 'ndp'.
45127c478bd9Sstevel@tonic-gate  * 'ndp' should be the address of a char pointer cell.  If the table
45137c478bd9Sstevel@tonic-gate  * does not exist (*ndp == 0), a new table is allocated and 'ndp'
45147c478bd9Sstevel@tonic-gate  * is stuffed.  If there is not enough space in the table for a new
45157c478bd9Sstevel@tonic-gate  * entry, more space is allocated.
45167c478bd9Sstevel@tonic-gate  */
45177c478bd9Sstevel@tonic-gate static boolean_t
eri_nd_load(caddr_t * nd_pparam,char * name,pfi_t get_pfi,pfi_t set_pfi,caddr_t data)45187c478bd9Sstevel@tonic-gate eri_nd_load(caddr_t *nd_pparam, char *name, pfi_t get_pfi,
45197c478bd9Sstevel@tonic-gate     pfi_t set_pfi, caddr_t data)
45207c478bd9Sstevel@tonic-gate {
45217c478bd9Sstevel@tonic-gate 	ND	*nd;
45227c478bd9Sstevel@tonic-gate 	NDE	*nde;
45237c478bd9Sstevel@tonic-gate 
45247c478bd9Sstevel@tonic-gate 	if (!nd_pparam)
45257c478bd9Sstevel@tonic-gate 		return (B_FALSE);
45267c478bd9Sstevel@tonic-gate 
4527d64540e3Sgd 	if ((nd = (void *)(*nd_pparam)) == NULL) {
45287c478bd9Sstevel@tonic-gate 		if ((nd = (ND *)kmem_zalloc(sizeof (ND), KM_NOSLEEP))
45297c478bd9Sstevel@tonic-gate 		    == NULL)
45307c478bd9Sstevel@tonic-gate 			return (B_FALSE);
45317c478bd9Sstevel@tonic-gate 		*nd_pparam = (caddr_t)nd;
45327c478bd9Sstevel@tonic-gate 	}
45337c478bd9Sstevel@tonic-gate 	if (nd->nd_tbl) {
45347c478bd9Sstevel@tonic-gate 		for (nde = nd->nd_tbl; nde->nde_name; nde++) {
45357c478bd9Sstevel@tonic-gate 			if (strcmp(name, nde->nde_name) == 0)
45367c478bd9Sstevel@tonic-gate 				goto fill_it;
45377c478bd9Sstevel@tonic-gate 		}
45387c478bd9Sstevel@tonic-gate 	}
45397c478bd9Sstevel@tonic-gate 	if (nd->nd_free_count <= 1) {
45407c478bd9Sstevel@tonic-gate 		if ((nde = (NDE *)kmem_zalloc(nd->nd_size +
45417c478bd9Sstevel@tonic-gate 		    NDE_ALLOC_SIZE, KM_NOSLEEP)) == NULL)
45427c478bd9Sstevel@tonic-gate 			return (B_FALSE);
45437c478bd9Sstevel@tonic-gate 
45447c478bd9Sstevel@tonic-gate 		nd->nd_free_count += NDE_ALLOC_COUNT;
45457c478bd9Sstevel@tonic-gate 		if (nd->nd_tbl) {
45467c478bd9Sstevel@tonic-gate 			bcopy((char *)nd->nd_tbl, (char *)nde, nd->nd_size);
45477c478bd9Sstevel@tonic-gate 			kmem_free((char *)nd->nd_tbl, nd->nd_size);
45487c478bd9Sstevel@tonic-gate 		} else {
45497c478bd9Sstevel@tonic-gate 			nd->nd_free_count--;
45507c478bd9Sstevel@tonic-gate 			nde->nde_name = "?";
45517c478bd9Sstevel@tonic-gate 			nde->nde_get_pfi = nd_get_names;
45527c478bd9Sstevel@tonic-gate 			nde->nde_set_pfi = nd_set_default;
45537c478bd9Sstevel@tonic-gate 		}
45547c478bd9Sstevel@tonic-gate 		nde->nde_data = (caddr_t)nd;
45557c478bd9Sstevel@tonic-gate 		nd->nd_tbl = nde;
45567c478bd9Sstevel@tonic-gate 		nd->nd_size += NDE_ALLOC_SIZE;
45577c478bd9Sstevel@tonic-gate 	}
45587c478bd9Sstevel@tonic-gate 	for (nde = nd->nd_tbl; nde->nde_name; nde++)
45597c478bd9Sstevel@tonic-gate 		;
45607c478bd9Sstevel@tonic-gate 	nd->nd_free_count--;
45617c478bd9Sstevel@tonic-gate fill_it:
45627c478bd9Sstevel@tonic-gate 	nde->nde_name = name;
45637c478bd9Sstevel@tonic-gate 	nde->nde_get_pfi = get_pfi ? get_pfi : nd_get_default;
45647c478bd9Sstevel@tonic-gate 	nde->nde_set_pfi = set_pfi ? set_pfi : nd_set_default;
45657c478bd9Sstevel@tonic-gate 	nde->nde_data = data;
45667c478bd9Sstevel@tonic-gate 	return (B_TRUE);
45677c478bd9Sstevel@tonic-gate }
45687c478bd9Sstevel@tonic-gate 
45697c478bd9Sstevel@tonic-gate /*
45707c478bd9Sstevel@tonic-gate  * Hardening Functions
45717c478bd9Sstevel@tonic-gate  * New Section
45727c478bd9Sstevel@tonic-gate  */
45737c478bd9Sstevel@tonic-gate #ifdef  DEBUG
4574d64540e3Sgd /*PRINTFLIKE5*/
45757c478bd9Sstevel@tonic-gate static void
eri_debug_msg(const char * file,int line,struct eri * erip,debug_msg_t type,const char * fmt,...)4576d64540e3Sgd eri_debug_msg(const char *file, int line, struct eri *erip,
4577297a64e7Sgd     debug_msg_t type, const char *fmt, ...)
45787c478bd9Sstevel@tonic-gate {
45797c478bd9Sstevel@tonic-gate 	char	msg_buffer[255];
45807c478bd9Sstevel@tonic-gate 	va_list ap;
45817c478bd9Sstevel@tonic-gate 
45827c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
45837c478bd9Sstevel@tonic-gate 	(void) vsprintf(msg_buffer, fmt, ap);
45847c478bd9Sstevel@tonic-gate 	va_end(ap);
45857c478bd9Sstevel@tonic-gate 
45867c478bd9Sstevel@tonic-gate 	if (eri_msg_out & ERI_CON_MSG) {
45877c478bd9Sstevel@tonic-gate 		if (((type <= eri_debug_level) && eri_debug_all) ||
4588d64540e3Sgd 		    ((type == eri_debug_level) && !eri_debug_all)) {
45897c478bd9Sstevel@tonic-gate 			if (erip)
4590d64540e3Sgd 				cmn_err(CE_CONT, "D: %s %s%d:(%s%d) %s\n",
4591d64540e3Sgd 				    debug_msg_string[type], file, line,
4592d64540e3Sgd 				    ddi_driver_name(erip->dip), erip->instance,
4593d64540e3Sgd 				    msg_buffer);
45947c478bd9Sstevel@tonic-gate 			else
45957c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, "D: %s %s(%d): %s\n",
4596d64540e3Sgd 				    debug_msg_string[type], file,
4597d64540e3Sgd 				    line, msg_buffer);
45987c478bd9Sstevel@tonic-gate 		}
45997c478bd9Sstevel@tonic-gate 	}
46007c478bd9Sstevel@tonic-gate }
46017c478bd9Sstevel@tonic-gate #endif
46027c478bd9Sstevel@tonic-gate 
46037c478bd9Sstevel@tonic-gate 
4604d64540e3Sgd /*PRINTFLIKE4*/
46057c478bd9Sstevel@tonic-gate static void
eri_fault_msg(struct eri * erip,uint_t severity,msg_t type,const char * fmt,...)4606d64540e3Sgd eri_fault_msg(struct eri *erip, uint_t severity, msg_t type,
4607*7e996435SToomas Soome     const char *fmt, ...)
46087c478bd9Sstevel@tonic-gate {
46097c478bd9Sstevel@tonic-gate 	char	msg_buffer[255];
46107c478bd9Sstevel@tonic-gate 	va_list	ap;
46117c478bd9Sstevel@tonic-gate 
46127c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
46137c478bd9Sstevel@tonic-gate 	(void) vsprintf(msg_buffer, fmt, ap);
46147c478bd9Sstevel@tonic-gate 	va_end(ap);
46157c478bd9Sstevel@tonic-gate 
46167c478bd9Sstevel@tonic-gate 	if (erip == NULL) {
46177c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "eri : %s", msg_buffer);
46187c478bd9Sstevel@tonic-gate 		return;
46197c478bd9Sstevel@tonic-gate 	}
46207c478bd9Sstevel@tonic-gate 
46217c478bd9Sstevel@tonic-gate 	if (severity == SEVERITY_HIGH) {
4622d64540e3Sgd 		cmn_err(CE_WARN, "%s%d : %s", ddi_driver_name(erip->dip),
46237c478bd9Sstevel@tonic-gate 		    erip->instance, msg_buffer);
46247c478bd9Sstevel@tonic-gate 	} else switch (type) {
46257c478bd9Sstevel@tonic-gate 	case ERI_VERB_MSG:
4626d64540e3Sgd 		cmn_err(CE_CONT, "?%s%d : %s", ddi_driver_name(erip->dip),
46277c478bd9Sstevel@tonic-gate 		    erip->instance, msg_buffer);
46287c478bd9Sstevel@tonic-gate 		break;
46297c478bd9Sstevel@tonic-gate 	case ERI_LOG_MSG:
4630d64540e3Sgd 		cmn_err(CE_NOTE, "^%s%d : %s", ddi_driver_name(erip->dip),
46317c478bd9Sstevel@tonic-gate 		    erip->instance, msg_buffer);
46327c478bd9Sstevel@tonic-gate 		break;
46337c478bd9Sstevel@tonic-gate 	case ERI_BUF_MSG:
4634d64540e3Sgd 		cmn_err(CE_NOTE, "!%s%d : %s", ddi_driver_name(erip->dip),
46357c478bd9Sstevel@tonic-gate 		    erip->instance, msg_buffer);
46367c478bd9Sstevel@tonic-gate 		break;
46377c478bd9Sstevel@tonic-gate 	case ERI_CON_MSG:
4638d64540e3Sgd 		cmn_err(CE_CONT, "%s%d : %s", ddi_driver_name(erip->dip),
46397c478bd9Sstevel@tonic-gate 		    erip->instance, msg_buffer);
46407c478bd9Sstevel@tonic-gate 	default:
46417c478bd9Sstevel@tonic-gate 		break;
46427c478bd9Sstevel@tonic-gate 	}
46437c478bd9Sstevel@tonic-gate }
46447c478bd9Sstevel@tonic-gate 
46457c478bd9Sstevel@tonic-gate /*
46467c478bd9Sstevel@tonic-gate  * Transceiver (xcvr) Functions
46477c478bd9Sstevel@tonic-gate  * New Section
46487c478bd9Sstevel@tonic-gate  */
46497c478bd9Sstevel@tonic-gate /*
46507c478bd9Sstevel@tonic-gate  * eri_stop_timer function is used by a function before doing link-related
46517c478bd9Sstevel@tonic-gate  * processing. It locks the "linklock" to protect the link-related data
46527c478bd9Sstevel@tonic-gate  * structures. This lock will be subsequently released in eri_start_timer().
46537c478bd9Sstevel@tonic-gate  */
46547c478bd9Sstevel@tonic-gate static void
eri_stop_timer(struct eri * erip)46557c478bd9Sstevel@tonic-gate eri_stop_timer(struct eri *erip)
46567c478bd9Sstevel@tonic-gate {
46577c478bd9Sstevel@tonic-gate 	timeout_id_t id;
46587c478bd9Sstevel@tonic-gate 	mutex_enter(&erip->linklock);
46597c478bd9Sstevel@tonic-gate 	if (erip->timerid) {
46607c478bd9Sstevel@tonic-gate 		erip->flags |= ERI_NOTIMEOUTS; /* prevent multiple timeout */
46617c478bd9Sstevel@tonic-gate 		id = erip->timerid;
46627c478bd9Sstevel@tonic-gate 		erip->timerid = 0; /* prevent other thread do untimeout */
46637c478bd9Sstevel@tonic-gate 		mutex_exit(&erip->linklock); /* no mutex across untimeout() */
46647c478bd9Sstevel@tonic-gate 
46657c478bd9Sstevel@tonic-gate 		(void) untimeout(id);
46667c478bd9Sstevel@tonic-gate 		mutex_enter(&erip->linklock); /* acquire mutex again */
46677c478bd9Sstevel@tonic-gate 		erip->flags &= ~ERI_NOTIMEOUTS;
46687c478bd9Sstevel@tonic-gate 	}
46697c478bd9Sstevel@tonic-gate }
46707c478bd9Sstevel@tonic-gate 
46717c478bd9Sstevel@tonic-gate /*
46727c478bd9Sstevel@tonic-gate  * If msec parameter is zero, just release "linklock".
46737c478bd9Sstevel@tonic-gate  */
46747c478bd9Sstevel@tonic-gate static void
eri_start_timer(struct eri * erip,fptrv_t func,clock_t msec)46757c478bd9Sstevel@tonic-gate eri_start_timer(struct eri *erip, fptrv_t func, clock_t msec)
46767c478bd9Sstevel@tonic-gate {
46777c478bd9Sstevel@tonic-gate 	if (msec) {
46787c478bd9Sstevel@tonic-gate 		if (!(erip->flags & ERI_NOTIMEOUTS) &&
4679d64540e3Sgd 		    (erip->flags & ERI_RUNNING)) {
4680d64540e3Sgd 			erip->timerid = timeout(func, (caddr_t)erip,
4681d64540e3Sgd 			    drv_usectohz(1000*msec));
46827c478bd9Sstevel@tonic-gate 		}
46837c478bd9Sstevel@tonic-gate 	}
46847c478bd9Sstevel@tonic-gate 
46857c478bd9Sstevel@tonic-gate 	mutex_exit(&erip->linklock);
46867c478bd9Sstevel@tonic-gate }
46877c478bd9Sstevel@tonic-gate 
46887c478bd9Sstevel@tonic-gate static int
eri_new_xcvr(struct eri * erip)46897c478bd9Sstevel@tonic-gate eri_new_xcvr(struct eri *erip)
46907c478bd9Sstevel@tonic-gate {
46917c478bd9Sstevel@tonic-gate 	int		status;
4692*7e996435SToomas Soome 	uint32_t	cfg;
46937c478bd9Sstevel@tonic-gate 	int		old_transceiver;
46947c478bd9Sstevel@tonic-gate 
46957c478bd9Sstevel@tonic-gate 	if (pci_report_pmcap(erip->dip, PCI_PM_IDLESPEED,
46967c478bd9Sstevel@tonic-gate 	    PCI_PM_IDLESPEED_NONE) == DDI_SUCCESS)
46977c478bd9Sstevel@tonic-gate 		erip->stats.pmcap = ERI_PMCAP_NONE;
46987c478bd9Sstevel@tonic-gate 
46997c478bd9Sstevel@tonic-gate 	status = B_FALSE;			/* no change */
47007c478bd9Sstevel@tonic-gate 	cfg = GET_MIFREG(mif_cfg);
4701d64540e3Sgd 	ERI_DEBUG_MSG2(erip, MIF_MSG, "cfg value = %X", cfg);
47027c478bd9Sstevel@tonic-gate 	old_transceiver = param_transceiver;
47037c478bd9Sstevel@tonic-gate 
47047c478bd9Sstevel@tonic-gate 	if ((cfg & ERI_MIF_CFGM1) && !use_int_xcvr) {
47057c478bd9Sstevel@tonic-gate 		ERI_DEBUG_MSG1(erip, PHY_MSG, "Found External XCVR");
47067c478bd9Sstevel@tonic-gate 		/*
47077c478bd9Sstevel@tonic-gate 		 * An External Transceiver was found and it takes priority
47087c478bd9Sstevel@tonic-gate 		 * over an internal, given the use_int_xcvr flag
47097c478bd9Sstevel@tonic-gate 		 * is false.
47107c478bd9Sstevel@tonic-gate 		 */
47117c478bd9Sstevel@tonic-gate 		if (old_transceiver != EXTERNAL_XCVR) {
47127c478bd9Sstevel@tonic-gate 			/*
47137c478bd9Sstevel@tonic-gate 			 * External transceiver has just been plugged
47147c478bd9Sstevel@tonic-gate 			 * in. Isolate the internal Transceiver.
47157c478bd9Sstevel@tonic-gate 			 */
47167c478bd9Sstevel@tonic-gate 			if (old_transceiver == INTERNAL_XCVR) {
47177c478bd9Sstevel@tonic-gate 				eri_mii_write(erip, ERI_PHY_BMCR,
4718d64540e3Sgd 				    (PHY_BMCR_ISOLATE | PHY_BMCR_PWRDN |
4719d64540e3Sgd 				    PHY_BMCR_LPBK));
47207c478bd9Sstevel@tonic-gate 			}
47217c478bd9Sstevel@tonic-gate 			status = B_TRUE;
47227c478bd9Sstevel@tonic-gate 		}
47237c478bd9Sstevel@tonic-gate 		/*
47247c478bd9Sstevel@tonic-gate 		 * Select the external Transceiver.
47257c478bd9Sstevel@tonic-gate 		 */
47267c478bd9Sstevel@tonic-gate 		erip->phyad = ERI_EXTERNAL_PHYAD;
47277c478bd9Sstevel@tonic-gate 		param_transceiver = EXTERNAL_XCVR;
47287c478bd9Sstevel@tonic-gate 		erip->mif_config &= ~ERI_MIF_CFGPD;
47297c478bd9Sstevel@tonic-gate 		erip->mif_config |= (erip->phyad << ERI_MIF_CFGPD_SHIFT);
47307c478bd9Sstevel@tonic-gate 		erip->mif_config |= ERI_MIF_CFGPS;
47317c478bd9Sstevel@tonic-gate 		PUT_MIFREG(mif_cfg, erip->mif_config);
47327c478bd9Sstevel@tonic-gate 
47337c478bd9Sstevel@tonic-gate 		PUT_MACREG(xifc, GET_MACREG(xifc) | BMAC_XIFC_MIIBUF_OE);
47347c478bd9Sstevel@tonic-gate 		drv_usecwait(ERI_MIF_POLL_DELAY);
47357c478bd9Sstevel@tonic-gate 	} else if (cfg & ERI_MIF_CFGM0) {
47367c478bd9Sstevel@tonic-gate 		ERI_DEBUG_MSG1(erip, PHY_MSG, "Found Internal XCVR");
47377c478bd9Sstevel@tonic-gate 		/*
47387c478bd9Sstevel@tonic-gate 		 * An Internal Transceiver was found or the
47397c478bd9Sstevel@tonic-gate 		 * use_int_xcvr flag is true.
47407c478bd9Sstevel@tonic-gate 		 */
47417c478bd9Sstevel@tonic-gate 		if (old_transceiver != INTERNAL_XCVR) {
47427c478bd9Sstevel@tonic-gate 			/*
47437c478bd9Sstevel@tonic-gate 			 * The external transceiver has just been
47447c478bd9Sstevel@tonic-gate 			 * disconnected or we're moving from a no
47457c478bd9Sstevel@tonic-gate 			 * transceiver state.
47467c478bd9Sstevel@tonic-gate 			 */
47477c478bd9Sstevel@tonic-gate 			if ((old_transceiver == EXTERNAL_XCVR) &&
4748d64540e3Sgd 			    (cfg & ERI_MIF_CFGM0)) {
47497c478bd9Sstevel@tonic-gate 				eri_mii_write(erip, ERI_PHY_BMCR,
4750d64540e3Sgd 				    (PHY_BMCR_ISOLATE | PHY_BMCR_PWRDN |
4751d64540e3Sgd 				    PHY_BMCR_LPBK));
47527c478bd9Sstevel@tonic-gate 			}
47537c478bd9Sstevel@tonic-gate 			status = B_TRUE;
47547c478bd9Sstevel@tonic-gate 		}
47557c478bd9Sstevel@tonic-gate 		/*
47567c478bd9Sstevel@tonic-gate 		 * Select the internal transceiver.
47577c478bd9Sstevel@tonic-gate 		 */
47587c478bd9Sstevel@tonic-gate 		erip->phyad = ERI_INTERNAL_PHYAD;
47597c478bd9Sstevel@tonic-gate 		param_transceiver = INTERNAL_XCVR;
47607c478bd9Sstevel@tonic-gate 		erip->mif_config &= ~ERI_MIF_CFGPD;
47617c478bd9Sstevel@tonic-gate 		erip->mif_config |= (erip->phyad << ERI_MIF_CFGPD_SHIFT);
47627c478bd9Sstevel@tonic-gate 		erip->mif_config &= ~ERI_MIF_CFGPS;
47637c478bd9Sstevel@tonic-gate 		PUT_MIFREG(mif_cfg, erip->mif_config);
47647c478bd9Sstevel@tonic-gate 
47657c478bd9Sstevel@tonic-gate 		PUT_MACREG(xifc, GET_MACREG(xifc) & ~ BMAC_XIFC_MIIBUF_OE);
47667c478bd9Sstevel@tonic-gate 		drv_usecwait(ERI_MIF_POLL_DELAY);
47677c478bd9Sstevel@tonic-gate 	} else {
47687c478bd9Sstevel@tonic-gate 		/*
47697c478bd9Sstevel@tonic-gate 		 * Did not find a valid xcvr.
47707c478bd9Sstevel@tonic-gate 		 */
4771d64540e3Sgd 		ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
4772d64540e3Sgd 		    "Eri_new_xcvr : Select None");
4773d64540e3Sgd 		param_transceiver = NO_XCVR;
4774d64540e3Sgd 		erip->xcvr_status = PHY_LINK_DOWN;
47757c478bd9Sstevel@tonic-gate 	}
47767c478bd9Sstevel@tonic-gate 
47777c478bd9Sstevel@tonic-gate 	if (erip->stats.pmcap == ERI_PMCAP_NONE) {
47787c478bd9Sstevel@tonic-gate 		if (pci_report_pmcap(erip->dip, PCI_PM_IDLESPEED,
47797c478bd9Sstevel@tonic-gate 		    (void *)4000) == DDI_SUCCESS)
47807c478bd9Sstevel@tonic-gate 			erip->stats.pmcap = ERI_PMCAP_4MHZ;
47817c478bd9Sstevel@tonic-gate 	}
47827c478bd9Sstevel@tonic-gate 
47837c478bd9Sstevel@tonic-gate 	return (status);
47847c478bd9Sstevel@tonic-gate }
47857c478bd9Sstevel@tonic-gate 
4786860c4cd4Scarlsonj /*
4787860c4cd4Scarlsonj  * This function is used for timers.  No locks are held on timer expiry.
4788860c4cd4Scarlsonj  */
4789860c4cd4Scarlsonj static void
eri_check_link(struct eri * erip)4790860c4cd4Scarlsonj eri_check_link(struct eri *erip)
4791860c4cd4Scarlsonj {
4792d64540e3Sgd 	link_state_t	linkupdate = eri_check_link_noind(erip);
4793d64540e3Sgd 
4794d64540e3Sgd 	if (linkupdate != LINK_STATE_UNKNOWN)
4795d64540e3Sgd 		mac_link_update(erip->mh, linkupdate);
4796860c4cd4Scarlsonj }
4797860c4cd4Scarlsonj 
47987c478bd9Sstevel@tonic-gate /*
47997c478bd9Sstevel@tonic-gate  * Compare our xcvr in our structure to the xcvr that we get from
48007c478bd9Sstevel@tonic-gate  * eri_check_mii_xcvr(). If they are different then mark the
48017c478bd9Sstevel@tonic-gate  * link down, reset xcvr, and return.
48027c478bd9Sstevel@tonic-gate  *
48037c478bd9Sstevel@tonic-gate  * Note without the MII connector, conditions can not change that
48047c478bd9Sstevel@tonic-gate  * will then use a external phy, thus this code has been cleaned
48057c478bd9Sstevel@tonic-gate  * to not even call the function or to possibly change the xcvr.
48067c478bd9Sstevel@tonic-gate  */
4807860c4cd4Scarlsonj static uint32_t
eri_check_link_noind(struct eri * erip)4808860c4cd4Scarlsonj eri_check_link_noind(struct eri *erip)
48097c478bd9Sstevel@tonic-gate {
48107c478bd9Sstevel@tonic-gate 	uint16_t stat, control, mif_ints;
48117c478bd9Sstevel@tonic-gate 	uint32_t link_timeout	= ERI_LINKCHECK_TIMER;
4812d64540e3Sgd 	uint32_t linkupdate = 0;
48137c478bd9Sstevel@tonic-gate 
48147c478bd9Sstevel@tonic-gate 	eri_stop_timer(erip);	/* acquire linklock */
48157c478bd9Sstevel@tonic-gate 
48167c478bd9Sstevel@tonic-gate 	mutex_enter(&erip->xmitlock);
48177c478bd9Sstevel@tonic-gate 	mutex_enter(&erip->xcvrlock);
48187c478bd9Sstevel@tonic-gate 	eri_mif_poll(erip, MIF_POLL_STOP);
48197c478bd9Sstevel@tonic-gate 
48207c478bd9Sstevel@tonic-gate 	(void) eri_mii_read(erip, ERI_PHY_BMSR, &stat);
48217c478bd9Sstevel@tonic-gate 	mif_ints = erip->mii_status ^ stat;
48227c478bd9Sstevel@tonic-gate 
48237c478bd9Sstevel@tonic-gate 	if (erip->openloop_autoneg) {
48247c478bd9Sstevel@tonic-gate 		(void) eri_mii_read(erip, ERI_PHY_BMSR, &stat);
48257c478bd9Sstevel@tonic-gate 		ERI_DEBUG_MSG3(erip, XCVR_MSG,
4826d64540e3Sgd 		    "eri_check_link:openloop stat %X mii_status %X",
4827d64540e3Sgd 		    stat, erip->mii_status);
48287c478bd9Sstevel@tonic-gate 		(void) eri_mii_read(erip, ERI_PHY_BMCR, &control);
48297c478bd9Sstevel@tonic-gate 		if (!(stat & PHY_BMSR_LNKSTS) &&
4830d64540e3Sgd 		    (erip->openloop_autoneg < 2)) {
48317c478bd9Sstevel@tonic-gate 			if (param_speed) {
48327c478bd9Sstevel@tonic-gate 				control &= ~PHY_BMCR_100M;
48337c478bd9Sstevel@tonic-gate 				param_anlpar_100hdx = 0;
48347c478bd9Sstevel@tonic-gate 				param_anlpar_10hdx = 1;
48357c478bd9Sstevel@tonic-gate 				param_speed = 0;
4836d64540e3Sgd 				erip->stats.ifspeed = 10;
48377c478bd9Sstevel@tonic-gate 
48387c478bd9Sstevel@tonic-gate 			} else {
48397c478bd9Sstevel@tonic-gate 				control |= PHY_BMCR_100M;
48407c478bd9Sstevel@tonic-gate 				param_anlpar_100hdx = 1;
48417c478bd9Sstevel@tonic-gate 				param_anlpar_10hdx = 0;
48427c478bd9Sstevel@tonic-gate 				param_speed = 1;
4843d64540e3Sgd 				erip->stats.ifspeed = 100;
48447c478bd9Sstevel@tonic-gate 			}
48457c478bd9Sstevel@tonic-gate 			ERI_DEBUG_MSG3(erip, XCVR_MSG,
4846d64540e3Sgd 			    "eri_check_link: trying speed %X stat %X",
4847d64540e3Sgd 			    param_speed, stat);
48487c478bd9Sstevel@tonic-gate 
48497c478bd9Sstevel@tonic-gate 			erip->openloop_autoneg ++;
48507c478bd9Sstevel@tonic-gate 			eri_mii_write(erip, ERI_PHY_BMCR, control);
48517c478bd9Sstevel@tonic-gate 			link_timeout = ERI_P_FAULT_TIMER;
48527c478bd9Sstevel@tonic-gate 		} else {
48537c478bd9Sstevel@tonic-gate 			erip->openloop_autoneg = 0;
4854d64540e3Sgd 			linkupdate = eri_mif_check(erip, stat, stat);
48557c478bd9Sstevel@tonic-gate 			if (erip->openloop_autoneg)
48567c478bd9Sstevel@tonic-gate 				link_timeout = ERI_P_FAULT_TIMER;
48577c478bd9Sstevel@tonic-gate 		}
48587c478bd9Sstevel@tonic-gate 		eri_mif_poll(erip, MIF_POLL_START);
48597c478bd9Sstevel@tonic-gate 		mutex_exit(&erip->xcvrlock);
48607c478bd9Sstevel@tonic-gate 		mutex_exit(&erip->xmitlock);
48617c478bd9Sstevel@tonic-gate 
48627c478bd9Sstevel@tonic-gate 		eri_start_timer(erip, eri_check_link, link_timeout);
4863d64540e3Sgd 		return (linkupdate);
48647c478bd9Sstevel@tonic-gate 	}
48657c478bd9Sstevel@tonic-gate 
4866d64540e3Sgd 	linkupdate = eri_mif_check(erip, mif_ints, stat);
48677c478bd9Sstevel@tonic-gate 	eri_mif_poll(erip, MIF_POLL_START);
48687c478bd9Sstevel@tonic-gate 	mutex_exit(&erip->xcvrlock);
48697c478bd9Sstevel@tonic-gate 	mutex_exit(&erip->xmitlock);
48707c478bd9Sstevel@tonic-gate 
48717c478bd9Sstevel@tonic-gate #ifdef ERI_RMAC_HANG_WORKAROUND
48727c478bd9Sstevel@tonic-gate 	/*
48737c478bd9Sstevel@tonic-gate 	 * Check if rx hung.
48747c478bd9Sstevel@tonic-gate 	 */
48757c478bd9Sstevel@tonic-gate 	if ((erip->flags & ERI_RUNNING) && param_linkup) {
48767c478bd9Sstevel@tonic-gate 		if (erip->check_rmac_hang) {
48777c478bd9Sstevel@tonic-gate 			ERI_DEBUG_MSG5(erip,
48787c478bd9Sstevel@tonic-gate 			    NONFATAL_MSG,
48797c478bd9Sstevel@tonic-gate 			    "check1 %d: macsm:%8x wr:%2x rd:%2x",
48807c478bd9Sstevel@tonic-gate 			    erip->check_rmac_hang,
48817c478bd9Sstevel@tonic-gate 			    GET_MACREG(macsm),
48827c478bd9Sstevel@tonic-gate 			    GET_ERXREG(rxfifo_wr_ptr),
48837c478bd9Sstevel@tonic-gate 			    GET_ERXREG(rxfifo_rd_ptr));
48847c478bd9Sstevel@tonic-gate 
48857c478bd9Sstevel@tonic-gate 			erip->check_rmac_hang = 0;
48867c478bd9Sstevel@tonic-gate 			erip->check2_rmac_hang ++;
48877c478bd9Sstevel@tonic-gate 
48887c478bd9Sstevel@tonic-gate 			erip->rxfifo_wr_ptr_c = GET_ERXREG(rxfifo_wr_ptr);
48897c478bd9Sstevel@tonic-gate 			erip->rxfifo_rd_ptr_c = GET_ERXREG(rxfifo_rd_ptr);
48907c478bd9Sstevel@tonic-gate 
48917c478bd9Sstevel@tonic-gate 			eri_start_timer(erip, eri_check_link,
48927c478bd9Sstevel@tonic-gate 			    ERI_CHECK_HANG_TIMER);
4893d64540e3Sgd 			return (linkupdate);
48947c478bd9Sstevel@tonic-gate 		}
48957c478bd9Sstevel@tonic-gate 
48967c478bd9Sstevel@tonic-gate 		if (erip->check2_rmac_hang) {
48977c478bd9Sstevel@tonic-gate 			ERI_DEBUG_MSG5(erip,
48987c478bd9Sstevel@tonic-gate 			    NONFATAL_MSG,
48997c478bd9Sstevel@tonic-gate 			    "check2 %d: macsm:%8x wr:%2x rd:%2x",
49007c478bd9Sstevel@tonic-gate 			    erip->check2_rmac_hang,
49017c478bd9Sstevel@tonic-gate 			    GET_MACREG(macsm),
49027c478bd9Sstevel@tonic-gate 			    GET_ERXREG(rxfifo_wr_ptr),
49037c478bd9Sstevel@tonic-gate 			    GET_ERXREG(rxfifo_rd_ptr));
49047c478bd9Sstevel@tonic-gate 
49057c478bd9Sstevel@tonic-gate 			erip->check2_rmac_hang = 0;
49067c478bd9Sstevel@tonic-gate 
49077c478bd9Sstevel@tonic-gate 			erip->rxfifo_wr_ptr = GET_ERXREG(rxfifo_wr_ptr);
49087c478bd9Sstevel@tonic-gate 			erip->rxfifo_rd_ptr = GET_ERXREG(rxfifo_rd_ptr);
49097c478bd9Sstevel@tonic-gate 
49107c478bd9Sstevel@tonic-gate 			if (((GET_MACREG(macsm) & BMAC_OVERFLOW_STATE) ==
49117c478bd9Sstevel@tonic-gate 			    BMAC_OVERFLOW_STATE) &&
49127c478bd9Sstevel@tonic-gate 			    ((erip->rxfifo_wr_ptr_c == erip->rxfifo_rd_ptr_c) ||
49137c478bd9Sstevel@tonic-gate 			    ((erip->rxfifo_rd_ptr == erip->rxfifo_rd_ptr_c) &&
49147c478bd9Sstevel@tonic-gate 			    (erip->rxfifo_wr_ptr == erip->rxfifo_wr_ptr_c)))) {
49157c478bd9Sstevel@tonic-gate 				ERI_DEBUG_MSG1(erip,
49167c478bd9Sstevel@tonic-gate 				    NONFATAL_MSG,
49177c478bd9Sstevel@tonic-gate 				    "RX hang: Reset mac");
49187c478bd9Sstevel@tonic-gate 
49197c478bd9Sstevel@tonic-gate 				HSTAT(erip, rx_hang);
49207c478bd9Sstevel@tonic-gate 				erip->linkcheck = 1;
49217c478bd9Sstevel@tonic-gate 
49227c478bd9Sstevel@tonic-gate 				eri_start_timer(erip, eri_check_link,
49237c478bd9Sstevel@tonic-gate 				    ERI_LINKCHECK_TIMER);
49247c478bd9Sstevel@tonic-gate 				(void) eri_init(erip);
4925d64540e3Sgd 				return (linkupdate);
49267c478bd9Sstevel@tonic-gate 			}
49277c478bd9Sstevel@tonic-gate 		}
49287c478bd9Sstevel@tonic-gate 	}
49297c478bd9Sstevel@tonic-gate #endif
49307c478bd9Sstevel@tonic-gate 
49317c478bd9Sstevel@tonic-gate 	/*
49327c478bd9Sstevel@tonic-gate 	 * Check if tx hung.
49337c478bd9Sstevel@tonic-gate 	 */
49347c478bd9Sstevel@tonic-gate #ifdef	ERI_TX_HUNG
4935d64540e3Sgd 	if ((erip->flags & ERI_RUNNING) && param_linkup &&
4936d64540e3Sgd 	    (eri_check_txhung(erip))) {
49377c478bd9Sstevel@tonic-gate 		HSTAT(erip, tx_hang);
49387c478bd9Sstevel@tonic-gate 		eri_reinit_txhung++;
49397c478bd9Sstevel@tonic-gate 		erip->linkcheck = 1;
49407c478bd9Sstevel@tonic-gate 		eri_start_timer(erip, eri_check_link, ERI_CHECK_HANG_TIMER);
49417c478bd9Sstevel@tonic-gate 		(void) eri_init(erip);
4942d64540e3Sgd 		return (linkupdate);
49437c478bd9Sstevel@tonic-gate 	}
49447c478bd9Sstevel@tonic-gate #endif
49457c478bd9Sstevel@tonic-gate 
49467c478bd9Sstevel@tonic-gate #ifdef ERI_PM_WORKAROUND
49477c478bd9Sstevel@tonic-gate 	if (erip->stats.pmcap == ERI_PMCAP_NONE) {
49487c478bd9Sstevel@tonic-gate 		if (pci_report_pmcap(erip->dip, PCI_PM_IDLESPEED,
49497c478bd9Sstevel@tonic-gate 		    (void *)4000) == DDI_SUCCESS)
49507c478bd9Sstevel@tonic-gate 			erip->stats.pmcap = ERI_PMCAP_4MHZ;
49517c478bd9Sstevel@tonic-gate 
49527c478bd9Sstevel@tonic-gate 		ERI_DEBUG_MSG2(erip, NONFATAL_MSG,
49537c478bd9Sstevel@tonic-gate 		    "eri_check_link: PMCAP %d", erip->stats.pmcap);
49547c478bd9Sstevel@tonic-gate 	}
49557c478bd9Sstevel@tonic-gate #endif
49567c478bd9Sstevel@tonic-gate 	if ((!param_mode) && (param_transceiver != NO_XCVR))
49577c478bd9Sstevel@tonic-gate 		eri_start_timer(erip, eri_check_link, ERI_CHECK_HANG_TIMER);
49587c478bd9Sstevel@tonic-gate 	else
49597c478bd9Sstevel@tonic-gate 		eri_start_timer(erip, eri_check_link, ERI_LINKCHECK_TIMER);
4960d64540e3Sgd 	return (linkupdate);
49617c478bd9Sstevel@tonic-gate }
49627c478bd9Sstevel@tonic-gate 
4963d64540e3Sgd static link_state_t
eri_mif_check(struct eri * erip,uint16_t mif_ints,uint16_t mif_data)49647c478bd9Sstevel@tonic-gate eri_mif_check(struct eri *erip, uint16_t mif_ints, uint16_t mif_data)
49657c478bd9Sstevel@tonic-gate {
49667c478bd9Sstevel@tonic-gate 	uint16_t control, aner, anlpar, anar, an_common;
49677c478bd9Sstevel@tonic-gate 	uint16_t old_mintrans;
49687c478bd9Sstevel@tonic-gate 	int restart_autoneg = 0;
4969d64540e3Sgd 	link_state_t retv;
49707c478bd9Sstevel@tonic-gate 
4971d64540e3Sgd 	ERI_DEBUG_MSG4(erip, XCVR_MSG, "eri_mif_check: mif_mask: %X, %X, %X",
4972d64540e3Sgd 	    erip->mif_mask, mif_ints, mif_data);
49737c478bd9Sstevel@tonic-gate 
49747c478bd9Sstevel@tonic-gate 	mif_ints &= ~erip->mif_mask;
49757c478bd9Sstevel@tonic-gate 	erip->mii_status = mif_data;
49767c478bd9Sstevel@tonic-gate 	/*
49777c478bd9Sstevel@tonic-gate 	 * Now check if someone has pulled the xcvr or
49787c478bd9Sstevel@tonic-gate 	 * a new xcvr has shown up
49797c478bd9Sstevel@tonic-gate 	 * If so try to find out what the new xcvr setup is.
49807c478bd9Sstevel@tonic-gate 	 */
49817c478bd9Sstevel@tonic-gate 	if (((mif_ints & PHY_BMSR_RES1) && (mif_data == 0xFFFF)) ||
4982d64540e3Sgd 	    (param_transceiver == NO_XCVR)) {
49837c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
4984d64540e3Sgd 		    "No status transceiver gone");
49857c478bd9Sstevel@tonic-gate 		if (eri_new_xcvr(erip)) {
49867c478bd9Sstevel@tonic-gate 			if (param_transceiver != NO_XCVR) {
49877c478bd9Sstevel@tonic-gate 				/*
49887c478bd9Sstevel@tonic-gate 				 * Reset the new PHY and bring up the link
49897c478bd9Sstevel@tonic-gate 				 */
49907c478bd9Sstevel@tonic-gate 				(void) eri_reset_xcvr(erip);
49917c478bd9Sstevel@tonic-gate 			}
49927c478bd9Sstevel@tonic-gate 		}
4993d64540e3Sgd 		return (LINK_STATE_UNKNOWN);
49947c478bd9Sstevel@tonic-gate 	}
49957c478bd9Sstevel@tonic-gate 
49967c478bd9Sstevel@tonic-gate 	if (param_autoneg && (mif_ints & PHY_BMSR_LNKSTS) &&
4997d64540e3Sgd 	    (mif_data & PHY_BMSR_LNKSTS) && (mif_data & PHY_BMSR_ANC)) {
49987c478bd9Sstevel@tonic-gate 		mif_ints |= PHY_BMSR_ANC;
49997c478bd9Sstevel@tonic-gate 		ERI_DEBUG_MSG3(erip, PHY_MSG,
5000d64540e3Sgd 		    "eri_mif_check: Set ANC bit mif_data %X mig_ints %X",
5001d64540e3Sgd 		    mif_data, mif_ints);
50027c478bd9Sstevel@tonic-gate 	}
50037c478bd9Sstevel@tonic-gate 
50047c478bd9Sstevel@tonic-gate 	if ((mif_ints & PHY_BMSR_ANC) && (mif_data & PHY_BMSR_ANC)) {
5005d64540e3Sgd 		ERI_DEBUG_MSG1(erip, PHY_MSG, "Auto-negotiation interrupt.");
50067c478bd9Sstevel@tonic-gate 
50077c478bd9Sstevel@tonic-gate 		/*
50087c478bd9Sstevel@tonic-gate 		 * Switch off Auto-negotiation interrupts and switch on
50097c478bd9Sstevel@tonic-gate 		 * Link ststus interrupts.
50107c478bd9Sstevel@tonic-gate 		 */
50117c478bd9Sstevel@tonic-gate 		erip->mif_mask |= PHY_BMSR_ANC;
50127c478bd9Sstevel@tonic-gate 		erip->mif_mask &= ~PHY_BMSR_LNKSTS;
50137c478bd9Sstevel@tonic-gate 		(void) eri_mii_read(erip, ERI_PHY_ANER, &aner);
50147c478bd9Sstevel@tonic-gate 		param_aner_lpancap = 1 && (aner & PHY_ANER_LPNW);
50157c478bd9Sstevel@tonic-gate 		if ((aner & PHY_ANER_MLF) || (eri_force_mlf)) {
50167c478bd9Sstevel@tonic-gate 			ERI_DEBUG_MSG1(erip, XCVR_MSG,
5017d64540e3Sgd 			    "parallel detection fault");
50187c478bd9Sstevel@tonic-gate 			/*
50197c478bd9Sstevel@tonic-gate 			 * Consider doing open loop auto-negotiation.
50207c478bd9Sstevel@tonic-gate 			 */
50217c478bd9Sstevel@tonic-gate 			ERI_DEBUG_MSG1(erip, XCVR_MSG,
5022d64540e3Sgd 			    "Going into Open loop Auto-neg");
50237c478bd9Sstevel@tonic-gate 			(void) eri_mii_read(erip, ERI_PHY_BMCR, &control);
50247c478bd9Sstevel@tonic-gate 
50257c478bd9Sstevel@tonic-gate 			control &= ~(PHY_BMCR_ANE | PHY_BMCR_RAN |
5026d64540e3Sgd 			    PHY_BMCR_FDX);
50277c478bd9Sstevel@tonic-gate 			if (param_anar_100fdx || param_anar_100hdx) {
50287c478bd9Sstevel@tonic-gate 				control |= PHY_BMCR_100M;
50297c478bd9Sstevel@tonic-gate 				param_anlpar_100hdx = 1;
50307c478bd9Sstevel@tonic-gate 				param_anlpar_10hdx = 0;
50317c478bd9Sstevel@tonic-gate 				param_speed = 1;
5032d64540e3Sgd 				erip->stats.ifspeed = 100;
5033d64540e3Sgd 
5034d64540e3Sgd 			} else if (param_anar_10fdx || param_anar_10hdx) {
5035d64540e3Sgd 				control &= ~PHY_BMCR_100M;
5036d64540e3Sgd 				param_anlpar_100hdx = 0;
5037d64540e3Sgd 				param_anlpar_10hdx = 1;
5038d64540e3Sgd 				param_speed = 0;
5039d64540e3Sgd 				erip->stats.ifspeed = 10;
50407c478bd9Sstevel@tonic-gate 			} else {
50417c478bd9Sstevel@tonic-gate 				ERI_FAULT_MSG1(erip, SEVERITY_NONE,
5042d64540e3Sgd 				    ERI_VERB_MSG,
5043d64540e3Sgd 				    "Transceiver speed set incorrectly.");
5044860c4cd4Scarlsonj 				return (0);
50457c478bd9Sstevel@tonic-gate 			}
50467c478bd9Sstevel@tonic-gate 
50477c478bd9Sstevel@tonic-gate 			(void) eri_mii_write(erip, ERI_PHY_BMCR, control);
50487c478bd9Sstevel@tonic-gate 			param_anlpar_100fdx = 0;
50497c478bd9Sstevel@tonic-gate 			param_anlpar_10fdx = 0;
50507c478bd9Sstevel@tonic-gate 			param_mode = 0;
50517c478bd9Sstevel@tonic-gate 			erip->openloop_autoneg = 1;
5052860c4cd4Scarlsonj 			return (0);
50537c478bd9Sstevel@tonic-gate 		}
50547c478bd9Sstevel@tonic-gate 		(void) eri_mii_read(erip, ERI_PHY_ANLPAR, &anlpar);
50557c478bd9Sstevel@tonic-gate 		(void) eri_mii_read(erip, ERI_PHY_ANAR, &anar);
50567c478bd9Sstevel@tonic-gate 		an_common = anar & anlpar;
50577c478bd9Sstevel@tonic-gate 
5058d64540e3Sgd 		ERI_DEBUG_MSG2(erip, XCVR_MSG, "an_common = 0x%X", an_common);
50597c478bd9Sstevel@tonic-gate 
50607c478bd9Sstevel@tonic-gate 		if (an_common & (PHY_ANLPAR_TXFDX | PHY_ANLPAR_TX)) {
50617c478bd9Sstevel@tonic-gate 			param_speed = 1;
5062d64540e3Sgd 			erip->stats.ifspeed = 100;
50637c478bd9Sstevel@tonic-gate 			param_mode = 1 && (an_common & PHY_ANLPAR_TXFDX);
50647c478bd9Sstevel@tonic-gate 
50657c478bd9Sstevel@tonic-gate 		} else if (an_common & (PHY_ANLPAR_10FDX | PHY_ANLPAR_10)) {
50667c478bd9Sstevel@tonic-gate 			param_speed = 0;
5067d64540e3Sgd 			erip->stats.ifspeed = 10;
50687c478bd9Sstevel@tonic-gate 			param_mode = 1 && (an_common & PHY_ANLPAR_10FDX);
50697c478bd9Sstevel@tonic-gate 
50707c478bd9Sstevel@tonic-gate 		} else an_common = 0x0;
50717c478bd9Sstevel@tonic-gate 
50727c478bd9Sstevel@tonic-gate 		if (!an_common) {
50737c478bd9Sstevel@tonic-gate 			ERI_FAULT_MSG1(erip, SEVERITY_MID, ERI_VERB_MSG,
5074d64540e3Sgd 			    "Transceiver: anar not set with speed selection");
50757c478bd9Sstevel@tonic-gate 		}
50767c478bd9Sstevel@tonic-gate 		param_anlpar_100T4 = 1 && (anlpar & PHY_ANLPAR_T4);
50777c478bd9Sstevel@tonic-gate 		param_anlpar_100fdx = 1 && (anlpar & PHY_ANLPAR_TXFDX);
50787c478bd9Sstevel@tonic-gate 		param_anlpar_100hdx = 1 && (anlpar & PHY_ANLPAR_TX);
50797c478bd9Sstevel@tonic-gate 		param_anlpar_10fdx = 1 && (anlpar & PHY_ANLPAR_10FDX);
50807c478bd9Sstevel@tonic-gate 		param_anlpar_10hdx = 1 && (anlpar & PHY_ANLPAR_10);
50817c478bd9Sstevel@tonic-gate 
50827c478bd9Sstevel@tonic-gate 		ERI_DEBUG_MSG2(erip, PHY_MSG,
5083d64540e3Sgd 		    "Link duplex = 0x%X", param_mode);
50847c478bd9Sstevel@tonic-gate 		ERI_DEBUG_MSG2(erip, PHY_MSG,
5085d64540e3Sgd 		    "Link speed = 0x%X", param_speed);
50867c478bd9Sstevel@tonic-gate 	/*	mif_ints |= PHY_BMSR_LNKSTS; prevent double msg */
50877c478bd9Sstevel@tonic-gate 	/*	mif_data |= PHY_BMSR_LNKSTS; prevent double msg */
50887c478bd9Sstevel@tonic-gate 	}
5089d64540e3Sgd 	retv = LINK_STATE_UNKNOWN;
50907c478bd9Sstevel@tonic-gate 	if (mif_ints & PHY_BMSR_LNKSTS) {
50917c478bd9Sstevel@tonic-gate 		if (mif_data & PHY_BMSR_LNKSTS) {
50927c478bd9Sstevel@tonic-gate 			ERI_DEBUG_MSG1(erip, PHY_MSG, "Link Up");
50937c478bd9Sstevel@tonic-gate 			/*
50947c478bd9Sstevel@tonic-gate 			 * Program Lu3X31T for mininum transition
50957c478bd9Sstevel@tonic-gate 			 */
50967c478bd9Sstevel@tonic-gate 			if (eri_phy_mintrans) {
50977c478bd9Sstevel@tonic-gate 				eri_mii_write(erip, 31, 0x8000);
50987c478bd9Sstevel@tonic-gate 				(void) eri_mii_read(erip, 0, &old_mintrans);
50997c478bd9Sstevel@tonic-gate 				eri_mii_write(erip, 0, 0x00F1);
51007c478bd9Sstevel@tonic-gate 				eri_mii_write(erip, 31, 0x0000);
51017c478bd9Sstevel@tonic-gate 			}
51027c478bd9Sstevel@tonic-gate 			/*
51037c478bd9Sstevel@tonic-gate 			 * The link is up.
51047c478bd9Sstevel@tonic-gate 			 */
51057c478bd9Sstevel@tonic-gate 			eri_init_txmac(erip);
51067c478bd9Sstevel@tonic-gate 			param_linkup = 1;
5107d64540e3Sgd 			erip->stats.link_up = LINK_STATE_UP;
51087c478bd9Sstevel@tonic-gate 			if (param_mode)
5109d64540e3Sgd 				erip->stats.link_duplex = LINK_DUPLEX_FULL;
51107c478bd9Sstevel@tonic-gate 			else
5111d64540e3Sgd 				erip->stats.link_duplex = LINK_DUPLEX_HALF;
51127c478bd9Sstevel@tonic-gate 
5113d64540e3Sgd 			retv = LINK_STATE_UP;
51147c478bd9Sstevel@tonic-gate 		} else {
5115d64540e3Sgd 			ERI_DEBUG_MSG1(erip, PHY_MSG, "Link down.");
51167c478bd9Sstevel@tonic-gate 			param_linkup = 0;
5117d64540e3Sgd 			erip->stats.link_up = LINK_STATE_DOWN;
5118d64540e3Sgd 			erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
5119d64540e3Sgd 			retv = LINK_STATE_DOWN;
51207c478bd9Sstevel@tonic-gate 			if (param_autoneg) {
51217c478bd9Sstevel@tonic-gate 				restart_autoneg = 1;
51227c478bd9Sstevel@tonic-gate 			}
51237c478bd9Sstevel@tonic-gate 		}
51247c478bd9Sstevel@tonic-gate 	} else {
51257c478bd9Sstevel@tonic-gate 		if (mif_data & PHY_BMSR_LNKSTS) {
51267c478bd9Sstevel@tonic-gate 			if (!param_linkup) {
51277c478bd9Sstevel@tonic-gate 				ERI_DEBUG_MSG1(erip, PHY_MSG,
5128d64540e3Sgd 				    "eri_mif_check: MIF data link up");
51297c478bd9Sstevel@tonic-gate 				/*
51307c478bd9Sstevel@tonic-gate 				 * Program Lu3X31T for minimum transition
51317c478bd9Sstevel@tonic-gate 				 */
51327c478bd9Sstevel@tonic-gate 				if (eri_phy_mintrans) {
51337c478bd9Sstevel@tonic-gate 					eri_mii_write(erip, 31, 0x8000);
51347c478bd9Sstevel@tonic-gate 					(void) eri_mii_read(erip, 0,
5135d64540e3Sgd 					    &old_mintrans);
51367c478bd9Sstevel@tonic-gate 					eri_mii_write(erip, 0, 0x00F1);
51377c478bd9Sstevel@tonic-gate 					eri_mii_write(erip, 31, 0x0000);
51387c478bd9Sstevel@tonic-gate 				}
51397c478bd9Sstevel@tonic-gate 				/*
51407c478bd9Sstevel@tonic-gate 				 * The link is up.
51417c478bd9Sstevel@tonic-gate 				 */
51427c478bd9Sstevel@tonic-gate 				eri_init_txmac(erip);
51437c478bd9Sstevel@tonic-gate 
51447c478bd9Sstevel@tonic-gate 				param_linkup = 1;
5145d64540e3Sgd 				erip->stats.link_up = LINK_STATE_UP;
51467c478bd9Sstevel@tonic-gate 				if (param_mode)
51477c478bd9Sstevel@tonic-gate 					erip->stats.link_duplex =
5148d64540e3Sgd 					    LINK_DUPLEX_FULL;
51497c478bd9Sstevel@tonic-gate 				else
51507c478bd9Sstevel@tonic-gate 					erip->stats.link_duplex =
5151d64540e3Sgd 					    LINK_DUPLEX_HALF;
51527c478bd9Sstevel@tonic-gate 
5153d64540e3Sgd 				retv = LINK_STATE_UP;
51547c478bd9Sstevel@tonic-gate 			}
51557c478bd9Sstevel@tonic-gate 		} else if (param_linkup) {
51567c478bd9Sstevel@tonic-gate 			/*
51577c478bd9Sstevel@tonic-gate 			 * The link is down now.
51587c478bd9Sstevel@tonic-gate 			 */
51597c478bd9Sstevel@tonic-gate 			ERI_DEBUG_MSG1(erip, PHY_MSG,
5160d64540e3Sgd 			    "eri_mif_check:Link was up and went down");
51617c478bd9Sstevel@tonic-gate 			param_linkup = 0;
5162d64540e3Sgd 			erip->stats.link_up = LINK_STATE_DOWN;
5163d64540e3Sgd 			erip->stats.link_duplex = LINK_DUPLEX_UNKNOWN;
5164d64540e3Sgd 			retv = LINK_STATE_DOWN;
51657c478bd9Sstevel@tonic-gate 			if (param_autoneg)
51667c478bd9Sstevel@tonic-gate 				restart_autoneg = 1;
51677c478bd9Sstevel@tonic-gate 		}
51687c478bd9Sstevel@tonic-gate 	}
51697c478bd9Sstevel@tonic-gate 	if (restart_autoneg) {
51707c478bd9Sstevel@tonic-gate 		/*
51717c478bd9Sstevel@tonic-gate 		 * Restart normal auto-negotiation.
51727c478bd9Sstevel@tonic-gate 		 */
51737c478bd9Sstevel@tonic-gate 		ERI_DEBUG_MSG1(erip, PHY_MSG,
5174d64540e3Sgd 		    "eri_mif_check:Restart AUto Negotiation");
51757c478bd9Sstevel@tonic-gate 		erip->openloop_autoneg = 0;
51767c478bd9Sstevel@tonic-gate 		param_mode = 0;
51777c478bd9Sstevel@tonic-gate 		param_speed = 0;
51787c478bd9Sstevel@tonic-gate 		param_anlpar_100T4 = 0;
51797c478bd9Sstevel@tonic-gate 		param_anlpar_100fdx = 0;
51807c478bd9Sstevel@tonic-gate 		param_anlpar_100hdx = 0;
51817c478bd9Sstevel@tonic-gate 		param_anlpar_10fdx = 0;
51827c478bd9Sstevel@tonic-gate 		param_anlpar_10hdx = 0;
51837c478bd9Sstevel@tonic-gate 		param_aner_lpancap = 0;
5184d64540e3Sgd 		(void) eri_mii_read(erip, ERI_PHY_BMCR, &control);
51857c478bd9Sstevel@tonic-gate 		control |= (PHY_BMCR_ANE | PHY_BMCR_RAN);
51867c478bd9Sstevel@tonic-gate 		eri_mii_write(erip, ERI_PHY_BMCR, control);
51877c478bd9Sstevel@tonic-gate 	}
51887c478bd9Sstevel@tonic-gate 	if (mif_ints & PHY_BMSR_JABDET) {
51897c478bd9Sstevel@tonic-gate 		if (mif_data & PHY_BMSR_JABDET) {
5190d64540e3Sgd 			ERI_DEBUG_MSG1(erip, PHY_MSG, "Jabber detected.");
51917c478bd9Sstevel@tonic-gate 			HSTAT(erip, jab);
51927c478bd9Sstevel@tonic-gate 			/*
51937c478bd9Sstevel@tonic-gate 			 * Reset the new PHY and bring up the link
5194d64540e3Sgd 			 * (Check for failure?)
51957c478bd9Sstevel@tonic-gate 			 */
51967c478bd9Sstevel@tonic-gate 			(void) eri_reset_xcvr(erip);
51977c478bd9Sstevel@tonic-gate 		}
51987c478bd9Sstevel@tonic-gate 	}
5199860c4cd4Scarlsonj 	return (retv);
52007c478bd9Sstevel@tonic-gate }
52017c478bd9Sstevel@tonic-gate 
52027c478bd9Sstevel@tonic-gate #define	PHYRST_PERIOD 500
52037c478bd9Sstevel@tonic-gate static int
eri_reset_xcvr(struct eri * erip)52047c478bd9Sstevel@tonic-gate eri_reset_xcvr(struct eri *erip)
52057c478bd9Sstevel@tonic-gate {
52067c478bd9Sstevel@tonic-gate 	uint16_t	stat;
52077c478bd9Sstevel@tonic-gate 	uint16_t	anar;
52087c478bd9Sstevel@tonic-gate 	uint16_t	control;
52097c478bd9Sstevel@tonic-gate 	uint16_t	idr1;
52107c478bd9Sstevel@tonic-gate 	uint16_t	idr2;
52117c478bd9Sstevel@tonic-gate 	uint16_t	nicr;
52127c478bd9Sstevel@tonic-gate 	uint32_t	speed_100;
52137c478bd9Sstevel@tonic-gate 	uint32_t	speed_10;
52147c478bd9Sstevel@tonic-gate 	int n;
52157c478bd9Sstevel@tonic-gate 
52167c478bd9Sstevel@tonic-gate #ifdef	ERI_10_10_FORCE_SPEED_WORKAROUND
52177c478bd9Sstevel@tonic-gate 	erip->ifspeed_old = erip->stats.ifspeed;
52187c478bd9Sstevel@tonic-gate #endif
52197c478bd9Sstevel@tonic-gate 	/*
52207c478bd9Sstevel@tonic-gate 	 * Reset Open loop auto-negotiation this means you can try
52217c478bd9Sstevel@tonic-gate 	 * Normal auto-negotiation, until you get a Multiple Link fault
52227c478bd9Sstevel@tonic-gate 	 * at which point you try 100M half duplex then 10M half duplex
52237c478bd9Sstevel@tonic-gate 	 * until you get a Link up.
52247c478bd9Sstevel@tonic-gate 	 */
52257c478bd9Sstevel@tonic-gate 	erip->openloop_autoneg = 0;
52267c478bd9Sstevel@tonic-gate 
52277c478bd9Sstevel@tonic-gate 	/*
52287c478bd9Sstevel@tonic-gate 	 * Reset the xcvr.
52297c478bd9Sstevel@tonic-gate 	 */
52307c478bd9Sstevel@tonic-gate 	eri_mii_write(erip, ERI_PHY_BMCR, PHY_BMCR_RESET);
52317c478bd9Sstevel@tonic-gate 
52327c478bd9Sstevel@tonic-gate 	/* Check for transceiver reset completion */
52337c478bd9Sstevel@tonic-gate 
52347c478bd9Sstevel@tonic-gate 	n = 1000;
52357c478bd9Sstevel@tonic-gate 	while (--n > 0) {
52367c478bd9Sstevel@tonic-gate 		drv_usecwait((clock_t)PHYRST_PERIOD);
52377c478bd9Sstevel@tonic-gate 		if (eri_mii_read(erip, ERI_PHY_BMCR, &control) == 1) {
52387c478bd9Sstevel@tonic-gate 			/* Transceiver does not talk MII */
52397c478bd9Sstevel@tonic-gate 			ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
5240d64540e3Sgd 			    "eri_reset_xcvr: no mii");
52417c478bd9Sstevel@tonic-gate 		}
52427c478bd9Sstevel@tonic-gate 		if ((control & PHY_BMCR_RESET) == 0)
52437c478bd9Sstevel@tonic-gate 			goto reset_done;
52447c478bd9Sstevel@tonic-gate 	}
52457c478bd9Sstevel@tonic-gate 	ERI_FAULT_MSG2(erip, SEVERITY_NONE, ERI_VERB_MSG,
5246d64540e3Sgd 	    "eri_reset_xcvr:reset_failed n == 0, control %x", control);
52477c478bd9Sstevel@tonic-gate 	goto eri_reset_xcvr_failed;
52487c478bd9Sstevel@tonic-gate 
52497c478bd9Sstevel@tonic-gate reset_done:
52507c478bd9Sstevel@tonic-gate 
52517c478bd9Sstevel@tonic-gate 	ERI_DEBUG_MSG2(erip, AUTOCONFIG_MSG,
5252d64540e3Sgd 	    "eri_reset_xcvr: reset complete in %d us",
5253d64540e3Sgd 	    (1000 - n) * PHYRST_PERIOD);
52547c478bd9Sstevel@tonic-gate 
52557c478bd9Sstevel@tonic-gate 	(void) eri_mii_read(erip, ERI_PHY_BMSR, &stat);
52567c478bd9Sstevel@tonic-gate 	(void) eri_mii_read(erip, ERI_PHY_ANAR, &anar);
52577c478bd9Sstevel@tonic-gate 	(void) eri_mii_read(erip, ERI_PHY_IDR1, &idr1);
52587c478bd9Sstevel@tonic-gate 	(void) eri_mii_read(erip, ERI_PHY_IDR2, &idr2);
52597c478bd9Sstevel@tonic-gate 
52607c478bd9Sstevel@tonic-gate 	ERI_DEBUG_MSG4(erip, XCVR_MSG,
5261d64540e3Sgd 	    "eri_reset_xcvr: control %x stat %x anar %x", control, stat, anar);
52627c478bd9Sstevel@tonic-gate 
52637c478bd9Sstevel@tonic-gate 	/*
52647c478bd9Sstevel@tonic-gate 	 * Initialize the read only transceiver ndd information
52657c478bd9Sstevel@tonic-gate 	 * the values are either 0 or 1.
52667c478bd9Sstevel@tonic-gate 	 */
52677c478bd9Sstevel@tonic-gate 	param_bmsr_ancap = 1 && (stat & PHY_BMSR_ACFG);
52687c478bd9Sstevel@tonic-gate 	param_bmsr_100T4 = 1 && (stat & PHY_BMSR_100T4);
52697c478bd9Sstevel@tonic-gate 	param_bmsr_100fdx = 1 && (stat & PHY_BMSR_100FDX);
52707c478bd9Sstevel@tonic-gate 	param_bmsr_100hdx = 1 && (stat & PHY_BMSR_100HDX);
52717c478bd9Sstevel@tonic-gate 	param_bmsr_10fdx = 1 && (stat & PHY_BMSR_10FDX);
52727c478bd9Sstevel@tonic-gate 	param_bmsr_10hdx = 1 && (stat & PHY_BMSR_10HDX);
52737c478bd9Sstevel@tonic-gate 
52747c478bd9Sstevel@tonic-gate 	/*
52757c478bd9Sstevel@tonic-gate 	 * Match up the ndd capabilities with the transceiver.
52767c478bd9Sstevel@tonic-gate 	 */
52777c478bd9Sstevel@tonic-gate 	param_autoneg &= param_bmsr_ancap;
52787c478bd9Sstevel@tonic-gate 	param_anar_100fdx &= param_bmsr_100fdx;
52797c478bd9Sstevel@tonic-gate 	param_anar_100hdx &= param_bmsr_100hdx;
52807c478bd9Sstevel@tonic-gate 	param_anar_10fdx &= param_bmsr_10fdx;
52817c478bd9Sstevel@tonic-gate 	param_anar_10hdx &= param_bmsr_10hdx;
52827c478bd9Sstevel@tonic-gate 
52837c478bd9Sstevel@tonic-gate 	/*
52847c478bd9Sstevel@tonic-gate 	 * Select the operation mode of the transceiver.
52857c478bd9Sstevel@tonic-gate 	 */
52867c478bd9Sstevel@tonic-gate 	if (param_autoneg) {
52877c478bd9Sstevel@tonic-gate 		/*
52887c478bd9Sstevel@tonic-gate 		 * Initialize our auto-negotiation capabilities.
52897c478bd9Sstevel@tonic-gate 		 */
52907c478bd9Sstevel@tonic-gate 		anar = PHY_SELECTOR;
52917c478bd9Sstevel@tonic-gate 		if (param_anar_100T4)
52927c478bd9Sstevel@tonic-gate 			anar |= PHY_ANAR_T4;
52937c478bd9Sstevel@tonic-gate 		if (param_anar_100fdx)
52947c478bd9Sstevel@tonic-gate 			anar |= PHY_ANAR_TXFDX;
52957c478bd9Sstevel@tonic-gate 		if (param_anar_100hdx)
52967c478bd9Sstevel@tonic-gate 			anar |= PHY_ANAR_TX;
52977c478bd9Sstevel@tonic-gate 		if (param_anar_10fdx)
52987c478bd9Sstevel@tonic-gate 			anar |= PHY_ANAR_10FDX;
52997c478bd9Sstevel@tonic-gate 		if (param_anar_10hdx)
53007c478bd9Sstevel@tonic-gate 			anar |= PHY_ANAR_10;
5301d64540e3Sgd 		ERI_DEBUG_MSG2(erip, XCVR_MSG, "anar = %x", anar);
53027c478bd9Sstevel@tonic-gate 		eri_mii_write(erip, ERI_PHY_ANAR, anar);
53037c478bd9Sstevel@tonic-gate 	}
53047c478bd9Sstevel@tonic-gate 
53057c478bd9Sstevel@tonic-gate 	/* Place the Transceiver in normal operation mode */
53067c478bd9Sstevel@tonic-gate 	if ((control & PHY_BMCR_ISOLATE) || (control & PHY_BMCR_LPBK)) {
53077c478bd9Sstevel@tonic-gate 		control &= ~(PHY_BMCR_ISOLATE | PHY_BMCR_LPBK);
53087c478bd9Sstevel@tonic-gate 		eri_mii_write(erip, ERI_PHY_BMCR,
5309d64540e3Sgd 		    (control & ~PHY_BMCR_ISOLATE));
53107c478bd9Sstevel@tonic-gate 	}
53117c478bd9Sstevel@tonic-gate 
53127c478bd9Sstevel@tonic-gate 	/*
53137c478bd9Sstevel@tonic-gate 	 * If Lu3X31T then allow nonzero eri_phy_mintrans
53147c478bd9Sstevel@tonic-gate 	 */
53157c478bd9Sstevel@tonic-gate 	if (eri_phy_mintrans &&
53167c478bd9Sstevel@tonic-gate 	    (idr1 != 0x43 || (idr2 & 0xFFF0) != 0x7420)) {
53177c478bd9Sstevel@tonic-gate 		eri_phy_mintrans = 0;
53187c478bd9Sstevel@tonic-gate 	}
53197c478bd9Sstevel@tonic-gate 	/*
53207c478bd9Sstevel@tonic-gate 	 * Initialize the mif interrupt mask.
53217c478bd9Sstevel@tonic-gate 	 */
53227c478bd9Sstevel@tonic-gate 	erip->mif_mask = (uint16_t)(~PHY_BMSR_RES1);
53237c478bd9Sstevel@tonic-gate 
53247c478bd9Sstevel@tonic-gate 	/*
53257c478bd9Sstevel@tonic-gate 	 * Establish link speeds and do necessary special stuff based
53267c478bd9Sstevel@tonic-gate 	 * in the speed.
53277c478bd9Sstevel@tonic-gate 	 */
53287c478bd9Sstevel@tonic-gate 	speed_100 = param_anar_100fdx | param_anar_100hdx;
53297c478bd9Sstevel@tonic-gate 	speed_10 = param_anar_10fdx | param_anar_10hdx;
53307c478bd9Sstevel@tonic-gate 
53317c478bd9Sstevel@tonic-gate 	ERI_DEBUG_MSG5(erip, XCVR_MSG, "eri_reset_xcvr: %d %d %d %d",
5332d64540e3Sgd 	    param_anar_100fdx, param_anar_100hdx, param_anar_10fdx,
5333d64540e3Sgd 	    param_anar_10hdx);
53347c478bd9Sstevel@tonic-gate 
53357c478bd9Sstevel@tonic-gate 	ERI_DEBUG_MSG3(erip, XCVR_MSG,
5336d64540e3Sgd 	    "eri_reset_xcvr: speed_100 %d speed_10 %d", speed_100, speed_10);
53377c478bd9Sstevel@tonic-gate 
53387c478bd9Sstevel@tonic-gate 	if ((!speed_100) && (speed_10)) {
53397c478bd9Sstevel@tonic-gate 		erip->mif_mask &= ~PHY_BMSR_JABDET;
53407c478bd9Sstevel@tonic-gate 		if (!(param_anar_10fdx) &&
53417c478bd9Sstevel@tonic-gate 		    (param_anar_10hdx) &&
53427c478bd9Sstevel@tonic-gate 		    (erip->link_pulse_disabled)) {
53437c478bd9Sstevel@tonic-gate 			param_speed = 0;
53447c478bd9Sstevel@tonic-gate 			param_mode = 0;
53457c478bd9Sstevel@tonic-gate 			(void) eri_mii_read(erip, ERI_PHY_NICR, &nicr);
53467c478bd9Sstevel@tonic-gate 			nicr &= ~PHY_NICR_LD;
53477c478bd9Sstevel@tonic-gate 			eri_mii_write(erip, ERI_PHY_NICR, nicr);
53487c478bd9Sstevel@tonic-gate 			param_linkup = 1;
5349d64540e3Sgd 			erip->stats.link_up = LINK_STATE_UP;
53507c478bd9Sstevel@tonic-gate 			if (param_mode)
5351d64540e3Sgd 				erip->stats.link_duplex = LINK_DUPLEX_FULL;
53527c478bd9Sstevel@tonic-gate 			else
5353d64540e3Sgd 				erip->stats.link_duplex = LINK_DUPLEX_HALF;
53547c478bd9Sstevel@tonic-gate 		}
53557c478bd9Sstevel@tonic-gate 	}
53567c478bd9Sstevel@tonic-gate 
53577c478bd9Sstevel@tonic-gate 	/*
53587c478bd9Sstevel@tonic-gate 	 * Clear the autonegotitation before re-starting
53597c478bd9Sstevel@tonic-gate 	 */
53607c478bd9Sstevel@tonic-gate 	control = PHY_BMCR_100M | PHY_BMCR_FDX;
53617c478bd9Sstevel@tonic-gate /*	eri_mii_write(erip, ERI_PHY_BMCR, control); */
53627c478bd9Sstevel@tonic-gate 	if (param_autoneg) {
53637c478bd9Sstevel@tonic-gate 		/*
53647c478bd9Sstevel@tonic-gate 		 * Setup the transceiver for autonegotiation.
53657c478bd9Sstevel@tonic-gate 		 */
53667c478bd9Sstevel@tonic-gate 		erip->mif_mask &= ~PHY_BMSR_ANC;
53677c478bd9Sstevel@tonic-gate 
53687c478bd9Sstevel@tonic-gate 		/*
53697c478bd9Sstevel@tonic-gate 		 * Clear the Auto-negotiation before re-starting
53707c478bd9Sstevel@tonic-gate 		 */
53717c478bd9Sstevel@tonic-gate 		eri_mii_write(erip, ERI_PHY_BMCR, control & ~PHY_BMCR_ANE);
53727c478bd9Sstevel@tonic-gate 
53737c478bd9Sstevel@tonic-gate 		/*
53747c478bd9Sstevel@tonic-gate 		 * Switch on auto-negotiation.
53757c478bd9Sstevel@tonic-gate 		 */
53767c478bd9Sstevel@tonic-gate 		control |= (PHY_BMCR_ANE | PHY_BMCR_RAN);
53777c478bd9Sstevel@tonic-gate 
53787c478bd9Sstevel@tonic-gate 		eri_mii_write(erip, ERI_PHY_BMCR, control);
53797c478bd9Sstevel@tonic-gate 	} else {
53807c478bd9Sstevel@tonic-gate 		/*
53817c478bd9Sstevel@tonic-gate 		 * Force the transceiver.
53827c478bd9Sstevel@tonic-gate 		 */
53837c478bd9Sstevel@tonic-gate 		erip->mif_mask &= ~PHY_BMSR_LNKSTS;
53847c478bd9Sstevel@tonic-gate 
53857c478bd9Sstevel@tonic-gate 		/*
53867c478bd9Sstevel@tonic-gate 		 * Switch off auto-negotiation.
53877c478bd9Sstevel@tonic-gate 		 */
53887c478bd9Sstevel@tonic-gate 		control &= ~(PHY_BMCR_FDX | PHY_BMCR_ANE | PHY_BMCR_RAN);
53897c478bd9Sstevel@tonic-gate 
53907c478bd9Sstevel@tonic-gate 		if (speed_100) {
53917c478bd9Sstevel@tonic-gate 			control |= PHY_BMCR_100M;
53927c478bd9Sstevel@tonic-gate 			param_aner_lpancap = 0; /* Clear LP nway */
53937c478bd9Sstevel@tonic-gate 			param_anlpar_10fdx = 0;
53947c478bd9Sstevel@tonic-gate 			param_anlpar_10hdx = 0;
53957c478bd9Sstevel@tonic-gate 			param_anlpar_100T4 = param_anar_100T4;
53967c478bd9Sstevel@tonic-gate 			param_anlpar_100fdx = param_anar_100fdx;
53977c478bd9Sstevel@tonic-gate 			param_anlpar_100hdx = param_anar_100hdx;
53987c478bd9Sstevel@tonic-gate 			param_speed = 1;
5399d64540e3Sgd 			erip->stats.ifspeed = 100;
54007c478bd9Sstevel@tonic-gate 			param_mode = param_anar_100fdx;
54017c478bd9Sstevel@tonic-gate 			if (param_mode) {
54027c478bd9Sstevel@tonic-gate 				param_anlpar_100hdx = 0;
5403d64540e3Sgd 				erip->stats.link_duplex = LINK_DUPLEX_FULL;
54047c478bd9Sstevel@tonic-gate 			} else {
5405d64540e3Sgd 				erip->stats.link_duplex = LINK_DUPLEX_HALF;
54067c478bd9Sstevel@tonic-gate 			}
54077c478bd9Sstevel@tonic-gate 		} else if (speed_10) {
54087c478bd9Sstevel@tonic-gate 			control &= ~PHY_BMCR_100M;
54097c478bd9Sstevel@tonic-gate 			param_aner_lpancap = 0; /* Clear LP nway */
54107c478bd9Sstevel@tonic-gate 			param_anlpar_100fdx = 0;
54117c478bd9Sstevel@tonic-gate 			param_anlpar_100hdx = 0;
54127c478bd9Sstevel@tonic-gate 			param_anlpar_100T4 = 0;
54137c478bd9Sstevel@tonic-gate 			param_anlpar_10fdx = param_anar_10fdx;
54147c478bd9Sstevel@tonic-gate 			param_anlpar_10hdx = param_anar_10hdx;
54157c478bd9Sstevel@tonic-gate 			param_speed = 0;
5416d64540e3Sgd 			erip->stats.ifspeed = 10;
54177c478bd9Sstevel@tonic-gate 			param_mode = param_anar_10fdx;
54187c478bd9Sstevel@tonic-gate 			if (param_mode) {
54197c478bd9Sstevel@tonic-gate 				param_anlpar_10hdx = 0;
5420d64540e3Sgd 				erip->stats.link_duplex = LINK_DUPLEX_FULL;
54217c478bd9Sstevel@tonic-gate 			} else {
5422d64540e3Sgd 				erip->stats.link_duplex = LINK_DUPLEX_HALF;
54237c478bd9Sstevel@tonic-gate 			}
54247c478bd9Sstevel@tonic-gate 		} else {
54257c478bd9Sstevel@tonic-gate 			ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_VERB_MSG,
5426d64540e3Sgd 			    "Transceiver speed set incorrectly.");
54277c478bd9Sstevel@tonic-gate 		}
54287c478bd9Sstevel@tonic-gate 
54297c478bd9Sstevel@tonic-gate 		if (param_mode) {
54307c478bd9Sstevel@tonic-gate 			control |= PHY_BMCR_FDX;
54317c478bd9Sstevel@tonic-gate 		}
54327c478bd9Sstevel@tonic-gate 
54337c478bd9Sstevel@tonic-gate 		ERI_DEBUG_MSG4(erip, PHY_MSG,
5434d64540e3Sgd 		    "control = %x status = %x param_mode %d",
5435d64540e3Sgd 		    control, stat, param_mode);
54367c478bd9Sstevel@tonic-gate 
54377c478bd9Sstevel@tonic-gate 		eri_mii_write(erip, ERI_PHY_BMCR, control);
54387c478bd9Sstevel@tonic-gate /*
54397c478bd9Sstevel@tonic-gate  *		if (param_mode) {
54407c478bd9Sstevel@tonic-gate  *			control |= PHY_BMCR_FDX;
54417c478bd9Sstevel@tonic-gate  *		}
54427c478bd9Sstevel@tonic-gate  *		control &= ~(PHY_BMCR_FDX | PHY_BMCR_ANE | PHY_BMCR_RAN);
54437c478bd9Sstevel@tonic-gate  *		eri_mii_write(erip, ERI_PHY_BMCR, control);
54447c478bd9Sstevel@tonic-gate  */
54457c478bd9Sstevel@tonic-gate 	}
54467c478bd9Sstevel@tonic-gate 
54477c478bd9Sstevel@tonic-gate #ifdef DEBUG
54487c478bd9Sstevel@tonic-gate 	(void) eri_mii_read(erip, ERI_PHY_BMCR, &control);
54497c478bd9Sstevel@tonic-gate 	(void) eri_mii_read(erip, ERI_PHY_BMSR, &stat);
54507c478bd9Sstevel@tonic-gate 	(void) eri_mii_read(erip, ERI_PHY_ANAR, &anar);
54517c478bd9Sstevel@tonic-gate #endif
54527c478bd9Sstevel@tonic-gate 	ERI_DEBUG_MSG4(erip, PHY_MSG,
5453d64540e3Sgd 	    "control %X status %X anar %X", control, stat, anar);
54547c478bd9Sstevel@tonic-gate 
54557c478bd9Sstevel@tonic-gate eri_reset_xcvr_exit:
54567c478bd9Sstevel@tonic-gate 	return (0);
54577c478bd9Sstevel@tonic-gate 
54587c478bd9Sstevel@tonic-gate eri_reset_xcvr_failed:
54597c478bd9Sstevel@tonic-gate 	return (1);
54607c478bd9Sstevel@tonic-gate }
54617c478bd9Sstevel@tonic-gate 
54627c478bd9Sstevel@tonic-gate #ifdef	ERI_10_10_FORCE_SPEED_WORKAROUND
54637c478bd9Sstevel@tonic-gate 
54647c478bd9Sstevel@tonic-gate static void
eri_xcvr_force_mode(struct eri * erip,uint32_t * link_timeout)54657c478bd9Sstevel@tonic-gate eri_xcvr_force_mode(struct eri *erip, uint32_t *link_timeout)
54667c478bd9Sstevel@tonic-gate {
54677c478bd9Sstevel@tonic-gate 
5468d64540e3Sgd 	if (!param_autoneg && !param_linkup && (erip->stats.ifspeed == 10) &&
5469d64540e3Sgd 	    (param_anar_10fdx | param_anar_10hdx)) {
54707c478bd9Sstevel@tonic-gate 		*link_timeout = SECOND(1);
54717c478bd9Sstevel@tonic-gate 		return;
54727c478bd9Sstevel@tonic-gate 	}
54737c478bd9Sstevel@tonic-gate 
5474d64540e3Sgd 	if (!param_autoneg && !param_linkup && (erip->ifspeed_old == 10) &&
5475d64540e3Sgd 	    (param_anar_100fdx | param_anar_100hdx)) {
54767c478bd9Sstevel@tonic-gate 		/*
54777c478bd9Sstevel@tonic-gate 		 * May have to set link partner's speed and mode.
54787c478bd9Sstevel@tonic-gate 		 */
54797c478bd9Sstevel@tonic-gate 		ERI_FAULT_MSG1(erip, SEVERITY_NONE, ERI_LOG_MSG,
54807c478bd9Sstevel@tonic-gate 		"May have to set link partner's speed and duplex mode.");
54817c478bd9Sstevel@tonic-gate 	}
54827c478bd9Sstevel@tonic-gate }
54837c478bd9Sstevel@tonic-gate #endif
54847c478bd9Sstevel@tonic-gate 
54857c478bd9Sstevel@tonic-gate static void
eri_mif_poll(struct eri * erip,soft_mif_enable_t enable)54867c478bd9Sstevel@tonic-gate eri_mif_poll(struct eri *erip, soft_mif_enable_t enable)
54877c478bd9Sstevel@tonic-gate {
54887c478bd9Sstevel@tonic-gate 	if (enable == MIF_POLL_START) {
5489d64540e3Sgd 		if (erip->mifpoll_enable && !erip->openloop_autoneg) {
54907c478bd9Sstevel@tonic-gate 			erip->mif_config |= ERI_MIF_CFGPE;
54917c478bd9Sstevel@tonic-gate 			PUT_MIFREG(mif_cfg, erip->mif_config);
54927c478bd9Sstevel@tonic-gate 			drv_usecwait(ERI_MIF_POLL_DELAY);
54937c478bd9Sstevel@tonic-gate 			PUT_GLOBREG(intmask, GET_GLOBREG(intmask) &
5494d64540e3Sgd 			    ~ERI_G_MASK_MIF_INT);
54957c478bd9Sstevel@tonic-gate 			PUT_MIFREG(mif_imask, erip->mif_mask);
54967c478bd9Sstevel@tonic-gate 		}
54977c478bd9Sstevel@tonic-gate 	} else if (enable == MIF_POLL_STOP) {
54987c478bd9Sstevel@tonic-gate 			erip->mif_config &= ~ERI_MIF_CFGPE;
54997c478bd9Sstevel@tonic-gate 			PUT_MIFREG(mif_cfg, erip->mif_config);
55007c478bd9Sstevel@tonic-gate 			drv_usecwait(ERI_MIF_POLL_DELAY);
55017c478bd9Sstevel@tonic-gate 			PUT_GLOBREG(intmask, GET_GLOBREG(intmask) |
5502d64540e3Sgd 			    ERI_G_MASK_MIF_INT);
55037c478bd9Sstevel@tonic-gate 			PUT_MIFREG(mif_imask, ERI_MIF_INTMASK);
55047c478bd9Sstevel@tonic-gate 	}
55057c478bd9Sstevel@tonic-gate 	ERI_DEBUG_MSG2(erip, XCVR_MSG, "MIF Config = 0x%X",
5506d64540e3Sgd 	    GET_MIFREG(mif_cfg));
55077c478bd9Sstevel@tonic-gate 	ERI_DEBUG_MSG2(erip, XCVR_MSG, "MIF imask = 0x%X",
5508d64540e3Sgd 	    GET_MIFREG(mif_imask));
55097c478bd9Sstevel@tonic-gate 	ERI_DEBUG_MSG2(erip, XCVR_MSG, "INT imask = 0x%X",
5510d64540e3Sgd 	    GET_GLOBREG(intmask));
55117c478bd9Sstevel@tonic-gate 	ERI_DEBUG_MSG1(erip, XCVR_MSG, "<== mif_poll");
55127c478bd9Sstevel@tonic-gate }
55137c478bd9Sstevel@tonic-gate 
55147c478bd9Sstevel@tonic-gate /* Decide if transmitter went dead and reinitialize everything */
55157c478bd9Sstevel@tonic-gate #ifdef	ERI_TX_HUNG
55167c478bd9Sstevel@tonic-gate static int eri_txhung_limit = 2;
55177c478bd9Sstevel@tonic-gate static int
eri_check_txhung(struct eri * erip)55187c478bd9Sstevel@tonic-gate eri_check_txhung(struct eri *erip)
55197c478bd9Sstevel@tonic-gate {
5520d64540e3Sgd 	boolean_t	macupdate = B_FALSE;
5521d64540e3Sgd 
55227c478bd9Sstevel@tonic-gate 	mutex_enter(&erip->xmitlock);
5523*7e996435SToomas Soome 	if (erip->flags & ERI_RUNNING) {
5524d64540e3Sgd 		erip->tx_completion = (uint32_t)(GET_ETXREG(tx_completion) &
5525d64540e3Sgd 		    ETX_COMPLETION_MASK);
5526d64540e3Sgd 		macupdate |= eri_reclaim(erip, erip->tx_completion);
5527*7e996435SToomas Soome 	}
55287c478bd9Sstevel@tonic-gate 
55297c478bd9Sstevel@tonic-gate 	/* Something needs to be sent out but it is not going out */
55307c478bd9Sstevel@tonic-gate 	if ((erip->tcurp != erip->tnextp) &&
55317c478bd9Sstevel@tonic-gate 	    (erip->stats.opackets64 == erip->erisave.reclaim_opackets) &&
55327c478bd9Sstevel@tonic-gate 	    (erip->stats.collisions == erip->erisave.starts))
55337c478bd9Sstevel@tonic-gate 		erip->txhung++;
55347c478bd9Sstevel@tonic-gate 	else
55357c478bd9Sstevel@tonic-gate 		erip->txhung = 0;
55367c478bd9Sstevel@tonic-gate 
55377c478bd9Sstevel@tonic-gate 	erip->erisave.reclaim_opackets = erip->stats.opackets64;
55387c478bd9Sstevel@tonic-gate 	erip->erisave.starts = erip->stats.collisions;
55397c478bd9Sstevel@tonic-gate 	mutex_exit(&erip->xmitlock);
55407c478bd9Sstevel@tonic-gate 
5541d64540e3Sgd 	if (macupdate)
5542d64540e3Sgd 		mac_tx_update(erip->mh);
5543d64540e3Sgd 
55447c478bd9Sstevel@tonic-gate 	return (erip->txhung >= eri_txhung_limit);
55457c478bd9Sstevel@tonic-gate }
55467c478bd9Sstevel@tonic-gate #endif
5547